]>
Commit | Line | Data |
---|---|---|
e0996aea BS |
1 | /* |
2 | * Copyright 2012 Red Hat Inc. | |
3 | * | |
4 | * Permission is hereby granted, free of charge, to any person obtaining a | |
5 | * copy of this software and associated documentation files (the "Software"), | |
6 | * to deal in the Software without restriction, including without limitation | |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
8 | * and/or sell copies of the Software, and to permit persons to whom the | |
9 | * Software is furnished to do so, subject to the following conditions: | |
10 | * | |
11 | * The above copyright notice and this permission notice shall be included in | |
12 | * all copies or substantial portions of the Software. | |
13 | * | |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
20 | * OTHER DEALINGS IN THE SOFTWARE. | |
21 | * | |
22 | * Authors: Ben Skeggs | |
23 | */ | |
d390b480 BS |
24 | #include <subdev/bios.h> |
25 | #include <subdev/bios/dcb.h> | |
e0996aea | 26 | |
d390b480 | 27 | #include <core/device.h> |
e0996aea BS |
28 | |
29 | u16 | |
d390b480 | 30 | dcb_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) |
e0996aea | 31 | { |
d390b480 | 32 | struct nvkm_device *device = nv_device(bios); |
e0996aea BS |
33 | u16 dcb = 0x0000; |
34 | ||
35 | if (device->card_type > NV_04) | |
36 | dcb = nv_ro16(bios, 0x36); | |
37 | if (!dcb) { | |
38 | nv_warn(bios, "DCB table not found\n"); | |
39 | return dcb; | |
40 | } | |
41 | ||
42 | *ver = nv_ro08(bios, dcb); | |
43 | ||
dae20439 | 44 | if (*ver >= 0x42) { |
565f571c | 45 | nv_warn(bios, "DCB version 0x%02x unknown\n", *ver); |
e0996aea BS |
46 | return 0x0000; |
47 | } else | |
48 | if (*ver >= 0x30) { | |
49 | if (nv_ro32(bios, dcb + 6) == 0x4edcbdcb) { | |
50 | *hdr = nv_ro08(bios, dcb + 1); | |
51 | *cnt = nv_ro08(bios, dcb + 2); | |
52 | *len = nv_ro08(bios, dcb + 3); | |
53 | return dcb; | |
54 | } | |
55 | } else | |
56 | if (*ver >= 0x20) { | |
57 | if (nv_ro32(bios, dcb + 4) == 0x4edcbdcb) { | |
58 | u16 i2c = nv_ro16(bios, dcb + 2); | |
59 | *hdr = 8; | |
60 | *cnt = (i2c - dcb) / 8; | |
61 | *len = 8; | |
62 | return dcb; | |
63 | } | |
64 | } else | |
65 | if (*ver >= 0x15) { | |
3bb076af | 66 | if (!nv_memcmp(bios, dcb - 7, "DEV_REC", 7)) { |
e0996aea BS |
67 | u16 i2c = nv_ro16(bios, dcb + 2); |
68 | *hdr = 4; | |
69 | *cnt = (i2c - dcb) / 10; | |
70 | *len = 10; | |
71 | return dcb; | |
72 | } | |
73 | } else { | |
74 | /* | |
75 | * v1.4 (some NV15/16, NV11+) seems the same as v1.5, but | |
76 | * always has the same single (crt) entry, even when tv-out | |
77 | * present, so the conclusion is this version cannot really | |
78 | * be used. | |
79 | * | |
80 | * v1.2 tables (some NV6/10, and NV15+) normally have the | |
81 | * same 5 entries, which are not specific to the card and so | |
82 | * no use. | |
83 | * | |
84 | * v1.2 does have an I2C table that read_dcb_i2c_table can | |
85 | * handle, but cards exist (nv11 in #14821) with a bad i2c | |
86 | * table pointer, so use the indices parsed in | |
87 | * parse_bmp_structure. | |
88 | * | |
89 | * v1.1 (NV5+, maybe some NV4) is entirely unhelpful | |
90 | */ | |
91 | nv_warn(bios, "DCB contains no useful data\n"); | |
92 | return 0x0000; | |
93 | } | |
94 | ||
95 | nv_warn(bios, "DCB header validation failed\n"); | |
96 | return 0x0000; | |
97 | } | |
98 | ||
99 | u16 | |
d390b480 | 100 | dcb_outp(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len) |
e0996aea BS |
101 | { |
102 | u8 hdr, cnt; | |
103 | u16 dcb = dcb_table(bios, ver, &hdr, &cnt, len); | |
104 | if (dcb && idx < cnt) | |
105 | return dcb + hdr + (idx * *len); | |
106 | return 0x0000; | |
107 | } | |
108 | ||
8e992c8d BS |
109 | static inline u16 |
110 | dcb_outp_hasht(struct dcb_output *outp) | |
111 | { | |
112 | return (outp->extdev << 8) | (outp->location << 4) | outp->type; | |
113 | } | |
114 | ||
115 | static inline u16 | |
116 | dcb_outp_hashm(struct dcb_output *outp) | |
117 | { | |
118 | return (outp->heads << 8) | (outp->link << 6) | outp->or; | |
119 | } | |
120 | ||
75f8693f | 121 | u16 |
d390b480 | 122 | dcb_outp_parse(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len, |
75f8693f BS |
123 | struct dcb_output *outp) |
124 | { | |
125 | u16 dcb = dcb_outp(bios, idx, ver, len); | |
595d373f | 126 | memset(outp, 0x00, sizeof(*outp)); |
75f8693f BS |
127 | if (dcb) { |
128 | if (*ver >= 0x20) { | |
129 | u32 conn = nv_ro32(bios, dcb + 0x00); | |
130 | outp->or = (conn & 0x0f000000) >> 24; | |
131 | outp->location = (conn & 0x00300000) >> 20; | |
132 | outp->bus = (conn & 0x000f0000) >> 16; | |
133 | outp->connector = (conn & 0x0000f000) >> 12; | |
134 | outp->heads = (conn & 0x00000f00) >> 8; | |
135 | outp->i2c_index = (conn & 0x000000f0) >> 4; | |
136 | outp->type = (conn & 0x0000000f); | |
137 | outp->link = 0; | |
138 | } else { | |
139 | dcb = 0x0000; | |
140 | } | |
141 | ||
142 | if (*ver >= 0x40) { | |
143 | u32 conf = nv_ro32(bios, dcb + 0x04); | |
144 | switch (outp->type) { | |
fc243d7f BS |
145 | case DCB_OUTPUT_DP: |
146 | switch (conf & 0x00e00000) { | |
147 | case 0x00000000: | |
148 | outp->dpconf.link_bw = 0x06; | |
149 | break; | |
150 | case 0x00200000: | |
151 | outp->dpconf.link_bw = 0x0a; | |
152 | break; | |
153 | case 0x00400000: | |
154 | default: | |
155 | outp->dpconf.link_bw = 0x14; | |
156 | break; | |
157 | } | |
158 | ||
dae20439 BS |
159 | outp->dpconf.link_nr = (conf & 0x0f000000) >> 24; |
160 | if (*ver < 0x41) { | |
161 | switch (outp->dpconf.link_nr) { | |
162 | case 0x0f: | |
163 | outp->dpconf.link_nr = 4; | |
164 | break; | |
165 | case 0x03: | |
166 | outp->dpconf.link_nr = 2; | |
167 | break; | |
168 | case 0x01: | |
169 | default: | |
170 | outp->dpconf.link_nr = 1; | |
171 | break; | |
172 | } | |
fc243d7f BS |
173 | } |
174 | ||
175 | /* fall-through... */ | |
75f8693f BS |
176 | case DCB_OUTPUT_TMDS: |
177 | case DCB_OUTPUT_LVDS: | |
75f8693f BS |
178 | outp->link = (conf & 0x00000030) >> 4; |
179 | outp->sorconf.link = outp->link; /*XXX*/ | |
f3ed1048 BS |
180 | outp->extdev = 0x00; |
181 | if (outp->location != 0) | |
182 | outp->extdev = (conf & 0x0000ff00) >> 8; | |
75f8693f BS |
183 | break; |
184 | default: | |
185 | break; | |
186 | } | |
187 | } | |
8e992c8d BS |
188 | |
189 | outp->hasht = dcb_outp_hasht(outp); | |
190 | outp->hashm = dcb_outp_hashm(outp); | |
75f8693f BS |
191 | } |
192 | return dcb; | |
193 | } | |
194 | ||
75f8693f | 195 | u16 |
d390b480 | 196 | dcb_outp_match(struct nvkm_bios *bios, u16 type, u16 mask, |
75f8693f BS |
197 | u8 *ver, u8 *len, struct dcb_output *outp) |
198 | { | |
199 | u16 dcb, idx = 0; | |
200 | while ((dcb = dcb_outp_parse(bios, idx++, ver, len, outp))) { | |
8e992c8d | 201 | if ((dcb_outp_hasht(outp) & 0x00ff) == (type & 0x00ff)) { |
75f8693f BS |
202 | if ((dcb_outp_hashm(outp) & mask) == mask) |
203 | break; | |
204 | } | |
205 | } | |
206 | return dcb; | |
207 | } | |
208 | ||
e0996aea | 209 | int |
d390b480 BS |
210 | dcb_outp_foreach(struct nvkm_bios *bios, void *data, |
211 | int (*exec)(struct nvkm_bios *, void *, int, u16)) | |
e0996aea BS |
212 | { |
213 | int ret, idx = -1; | |
214 | u8 ver, len; | |
215 | u16 outp; | |
216 | ||
217 | while ((outp = dcb_outp(bios, ++idx, &ver, &len))) { | |
218 | if (nv_ro32(bios, outp) == 0x00000000) | |
219 | break; /* seen on an NV11 with DCB v1.5 */ | |
220 | if (nv_ro32(bios, outp) == 0xffffffff) | |
221 | break; /* seen on an NV17 with DCB v2.0 */ | |
222 | ||
223 | if (nv_ro08(bios, outp) == DCB_OUTPUT_UNUSED) | |
224 | continue; | |
225 | if (nv_ro08(bios, outp) == DCB_OUTPUT_EOL) | |
226 | break; | |
227 | ||
228 | ret = exec(bios, data, idx, outp); | |
229 | if (ret) | |
230 | return ret; | |
231 | } | |
232 | ||
233 | return 0; | |
234 | } |