xref: /netbsd-src/sys/external/bsd/drm2/dist/drm/nouveau/nvkm/subdev/bios/nouveau_nvkm_subdev_bios_dp.c (revision 41ec02673d281bbb3d38e6c78504ce6e30c228c1)
1 /*	$NetBSD: nouveau_nvkm_subdev_bios_dp.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_dp.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/dp.h>
32 
33 u16
nvbios_dp_table(struct nvkm_bios * bios,u8 * ver,u8 * hdr,u8 * cnt,u8 * len)34 nvbios_dp_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
35 {
36 	struct bit_entry d;
37 
38 	if (!bit_entry(bios, 'd', &d)) {
39 		if (d.version == 1 && d.length >= 2) {
40 			u16 data = nvbios_rd16(bios, d.offset);
41 			if (data) {
42 				*ver = nvbios_rd08(bios, data + 0x00);
43 				switch (*ver) {
44 				case 0x20:
45 				case 0x21:
46 				case 0x30:
47 				case 0x40:
48 				case 0x41:
49 				case 0x42:
50 					*hdr = nvbios_rd08(bios, data + 0x01);
51 					*len = nvbios_rd08(bios, data + 0x02);
52 					*cnt = nvbios_rd08(bios, data + 0x03);
53 					return data;
54 				default:
55 					break;
56 				}
57 			}
58 		}
59 	}
60 
61 	return 0x0000;
62 }
63 
64 static u16
nvbios_dpout_entry(struct nvkm_bios * bios,u8 idx,u8 * ver,u8 * hdr,u8 * cnt,u8 * len)65 nvbios_dpout_entry(struct nvkm_bios *bios, u8 idx,
66 		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
67 {
68 	u16 data = nvbios_dp_table(bios, ver, hdr, cnt, len);
69 	if (data && idx < *cnt) {
70 		u16 outp = nvbios_rd16(bios, data + *hdr + idx * *len);
71 		switch (*ver * !!outp) {
72 		case 0x20:
73 		case 0x21:
74 		case 0x30:
75 			*hdr = nvbios_rd08(bios, data + 0x04);
76 			*len = nvbios_rd08(bios, data + 0x05);
77 			*cnt = nvbios_rd08(bios, outp + 0x04);
78 			break;
79 		case 0x40:
80 		case 0x41:
81 		case 0x42:
82 			*hdr = nvbios_rd08(bios, data + 0x04);
83 			*cnt = 0;
84 			*len = 0;
85 			break;
86 		default:
87 			break;
88 		}
89 		return outp;
90 	}
91 	*ver = 0x00;
92 	return 0x0000;
93 }
94 
95 u16
nvbios_dpout_parse(struct nvkm_bios * bios,u8 idx,u8 * ver,u8 * hdr,u8 * cnt,u8 * len,struct nvbios_dpout * info)96 nvbios_dpout_parse(struct nvkm_bios *bios, u8 idx,
97 		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
98 		   struct nvbios_dpout *info)
99 {
100 	u16 data = nvbios_dpout_entry(bios, idx, ver, hdr, cnt, len);
101 	memset(info, 0x00, sizeof(*info));
102 	if (data && *ver) {
103 		info->type = nvbios_rd16(bios, data + 0x00);
104 		info->mask = nvbios_rd16(bios, data + 0x02);
105 		switch (*ver) {
106 		case 0x20:
107 			info->mask |= 0x00c0; /* match any link */
108 			/* fall-through */
109 		case 0x21:
110 		case 0x30:
111 			info->flags     = nvbios_rd08(bios, data + 0x05);
112 			info->script[0] = nvbios_rd16(bios, data + 0x06);
113 			info->script[1] = nvbios_rd16(bios, data + 0x08);
114 			if (*len >= 0x0c)
115 				info->lnkcmp    = nvbios_rd16(bios, data + 0x0a);
116 			if (*len >= 0x0f) {
117 				info->script[2] = nvbios_rd16(bios, data + 0x0c);
118 				info->script[3] = nvbios_rd16(bios, data + 0x0e);
119 			}
120 			if (*len >= 0x11)
121 				info->script[4] = nvbios_rd16(bios, data + 0x10);
122 			break;
123 		case 0x40:
124 		case 0x41:
125 		case 0x42:
126 			info->flags     = nvbios_rd08(bios, data + 0x04);
127 			info->script[0] = nvbios_rd16(bios, data + 0x05);
128 			info->script[1] = nvbios_rd16(bios, data + 0x07);
129 			info->lnkcmp    = nvbios_rd16(bios, data + 0x09);
130 			info->script[2] = nvbios_rd16(bios, data + 0x0b);
131 			info->script[3] = nvbios_rd16(bios, data + 0x0d);
132 			info->script[4] = nvbios_rd16(bios, data + 0x0f);
133 			break;
134 		default:
135 			data = 0x0000;
136 			break;
137 		}
138 	}
139 	return data;
140 }
141 
142 u16
nvbios_dpout_match(struct nvkm_bios * bios,u16 type,u16 mask,u8 * ver,u8 * hdr,u8 * cnt,u8 * len,struct nvbios_dpout * info)143 nvbios_dpout_match(struct nvkm_bios *bios, u16 type, u16 mask,
144 		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
145 		   struct nvbios_dpout *info)
146 {
147 	u16 data, idx = 0;
148 	while ((data = nvbios_dpout_parse(bios, idx++, ver, hdr, cnt, len, info)) || *ver) {
149 		if (data && info->type == type) {
150 			if ((info->mask & mask) == mask)
151 				break;
152 		}
153 	}
154 	return data;
155 }
156 
157 static u16
nvbios_dpcfg_entry(struct nvkm_bios * bios,u16 outp,u8 idx,u8 * ver,u8 * hdr,u8 * cnt,u8 * len)158 nvbios_dpcfg_entry(struct nvkm_bios *bios, u16 outp, u8 idx,
159 		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
160 {
161 	if (*ver >= 0x40) {
162 		outp = nvbios_dp_table(bios, ver, hdr, cnt, len);
163 		*hdr = *hdr + (*len * * cnt);
164 		*len = nvbios_rd08(bios, outp + 0x06);
165 		*cnt = nvbios_rd08(bios, outp + 0x07) *
166 		       nvbios_rd08(bios, outp + 0x05);
167 	}
168 
169 	if (idx < *cnt)
170 		return outp + *hdr + (idx * *len);
171 
172 	return 0x0000;
173 }
174 
175 u16
nvbios_dpcfg_parse(struct nvkm_bios * bios,u16 outp,u8 idx,u8 * ver,u8 * hdr,u8 * cnt,u8 * len,struct nvbios_dpcfg * info)176 nvbios_dpcfg_parse(struct nvkm_bios *bios, u16 outp, u8 idx,
177 		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
178 		   struct nvbios_dpcfg *info)
179 {
180 	u16 data = nvbios_dpcfg_entry(bios, outp, idx, ver, hdr, cnt, len);
181 	memset(info, 0x00, sizeof(*info));
182 	if (data) {
183 		switch (*ver) {
184 		case 0x20:
185 		case 0x21:
186 			info->dc    = nvbios_rd08(bios, data + 0x02);
187 			info->pe    = nvbios_rd08(bios, data + 0x03);
188 			info->tx_pu = nvbios_rd08(bios, data + 0x04);
189 			break;
190 		case 0x30:
191 		case 0x40:
192 		case 0x41:
193 			info->pc    = nvbios_rd08(bios, data + 0x00);
194 			info->dc    = nvbios_rd08(bios, data + 0x01);
195 			info->pe    = nvbios_rd08(bios, data + 0x02);
196 			info->tx_pu = nvbios_rd08(bios, data + 0x03);
197 			break;
198 		case 0x42:
199 			info->dc    = nvbios_rd08(bios, data + 0x00);
200 			info->pe    = nvbios_rd08(bios, data + 0x01);
201 			info->tx_pu = nvbios_rd08(bios, data + 0x02);
202 			break;
203 		default:
204 			data = 0x0000;
205 			break;
206 		}
207 	}
208 	return data;
209 }
210 
211 u16
nvbios_dpcfg_match(struct nvkm_bios * bios,u16 outp,u8 pc,u8 vs,u8 pe,u8 * ver,u8 * hdr,u8 * cnt,u8 * len,struct nvbios_dpcfg * info)212 nvbios_dpcfg_match(struct nvkm_bios *bios, u16 outp, u8 pc, u8 vs, u8 pe,
213 		   u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
214 		   struct nvbios_dpcfg *info)
215 {
216 	u8 idx = 0xff;
217 	u16 data;
218 
219 	if (*ver >= 0x30) {
220 		static const u8 vsoff[] = { 0, 4, 7, 9 };
221 		idx = (pc * 10) + vsoff[vs] + pe;
222 		if (*ver >= 0x40 && *ver <= 0x41 && *hdr >= 0x12)
223 			idx += nvbios_rd08(bios, outp + 0x11) * 40;
224 		else
225 		if (*ver >= 0x42)
226 			idx += nvbios_rd08(bios, outp + 0x11) * 10;
227 	} else {
228 		while ((data = nvbios_dpcfg_entry(bios, outp, ++idx,
229 						  ver, hdr, cnt, len))) {
230 			if (nvbios_rd08(bios, data + 0x00) == vs &&
231 			    nvbios_rd08(bios, data + 0x01) == pe)
232 				break;
233 		}
234 	}
235 
236 	return nvbios_dpcfg_parse(bios, outp, idx, ver, hdr, cnt, len, info);
237 }
238