xref: /netbsd-src/sys/external/bsd/drm2/dist/drm/nouveau/nvkm/subdev/bios/nouveau_nvkm_subdev_bios_mxm.c (revision 41ec02673d281bbb3d38e6c78504ce6e30c228c1)
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
mxm_table(struct nvkm_bios * bios,u8 * ver,u8 * hdr)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
mxm_sor_map(struct nvkm_bios * bios,u8 conn)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
mxm_ddc_map(struct nvkm_bios * bios,u8 port)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