1 | /* SPDX-License-Identifier: MIT */ |
2 | /* |
3 | * drm_panel_orientation_quirks.c -- Quirks for non-normal panel orientation |
4 | * |
5 | * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com> |
6 | * |
7 | * Note the quirks in this file are shared with fbdev/efifb and as such |
8 | * must not depend on other drm code. |
9 | */ |
10 | |
11 | #include <linux/dmi.h> |
12 | #include <linux/module.h> |
13 | #include <drm/drm_connector.h> |
14 | #include <drm/drm_utils.h> |
15 | |
16 | #ifdef CONFIG_DMI |
17 | |
18 | /* |
19 | * Some x86 clamshell design devices use portrait tablet screens and a display |
20 | * engine which cannot rotate in hardware, so we need to rotate the fbcon to |
21 | * compensate. Unfortunately these (cheap) devices also typically have quite |
22 | * generic DMI data, so we match on a combination of DMI data, screen resolution |
23 | * and a list of known BIOS dates to avoid false positives. |
24 | */ |
25 | |
26 | struct drm_dmi_panel_orientation_data { |
27 | int width; |
28 | int height; |
29 | const char * const *bios_dates; |
30 | int orientation; |
31 | }; |
32 | |
33 | static const struct drm_dmi_panel_orientation_data gpd_micropc = { |
34 | .width = 720, |
35 | .height = 1280, |
36 | .bios_dates = (const char * const []){ "04/26/2019" , |
37 | NULL }, |
38 | .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, |
39 | }; |
40 | |
41 | static const struct drm_dmi_panel_orientation_data gpd_onemix2s = { |
42 | .width = 1200, |
43 | .height = 1920, |
44 | .bios_dates = (const char * const []){ "05/21/2018" , "10/26/2018" , |
45 | "03/04/2019" , NULL }, |
46 | .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, |
47 | }; |
48 | |
49 | static const struct drm_dmi_panel_orientation_data gpd_pocket = { |
50 | .width = 1200, |
51 | .height = 1920, |
52 | .bios_dates = (const char * const []){ "05/26/2017" , "06/28/2017" , |
53 | "07/05/2017" , "08/07/2017" , NULL }, |
54 | .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, |
55 | }; |
56 | |
57 | static const struct drm_dmi_panel_orientation_data gpd_pocket2 = { |
58 | .width = 1200, |
59 | .height = 1920, |
60 | .bios_dates = (const char * const []){ "06/28/2018" , "08/28/2018" , |
61 | "12/07/2018" , NULL }, |
62 | .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, |
63 | }; |
64 | |
65 | static const struct drm_dmi_panel_orientation_data gpd_win = { |
66 | .width = 720, |
67 | .height = 1280, |
68 | .bios_dates = (const char * const []){ |
69 | "10/25/2016" , "11/18/2016" , "12/23/2016" , "12/26/2016" , |
70 | "02/21/2017" , "03/20/2017" , "05/25/2017" , NULL }, |
71 | .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, |
72 | }; |
73 | |
74 | static const struct drm_dmi_panel_orientation_data gpd_win2 = { |
75 | .width = 720, |
76 | .height = 1280, |
77 | .bios_dates = (const char * const []){ |
78 | "12/07/2017" , "05/24/2018" , "06/29/2018" , NULL }, |
79 | .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, |
80 | }; |
81 | |
82 | static const struct drm_dmi_panel_orientation_data itworks_tw891 = { |
83 | .width = 800, |
84 | .height = 1280, |
85 | .bios_dates = (const char * const []){ "10/16/2015" , NULL }, |
86 | .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, |
87 | }; |
88 | |
89 | static const struct drm_dmi_panel_orientation_data onegx1_pro = { |
90 | .width = 1200, |
91 | .height = 1920, |
92 | .bios_dates = (const char * const []){ "12/17/2020" , NULL }, |
93 | .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, |
94 | }; |
95 | |
96 | static const struct drm_dmi_panel_orientation_data lcd720x1280_rightside_up = { |
97 | .width = 720, |
98 | .height = 1280, |
99 | .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, |
100 | }; |
101 | |
102 | static const struct drm_dmi_panel_orientation_data lcd800x1280_leftside_up = { |
103 | .width = 800, |
104 | .height = 1280, |
105 | .orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP, |
106 | }; |
107 | |
108 | static const struct drm_dmi_panel_orientation_data lcd800x1280_rightside_up = { |
109 | .width = 800, |
110 | .height = 1280, |
111 | .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, |
112 | }; |
113 | |
114 | static const struct drm_dmi_panel_orientation_data lcd1080x1920_leftside_up = { |
115 | .width = 1080, |
116 | .height = 1920, |
117 | .orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP, |
118 | }; |
119 | |
120 | static const struct drm_dmi_panel_orientation_data lcd1200x1920_rightside_up = { |
121 | .width = 1200, |
122 | .height = 1920, |
123 | .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, |
124 | }; |
125 | |
126 | static const struct drm_dmi_panel_orientation_data lcd1280x1920_rightside_up = { |
127 | .width = 1280, |
128 | .height = 1920, |
129 | .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, |
130 | }; |
131 | |
132 | static const struct drm_dmi_panel_orientation_data lcd1600x2560_leftside_up = { |
133 | .width = 1600, |
134 | .height = 2560, |
135 | .orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP, |
136 | }; |
137 | |
138 | static const struct drm_dmi_panel_orientation_data lcd1600x2560_rightside_up = { |
139 | .width = 1600, |
140 | .height = 2560, |
141 | .orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, |
142 | }; |
143 | |
144 | static const struct dmi_system_id orientation_data[] = { |
145 | { /* Acer One 10 (S1003) */ |
146 | .matches = { |
147 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Acer" ), |
148 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "One S1003" ), |
149 | }, |
150 | .driver_data = (void *)&lcd800x1280_rightside_up, |
151 | }, { /* Acer Switch V 10 (SW5-017) */ |
152 | .matches = { |
153 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Acer" ), |
154 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "SW5-017" ), |
155 | }, |
156 | .driver_data = (void *)&lcd800x1280_rightside_up, |
157 | }, { /* Anbernic Win600 */ |
158 | .matches = { |
159 | DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Anbernic" ), |
160 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Win600" ), |
161 | }, |
162 | .driver_data = (void *)&lcd720x1280_rightside_up, |
163 | }, { /* Asus T100HA */ |
164 | .matches = { |
165 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
166 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100HAN" ), |
167 | }, |
168 | .driver_data = (void *)&lcd800x1280_leftside_up, |
169 | }, { /* Asus T101HA */ |
170 | .matches = { |
171 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
172 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T101HA" ), |
173 | }, |
174 | .driver_data = (void *)&lcd800x1280_rightside_up, |
175 | }, { /* Asus T103HAF */ |
176 | .matches = { |
177 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
178 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T103HAF" ), |
179 | }, |
180 | .driver_data = (void *)&lcd800x1280_rightside_up, |
181 | }, { /* AYA NEO 2021 */ |
182 | .matches = { |
183 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "AYADEVICE" ), |
184 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "AYA NEO 2021" ), |
185 | }, |
186 | .driver_data = (void *)&lcd800x1280_rightside_up, |
187 | }, { /* AYA NEO AIR */ |
188 | .matches = { |
189 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "AYANEO" ), |
190 | DMI_MATCH(DMI_PRODUCT_NAME, "AIR" ), |
191 | }, |
192 | .driver_data = (void *)&lcd1080x1920_leftside_up, |
193 | }, { /* AYA NEO NEXT */ |
194 | .matches = { |
195 | DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AYANEO" ), |
196 | DMI_MATCH(DMI_BOARD_NAME, "NEXT" ), |
197 | }, |
198 | .driver_data = (void *)&lcd800x1280_rightside_up, |
199 | }, { /* Chuwi HiBook (CWI514) */ |
200 | .matches = { |
201 | DMI_MATCH(DMI_BOARD_VENDOR, "Hampoo" ), |
202 | DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR" ), |
203 | /* Above matches are too generic, add bios-date match */ |
204 | DMI_MATCH(DMI_BIOS_DATE, "05/07/2016" ), |
205 | }, |
206 | .driver_data = (void *)&lcd1200x1920_rightside_up, |
207 | }, { /* Chuwi Hi10 Pro (CWI529) */ |
208 | .matches = { |
209 | DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Hampoo" ), |
210 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Hi10 pro tablet" ), |
211 | }, |
212 | .driver_data = (void *)&lcd1200x1920_rightside_up, |
213 | }, { /* Dynabook K50 */ |
214 | .matches = { |
215 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dynabook Inc." ), |
216 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "dynabook K50/FR" ), |
217 | }, |
218 | .driver_data = (void *)&lcd800x1280_leftside_up, |
219 | }, { /* GPD MicroPC (generic strings, also match on bios date) */ |
220 | .matches = { |
221 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Default string" ), |
222 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string" ), |
223 | DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Default string" ), |
224 | DMI_EXACT_MATCH(DMI_BOARD_NAME, "Default string" ), |
225 | }, |
226 | .driver_data = (void *)&gpd_micropc, |
227 | }, { /* GPD MicroPC (later BIOS versions with proper DMI strings) */ |
228 | .matches = { |
229 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "GPD" ), |
230 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "MicroPC" ), |
231 | }, |
232 | .driver_data = (void *)&lcd720x1280_rightside_up, |
233 | }, { /* GPD Win Max */ |
234 | .matches = { |
235 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "GPD" ), |
236 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "G1619-01" ), |
237 | }, |
238 | .driver_data = (void *)&lcd800x1280_rightside_up, |
239 | }, { /* |
240 | * GPD Pocket, note that the DMI data is less generic then |
241 | * it seems, devices with a board-vendor of "AMI Corporation" |
242 | * are quite rare, as are devices which have both board- *and* |
243 | * product-id set to "Default String" |
244 | */ |
245 | .matches = { |
246 | DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation" ), |
247 | DMI_EXACT_MATCH(DMI_BOARD_NAME, "Default string" ), |
248 | DMI_EXACT_MATCH(DMI_BOARD_SERIAL, "Default string" ), |
249 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string" ), |
250 | }, |
251 | .driver_data = (void *)&gpd_pocket, |
252 | }, { /* GPD Pocket 2 (generic strings, also match on bios date) */ |
253 | .matches = { |
254 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Default string" ), |
255 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string" ), |
256 | DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Default string" ), |
257 | DMI_EXACT_MATCH(DMI_BOARD_NAME, "Default string" ), |
258 | }, |
259 | .driver_data = (void *)&gpd_pocket2, |
260 | }, { /* GPD Win (same note on DMI match as GPD Pocket) */ |
261 | .matches = { |
262 | DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation" ), |
263 | DMI_EXACT_MATCH(DMI_BOARD_NAME, "Default string" ), |
264 | DMI_EXACT_MATCH(DMI_BOARD_SERIAL, "Default string" ), |
265 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string" ), |
266 | }, |
267 | .driver_data = (void *)&gpd_win, |
268 | }, { /* GPD Win 2 (too generic strings, also match on bios date) */ |
269 | .matches = { |
270 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Default string" ), |
271 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string" ), |
272 | DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Default string" ), |
273 | DMI_EXACT_MATCH(DMI_BOARD_NAME, "Default string" ), |
274 | }, |
275 | .driver_data = (void *)&gpd_win2, |
276 | }, { /* GPD Win 3 */ |
277 | .matches = { |
278 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "GPD" ), |
279 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "G1618-03" ) |
280 | }, |
281 | .driver_data = (void *)&lcd720x1280_rightside_up, |
282 | }, { /* I.T.Works TW891 */ |
283 | .matches = { |
284 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "To be filled by O.E.M." ), |
285 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "TW891" ), |
286 | DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "To be filled by O.E.M." ), |
287 | DMI_EXACT_MATCH(DMI_BOARD_NAME, "TW891" ), |
288 | }, |
289 | .driver_data = (void *)&itworks_tw891, |
290 | }, { /* KD Kurio Smart C15200 2-in-1 */ |
291 | .matches = { |
292 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "KD Interactive" ), |
293 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Kurio Smart" ), |
294 | DMI_EXACT_MATCH(DMI_BOARD_NAME, "KDM960BCP" ), |
295 | }, |
296 | .driver_data = (void *)&lcd800x1280_rightside_up, |
297 | }, { /* |
298 | * Lenovo Ideapad Miix 310 laptop, only some production batches |
299 | * have a portrait screen, the resolution checks makes the quirk |
300 | * apply only to those batches. |
301 | */ |
302 | .matches = { |
303 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO" ), |
304 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "80SG" ), |
305 | DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "MIIX 310-10ICR" ), |
306 | }, |
307 | .driver_data = (void *)&lcd800x1280_rightside_up, |
308 | }, { /* Lenovo Ideapad Miix 320 */ |
309 | .matches = { |
310 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO" ), |
311 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "80XF" ), |
312 | DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo MIIX 320-10ICR" ), |
313 | }, |
314 | .driver_data = (void *)&lcd800x1280_rightside_up, |
315 | }, { /* Lenovo Ideapad D330-10IGM (HD) */ |
316 | .matches = { |
317 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO" ), |
318 | DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad D330-10IGM" ), |
319 | }, |
320 | .driver_data = (void *)&lcd800x1280_rightside_up, |
321 | }, { /* Lenovo Ideapad D330-10IGM (FHD) */ |
322 | .matches = { |
323 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO" ), |
324 | DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad D330-10IGM" ), |
325 | }, |
326 | .driver_data = (void *)&lcd1200x1920_rightside_up, |
327 | }, { /* Lenovo Ideapad D330-10IGL (HD) */ |
328 | .matches = { |
329 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO" ), |
330 | DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad D330-10IGL" ), |
331 | }, |
332 | .driver_data = (void *)&lcd800x1280_rightside_up, |
333 | }, { /* Lenovo IdeaPad Duet 3 10IGL5 */ |
334 | .matches = { |
335 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO" ), |
336 | DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "IdeaPad Duet 3 10IGL5" ), |
337 | }, |
338 | .driver_data = (void *)&lcd1200x1920_rightside_up, |
339 | }, { /* Lenovo Yoga Book X90F / X90L */ |
340 | .matches = { |
341 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel Corporation" ), |
342 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM" ), |
343 | DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "YETI-11" ), |
344 | }, |
345 | .driver_data = (void *)&lcd1200x1920_rightside_up, |
346 | }, { /* Lenovo Yoga Book X91F / X91L */ |
347 | .matches = { |
348 | /* Non exact match to match F + L versions */ |
349 | DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X91" ), |
350 | }, |
351 | .driver_data = (void *)&lcd1200x1920_rightside_up, |
352 | }, { /* Lenovo Yoga Tablet 2 830F / 830L */ |
353 | .matches = { |
354 | /* |
355 | * Note this also matches the Lenovo Yoga Tablet 2 1050F/L |
356 | * since that uses the same mainboard. The resolution match |
357 | * will limit this to only matching on the 830F/L. Neither has |
358 | * any external video outputs so those are not a concern. |
359 | */ |
360 | DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp." ), |
361 | DMI_MATCH(DMI_PRODUCT_NAME, "VALLEYVIEW C0 PLATFORM" ), |
362 | DMI_MATCH(DMI_BOARD_NAME, "BYT-T FFD8" ), |
363 | /* Partial match on beginning of BIOS version */ |
364 | DMI_MATCH(DMI_BIOS_VERSION, "BLADE_21" ), |
365 | }, |
366 | .driver_data = (void *)&lcd1200x1920_rightside_up, |
367 | }, { /* Lenovo Yoga Tab 3 X90F */ |
368 | .matches = { |
369 | DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation" ), |
370 | DMI_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM" ), |
371 | DMI_MATCH(DMI_PRODUCT_VERSION, "Blade3-10A-001" ), |
372 | }, |
373 | .driver_data = (void *)&lcd1600x2560_rightside_up, |
374 | }, { /* Nanote UMPC-01 */ |
375 | .matches = { |
376 | DMI_MATCH(DMI_SYS_VENDOR, "RWC CO.,LTD" ), |
377 | DMI_MATCH(DMI_PRODUCT_NAME, "UMPC-01" ), |
378 | }, |
379 | .driver_data = (void *)&lcd1200x1920_rightside_up, |
380 | }, { /* OneGX1 Pro */ |
381 | .matches = { |
382 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "SYSTEM_MANUFACTURER" ), |
383 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "SYSTEM_PRODUCT_NAME" ), |
384 | DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Default string" ), |
385 | }, |
386 | .driver_data = (void *)&onegx1_pro, |
387 | }, { /* OneXPlayer */ |
388 | .matches = { |
389 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ONE-NETBOOK TECHNOLOGY CO., LTD." ), |
390 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ONE XPLAYER" ), |
391 | }, |
392 | .driver_data = (void *)&lcd1600x2560_leftside_up, |
393 | }, { /* Samsung GalaxyBook 10.6 */ |
394 | .matches = { |
395 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD." ), |
396 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Galaxy Book 10.6" ), |
397 | }, |
398 | .driver_data = (void *)&lcd1280x1920_rightside_up, |
399 | }, { /* Valve Steam Deck */ |
400 | .matches = { |
401 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Valve" ), |
402 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Jupiter" ), |
403 | DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "1" ), |
404 | }, |
405 | .driver_data = (void *)&lcd800x1280_rightside_up, |
406 | }, { /* VIOS LTH17 */ |
407 | .matches = { |
408 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "VIOS" ), |
409 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "LTH17" ), |
410 | }, |
411 | .driver_data = (void *)&lcd800x1280_rightside_up, |
412 | }, { /* One Mix 2S (generic strings, also match on bios date) */ |
413 | .matches = { |
414 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Default string" ), |
415 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string" ), |
416 | DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Default string" ), |
417 | DMI_EXACT_MATCH(DMI_BOARD_NAME, "Default string" ), |
418 | }, |
419 | .driver_data = (void *)&gpd_onemix2s, |
420 | }, |
421 | {} |
422 | }; |
423 | |
424 | /** |
425 | * drm_get_panel_orientation_quirk - Check for panel orientation quirks |
426 | * @width: width in pixels of the panel |
427 | * @height: height in pixels of the panel |
428 | * |
429 | * This function checks for platform specific (e.g. DMI based) quirks |
430 | * providing info on panel_orientation for systems where this cannot be |
431 | * probed from the hard-/firm-ware. To avoid false-positive this function |
432 | * takes the panel resolution as argument and checks that against the |
433 | * resolution expected by the quirk-table entry. |
434 | * |
435 | * Note this function is also used outside of the drm-subsys, by for example |
436 | * the efifb code. Because of this this function gets compiled into its own |
437 | * kernel-module when built as a module. |
438 | * |
439 | * Returns: |
440 | * A DRM_MODE_PANEL_ORIENTATION_* value if there is a quirk for this system, |
441 | * or DRM_MODE_PANEL_ORIENTATION_UNKNOWN if there is no quirk. |
442 | */ |
443 | int drm_get_panel_orientation_quirk(int width, int height) |
444 | { |
445 | const struct dmi_system_id *match; |
446 | const struct drm_dmi_panel_orientation_data *data; |
447 | const char *bios_date; |
448 | int i; |
449 | |
450 | for (match = dmi_first_match(list: orientation_data); |
451 | match; |
452 | match = dmi_first_match(list: match + 1)) { |
453 | data = match->driver_data; |
454 | |
455 | if (data->width != width || |
456 | data->height != height) |
457 | continue; |
458 | |
459 | if (!data->bios_dates) |
460 | return data->orientation; |
461 | |
462 | bios_date = dmi_get_system_info(field: DMI_BIOS_DATE); |
463 | if (!bios_date) |
464 | continue; |
465 | |
466 | i = match_string(array: data->bios_dates, n: -1, string: bios_date); |
467 | if (i >= 0) |
468 | return data->orientation; |
469 | } |
470 | |
471 | return DRM_MODE_PANEL_ORIENTATION_UNKNOWN; |
472 | } |
473 | EXPORT_SYMBOL(drm_get_panel_orientation_quirk); |
474 | |
475 | #else |
476 | |
477 | /* There are no quirks for non x86 devices yet */ |
478 | int drm_get_panel_orientation_quirk(int width, int height) |
479 | { |
480 | return DRM_MODE_PANEL_ORIENTATION_UNKNOWN; |
481 | } |
482 | EXPORT_SYMBOL(drm_get_panel_orientation_quirk); |
483 | |
484 | #endif |
485 | |
486 | MODULE_LICENSE("Dual MIT/GPL" ); |
487 | |