Home | History | Annotate | Line # | Download | only in bios
      1 /*	$NetBSD: nouveau_nvkm_subdev_bios_mxm.c,v 1.3 2021/12/18 23:45:38 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright 2012 Red Hat Inc.
      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: Ben Skeggs
     25  */
     26 #include <sys/cdefs.h>
     27 __KERNEL_RCSID(0, "$NetBSD: nouveau_nvkm_subdev_bios_mxm.c,v 1.3 2021/12/18 23:45:38 riastradh Exp $");
     28 
     29 #include <subdev/bios.h>
     30 #include <subdev/bios/bit.h>
     31 #include <subdev/bios/mxm.h>
     32 
     33 u16
     34 mxm_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr)
     35 {
     36 	struct nvkm_subdev *subdev = &bios->subdev;
     37 	struct bit_entry x;
     38 
     39 	if (bit_entry(bios, 'x', &x)) {
     40 		nvkm_debug(subdev, "BIT 'x' table not present\n");
     41 		return 0x0000;
     42 	}
     43 
     44 	*ver = x.version;
     45 	*hdr = x.length;
     46 	if (*ver != 1 || *hdr < 3) {
     47 		nvkm_warn(subdev, "BIT 'x' table %d/%d unknown\n", *ver, *hdr);
     48 		return 0x0000;
     49 	}
     50 
     51 	return x.offset;
     52 }
     53 
     54 /* These map MXM v2.x digital connection values to the appropriate SOR/link,
     55  * hopefully they're correct for all boards within the same chipset...
     56  *
     57  * MXM v3.x VBIOS are nicer and provide pointers to these tables.
     58  */
     59 static u8 g84_sor_map[16] = {
     60 	0x00, 0x12, 0x22, 0x11, 0x32, 0x31, 0x11, 0x31,
     61 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
     62 };
     63 
     64 static u8 g92_sor_map[16] = {
     65 	0x00, 0x12, 0x22, 0x11, 0x32, 0x31, 0x11, 0x31,
     66 	0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
     67 };
     68 
     69 static u8 g94_sor_map[16] = {
     70 	0x00, 0x14, 0x24, 0x11, 0x34, 0x31, 0x11, 0x31,
     71 	0x11, 0x31, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00
     72 };
     73 
     74 static u8 g98_sor_map[16] = {
     75 	0x00, 0x14, 0x12, 0x11, 0x00, 0x31, 0x11, 0x31,
     76 	0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
     77 };
     78 
     79 u8
     80 mxm_sor_map(struct nvkm_bios *bios, u8 conn)
     81 {
     82 	struct nvkm_subdev *subdev = &bios->subdev;
     83 	u8  ver, hdr;
     84 	u16 mxm = mxm_table(bios, &ver, &hdr);
     85 	if (mxm && hdr >= 6) {
     86 		u16 map = nvbios_rd16(bios, mxm + 4);
     87 		if (map) {
     88 			ver = nvbios_rd08(bios, map);
     89 			if (ver == 0x10 || ver == 0x11) {
     90 				if (conn < nvbios_rd08(bios, map + 3)) {
     91 					map += nvbios_rd08(bios, map + 1);
     92 					map += conn;
     93 					return nvbios_rd08(bios, map);
     94 				}
     95 
     96 				return 0x00;
     97 			}
     98 
     99 			nvkm_warn(subdev, "unknown sor map v%02x\n", ver);
    100 		}
    101 	}
    102 
    103 	if (bios->version.chip == 0x84 || bios->version.chip == 0x86)
    104 		return g84_sor_map[conn];
    105 	if (bios->version.chip == 0x92)
    106 		return g92_sor_map[conn];
    107 	if (bios->version.chip == 0x94 || bios->version.chip == 0x96)
    108 		return g94_sor_map[conn];
    109 	if (bios->version.chip == 0x98)
    110 		return g98_sor_map[conn];
    111 
    112 	nvkm_warn(subdev, "missing sor map\n");
    113 	return 0x00;
    114 }
    115 
    116 u8
    117 mxm_ddc_map(struct nvkm_bios *bios, u8 port)
    118 {
    119 	struct nvkm_subdev *subdev = &bios->subdev;
    120 	u8  ver, hdr;
    121 	u16 mxm = mxm_table(bios, &ver, &hdr);
    122 	if (mxm && hdr >= 8) {
    123 		u16 map = nvbios_rd16(bios, mxm + 6);
    124 		if (map) {
    125 			ver = nvbios_rd08(bios, map);
    126 			if (ver == 0x10) {
    127 				if (port < nvbios_rd08(bios, map + 3)) {
    128 					map += nvbios_rd08(bios, map + 1);
    129 					map += port;
    130 					return nvbios_rd08(bios, map);
    131 				}
    132 
    133 				return 0x00;
    134 			}
    135 
    136 			nvkm_warn(subdev, "unknown ddc map v%02x\n", ver);
    137 		}
    138 	}
    139 
    140 	/* v2.x: directly write port as dcb i2cidx */
    141 	return (port << 4) | port;
    142 }
    143