Home | History | Annotate | Line # | Download | only in bios
      1 /*	$NetBSD: nouveau_nvkm_subdev_bios_extdev.c,v 1.3 2021/12/18 23:45:38 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright 2012 Nouveau Community
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     22  * OTHER DEALINGS IN THE SOFTWARE.
     23  *
     24  * Authors: Martin Peres
     25  */
     26 #include <sys/cdefs.h>
     27 __KERNEL_RCSID(0, "$NetBSD: nouveau_nvkm_subdev_bios_extdev.c,v 1.3 2021/12/18 23:45:38 riastradh Exp $");
     28 
     29 #include <subdev/bios.h>
     30 #include <subdev/bios/dcb.h>
     31 #include <subdev/bios/extdev.h>
     32 
     33 static u16
     34 extdev_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *len, u8 *cnt)
     35 {
     36 	u8  dcb_ver, dcb_hdr, dcb_cnt, dcb_len;
     37 	u16 dcb, extdev = 0;
     38 
     39 	dcb = dcb_table(bios, &dcb_ver, &dcb_hdr, &dcb_cnt, &dcb_len);
     40 	if (!dcb || (dcb_ver != 0x30 && dcb_ver != 0x40 && dcb_ver != 0x41))
     41 		return 0x0000;
     42 
     43 	extdev = nvbios_rd16(bios, dcb + 18);
     44 	if (!extdev)
     45 		return 0x0000;
     46 
     47 	*ver = nvbios_rd08(bios, extdev + 0);
     48 	*hdr = nvbios_rd08(bios, extdev + 1);
     49 	*cnt = nvbios_rd08(bios, extdev + 2);
     50 	*len = nvbios_rd08(bios, extdev + 3);
     51 	return extdev + *hdr;
     52 }
     53 
     54 bool
     55 nvbios_extdev_skip_probe(struct nvkm_bios *bios)
     56 {
     57 	u8  ver, hdr, len, cnt;
     58 	u16 data = extdev_table(bios, &ver, &hdr, &len, &cnt);
     59 	if (data && ver == 0x40 && hdr >= 5) {
     60 		u8 flags = nvbios_rd08(bios, data - hdr + 4);
     61 		if (flags & 1)
     62 			return true;
     63 	}
     64 	return false;
     65 }
     66 
     67 static u16
     68 nvbios_extdev_entry(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len)
     69 {
     70 	u8 hdr, cnt;
     71 	u16 extdev = extdev_table(bios, ver, &hdr, len, &cnt);
     72 	if (extdev && idx < cnt)
     73 		return extdev + idx * *len;
     74 	return 0x0000;
     75 }
     76 
     77 static void
     78 extdev_parse_entry(struct nvkm_bios *bios, u16 offset,
     79 		   struct nvbios_extdev_func *entry)
     80 {
     81 	entry->type = nvbios_rd08(bios, offset + 0);
     82 	entry->addr = nvbios_rd08(bios, offset + 1);
     83 	entry->bus = (nvbios_rd08(bios, offset + 2) >> 4) & 1;
     84 }
     85 
     86 int
     87 nvbios_extdev_parse(struct nvkm_bios *bios, int idx,
     88 		    struct nvbios_extdev_func *func)
     89 {
     90 	u8 ver, len;
     91 	u16 entry;
     92 
     93 	if (!(entry = nvbios_extdev_entry(bios, idx, &ver, &len)))
     94 		return -EINVAL;
     95 
     96 	extdev_parse_entry(bios, entry, func);
     97 	return 0;
     98 }
     99 
    100 int
    101 nvbios_extdev_find(struct nvkm_bios *bios, enum nvbios_extdev_type type,
    102 		   struct nvbios_extdev_func *func)
    103 {
    104 	u8 ver, len, i;
    105 	u16 entry;
    106 
    107 	i = 0;
    108 	while ((entry = nvbios_extdev_entry(bios, i++, &ver, &len))) {
    109 		extdev_parse_entry(bios, entry, func);
    110 		if (func->type == type)
    111 			return 0;
    112 	}
    113 
    114 	return -EINVAL;
    115 }
    116