• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 Allwinnertech Co.Ltd
3  * Authors: zhengwanyu
4  *
5  * This program is free software; you can redistribute  it and/or modify it
6  * under  the terms of  the GNU General  Public License as published by the
7  * Free Software Foundation;  either version 2 of the  License, or (at your
8  * option) any later version.
9  *
10  */
11 
12 #include <linux/dma-mapping.h>
13 #include <linux/clk.h>
14 #include <drm/drm_print.h>
15 
16 #include "sunxi_common.h"
17 #include "sunxi_tcon.h"
18 #include "sunxi_lcd.h"
19 
20 #if defined(CONFIG_AW_DRM_BACKLIGHT)
21 #include "sunxi_backlight.h"
22 #endif
23 
24 #define LCD_PIN_STATE_ACTIVE "active"
25 #define LCD_PIN_STATE_SLEEP "sleep"
26 
27 static struct sunxi_lcd_drv *lcd_drv;
28 static struct device *g_lcd_dev; /* fix me */
29 
sunxi_lcd_get_count(void)30 unsigned char sunxi_lcd_get_count(void)
31 {
32     return lcd_drv->lcd_cnt;
33 }
34 
35 struct sunxi_dispdev_name sunxi_lcd_connector_type_name[] = {
36     {LCD_IF_HV,    "RGB"},
37     {LCD_IF_CPU,    "CPU"},
38     {LCD_IF_LVDS,    "LVDS"},
39     {LCD_IF_DSI,    "DSI"},
40     {LCD_IF_EDP,    "EDP"},
41     {LCD_IF_EXT_DSI, "EXT_DSI"},
42     {LCD_IF_VDPO,    "VDPO"},
43 };
44 
45 /*RGB*/
46 struct sunxi_dispdev_name sunxi_hv_if_name[] = {
47     {PARALLEL_RGB,    "PARALLEL_RGB"},
48     {SERIAL_RGB,    "SERIAL_RGB"},
49     {DUMMY_RGB,    "DUMMY_RGB"},
50     {RGB_DUMMY,    "RGB_DUMMY"},
51     {SERIAL_YUV,    "SERIAL_YUV"},
52 };
53 
54 /*CPU*/
55 struct sunxi_dispdev_name sunxi_cpu_if_name[] = {
56     {RGB666_18_1,    "RGB666_18_1"},
57     {RGB565_16_1,    "RGB565_16_1"},
58     {RGB666_18_3,    "RGB666_18_3"},
59     {RGB565_16_2,    "RGB565_16_2"},
60     {RGB666_9_1,    "RGB666_9_1"},
61     {RGB666_8_3,    "RGB666_8_3"},
62     {RGB565_8_2,    "RGB565_8_2"},
63 };
64 
65 struct sunxi_dispdev_name sunxi_lvds_if_name[] = {
66     {SINGLE_LINK,    "SINGLE_LINK"},
67     {DUAL_LINK,    "DUAL_LINK"},
68 };
69 
70 struct sunxi_dispdev_name sunxi_dsi_if_name[] = {
71     {VIDEO_MODE,        "VIDEO_MODE"},
72     {COMMAND_MODE,        "COMMAND_MODE"},
73     {VIDEO_BURST_MODE,    "VIDEO_BURST_MODE"},
74 };
75 
76 struct __lcd_panel *sunxi_panel[] = {
77 #ifdef CONFIG_EINK_PANEL_USED
78     &default_eink,
79 #endif
80 #ifdef CONFIG_LCD_SUPPORT_DEFAULT
81     &default_panel,
82 #endif
83 #ifdef CONFIG_LCD_SUPPORT_LT070ME05000
84     &lt070me05000_panel,
85 #endif
86 #ifdef CONFIG_LCD_SUPPORT_WTQ05027D01
87     &wtq05027d01_panel,
88 #endif
89 #ifdef CONFIG_LCD_SUPPORT_T27P06
90     &t27p06_panel,
91 #endif
92 #ifdef CONFIG_LCD_SUPPORT_DX0960BE40A1
93     &dx0960be40a1_panel,
94 #endif
95 #ifdef CONFIG_LCD_SUPPORT_TFT720X1280
96     &tft720x1280_panel,
97 #endif
98 #ifdef CONFIG_LCD_SUPPORT_S6D7AA0X01
99     &S6D7AA0X01_panel,
100 #endif
101 #ifdef CONFIG_LCD_SUPPORT_GG1P4062UTSW
102     &gg1p4062utsw_panel,
103 #endif
104 #ifdef CONFIG_LCD_SUPPORT_LS029B3SX02
105     &ls029b3sx02_panel,
106 #endif
107 #ifdef CONFIG_LCD_SUPPORT_HE0801A068
108     &he0801a068_panel,
109 #endif
110 #ifdef CONFIG_LCD_SUPPORT_INET_DSI_PANEL
111     &inet_dsi_panel,
112 #endif
113 #ifdef CONFIG_LCD_SUPPORT_LQ101R1SX03
114     &lq101r1sx03_panel,
115 #endif
116     /* add new panel below */
117 #ifdef CONFIG_LCD_SUPPORT_WILLIAMLCD
118     &WilliamLcd_panel,
119 #endif
120 
121 #ifdef CONFIG_LCD_SUPPORT_KD101N51
122     &kd101n51_panel,
123 #endif
124 
125 #ifdef CONFIG_LCD_SUPPORT_BP101WX1
126     &bp101wx1_panel,
127 #endif
128 };
129 
sunxi_lcd_get_connector_type_name(int type)130 static char *sunxi_lcd_get_connector_type_name(int type)
131 {
132     int i, cnt;
133 
134     cnt  = sizeof(sunxi_lcd_connector_type_name)
135             / sizeof(struct sunxi_dispdev_name);
136 
137     for (i = 0; i < cnt; i++)
138         if (sunxi_lcd_connector_type_name[i].device == type)
139             return sunxi_lcd_connector_type_name[i].name;
140 
141     return NULL;
142 }
143 
144 /*RGB*/
sunxi_lcd_get_hv_if_name(int type)145 static char *sunxi_lcd_get_hv_if_name(int type)
146 {
147     int i, cnt;
148 
149     cnt  = sizeof(sunxi_hv_if_name)
150             / sizeof(struct sunxi_dispdev_name);
151 
152     for (i = 0; i < cnt; i++)
153         if (sunxi_hv_if_name[i].device == type)
154             return sunxi_hv_if_name[i].name;
155 
156     return NULL;
157 }
158 
sunxi_lcd_get_cpu_if_name(int type)159 static char *sunxi_lcd_get_cpu_if_name(int type)
160 {
161     int i, cnt;
162 
163     cnt  = sizeof(sunxi_cpu_if_name)
164             / sizeof(struct sunxi_dispdev_name);
165 
166     for (i = 0; i < cnt; i++)
167         if (sunxi_cpu_if_name[i].device == type)
168             return sunxi_cpu_if_name[i].name;
169 
170     return NULL;
171 }
172 
sunxi_lcd_get_lvds_if_name(int type)173 static char *sunxi_lcd_get_lvds_if_name(int type)
174 {
175     int i, cnt;
176 
177     cnt  = sizeof(sunxi_lvds_if_name)
178             / sizeof(struct sunxi_dispdev_name);
179 
180     for (i = 0; i < cnt; i++)
181         if (sunxi_lvds_if_name[i].device == type)
182             return sunxi_lvds_if_name[i].name;
183 
184     return NULL;
185 }
186 
sunxi_lcd_get_dsi_if_name(int type)187 static char *sunxi_lcd_get_dsi_if_name(int type)
188 {
189     int i, cnt;
190 
191     cnt  = sizeof(sunxi_dsi_if_name)
192             / sizeof(struct sunxi_dispdev_name);
193 
194     for (i = 0; i < cnt; i++)
195         if (sunxi_dsi_if_name[i].device == type)
196             return sunxi_dsi_if_name[i].name;
197 
198     return NULL;
199 }
200 
sunxi_lcd_get_panel(char * name)201 static struct __lcd_panel *sunxi_lcd_get_panel(char *name)
202 {
203     int i;
204 
205     for (i = 0; i < ARRAY_SIZE(sunxi_panel); i++)
206         if (sunxi_panel[i] && (!strcmp(name, sunxi_panel[i]->name)))
207             return sunxi_panel[i];
208 
209     return NULL;
210 }
211 
212 /**
213  * @name       :sunxi_dsi_io_cfg
214  * @brief      :open dsi io
215  * @param[IN]  :type_id:dsi index
216  * @param[OUT] :enable:1->en, 0->disable
217  * @return     :always 0
218  */
sunxi_dsi_io_cfg(int lcd_id,unsigned int enable)219 static int sunxi_dsi_io_cfg(int lcd_id, unsigned int enable)
220 {
221     int type_id = -1;
222     struct disp_panel_para *panel = NULL;
223 
224     type_id = sunxi_lcd_get_type_id(lcd_id);
225     panel = sunxi_lcd_get_panel_para(lcd_id);
226 
227     if (!panel || type_id < 0) {
228         DRM_ERROR("NULL pointer!\n");
229         return -1;
230     }
231 
232     if (enable == 1) {
233 #if defined(SUPPORT_DSI)
234         dsi_io_open(type_id, panel);
235         if (panel->lcd_tcon_mode == DISP_TCON_DUAL_DSI &&
236             type_id + 1 < DEVICE_DSI_NUM)
237             dsi_io_open(type_id + 1, panel);
238 #endif
239     } else {
240 #if defined(SUPPORT_DSI)
241         dsi_io_close(type_id);
242         if (panel->lcd_tcon_mode == DISP_TCON_DUAL_DSI &&
243             type_id + 1 < DEVICE_DSI_NUM)
244             dsi_io_close(type_id + 1);
245 #endif
246     }
247     return 0;
248 }
249 
250 /**
251  * @name       :sunxi_lcd_get_lcd
252  * @brief      :get lcd structure of specified lcd id
253  * @param[IN]  :lcd_id: id of lcd
254  * @return     :a pointer of sunxi_lcd or NULL if fail to get one
255  */
sunxi_lcd_get_lcd(unsigned int lcd_id)256 struct sunxi_lcd *sunxi_lcd_get_lcd(unsigned int lcd_id)
257 {
258     struct sunxi_lcd *lcd = NULL;
259 
260     if (lcd_id < LCD_NUM_MAX)
261         lcd = &lcd_drv->hwlcd[lcd_id];
262 
263     return lcd;
264 }
265 
sunxi_lcd_get_hw_funcs(int lcd_id)266 struct sunxi_lcd_funcs *sunxi_lcd_get_hw_funcs(int lcd_id)
267 {
268     struct sunxi_lcd *lcd;
269 
270     lcd = sunxi_lcd_get_lcd(lcd_id);
271 
272     return lcd->funcs;
273 }
274 
275 
276 /***********###############pinctrl and pin power################*********/
277 /* pin power
278  * pin set state: Active or Sleep
279  * explain: pin_cfg belongs to pinctrl that configured int DTS.
280  * pin_power: means that power conresponse to the pinctrl configured int DTS.
281  */
sunxi_lcd_pin_cfg(unsigned int lcd_id,unsigned char enable)282 int sunxi_lcd_pin_cfg(unsigned int lcd_id, unsigned char enable)
283 {
284     int i, ret = 0;
285     struct disp_lcd_cfg *cfg;
286     struct sunxi_lcd *lcd;
287     char dev_name[25];
288 
289     lcd = sunxi_lcd_get_lcd(lcd_id);
290     if (!lcd) {
291         DRM_ERROR("Null lcd pointer!\n");
292         return -1;
293     }
294     cfg = &lcd->lcd_cfg;
295 
296     /*set pin power enable*/
297     if (enable) {
298         for (i = 0; i < LCD_GPIO_REGU_NUM; i++) {
299             if (cfg->lcd_power_used[i]) {
300                 ret = sunxi_drm_sys_power_enable(g_lcd_dev,
301                     cfg->lcd_pin_power[i]);
302                 if (ret) {
303                     DRM_ERROR("sunxi_lcd_pin_cfg"
304                     " sunxi_drm_sys_power_enable failed");
305                 }
306             }
307         }
308     }
309 
310     sprintf(dev_name, "lcd%d", lcd_id);
311     ret = sunxi_drm_sys_pin_set_state(dev_name, enable ?
312                 LCD_PIN_STATE_ACTIVE : LCD_PIN_STATE_SLEEP);
313     if (ret) {
314         DRM_ERROR("sunxi_drm_sys_pin_set_state failed\n");
315         return ret;
316     }
317 
318     if (lcd->type == LCD_IF_DSI)
319         sunxi_dsi_io_cfg(lcd_id, enable);
320 
321 
322     /*set pin power disable*/
323     if (!enable) {
324         for (i = 0; i < LCD_GPIO_REGU_NUM; i++) {
325             if (cfg->lcd_power_used[i]) {
326                 ret = sunxi_drm_sys_power_disable(g_lcd_dev,
327                     cfg->lcd_pin_power[i]);
328                 if (ret) {
329                     DRM_ERROR("sunxi_lcd_pin_cfg"
330                     " sunxi_drm_sys_power_disable failed");
331                     return -1;
332                 }
333             }
334         }
335     }
336 
337     return 0;
338 }
339 
340 
341 /***********#########################lcd power#####################***********/
sunxi_lcd_all_power_enable(unsigned int lcd_id)342 int sunxi_lcd_all_power_enable(unsigned int lcd_id)
343 {
344     int i, ret;
345     struct sunxi_lcd *lcd;
346     char *power;
347 
348     lcd = sunxi_lcd_get_lcd(lcd_id);
349     if (!lcd) {
350         DRM_ERROR("Null lcd pointer!\n");
351         return -1;
352     }
353 
354     power = lcd->lcd_cfg.lcd_bl_en_power;
355     if (strcmp(power, "")) {
356         ret = sunxi_drm_sys_power_enable(g_lcd_dev, power);
357         if (ret) {
358             DRM_ERROR("disp_lcd_power_enable:%s failed\n", power);
359             return ret;
360         }
361     }
362 
363     for (i = 0; i < LCD_POWER_NUM; i++) {
364         if (!lcd->lcd_cfg.lcd_power_used[i])
365             continue;
366         power = lcd->lcd_cfg.lcd_power[i];
367         ret = sunxi_drm_sys_power_enable(g_lcd_dev, power);
368         if (ret) {
369             DRM_ERROR("disp_lcd_power_enable:%s failed\n", power);
370             return ret;
371         }
372     }
373 
374     for (i = 0; i < LCD_POWER_NUM; i++) {
375         if (!lcd->lcd_cfg.lcd_fix_power_used[i])
376             continue;
377         power = lcd->lcd_cfg.lcd_fix_power[i];
378         ret = sunxi_drm_sys_power_enable(g_lcd_dev, power);
379         if (ret) {
380             DRM_ERROR("disp_lcd_power_enable:%s failed\n", power);
381             return ret;
382         }
383     }
384 
385     for (i = 0; i < LCD_GPIO_REGU_NUM; i++) {
386         if (!lcd->lcd_cfg.lcd_power_used[i])
387             continue;
388         power = lcd->lcd_cfg.lcd_gpio_power[i];
389         ret = sunxi_drm_sys_power_enable(g_lcd_dev, power);
390         if (ret) {
391             DRM_ERROR("disp_lcd_power_enable:%s failed\n", power);
392             return ret;
393         }
394     }
395 
396     for (i = 0; i < LCD_GPIO_REGU_NUM; i++) {
397         if (!lcd->lcd_cfg.lcd_power_used[i])
398             continue;
399         power = lcd->lcd_cfg.lcd_pin_power[i];
400         ret = sunxi_drm_sys_power_enable(g_lcd_dev, power);
401         if (ret) {
402             DRM_ERROR("disp_lcd_power_enable:%s failed\n", power);
403             return ret;
404         }
405     }
406 
407     return 0;
408 }
409 
410 /*
411  * The power effect on the whole lcd
412  */
sunxi_lcd_power_enable(unsigned int lcd_id,u32 power_id)413 int sunxi_lcd_power_enable(unsigned int lcd_id, u32 power_id)
414 {
415     int ret = 0;
416     struct sunxi_lcd *lcd;
417 
418     lcd = sunxi_lcd_get_lcd(lcd_id);
419     if (!lcd) {
420         DRM_ERROR("Null lcd pointer!\n");
421         return -1;
422     }
423 
424     if (lcd->lcd_cfg.lcd_power_used[power_id]) {
425         /* regulator type */
426         ret = sunxi_drm_sys_power_enable(g_lcd_dev, lcd->lcd_cfg.lcd_power[power_id]);
427         if (ret) {
428             DRM_ERROR("disp_lcd_power_enable"
429                 " sunxi_drm_sys_power_disable failed");
430             return -1;
431         }
432     }
433 
434     return 0;
435 }
436 
sunxi_lcd_power_disable(unsigned int lcd_id,u32 power_id)437 int sunxi_lcd_power_disable(unsigned int lcd_id, u32 power_id)
438 {
439     int ret = 0;
440     struct sunxi_lcd *lcd;
441 
442     lcd = sunxi_lcd_get_lcd(lcd_id);
443     if (!lcd) {
444         DRM_ERROR("Null lcd pointer!\n");
445         return -1;
446     }
447     if (lcd->lcd_cfg.lcd_power_used[power_id]) {
448         /* regulator type */
449         ret = sunxi_drm_sys_power_disable(g_lcd_dev, lcd->lcd_cfg.lcd_power[power_id]);
450         if (ret) {
451             DRM_ERROR("disp_lcd_power_enable"
452                 " sunxi_drm_sys_power_disable failed");
453             return -1;
454         }
455     }
456 
457 
458     return 0;
459 }
460 
461 /***********#########################lcd power#####################***********/
462 
sunxi_lcd_fix_power_enable(struct sunxi_lcd * lcd)463 int sunxi_lcd_fix_power_enable(struct sunxi_lcd *lcd)
464 {
465     int ret = 0, i;
466 
467     for (i = 0; i < LCD_POWER_NUM; i++) {
468         if (lcd->lcd_cfg.lcd_fix_power_used[i]) {
469             /* regulator type */
470             ret = sunxi_drm_sys_power_enable(g_lcd_dev, lcd->lcd_cfg.lcd_fix_power[i]);
471             if (ret) {
472                 DRM_ERROR("disp_lcd_power_enable"
473                     " sunxi_drm_sys_power_disable failed");
474                 return -1;
475             }
476         }
477     }
478 
479     return 0;
480 }
481 
sunxi_lcd_fix_power_disable(struct sunxi_lcd * lcd)482 int sunxi_lcd_fix_power_disable(struct sunxi_lcd *lcd)
483 {
484     int ret = 0, i;
485 
486     for (i = 0; i < LCD_POWER_NUM; i++) {
487         if (lcd->lcd_cfg.lcd_fix_power_used[i]) {
488             /* regulator type */
489             ret = sunxi_drm_sys_power_disable(g_lcd_dev, lcd->lcd_cfg.lcd_fix_power[i]);
490             if (ret) {
491                 DRM_ERROR("disp_lcd_power_enable"
492                     " sunxi_drm_sys_power_disable failed");
493                 return -1;
494             }
495         }
496     }
497 
498 
499     return 0;
500 }
501 
502 
503 /***********##############lcd_gpio and lcd_gpio_power################*********/
504 /*
505  *lcd_gpio: the general gpio that used in whole lcd
506  *lcd_gpio_power: the coresponsible power of lcd_gpio
507  */
sunxi_lcd_gpio_power_enable(struct sunxi_lcd * lcd,u32 power_id)508 static int sunxi_lcd_gpio_power_enable(struct sunxi_lcd *lcd, u32 power_id)
509 {
510     int ret = 0;
511 
512     if (lcd->lcd_cfg.lcd_power_used[power_id]) {
513         /* regulator type */
514         ret = sunxi_drm_sys_power_enable(g_lcd_dev, lcd->lcd_cfg.lcd_gpio_power[power_id]);
515         if (ret) {
516             DRM_ERROR("disp_lcd_power_enable"
517                 " sunxi_drm_sys_power_disable failed");
518             return -1;
519         }
520     }
521 
522     return 0;
523 }
524 
sunxi_lcd_gpio_power_disable(struct sunxi_lcd * lcd,u32 power_id)525 static int sunxi_lcd_gpio_power_disable(struct sunxi_lcd *lcd, u32 power_id)
526 {
527     int ret = 0;
528 
529     if (lcd->lcd_cfg.lcd_power_used[power_id]) {
530         /* regulator type */
531         ret = sunxi_drm_sys_power_disable(g_lcd_dev, lcd->lcd_cfg.lcd_gpio_power[power_id]);
532         if (ret) {
533             DRM_ERROR("disp_lcd_power_enable"
534                 " sunxi_drm_sys_power_disable failed");
535             return -1;
536         }
537     }
538 
539 
540     return 0;
541 }
542 
543 /* enable lcd_gpio power and set it as sys_config set
544  * lcd_gpio: the gpio effect on whole lcd, has no speciffic function, like bl_en
545  * gpio
546  */
sunxi_lcd_gpio_init(struct sunxi_lcd * lcd)547 int sunxi_lcd_gpio_init(struct sunxi_lcd *lcd)
548 {
549     int i;
550     struct disp_lcd_cfg *lcd_cfg = &lcd->lcd_cfg;
551 
552     for (i = 0; i < LCD_GPIO_REGU_NUM; i++) {
553         if (sunxi_lcd_gpio_power_enable(lcd, i) < 0) {
554             DRM_ERROR("sunxi_lcd_power_enable failed\n");
555         }
556     }
557 
558     for (i = 0; i < LCD_GPIO_NUM; i++) {
559         lcd_cfg->gpio_hdl[i] = 0;
560         if (lcd_cfg->lcd_gpio_used[i]) {
561             lcd_cfg->gpio_hdl[i]
562                 = sunxi_drm_sys_gpio_request((struct disp_gpio_info *)&lcd_cfg->lcd_gpio[i]);
563             if (lcd_cfg->gpio_hdl[i] < 0) {
564                 DRM_ERROR("%s"
565                 " sunxi_drm_sys_gpio_request failed", __func__);
566             }
567         }
568     }
569 
570     return 0;
571 }
572 
sunxi_lcd_gpio_exit(struct sunxi_lcd * lcd)573 int sunxi_lcd_gpio_exit(struct sunxi_lcd *lcd)
574 {
575     int i;
576     struct disp_gpio_info gpio_info;
577     struct disp_lcd_cfg *lcd_cfg = &lcd->lcd_cfg;
578 
579     for (i = 0; i < LCD_GPIO_NUM; i++) {
580         if (lcd_cfg->gpio_hdl[i]) {
581             sunxi_drm_sys_gpio_release(lcd_cfg->gpio_hdl[i]);
582 
583             memcpy(&gpio_info, &(lcd_cfg->lcd_gpio[i]),
584                    sizeof(struct disp_gpio_info));
585 
586             lcd_cfg->gpio_hdl[i] = sunxi_drm_sys_gpio_request(&gpio_info);
587             if (lcd_cfg->gpio_hdl[i] < 0) {
588                 DRM_ERROR("sunxi_drm_sys_gpio_request failed\n");
589             }
590             sunxi_drm_sys_gpio_release(lcd_cfg->gpio_hdl[i]);
591             lcd_cfg->gpio_hdl[i] = 0;
592         }
593     }
594 
595     /* io-pad */
596     for (i = LCD_GPIO_REGU_NUM - 1; i >= 0; i--) {
597         if (sunxi_lcd_gpio_power_disable(lcd, i) < 0) {
598             DRM_ERROR("sunxi_lcd_power_disable failed\n");
599         }
600     }
601 
602     return 0;
603 }
604 
605 /* direction: input(0), output(1) */
sunxi_lcd_gpio_set_direction(struct sunxi_lcd * lcd,unsigned int io_index,unsigned int direction)606 int sunxi_lcd_gpio_set_direction(struct sunxi_lcd *lcd, unsigned int io_index,
607                 unsigned int direction)
608 {
609     char gpio_name[20];
610 
611     sprintf(gpio_name, "lcd_gpio_%d", io_index);
612     return sunxi_drm_sys_gpio_set_direction(lcd->lcd_cfg.gpio_hdl[io_index],
613                        direction, gpio_name);
614 }
615 
sunxi_lcd_gpio_set_value(unsigned int lcd_id,unsigned int io_index,unsigned int data)616 int sunxi_lcd_gpio_set_value(unsigned int lcd_id, unsigned int io_index,
617                     unsigned int data)
618 {
619     char gpio_name[20];
620     struct sunxi_lcd *lcd;
621 
622     lcd = sunxi_lcd_get_lcd(lcd_id);
623     if (!lcd) {
624         DRM_ERROR("Null lcd pointer!\n");
625         return -1;
626     }
627 
628     if (io_index >= LCD_GPIO_NUM) {
629         DRM_ERROR("gpio num out of range\n");
630         return -1;
631     }
632 
633     sprintf(gpio_name, "lcd_gpio_%d", io_index);
634 
635     return sunxi_drm_sys_gpio_set_value(lcd->lcd_cfg.lcd_gpio[io_index].gpio/*lcd->lcd_cfg.gpio_hdl[io_index]*/,
636                             data, gpio_name);
637 }
638 
sunxi_lcd_get_tcon_id(unsigned int lcd_id)639 unsigned int sunxi_lcd_get_tcon_id(unsigned int lcd_id)
640 {
641     int tcon_id = sunxi_tcon_lcd_get_tcon_id(lcd_id);
642 
643     if (tcon_id < 0) {
644         DRM_ERROR("\n");
645         return -1;
646     }
647 
648     return tcon_id;
649 }
650 
sunxi_lcd_get_type_id(unsigned int lcd_id)651 unsigned int sunxi_lcd_get_type_id(unsigned int lcd_id)
652 {
653     struct sunxi_lcd *lcd;
654 
655     lcd = sunxi_lcd_get_lcd(lcd_id);
656     if (!lcd) {
657         DRM_ERROR("Null lcd pointer!\n");
658         return 0;
659     }
660 
661     return lcd->type_id;
662 }
663 
sunxi_lcd_get_type(unsigned int lcd_id)664 unsigned int sunxi_lcd_get_type(unsigned int lcd_id)
665 {
666     struct sunxi_lcd *lcd;
667 
668     lcd = sunxi_lcd_get_lcd(lcd_id);
669     if (!lcd) {
670         DRM_ERROR("Null lcd pointer!\n");
671         return 0;
672     }
673 
674     return lcd->type;
675 }
676 
sunxi_lcd_get_panel_para(unsigned int lcd_id)677 struct disp_panel_para *sunxi_lcd_get_panel_para(unsigned int lcd_id)
678 {
679     struct sunxi_lcd *lcd;
680 
681     lcd = sunxi_lcd_get_lcd(lcd_id);
682     if (!lcd) {
683         DRM_ERROR("Null lcd pointer!\n");
684         return 0;
685     }
686 
687     return &lcd->panel_para;
688 }
689 
sunxi_lcd_get_panel_ext_para(unsigned int lcd_id)690 struct panel_extend_para *sunxi_lcd_get_panel_ext_para(unsigned int lcd_id)
691 {
692     struct sunxi_lcd *lcd;
693 
694     lcd = sunxi_lcd_get_lcd(lcd_id);
695     if (!lcd) {
696         DRM_ERROR("Null lcd pointer!\n");
697         return NULL;
698     }
699 
700     return &lcd->extend_para;
701 }
702 
sunxi_lcd_get_panel_func(unsigned int lcd_id)703 struct disp_lcd_panel_fun *sunxi_lcd_get_panel_func(unsigned int lcd_id)
704 {
705     struct sunxi_lcd *lcd;
706 
707     lcd = sunxi_lcd_get_lcd(lcd_id);
708     if (!lcd) {
709         DRM_ERROR("Null lcd pointer!\n");
710         return NULL;
711     }
712     if (!lcd->panel) {
713         DRM_ERROR("lcd%d has NO panel\n", lcd_id);
714         return NULL;
715     }
716 
717     return &lcd->panel->func;
718 }
719 
720 /*
721  *@return: MHz
722  */
sunxi_lcd_get_dclk(unsigned int lcd_id)723 unsigned int sunxi_lcd_get_dclk(unsigned int lcd_id)
724 {
725     struct disp_panel_para *para = sunxi_lcd_get_panel_para(lcd_id);
726 
727     return para->lcd_dclk_freq;
728 }
729 
sunxi_lcd_get_lcd_if(unsigned int lcd_id)730 unsigned int sunxi_lcd_get_lcd_if(unsigned int lcd_id)
731 {
732     struct disp_panel_para *para = sunxi_lcd_get_panel_para(lcd_id);
733 
734     return para->lcd_if;
735 }
736 
sunxi_lcd_get_usec_per_line(unsigned int lcd_id)737 unsigned int sunxi_lcd_get_usec_per_line(unsigned int lcd_id)
738 {
739     unsigned int usec_per_line;
740     struct disp_panel_para *para = sunxi_lcd_get_panel_para(lcd_id);
741 
742     usec_per_line = para->lcd_ht / para->lcd_dclk_freq;
743 
744     return usec_per_line;
745 }
746 
747 /**
748  * @name       :sunxi_lcd_clk_config
749  * @brief      :set lcd clk rate
750  * @param[IN]  :lcd_id:lcd index
751  * @return     :0 if success, -1 else
752  * @TODO       :set dual dsi clk
753  */
sunxi_lcd_clk_config(unsigned int lcd_id)754 static int sunxi_lcd_clk_config(unsigned int lcd_id)
755 {
756     int ret = -1;
757     struct lcd_clk_info clk_info;
758     struct disp_panel_para *p_panel = NULL;
759     unsigned long dclk_rate = 33000000;
760     unsigned long pll_rate = 297000000, lcd_rate = 33000000;
761     unsigned long dsi_rate = 0;
762     unsigned long dsi_rate_set = 0, pll_rate_set = 0;
763     struct sunxi_lcd *lcd = NULL;
764     struct clk *parent_clk = NULL;
765 
766     p_panel = sunxi_lcd_get_panel_para(lcd_id);
767 
768     lcd = sunxi_lcd_get_lcd(lcd_id);
769 
770     if (!lcd || !p_panel) {
771         DRM_ERROR("Null lcd or panel pointer!\n");
772         return -1;
773     }
774 
775     /* no need to set clk rate */
776     if (p_panel->lcd_if != LCD_IF_DSI)
777         return 0;
778 
779 
780     memset(&clk_info, 0, sizeof(struct lcd_clk_info));
781     ret = sunxi_tcon_get_clk_info(lcd_id, &clk_info);
782     if (ret) {
783         DRM_WARN("Get clk_info fail!\n");
784         return ret;
785     }
786     dclk_rate = ((unsigned long long)sunxi_lcd_get_dclk(lcd_id)) * 1000000;
787 
788     lcd_rate = dclk_rate * clk_info.dsi_div;
789     pll_rate = lcd_rate * clk_info.lcd_div;
790     dsi_rate = pll_rate / clk_info.dsi_div;
791     pll_rate_set = pll_rate;
792     parent_clk = clk_get_parent(lcd->mclk);
793     if (parent_clk)
794         pll_rate_set = clk_get_rate(parent_clk);
795 
796     if (p_panel->lcd_if == LCD_IF_DSI) {
797         if (p_panel->lcd_dsi_if == LCD_DSI_IF_COMMAND_MODE)
798             dsi_rate_set = pll_rate_set;
799         else
800             dsi_rate_set = pll_rate_set / clk_info.dsi_div;
801 
802         dsi_rate_set =
803             (clk_info.dsi_rate == 0) ? dsi_rate_set : clk_info.dsi_rate;
804         clk_set_rate(lcd->mclk, dsi_rate_set);
805         dsi_rate_set = clk_get_rate(lcd->mclk);
806         if (dsi_rate_set != dsi_rate)
807             DRM_WARN("Dsi rate to be set:%lu, real clk rate:%lu\n", dsi_rate,
808                  dsi_rate_set);
809     }
810 
811     return ret;
812 }
813 
sunxi_lcd_is_use_irq(unsigned int lcd_id)814 bool sunxi_lcd_is_use_irq(unsigned int lcd_id)
815 {
816     struct sunxi_lcd *lcd;
817 
818     lcd = sunxi_lcd_get_lcd(lcd_id);
819     if (!lcd) {
820         DRM_ERROR("Null lcd pointer!\n");
821         return false;
822     }
823 
824     return lcd->irq_used;
825 }
826 
sunxi_lcd_get_irq_no(unsigned int lcd_id)827 unsigned int sunxi_lcd_get_irq_no(unsigned int lcd_id)
828 {
829     struct sunxi_lcd *lcd;
830 
831     lcd = sunxi_lcd_get_lcd(lcd_id);
832     if (!lcd) {
833         DRM_ERROR("Null lcd pointer!\n");
834         return 0;
835     }
836 
837     return lcd->irq_no;
838 }
839 
sunxi_lcd_prepare(unsigned int lcd_id)840 static int sunxi_lcd_prepare(unsigned int lcd_id)
841 {
842     int ret = 0;
843     struct sunxi_lcd *lcd;
844 
845     lcd = sunxi_lcd_get_lcd(lcd_id);
846     if (!lcd) {
847         DRM_ERROR("Null lcd pointer!\n");
848         return -1;
849     }
850 
851     if (lcd_drv->res.rst_bus_lvds) {
852         ret = reset_control_deassert(lcd_drv->res.rst_bus_lvds);
853         if (ret) {
854             DRM_ERROR("reset_control_deassert for rst_bus_lvds failed!\n");
855             return -1;
856         }
857     }
858 
859     sunxi_lcd_clk_config(lcd_id);
860     if (lcd->mclk) {
861         ret = clk_prepare_enable(lcd->mclk);
862         if (ret) {
863             DRM_ERROR("clk_prepare_enable failed\n");
864             return -1;
865         }
866     }
867 
868     if (lcd->mclk_bus) {
869         ret = clk_prepare_enable(lcd->mclk_bus);
870         if (ret) {
871             DRM_ERROR("clk_prepare_enable failed\n");
872             return -1;
873         }
874     }
875 
876     ret = sunxi_lcd_fix_power_enable(lcd);
877     if (ret) {
878         DRM_ERROR("sunxi_lcd_fix_power_enable failed\n");
879         return -1;
880     }
881 
882     ret = sunxi_lcd_gpio_init(lcd);
883     if (ret) {
884         DRM_ERROR("sunxi_lcd_gpio_init failed\n");
885         return -1;
886     }
887 
888     return 0;
889 }
890 
sunxi_lcd_sw_prepare(unsigned int lcd_id)891 static int sunxi_lcd_sw_prepare(unsigned int lcd_id)
892 {
893     int ret = 0;
894     struct sunxi_lcd *lcd;
895 
896     lcd = sunxi_lcd_get_lcd(lcd_id);
897     if (!lcd) {
898         DRM_ERROR("Null lcd pointer!\n");
899         return -1;
900     }
901 
902     if (lcd->mclk) {
903         ret = clk_prepare_enable(lcd->mclk);
904         if (ret) {
905             DRM_ERROR("clk_prepare_enable failed\n");
906             return -1;
907         }
908     }
909 
910     ret = sunxi_lcd_fix_power_enable(lcd);
911     if (ret) {
912         DRM_ERROR("sunxi_lcd_fix_power_enable failed\n");
913         return -1;
914     }
915 
916     ret = sunxi_lcd_gpio_init(lcd);
917     if (ret) {
918         DRM_ERROR("sunxi_lcd_gpio_init failed\n");
919         return -1;
920     }
921 
922     return 0;
923 }
924 
925 
sunxi_lcd_unprepare(unsigned int lcd_id)926 static void sunxi_lcd_unprepare(unsigned int lcd_id)
927 {
928     int ret = 0;
929     struct sunxi_lcd *lcd;
930 
931     lcd = sunxi_lcd_get_lcd(lcd_id);
932     if (!lcd) {
933         DRM_ERROR("Null lcd pointer!\n");
934         return;
935     }
936 
937     ret = sunxi_lcd_gpio_exit(lcd);
938     if (ret) {
939         DRM_ERROR("sunxi_lcd_gpio_exit failed\n");
940         return;
941     }
942 
943     ret = sunxi_lcd_fix_power_disable(lcd);
944     if (ret) {
945         DRM_ERROR("sunxi_lcd_fix_power_disable failed\n");
946         return;
947     }
948 
949     if (lcd->mclk)
950         clk_disable_unprepare(lcd->mclk);
951 
952 }
953 
sunxi_lcd_sw_enable(unsigned int lcd_id)954 int sunxi_lcd_sw_enable(unsigned int lcd_id)
955 {
956     struct disp_lcd_panel_fun *panel_func = NULL;
957 
958     panel_func = sunxi_lcd_get_panel_func(lcd_id);
959 
960     sunxi_lcd_sw_prepare(lcd_id);
961 
962     if (!panel_func->cfg_open_flow) {
963         DRM_ERROR("cfg_sw_open_flow hdl is NULL\n");
964         return -1;
965     }
966     panel_func->cfg_open_flow(lcd_id);
967 
968     return 0;
969 }
970 
sunxi_lcd_dsi_enable(unsigned int lcd_id)971 static int sunxi_lcd_dsi_enable(unsigned int lcd_id)
972 {
973     int ret;
974     struct disp_panel_para *panel_para;
975     struct disp_lcd_panel_fun *panel_func = NULL;
976     struct sunxi_lcd *lcd = sunxi_lcd_get_lcd(lcd_id);
977 
978     ret = sunxi_lcd_prepare(lcd_id);
979     if (ret < 0) {
980         DRM_ERROR("sunxi_lcd:%d prepare fialed\n", lcd_id);
981         return -1;
982     }
983 
984     panel_para = sunxi_lcd_get_panel_para(lcd_id);
985     panel_func = sunxi_lcd_get_panel_func(lcd_id);
986     if (!panel_para) {
987         DRM_ERROR("lcd_id:%d panel_para is NULL\n", lcd_id);
988         return -1;
989     }
990 #if defined(SUPPORT_DSI)
991     if (dsi_cfg(lcd->type_id, panel_para) != 0) {
992         DRM_ERROR("dsi_cfg failed\n");
993         return -1;
994     }
995 #endif
996     if (!panel_func) {
997         DRM_ERROR("GET panal_func Failed!\n");
998         return -1;
999     }
1000 
1001     if (!panel_func->cfg_open_flow) {
1002         DRM_ERROR("cfg_open_flow hdl is NULL\n");
1003         return -1;
1004     }
1005     panel_func->cfg_open_flow(lcd_id);
1006 
1007     return 0;
1008 }
1009 
sunxi_lcd_dsi_disable(unsigned int lcd_id)1010 static void sunxi_lcd_dsi_disable(unsigned int lcd_id)
1011 {
1012     struct disp_lcd_panel_fun *panel_func = NULL;
1013 
1014     panel_func = sunxi_lcd_get_panel_func(lcd_id);
1015     if (!panel_func) {
1016         DRM_ERROR("GET panal_func Failed!\n");
1017         return;
1018     }
1019 
1020     if (!panel_func->cfg_close_flow) {
1021         DRM_ERROR("cfg_open_close hdl is NULL\n");
1022         return;
1023     }
1024     panel_func->cfg_close_flow(lcd_id);
1025 #if defined(SUPPORT_DSI)
1026     if (dsi_exit(lcd_id) != 0) {
1027         DRM_ERROR("dsi_exit failed\n");
1028         return;
1029     }
1030 #endif
1031     sunxi_lcd_unprepare(lcd_id);
1032 
1033 }
1034 
sunxi_lcd_hv_enable(unsigned int lcd_id)1035 static int sunxi_lcd_hv_enable(unsigned int lcd_id)
1036 {
1037     int ret;
1038     struct disp_lcd_panel_fun *panel_func = NULL;
1039 
1040     /*set lcd output*/
1041     ret = sunxi_lcd_prepare(lcd_id);
1042     if (ret < 0) {
1043         DRM_ERROR("sunxi_lcd:%d prepare fialed\n", lcd_id);
1044         return -1;
1045     }
1046 
1047     panel_func = sunxi_lcd_get_panel_func(lcd_id);
1048     if (!panel_func) {
1049         DRM_ERROR("GET panal_func Failed!\n");
1050         return -1;
1051     }
1052 
1053     if (!panel_func->cfg_open_flow) {
1054         DRM_ERROR("cfg_open_flow hdl is NULL\n");
1055         return -1;
1056     }
1057 
1058     panel_func->cfg_open_flow(lcd_id);
1059 
1060     return 0;
1061 
1062 }
1063 
sunxi_lcd_hv_disable(unsigned int lcd_id)1064 static void sunxi_lcd_hv_disable(unsigned int lcd_id)
1065 {
1066     struct disp_lcd_panel_fun *panel_func = NULL;
1067 
1068     panel_func = sunxi_lcd_get_panel_func(lcd_id);
1069     if (!panel_func) {
1070         DRM_ERROR("GET panal_func Failed!\n");
1071         return;
1072     }
1073 
1074     if (!panel_func->cfg_close_flow) {
1075         DRM_ERROR("cfg_open_close hdl is NULL\n");
1076         return;
1077     }
1078     panel_func->cfg_close_flow(lcd_id);
1079 
1080     sunxi_lcd_unprepare(lcd_id);
1081 }
1082 
sunxi_lcd_lvds_enable(unsigned int lcd_id)1083 static int sunxi_lcd_lvds_enable(unsigned int lcd_id)
1084 {
1085     int ret;
1086     struct disp_lcd_panel_fun *panel_func = NULL;
1087 
1088     /*set lcd output*/
1089     ret = sunxi_lcd_prepare(lcd_id);
1090     if (ret < 0) {
1091         DRM_ERROR("sunxi_lcd:%d prepare fialed\n", lcd_id);
1092         return -1;
1093     }
1094 
1095     panel_func = sunxi_lcd_get_panel_func(lcd_id);
1096     if (!panel_func) {
1097         DRM_ERROR("GET panal_func Failed!\n");
1098         return -1;
1099     }
1100 
1101     if (!panel_func->cfg_open_flow) {
1102         DRM_ERROR("cfg_open_flow hdl is NULL\n");
1103         return -1;
1104     }
1105 
1106     panel_func->cfg_open_flow(lcd_id);
1107 
1108     return 0;
1109 
1110 }
1111 
sunxi_lcd_lvds_disable(unsigned int lcd_id)1112 static void sunxi_lcd_lvds_disable(unsigned int lcd_id)
1113 {
1114     struct disp_lcd_panel_fun *panel_func = NULL;
1115 
1116     panel_func = sunxi_lcd_get_panel_func(lcd_id);
1117     if (!panel_func) {
1118         DRM_ERROR("GET panal_func Failed!\n");
1119         return;
1120     }
1121 
1122     if (!panel_func->cfg_close_flow) {
1123         DRM_ERROR("cfg_open_close hdl is NULL\n");
1124         return;
1125     }
1126     panel_func->cfg_close_flow(lcd_id);
1127 
1128     sunxi_lcd_unprepare(lcd_id);
1129 }
1130 
backlight_info_show(struct device * dev,struct device_attribute * attr,char * buf)1131 static ssize_t backlight_info_show(struct device *dev,
1132                  struct device_attribute *attr, char *buf)
1133 {
1134 #if defined(CONFIG_AW_DRM_BACKLIGHT)
1135     return sunxi_backlight_info(buf);
1136 #else
1137     DRM_WARN("You must select CONFIG_AW_DRM_BACKLIGHT in menuconfig!\n");
1138     return 0;
1139 #endif
1140 }
1141 
backlight_info_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1142 static ssize_t backlight_info_store(struct device *dev,
1143                   struct device_attribute *attr,
1144                   const char *buf, size_t count)
1145 {
1146     return count;
1147 }
1148 
1149 static DEVICE_ATTR(backlight_info, 0660, backlight_info_show,
1150                     backlight_info_store);
1151 
sunxi_lcd_cfg_dump(char * buf,struct disp_lcd_cfg * cfg)1152 static ssize_t sunxi_lcd_cfg_dump(char *buf, struct disp_lcd_cfg *cfg)
1153 {
1154     ssize_t n = 0;
1155     unsigned int i;
1156 
1157     if (cfg->lcd_bl_en_used) {
1158         n += sprintf(buf + n, "lcd_bl_en gpio_name:%s  gpio:%d\n",
1159         cfg->lcd_bl_en.name, cfg->lcd_bl_en.gpio);
1160         n += sprintf(buf + n, "lcd_bl_en_power:%s\n",
1161                         cfg->lcd_bl_en_power);
1162     }
1163 
1164     for (i = 0; i < LCD_POWER_NUM; i++) {
1165         if (cfg->lcd_power_used[i])
1166             n += sprintf(buf + n, "lcd_power%d:%s\n",
1167                 i, cfg->lcd_power[i]);
1168     }
1169 
1170     for (i = 0; i < LCD_POWER_NUM; i++) {
1171         if (cfg->lcd_fix_power_used[i])
1172             n += sprintf(buf + n, "lcd_fix_power%d:%s\n",
1173                 i, cfg->lcd_fix_power[i]);
1174     }
1175 
1176     for (i = 0; i < LCD_GPIO_NUM; i++) {
1177         if (cfg->lcd_gpio_used[i])
1178             n += sprintf(buf + n, "lcd_gpio%d name:%s  gpio:%d\n",
1179                     i, cfg->lcd_gpio[i].name,
1180                     cfg->lcd_gpio[i].gpio);
1181     }
1182 
1183     for (i = 0; i < LCD_GPIO_REGU_NUM; i++) {
1184         if (cfg->lcd_power_used[i])
1185             n += sprintf(buf + n, "lcd_gpio_power%d:%s\n",
1186                         i, cfg->lcd_gpio_power[i]);
1187     }
1188 
1189     for (i = 0; i < LCD_GPIO_REGU_NUM; i++) {
1190         if (cfg->lcd_power_used[i])
1191             n += sprintf(buf + n, "lcd_pin_power%d:%s\n",
1192                         i, cfg->lcd_pin_power[i]);
1193     }
1194 
1195     n += sprintf(buf + n, "backlight_bright:%u\n", cfg->backlight_bright);
1196     n += sprintf(buf + n, "backlight_dimming:%u\n", cfg->backlight_dimming);
1197     n += sprintf(buf + n, "lcd_bright:%u\n", cfg->lcd_bright);
1198     n += sprintf(buf + n, "lcd_contrast:%u\n", cfg->lcd_contrast);
1199     n += sprintf(buf + n, "lcd_saturation:%u\n", cfg->lcd_saturation);
1200     n += sprintf(buf + n, "lcd_hue:%u\n", cfg->lcd_hue);
1201 
1202     return n;
1203 }
1204 
sunxi_lcd_exten_para_dump(char * buf,struct panel_extend_para * para)1205 static ssize_t sunxi_lcd_exten_para_dump(char *buf,
1206                 struct panel_extend_para *para)
1207 {
1208     ssize_t n = 0;
1209 
1210     n += sprintf(buf + n, "lcd_gamma_en:%u\n", para->lcd_gamma_en);
1211     n += sprintf(buf + n, "lcd_cmap_en:%u\n", para->lcd_cmap_en);
1212 
1213     return n;
1214 }
1215 
sunxi_lcd_panel_para_dump(char * buf,struct disp_panel_para * para)1216 static ssize_t sunxi_lcd_panel_para_dump(char *buf, struct disp_panel_para *para)
1217 {
1218     ssize_t n = 0;
1219 
1220     n += sprintf(buf + n, "lcd_if:%s\n",
1221             sunxi_lcd_get_connector_type_name(para->lcd_if));
1222     n += sprintf(buf + n, "lcd_width:%u\n", para->lcd_width);
1223     n += sprintf(buf + n, "lcd_height:%u\n", para->lcd_height);
1224     n += sprintf(buf + n, "lcd_dclk_freq:%u\n", para->lcd_dclk_freq);
1225     n += sprintf(buf + n, "lcd_frm:%u\n", para->lcd_frm);
1226     n += sprintf(buf + n, "lcd_rb_swap:%u\n", para->lcd_rb_swap);
1227     n += sprintf(buf + n, "lcd_gamma_en:%u\n", para->lcd_gamma_en);
1228     n += sprintf(buf + n, "lcd_cmap_en:%u\n", para->lcd_cmap_en);
1229     n += sprintf(buf + n, "lcd_xtal_freq:%u\n", para->lcd_xtal_freq);
1230     n += sprintf(buf + n, "lcd_size:%s\n", para->lcd_size);
1231     n += sprintf(buf + n, "lcd_model_name:%s\n", para->lcd_model_name);
1232     if (para->lcd_pwm_used) {
1233         n += sprintf(buf + n, "lcd_pwm_ch:%u\n", para->lcd_pwm_ch);
1234         n += sprintf(buf + n, "lcd_pwm_freq:%u\n", para->lcd_pwm_freq);
1235         n += sprintf(buf + n, "lcd_pwm_pol:%u\n", para->lcd_pwm_pol);
1236     } else {
1237         n += sprintf(buf + n, "%s\n", "NOT use PWM");
1238     }
1239 
1240     if (para->lcd_if == LCD_IF_LVDS) {
1241         n += sprintf(buf + n, "lcd_lvds_if:%s\n",
1242             sunxi_lcd_get_lvds_if_name(para->lcd_hv_if));
1243         n += sprintf(buf + n, "lcd_lvds_mode:%u\n",
1244                         para->lcd_lvds_mode);
1245         n += sprintf(buf + n, "lcd_lvds_colordepth:%u\n",
1246                         para->lcd_lvds_colordepth);
1247         n += sprintf(buf + n, "lcd_lvds_io_polarity:%u\n",
1248                         para->lcd_lvds_io_polarity);
1249         n += sprintf(buf + n, "lcd_lvds_clk_polarity:%u\n",
1250                         para->lcd_lvds_clk_polarity);
1251     } else if (para->lcd_if == LCD_IF_HV) { /*RGB*/
1252         n += sprintf(buf + n, "lcd_hv_if:%s\n",
1253             sunxi_lcd_get_hv_if_name(para->lcd_hv_if));
1254         n += sprintf(buf + n, "lcd_hv_clk_phase:%u\n",
1255                         para->lcd_hv_clk_phase);
1256         n += sprintf(buf + n, "lcd_hv_sync_polarity:%u\n",
1257                         para->lcd_hv_sync_polarity);
1258         n += sprintf(buf + n, "lcd_hv_srgb_seq:%u\n",
1259                         para->lcd_hv_srgb_seq);
1260         n += sprintf(buf + n, "lcd_hv_syuv_seq:%u\n",
1261                         para->lcd_hv_syuv_seq);
1262         n += sprintf(buf + n, "lcd_hv_syuv_fdly:%u\n",
1263                         para->lcd_hv_syuv_fdly);
1264     } else if (para->lcd_if == LCD_IF_CPU) {
1265         n += sprintf(buf + n, "lcd_cpu_if:%s\n",
1266             sunxi_lcd_get_cpu_if_name(para->lcd_cpu_if));
1267         n += sprintf(buf + n, "lcd_cpu_te:%u\n", para->lcd_cpu_te);
1268     } else if (para->lcd_if == LCD_IF_DSI) {
1269         n += sprintf(buf + n, "lcd_dsi_if:%s\n",
1270             sunxi_lcd_get_dsi_if_name(para->lcd_dsi_if));
1271         n += sprintf(buf + n, "lcd_dsi_lane:%u\n", para->lcd_dsi_lane);
1272         n += sprintf(buf + n, "lcd_dsi_format:%u\n",
1273                             para->lcd_dsi_format);
1274         n += sprintf(buf + n, "lcd_dsi_eotp:%u\n", para->lcd_dsi_eotp);
1275         n += sprintf(buf + n, "lcd_dsi_te:%u\n", para->lcd_dsi_te);
1276     } else if (para->lcd_if == LCD_IF_EDP) {
1277     }
1278 
1279     return n;
1280 }
1281 
lcd_info_show(struct device * dev,struct device_attribute * attr,char * buf)1282 static ssize_t lcd_info_show(struct device *dev,
1283                  struct device_attribute *attr, char *buf)
1284 {
1285     ssize_t n = 0;
1286     unsigned int i;
1287     struct sunxi_lcd *lcd;
1288 
1289     n += sprintf(buf + n, "%s\n", "sunxi LCD info:");
1290     n += sprintf(buf + n, "lcd count:%u\n", lcd_drv->lcd_cnt);
1291     if (lcd_drv->lvds_cnt)
1292         n += sprintf(buf + n, "lvds count:%u\n", lcd_drv->lvds_cnt);
1293     if (lcd_drv->rgb_cnt)
1294         n += sprintf(buf + n, "rgb count:%u\n", lcd_drv->rgb_cnt);
1295     if (lcd_drv->dsi_cnt)
1296         n += sprintf(buf + n, "dsi count:%u\n", lcd_drv->dsi_cnt);
1297     if (lcd_drv->edp_cnt)
1298         n += sprintf(buf + n, "edp count:%u\n", lcd_drv->edp_cnt);
1299     n += sprintf(buf + n, "\n");
1300 
1301     for (i = 0; i < lcd_drv->lcd_cnt; i++) {
1302         lcd = sunxi_lcd_get_lcd(i);
1303         if (!lcd) {
1304             DRM_ERROR("Null lcd pointer!\n");
1305             return 0;
1306         }
1307         n += sprintf(buf + n, "id:%d\n", lcd->id);
1308         if (!lcd->is_used) {
1309             n += sprintf(buf + n, "%s\n\n", "NOT used");
1310             continue;
1311         }
1312 
1313         n += sprintf(buf + n, "type:%s%d\n",
1314             sunxi_lcd_get_connector_type_name(lcd->type),
1315                     lcd->type_id);
1316 
1317         if (!lcd->reg_base)
1318             n += sprintf(buf + n, "%s\n", "Do NOT have reg_base"
1319                 ", rely on TCON");
1320         else
1321             n += sprintf(buf + n, "reg_base:%lu\n", lcd->reg_base);
1322 
1323         if (lcd->mclk) {
1324             n += sprintf(buf + n, "clk_name:%s clk_rate: %lu"
1325                         "  enable count:%d\n",
1326                     __clk_get_name(lcd->mclk),
1327                     clk_get_rate(lcd->mclk),
1328                     __clk_get_enable_count(lcd->mclk));
1329         } else {
1330             n += sprintf(buf + n, "%s\n", "ERROR: NOT have CLK");
1331         }
1332 
1333         if (lcd->irq_used)
1334             n += sprintf(buf + n, "irq_no:%u\n", lcd->irq_no);
1335         else
1336             n += sprintf(buf + n, "%s\n", "NOT use irq and "
1337                 "do NOT have irq_no ");
1338 
1339         if (lcd->use_bl)
1340             n += sprintf(buf + n, "Use Backlight\n");
1341         else
1342             n += sprintf(buf + n, "NOT use Backlight\n");
1343 
1344         n += sunxi_lcd_cfg_dump(buf + n, &lcd->lcd_cfg);
1345         n += sunxi_lcd_exten_para_dump(buf + n, &lcd->extend_para);
1346         n += sunxi_lcd_panel_para_dump(buf + n, &lcd->panel_para);
1347 
1348         n += sprintf(buf + n, "\n");
1349     }
1350 
1351 
1352 
1353     return n;
1354 }
1355 
lcd_info_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1356 static ssize_t lcd_info_store(struct device *dev,
1357                   struct device_attribute *attr,
1358                   const char *buf, size_t count)
1359 {
1360     return count;
1361 }
1362 
1363 static DEVICE_ATTR(lcd_info, 0660, lcd_info_show, lcd_info_store);
1364 
lcd_reg_show(struct device * dev,struct device_attribute * attr,char * buf)1365 static ssize_t lcd_reg_show(struct device *dev,
1366                  struct device_attribute *attr, char *buf)
1367 {
1368     return 0;
1369 }
1370 
lcd_reg_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1371 static ssize_t lcd_reg_store(struct device *dev,
1372                   struct device_attribute *attr,
1373                   const char *buf, size_t count)
1374 {
1375     return count;
1376 }
1377 
1378 static DEVICE_ATTR(reg, 0660, lcd_reg_show, lcd_reg_store);
1379 
1380 
1381 static struct attribute *lcd_attributes[] = {
1382     &dev_attr_lcd_info.attr,
1383     &dev_attr_reg.attr,
1384     &dev_attr_backlight_info.attr,
1385     NULL
1386 };
1387 
1388 static struct attribute_group lcd_attribute_group = {
1389     .name = "attr",
1390     .attrs = lcd_attributes,
1391 };
1392 
sunxi_lcd_dts_parse_lcd_core(struct platform_device * pdev,struct sunxi_lcd_resource * res)1393 static int sunxi_lcd_dts_parse_lcd_core(struct platform_device *pdev,
1394                 struct sunxi_lcd_resource *res)
1395 {
1396     unsigned int count = 0, i;
1397     struct device_node *node = pdev->dev.of_node;
1398 
1399     /*for (i = 0; i < DEVICE_DSI_NUM; i++) {
1400         res->reg_base[SUNXI_DSI0 + i]
1401             = (uintptr_t __force)of_iomap(node, i);
1402         if (!res->reg_base[SUNXI_DSI0 + i]) {
1403             DRM_ERROR("unable to map dsi-%d registers\n",
1404                             i);
1405             return -EINVAL;
1406         }
1407     }
1408 
1409     count = 0;*/
1410 #ifdef SUPPORT_LVDS
1411 #ifndef CONFIG_ARCH_SUN50IW9
1412     res->mclk[SUNXI_LVDS0] = of_clk_get(node, count);
1413     if (IS_ERR(res->mclk[SUNXI_LVDS0])) {
1414         DRM_ERROR("fail to get clk for lvds\n");
1415         return -EINVAL;
1416     }
1417     count++;
1418 #endif
1419     res->rst_bus_lvds = devm_reset_control_get_shared(&pdev->dev, "rst_bus_lvds");
1420     if (IS_ERR(res->rst_bus_lvds)) {
1421         DRM_ERROR("fail to get reset clk for rst_bus_lvds\n");
1422         return -EINVAL;
1423     }
1424 #endif
1425 #if 0
1426     for (i = 0; i < DRM_DSI_NUM; i++) {
1427         res->mclk[SUNXI_DSI0 + i] = of_clk_get(node, count);
1428         if (IS_ERR(res->mclk[SUNXI_DSI0 + i])) {
1429             DRM_ERROR("fail to get clk for dsi\n");
1430             return -EINVAL;
1431         }
1432         count++;
1433     }
1434 
1435     count = 0;
1436     for (i = 0; i < DRM_DSI_NUM; i++) {
1437         res->irq_no[SUNXI_DSI0 + i] = irq_of_parse_and_map(node, count);
1438         if (!res->irq_no[SUNXI_DSI0 + i]) {
1439             DRM_ERROR("[SUNXI-TCON]get irq no of DSI%d failed\n", i);
1440             return -EINVAL;
1441         }
1442         count++;
1443     }
1444 #endif
1445     return 0;
1446 }
1447 
sunxi_lcd_init_al(struct sunxi_lcd_resource * res)1448 static int sunxi_lcd_init_al(struct sunxi_lcd_resource *res)
1449 {
1450 #if 0 // defined(SUPPORT_DSI)
1451     int i;
1452     for (i = 0; i < DRM_DSI_NUM; ++i)
1453         dsi_set_reg_base(i, res->reg_base[SUNXI_DSI0 + i]);
1454 #endif
1455     return 0;
1456 }
1457 
1458 /* parse lcd gpio info
1459  * lcd_bl_en: backlight enable gpio
1460  * lcd_gpio_xxx: lcd general gpio
1461  * lcd_gpio_sda/scl
1462  */
sunxi_lcd_dts_parse_gpio_info(struct platform_device * pdev,struct disp_lcd_cfg * lcd_cfg)1463 static int sunxi_lcd_dts_parse_gpio_info(struct platform_device *pdev,
1464                     struct disp_lcd_cfg  *lcd_cfg)
1465 {
1466     struct disp_gpio_info *gpio_info;
1467     char sub_name[25];
1468     int ret, i;
1469     struct device_node *node = pdev->dev.of_node;
1470 
1471     /* lcd_bl_en gpio
1472      * gpio for enable LCD backlight
1473      * NOTE: it is NOT PWM
1474      */
1475     lcd_cfg->lcd_bl_en_used = 0;
1476     gpio_info = (struct disp_gpio_info *)&(lcd_cfg->lcd_bl_en);
1477     ret = sunxi_drm_get_sys_item_gpio(node, "lcd_bl_en", gpio_info);
1478     if (ret == 0) {
1479         lcd_cfg->lcd_bl_en_used = 1;
1480         DRM_INFO("[SUNXI-LCD]get gpio:lcd_bl_en: ");
1481         DRM_INFO("[SUNXI-LCD]name:%s gpio:%d\n",
1482                 gpio_info->name, gpio_info->gpio);
1483     }
1484 
1485     /* lcd_gpio_0/1/2
1486      * LCD common gpio, such as LCD-RST/ so on
1487      */
1488     for (i = 0; i < LCD_GPIO_NUM; i++) {
1489         sprintf(sub_name, "lcd_gpio_%d", i);
1490         gpio_info = (struct disp_gpio_info *)&(lcd_cfg->lcd_gpio[i]);
1491         ret = sunxi_drm_get_sys_item_gpio(node, sub_name, gpio_info);
1492         if (ret == 0) {
1493             lcd_cfg->lcd_gpio_used[i] = 1;
1494             DRM_INFO("[SUNXI-LCD]get gpio:%s: ", sub_name);
1495             DRM_INFO("[SUNXI-LCD]name:%s gpio:%d\n",
1496                 gpio_info->name, gpio_info->gpio);
1497         }
1498     }
1499 
1500     /* lcd_gpio_scl,lcd_gpio_sda */
1501     gpio_info = (struct disp_gpio_info *)&(lcd_cfg->lcd_gpio[LCD_GPIO_SCL]);
1502     ret = sunxi_drm_get_sys_item_gpio(node, "lcd_gpio_scl", gpio_info);
1503     if (ret == 0) {
1504         lcd_cfg->lcd_gpio_used[LCD_GPIO_SCL] = 1;
1505         DRM_INFO("[SUNXI-LCD]get lcd_gpio_scl: ");
1506         DRM_INFO("[SUNXI-LCD]name:%s gpio:%d\n",
1507                 gpio_info->name, gpio_info->gpio);
1508     }
1509 
1510     gpio_info = (struct disp_gpio_info *)&(lcd_cfg->lcd_gpio[LCD_GPIO_SDA]);
1511     ret = sunxi_drm_get_sys_item_gpio(node, "lcd_gpio_sda", gpio_info);
1512     if (ret == 0) {
1513         lcd_cfg->lcd_gpio_used[LCD_GPIO_SDA] = 1;
1514         DRM_INFO("[SUNXI-LCD]get lcd_gpio_sda: ");
1515         DRM_INFO("[SUNXI-LCD]name:%s gpio:%d\n",
1516                 gpio_info->name, gpio_info->gpio);
1517     }
1518 
1519     return 0;
1520 }
1521 
1522 /* parse LCD power info
1523  * lcd_bl_en_power
1524  * lcd_fix_power
1525  * lcd_power/lcd_power0/1/2
1526  * lcd_gpio_power
1527  * lcd_pin_power
1528  */
sunxi_lcd_dts_parse_power_info(struct platform_device * pdev,struct disp_lcd_cfg * lcd_cfg)1529 static int sunxi_lcd_dts_parse_power_info(struct platform_device *pdev,
1530                 struct disp_lcd_cfg  *lcd_cfg)
1531 {
1532     char sub_name[25];
1533     struct device_node *node = pdev->dev.of_node;
1534     int ret, i;
1535     g_lcd_dev = &pdev->dev;
1536     /* lcd_bl_en_power */
1537     sprintf(sub_name, "lcd_bl_en_power");
1538     ret = sunxi_drm_get_sys_item_char(node, sub_name,
1539         lcd_cfg->lcd_bl_en_power);
1540     if (ret == 0)
1541         DRM_INFO("[SUNXI-LCD]get %s(%s)\n", sub_name,
1542                 lcd_cfg->lcd_bl_en_power);
1543 
1544     /* lcd fix power
1545      * lcd connector type specific power
1546      * often used for vcc-dsi/vcc-lvds
1547      */
1548     for (i = 0; i < LCD_POWER_NUM; i++) {
1549         if (i == 0)
1550             sprintf(sub_name, "lcd_fix_power");
1551         else
1552             sprintf(sub_name, "lcd_fix_power%d", i);
1553 
1554         lcd_cfg->lcd_fix_power_used[i] = 0;
1555         ret = sunxi_drm_get_sys_item_char(node, sub_name,
1556             lcd_cfg->lcd_fix_power[i]);
1557         if (ret == 0) {
1558             lcd_cfg->lcd_fix_power_used[i] = 1;
1559             DRM_INFO("[SUNXI-LCD]get %s(%s)\n", sub_name,
1560                     lcd_cfg->lcd_fix_power[i]);
1561         }
1562     }
1563 
1564     /* lcd_power lcd common power
1565      * such as: vcc-lcd
1566      */
1567     for (i = 0; i < LCD_POWER_NUM; i++) {
1568         if (i == 0)
1569             sprintf(sub_name, "lcd_power");
1570         else
1571             sprintf(sub_name, "lcd_power%d", i);
1572 
1573         lcd_cfg->lcd_power_used[i] = 0;
1574         ret = sunxi_drm_get_sys_item_char(node, sub_name,
1575             lcd_cfg->lcd_power[i]);
1576         if (ret == 0) {
1577             lcd_cfg->lcd_power_used[i] = 1;
1578             DRM_INFO("[SUNXI-LCD]get %s(%s)\n", sub_name,
1579                     lcd_cfg->lcd_power[i]);
1580         }
1581     }
1582 
1583     for (i = 0; i < LCD_GPIO_REGU_NUM; i++) {
1584         sprintf(sub_name, "lcd_gpio_power%d", i);
1585         ret = sunxi_drm_get_sys_item_char(node, sub_name,
1586             lcd_cfg->lcd_gpio_power[i]);
1587         if (ret == 0) {
1588             lcd_cfg->lcd_power_used[i] = 1;
1589             DRM_INFO("[SUNXI-LCD]get %s(%s)\n", sub_name,
1590                     lcd_cfg->lcd_gpio_power[i]);
1591         }
1592     }
1593 
1594     /* lcd power for pin, such as: vcc-pd */
1595     for (i = 0; i < LCD_GPIO_REGU_NUM; i++) {
1596         if (0 == i)
1597             sprintf(sub_name, "lcd_pin_power");
1598         else
1599             sprintf(sub_name, "lcd_pin_power%d", i);
1600 
1601         ret = sunxi_drm_get_sys_item_char(node, sub_name,
1602             lcd_cfg->lcd_pin_power[i]);
1603         if (ret == 0) {
1604             lcd_cfg->lcd_power_used[i] = 1;
1605             DRM_INFO("[SUNXI-LCD]get %s(%s)\n", sub_name,
1606                     lcd_cfg->lcd_pin_power[i]);
1607         }
1608     }
1609 
1610     return 0;
1611 }
1612 
1613 /* lcd backlight
1614  * NOTE: is often PWM, different from backlight enable(lcd_bl_en)
1615  */
sunxi_lcd_dts_parse_backlight_info(struct platform_device * pdev,struct disp_lcd_cfg * lcd_cfg)1616 static int sunxi_lcd_dts_parse_backlight_info(struct platform_device *pdev,
1617                     struct disp_lcd_cfg  *lcd_cfg)
1618 {
1619     struct device_node *node = pdev->dev.of_node;
1620     int ret, i, value = 1;
1621     char sub_name[25];
1622 
1623     /* backlight adjust */
1624     for (i = 0; i < 101; i++) {
1625         sprintf(sub_name, "lcd_bl_%d_percent", i);
1626         lcd_cfg->backlight_curve_adjust[i] = 0;
1627 
1628         if (i == 100) {
1629             lcd_cfg->backlight_curve_adjust[i] = 255;
1630         }
1631 
1632         ret = of_property_read_u32(node, sub_name, &value);
1633         if (ret == 0) {
1634             value = (value > 100) ? 100:value;
1635             value = value * 255 / 100;
1636             lcd_cfg->backlight_curve_adjust[i] = value;
1637         }
1638     }
1639 
1640     sprintf(sub_name, "lcd_backlight");
1641     ret = of_property_read_u32(node, sub_name, &value);
1642     if (ret == 0) {
1643         value = (value > 256) ? 256:value;
1644         lcd_cfg->backlight_bright = value;
1645     } else {
1646         lcd_cfg->backlight_bright = 197;
1647     }
1648     lcd_cfg->lcd_bright = lcd_cfg->backlight_bright;
1649 
1650     return 0;
1651 }
1652 
sunxi_lcd_dts_parse_pannel_timing(struct platform_device * pdev,struct disp_panel_para * info)1653 static int sunxi_lcd_dts_parse_pannel_timing(struct platform_device *pdev,
1654                         struct disp_panel_para *info)
1655 {
1656     struct device_node *node = pdev->dev.of_node;
1657     int ret, value = 1;
1658 
1659     /* display mode */
1660     ret = of_property_read_u32(node, "lcd_x", &value);
1661     if (ret != 0) {
1662         DRM_ERROR("parse lcd_x failed\n");
1663         return -1;
1664     }
1665     info->lcd_x = value;
1666 
1667     ret = of_property_read_u32(node, "lcd_y", &value);
1668     if (ret != 0) {
1669         DRM_ERROR("parse lcd_y failed\n");
1670         return -1;
1671     }
1672     info->lcd_y = value;
1673 
1674     ret = of_property_read_u32(node, "lcd_hbp", &value);
1675     if (ret == 0)
1676         info->lcd_hbp = value;
1677 
1678     ret = of_property_read_u32(node, "lcd_ht", &value);
1679     if (ret == 0)
1680         info->lcd_ht = value;
1681 
1682     ret = of_property_read_u32(node, "lcd_vbp", &value);
1683     if (ret == 0)
1684         info->lcd_vbp = value;
1685 
1686     ret = of_property_read_u32(node, "lcd_vt", &value);
1687     if (ret == 0)
1688         info->lcd_vt = value;
1689 
1690     ret = of_property_read_u32(node, "lcd_vspw", &value);
1691     if (ret == 0)
1692         info->lcd_vspw = value;
1693 
1694     ret = of_property_read_u32(node, "lcd_hspw", &value);
1695     if (ret == 0)
1696         info->lcd_hspw = value;
1697 
1698     return 0;
1699 }
1700 
sunxi_lcd_dts_parse_pwm(struct platform_device * pdev,struct disp_panel_para * info)1701 static int sunxi_lcd_dts_parse_pwm(struct platform_device *pdev,
1702                     struct disp_panel_para *info)
1703 {
1704     struct device_node *node = pdev->dev.of_node;
1705     int ret, value = 1;
1706 
1707     ret = of_property_read_u32(node, "lcd_pwm_ch", &value);
1708     if (ret != 0) {
1709         DRM_ERROR("parse lcd_pwm_ch failed\n");
1710         return -1;
1711     }
1712     info->lcd_pwm_ch = value;
1713 
1714     ret = of_property_read_u32(node, "lcd_pwm_freq", &value);
1715     if (ret != 0) {
1716         DRM_ERROR("parse lcd_pwm_freq failed\n");
1717         return -1;
1718     }
1719     info->lcd_pwm_freq = value;
1720 
1721     ret = of_property_read_u32(node, "lcd_pwm_pol", &value);
1722     if (ret != 0) {
1723         DRM_ERROR("parse lcd_pwm_pol failed\n");
1724         return -1;
1725     }
1726     info->lcd_pwm_pol = value;
1727 
1728 
1729     return 0;
1730 }
1731 
1732 /* RGB */
sunxi_lcd_dts_parse_hv(struct platform_device * pdev,struct disp_panel_para * info)1733 static int sunxi_lcd_dts_parse_hv(struct platform_device *pdev,
1734                     struct disp_panel_para *info)
1735 {
1736     struct device_node *node = pdev->dev.of_node;
1737     int ret, value = 1;
1738 
1739     ret = of_property_read_u32(node, "lcd_hv_if", &value);
1740     if (ret != 0) {
1741         DRM_ERROR("parse lcd_hv_if failed\n");
1742         return -1;
1743     }
1744     info->lcd_hv_if = value;
1745 
1746     ret = of_property_read_u32(node, "lcd_hv_clk_phase", &value);
1747     if (ret != 0) {
1748         DRM_ERROR("parse lcd_hv_clk_phase failed\n");
1749         return -1;
1750     }
1751     info->lcd_hv_clk_phase = value;
1752 
1753     ret = of_property_read_u32(node, "lcd_hv_sync_polarity", &value);
1754     if (ret != 0) {
1755         DRM_ERROR("parse lcd_hv_sync_polarity failed\n");
1756         return -1;
1757     }
1758     info->lcd_hv_sync_polarity = value;
1759 
1760     ret = of_property_read_u32(node, "lcd_hv_srgb_seq", &value);
1761     if (ret != 0) {
1762         DRM_ERROR("parse lcd_hv_srgb_seq failed\n");
1763         return -1;
1764     }
1765     info->lcd_hv_srgb_seq = value;
1766 
1767     ret = of_property_read_u32(node, "lcd_hv_syuv_seq", &value);
1768     if (ret != 0) {
1769         DRM_ERROR("parse lcd_hv_syuv_seq failed\n");
1770         return -1;
1771     }
1772     info->lcd_hv_syuv_seq = value;
1773 
1774     ret = of_property_read_u32(node, "lcd_hv_syuv_fdly", &value);
1775     if (ret != 0) {
1776         DRM_ERROR("parse lcd_hv_syuv_fdly failed\n");
1777         return -1;
1778     }
1779     info->lcd_hv_syuv_fdly = value;
1780 
1781     return 0;
1782 }
1783 
sunxi_lcd_dts_parse_lvds(struct platform_device * pdev,struct disp_panel_para * info)1784 static int sunxi_lcd_dts_parse_lvds(struct platform_device *pdev,
1785                     struct disp_panel_para *info)
1786 {
1787     struct device_node *node = pdev->dev.of_node;
1788     int ret, value = 1;
1789 
1790     ret = of_property_read_u32(node, "lcd_lvds_if", &value);
1791     if (ret != 0) {
1792         DRM_ERROR("parse lcd_lvds_if failed\n");
1793         return -1;
1794     }
1795     info->lcd_lvds_if = value;
1796 
1797     ret = of_property_read_u32(node, "lcd_lvds_mode", &value);
1798     if (ret != 0) {
1799         DRM_ERROR("parse lcd_lvds_mode failed\n");
1800         return -1;
1801     }
1802     info->lcd_lvds_mode = value;
1803 
1804     ret = of_property_read_u32(node, "lcd_lvds_colordepth",
1805         &value);
1806     if (ret != 0) {
1807         DRM_ERROR("parse lcd_lvds_colordepth failed\n");
1808         return -1;
1809     }
1810     info->lcd_lvds_colordepth = value;
1811 
1812     ret = of_property_read_u32(node, "lcd_lvds_io_polarity",
1813         &value);
1814     if (ret == 0)
1815         info->lcd_lvds_io_polarity = value;
1816 
1817     ret = of_property_read_u32(node, "lcd_lvds_clk_polarity",
1818         &value);
1819     if (ret == 0)
1820         info->lcd_lvds_clk_polarity = value;
1821 
1822     return 0;
1823 }
1824 
sunxi_lcd_dts_parse_cpu(struct platform_device * pdev,struct disp_panel_para * info)1825 static int sunxi_lcd_dts_parse_cpu(struct platform_device *pdev,
1826                     struct disp_panel_para *info)
1827 {
1828     struct device_node *node = pdev->dev.of_node;
1829     int ret, value = 1;
1830 
1831     ret = of_property_read_u32(node, "lcd_cpu_if", &value);
1832     if (ret != 0) {
1833         DRM_ERROR("parse lcd_cpu_if failed\n");
1834         return -1;
1835     }
1836     info->lcd_cpu_if = value;
1837 
1838     ret = of_property_read_u32(node, "lcd_cpu_te", &value);
1839     if (ret != 0) {
1840         DRM_ERROR("parse lcd_cpu_te failed\n");
1841         return -1;
1842     }
1843     info->lcd_cpu_te = value;
1844 
1845     return 0;
1846 }
1847 
sunxi_lcd_dts_parse_dsi(struct platform_device * pdev,struct disp_panel_para * info)1848 static int sunxi_lcd_dts_parse_dsi(struct platform_device *pdev,
1849                     struct disp_panel_para *info)
1850 {
1851     struct device_node *node = pdev->dev.of_node;
1852     int ret, value = 1;
1853 
1854     ret = of_property_read_u32(node, "lcd_dsi_if", &value);
1855     if (ret != 0) {
1856         DRM_ERROR("parse lcd_dsi_if failed\n");
1857         return -1;
1858     }
1859     info->lcd_dsi_if = value;
1860 
1861     ret = of_property_read_u32(node, "lcd_dsi_lane", &value);
1862     if (ret != 0) {
1863         DRM_ERROR("parse lcd_dsi_lane failed\n");
1864         return -1;
1865     }
1866     info->lcd_dsi_lane = value;
1867 
1868     ret = of_property_read_u32(node, "lcd_dsi_format",
1869         &value);
1870     if (ret != 0) {
1871         DRM_ERROR("parse lcd_dsi_format failed\n");
1872         return -1;
1873     }
1874     info->lcd_dsi_format = value;
1875 
1876     ret = of_property_read_u32(node, "lcd_dsi_eotp", &value);
1877     if (ret != 0) {
1878         DRM_ERROR("parse lcd_dsi_eotp failed\n");
1879         return -1;
1880     }
1881     info->lcd_dsi_eotp = value;
1882 
1883     ret = of_property_read_u32(node, "lcd_dsi_te", &value);
1884     if (ret != 0) {
1885         DRM_ERROR("parse lcd_dsi_te failed\n");
1886         return -1;
1887     }
1888     info->lcd_dsi_te = value;
1889 
1890     return 0;
1891 }
1892 
sunxi_lcd_dts_parse_edp(struct platform_device * pdev,struct disp_panel_para * info)1893 static int sunxi_lcd_dts_parse_edp(struct platform_device *pdev,
1894                     struct disp_panel_para *info)
1895 {
1896     struct device_node *node = pdev->dev.of_node;
1897     int ret, value = 1;
1898 
1899     ret = of_property_read_u32(node, "lcd_edp_rate", &value);
1900     if (ret != 0) {
1901         DRM_ERROR("parse lcd_edp_rate failed\n");
1902         return -1;
1903     }
1904     // info->lcd_edp_rate = value
1905 
1906     ret = of_property_read_u32(node, "lcd_edp_lane", &value);
1907     if (ret != 0) {
1908         DRM_ERROR("parse lcd_edp_lane failed\n");
1909         return -1;
1910     }
1911     // info->lcd_edp_lane = value
1912 
1913     ret = of_property_read_u32(node, "lcd_edp_colordepth", &value);
1914     if (ret != 0) {
1915         DRM_ERROR("parse lcd_edp_colordepth failed\n");
1916         return -1;
1917     }
1918     // info->lcd_edp_colordepth = value
1919 
1920     ret = of_property_read_u32(node, "lcd_edp_fps", &value);
1921     if (ret != 0) {
1922         DRM_ERROR("parse lcd_edp_fps failed\n");
1923         return -1;
1924     }
1925     // info->lcd_edp_fps = value
1926 
1927     return 0;
1928 }
1929 
sunxi_lcd_dts_parse_panel_info(struct platform_device * pdev,struct disp_panel_para * info)1930 static int sunxi_lcd_dts_parse_panel_info(struct platform_device *pdev,
1931                     struct disp_panel_para *info)
1932 {
1933     struct device_node *node = pdev->dev.of_node;
1934     int ret, value = 1;
1935 
1936 
1937     ret = of_property_read_u32(node, "lcd_width", &value);
1938     if (ret < 0) {
1939         DRM_ERROR("get lcd_width failed\n");
1940         return -1;
1941     }
1942     info->lcd_width = value;
1943 
1944     ret = of_property_read_u32(node, "lcd_height", &value);
1945     if (ret < 0) {
1946         DRM_ERROR("get lcd_height failed\n");
1947         return -1;
1948     }
1949     info->lcd_height = value;
1950 
1951     ret = of_property_read_u32(node, "lcd_dclk_freq", &value);
1952     if (ret < 0) {
1953         DRM_ERROR("get lcd_dclk_freq failed\n");
1954         return -1;
1955     }
1956     info->lcd_dclk_freq = value;
1957 
1958     ret = sunxi_lcd_dts_parse_pannel_timing(pdev, info);
1959     if (ret < 0) {
1960         DRM_ERROR("sunxi_lcd_dts_parse_pannel_timing failed\n");
1961         return -1;
1962     }
1963 
1964 
1965     ret = of_property_read_u32(node, "lcd_pwm_used", &value);
1966     if (ret == 0) {
1967         info->lcd_pwm_used = value;
1968         if (sunxi_lcd_dts_parse_pwm(pdev, info)) {
1969             DRM_ERROR("sunxi_lcd_dts_parse_pwm failed\n");
1970             return -1;
1971         }
1972     } else {
1973         DRM_INFO("[SUNXI-LCD]NOT use PWM\n");
1974     }
1975 
1976     ret = of_property_read_u32(node, "lcd_if", &value);
1977     if (ret != 0) {
1978         DRM_ERROR("parse lcd_if failed\n");
1979         return -1;
1980     }
1981     info->lcd_if = value;
1982 
1983     if (info->lcd_if == LCD_IF_HV) { /* RGB */
1984         /* if (sunxi_lcd_dts_parse_hv(pdev, info)) {
1985                DRM_ERROR("sunxi_lcd_dts_parse_hv failed\n");
1986                return -1;
1987            } */
1988     } else if (info->lcd_if == LCD_IF_LVDS) {
1989         if (sunxi_lcd_dts_parse_lvds(pdev, info)) {
1990             DRM_ERROR("sunxi_lcd_dts_parse_lvds failed\n");
1991             return -1;
1992         }
1993     } else if (info->lcd_if == LCD_IF_CPU) {
1994         if (sunxi_lcd_dts_parse_cpu(pdev, info)) {
1995             DRM_ERROR("sunxi_lcd_dts_parse_lvds failed\n");
1996             return -1;
1997         }
1998     } else if (info->lcd_if == LCD_IF_DSI) {
1999         if (sunxi_lcd_dts_parse_dsi(pdev, info)) {
2000             DRM_ERROR("sunxi_lcd_dts_parse_dsi failed\n");
2001             return -1;
2002         }
2003     } else if (info->lcd_if == LCD_IF_EDP) {
2004         if (sunxi_lcd_dts_parse_edp(pdev, info)) {
2005             DRM_ERROR("sunxi_lcd_dts_parse_edp failed\n");
2006             return -1;
2007         }
2008     }
2009 
2010     ret = of_property_read_u32(node, "lcd_frm", &value);
2011     if (ret == 0)
2012         info->lcd_frm = value;
2013 
2014     ret = of_property_read_u32(node, "lcd_rb_swap", &value);
2015     if (ret == 0)
2016         info->lcd_rb_swap = value;
2017 
2018     ret = of_property_read_u32(node, "lcd_gamma_en", &value);
2019     if (ret == 0)
2020         info->lcd_gamma_en = value;
2021 
2022     ret = of_property_read_u32(node, "lcd_cmap_en", &value);
2023     if (ret == 0)
2024         info->lcd_cmap_en = value;
2025 
2026     ret = of_property_read_u32(node, "lcd_xtal_freq", &value);
2027     if (ret == 0)
2028         info->lcd_xtal_freq = value;
2029 
2030     ret = sunxi_drm_get_sys_item_char(node, "lcd_size",
2031         (void *)info->lcd_size);
2032     ret = sunxi_drm_get_sys_item_char(node, "lcd_model_name",
2033         (void *)info->lcd_model_name);
2034     if (ret) {
2035         ret = sunxi_drm_get_sys_item_char(node, "lcd_driver_name",
2036                 (void *)info->lcd_model_name);
2037         if (ret) {
2038             DRM_ERROR("get lcd_driver_name failed\n");
2039             return -1;
2040         }
2041         DRM_INFO("[SUNXI-LCD]get lcd panel driver:%s\n",
2042                     info->lcd_model_name);
2043     } else {
2044         DRM_INFO("[SUNXI-LCD]get lcd panel driver:%s\n",
2045                     info->lcd_model_name);
2046     }
2047 
2048     return 0;
2049 }
2050 
sunxi_lcd_dts_parse(struct platform_device * pdev,struct sunxi_lcd * sunxi_lcd)2051 int sunxi_lcd_dts_parse(struct platform_device *pdev,
2052             struct sunxi_lcd *sunxi_lcd)
2053 {
2054     struct disp_lcd_cfg  *lcd_cfg;
2055     struct disp_panel_para  *info;
2056 
2057     lcd_cfg = &sunxi_lcd->lcd_cfg;
2058     info = &sunxi_lcd->panel_para;
2059 
2060     if (sunxi_lcd_dts_parse_gpio_info(pdev, lcd_cfg) < 0) {
2061         DRM_ERROR("sunxi_lcd_dts_parse_gpio_info failed\n");
2062         return -1;
2063     }
2064 
2065     if (sunxi_lcd_dts_parse_power_info(pdev, lcd_cfg) < 0) {
2066         DRM_ERROR("sunxi_lcd_dts_parse_power_info failed\n");
2067         return -1;
2068     }
2069 
2070     if (sunxi_lcd_dts_parse_backlight_info(pdev, lcd_cfg) < 0) {
2071         DRM_ERROR("sunxi_lcd_dts_parse_backlight_info failed\n");
2072         return -1;
2073     }
2074 
2075     if (sunxi_lcd_dts_parse_panel_info(pdev, info) < 0) {
2076         DRM_ERROR("sunxi_lcd_dts_parse_panel_info failed\n");
2077         return -1;
2078     }
2079 
2080     return 0;
2081 }
2082 
sunxi_lcd_cal_backlight_curve(struct sunxi_lcd * lcd)2083 static int sunxi_lcd_cal_backlight_curve(struct sunxi_lcd *lcd)
2084 {
2085     unsigned int i = 0, j = 0;
2086     unsigned int items = 0;
2087     unsigned int lcd_bright_curve_tbl[101][2];
2088     struct disp_lcd_cfg *cfg = &lcd->lcd_cfg;
2089     struct panel_extend_para *extend_para = &lcd->extend_para;
2090 
2091     for (i = 0; i < 101; i++) {
2092         if (cfg->backlight_curve_adjust[i] == 0) {
2093             if (i == 0) {
2094                 lcd_bright_curve_tbl[items][0] = 0;
2095                 lcd_bright_curve_tbl[items][1] = 0;
2096                 items++;
2097             }
2098         } else {
2099             lcd_bright_curve_tbl[items][0] = 255 * i / 100;
2100             lcd_bright_curve_tbl[items][1] =
2101                         cfg->backlight_curve_adjust[i];
2102             items++;
2103         }
2104     }
2105 
2106     for (i = 0; i < items - 1; i++) {
2107         u32 num = lcd_bright_curve_tbl[i + 1][0]
2108                 - lcd_bright_curve_tbl[i][0];
2109 
2110         for (j = 0; j < num; j++) {
2111             u32 value = 0;
2112 
2113             value = lcd_bright_curve_tbl[i][1]
2114                 + ((lcd_bright_curve_tbl[i + 1][1]
2115                 - lcd_bright_curve_tbl[i][1]) * j) / num;
2116             extend_para->lcd_bright_curve_tbl[
2117                     lcd_bright_curve_tbl[i][0] + j] = value;
2118         }
2119     }
2120 
2121     extend_para->lcd_bright_curve_tbl[255] =
2122                     lcd_bright_curve_tbl[items - 1][1];
2123 
2124     return 0;
2125 }
2126 
2127 #if defined(CONFIG_AW_DRM_BACKLIGHT)
sunxi_lcd_backlight_init(struct sunxi_lcd * lcd)2128 static int sunxi_lcd_backlight_init(struct sunxi_lcd *lcd)
2129 {
2130     struct backlight_config bl_cfg;
2131     struct disp_lcd_cfg     *lcd_cfg = &lcd->lcd_cfg;
2132     struct disp_panel_para  *panel_para = &lcd->panel_para;
2133     struct panel_extend_para *extend_para = &lcd->extend_para;
2134     int ret = 0;
2135 
2136     bl_cfg.use_bl_en = lcd_cfg->lcd_bl_en_used;
2137     memcpy(&bl_cfg.bl_en_gpio, &lcd_cfg->lcd_bl_en,
2138             sizeof(struct disp_gpio_info));
2139     memcpy(bl_cfg.bl_en_power, lcd_cfg->lcd_bl_en_power, LCD_POWER_STR_LEN);
2140 
2141     if (sunxi_lcd_cal_backlight_curve(lcd) < 0) {
2142         DRM_ERROR("sunxi_lcd_cal_backlight_curve failed\n");
2143         return -1;
2144     }
2145 
2146     bl_cfg.bright = lcd_cfg->backlight_bright;
2147     bl_cfg.use_pwm = panel_para->lcd_pwm_used;
2148     if (bl_cfg.use_pwm) {
2149         bl_cfg.pwm.lcd_pwm_ch = panel_para->lcd_pwm_ch;
2150         bl_cfg.pwm.lcd_pwm_pol = panel_para->lcd_pwm_pol;
2151         bl_cfg.pwm.lcd_pwm_freq = panel_para->lcd_pwm_freq;
2152     }
2153 
2154     ret = sunxi_backlight_init(lcd->id, &bl_cfg,
2155             extend_para->lcd_bright_curve_tbl);
2156     if (ret < 0) {
2157         DRM_ERROR("sunxi_backlight_init failed\n");
2158         return -1;
2159     }
2160 
2161     return 0;
2162 }
2163 
sunxi_lcd_backlight_remove(struct sunxi_lcd * lcd)2164 static void sunxi_lcd_backlight_remove(struct sunxi_lcd *lcd)
2165 {
2166     sunxi_backlight_remove(lcd->id);
2167 }
2168 #endif
2169 
2170 static struct sunxi_lcd_funcs sunxi_hv_funcs = {
2171     .get_type = sunxi_lcd_get_type,
2172     .get_panel_para = sunxi_lcd_get_panel_para,
2173     .is_use_irq = sunxi_lcd_is_use_irq,
2174     .get_irq_no = sunxi_lcd_get_irq_no,
2175 
2176     .enable = sunxi_lcd_hv_enable,
2177     .sw_enable = sunxi_lcd_sw_enable,
2178     .disable = sunxi_lcd_hv_disable,
2179 };
2180 
2181 static struct sunxi_lcd_funcs sunxi_lvds_funcs = {
2182     .get_type = sunxi_lcd_get_type,
2183     .get_panel_para = sunxi_lcd_get_panel_para,
2184     .is_use_irq = sunxi_lcd_is_use_irq,
2185     .get_irq_no = sunxi_lcd_get_irq_no,
2186 
2187     .enable = sunxi_lcd_lvds_enable,
2188     .sw_enable = sunxi_lcd_sw_enable,
2189     .disable = sunxi_lcd_lvds_disable,
2190 };
2191 
2192 static struct sunxi_lcd_funcs sunxi_dsi_funcs = {
2193     .get_type = sunxi_lcd_get_type,
2194     .get_panel_para = sunxi_lcd_get_panel_para,
2195     .is_use_irq = sunxi_lcd_is_use_irq,
2196     .get_irq_no = sunxi_lcd_get_irq_no,
2197 
2198     .enable = sunxi_lcd_dsi_enable,
2199     .sw_enable = sunxi_lcd_sw_enable,
2200     .disable = sunxi_lcd_dsi_disable,
2201 };
2202 
sunxi_lcd_probe(struct platform_device * pdev)2203 static int sunxi_lcd_probe(struct platform_device *pdev)
2204 {
2205     u32 lcd_used = 0, id;
2206     struct sunxi_lcd *lcd;
2207     struct sunxi_lcd_resource *res;
2208 
2209     res = &lcd_drv->res;
2210 
2211     DRM_INFO("pdev name:%s\n", pdev->name);
2212 
2213 /* init LCD CORE */
2214     if ((!strcmp(pdev->name, "lcd-core"))
2215         || strstr(pdev->name, "lcd-core")) {
2216         DRM_INFO("[SUNXI-LCD]: find sunxi-lcd\n");
2217         if (sunxi_lcd_dts_parse_lcd_core(pdev, res) < 0) {
2218             DRM_ERROR("sunxi_lcd_dts_parse_lcd_core failed");
2219             DRM_ERROR("probe failed\n");
2220             return -EINVAL;
2221         }
2222 
2223         if (sunxi_lcd_init_al(&lcd_drv->res) < 0) {
2224             DRM_ERROR("sunxi_lcd_init_al failed");
2225             DRM_ERROR("probe failed\n");
2226             return -EINVAL;
2227         }
2228 
2229 #if defined(CONFIG_AW_DRM_BACKLIGHT)
2230         /* initial backlight driver */
2231         if (sunxi_backlight_drv_init() < 0) {
2232             DRM_ERROR("sunxi_backlight_drv_init failed");
2233             DRM_ERROR("probe failed\n");
2234             return -EINVAL;
2235         }
2236 #endif
2237 
2238 
2239         DRM_INFO("[SUNXI-LCD]lcd-core probe end\n");
2240         return 0;
2241     }
2242 
2243 /* init lcd0/1/2/3 */
2244     id = lcd_drv->lcd_cnt;
2245 
2246     lcd = &lcd_drv->hwlcd[id];
2247     lcd->id = id;
2248     lcd->pdev = pdev;
2249 
2250     if (of_property_read_u32(pdev->dev.of_node,
2251             "lcd_used", &lcd_used)) {
2252         DRM_ERROR("DTS parse lcd_used failed\n");
2253         goto lcd_err;
2254     }
2255 
2256     if (!lcd_used) {
2257         DRM_INFO("[SUNXI-LCD]Warn: lcd%d is NOT be used!\n", id);
2258         goto lcd_err;
2259     }
2260 
2261     lcd->is_used = true;
2262 
2263     if (sunxi_lcd_dts_parse(pdev, lcd) < 0) {
2264         DRM_ERROR("sunxi_lcd_dts_parse failed\n");
2265         goto lcd_err;
2266     }
2267     lcd->type = lcd->panel_para.lcd_if;
2268 
2269     lcd->extend_para.lcd_gamma_en =  lcd->panel_para.lcd_gamma_en;
2270 
2271 /* LCD-CORE dispatch reg_base/irq_no/clk to sunxi_lcd */
2272     if (lcd->type == LCD_IF_DSI) { /* DSI */
2273 #ifdef SUPPORT_DSI
2274         lcd->type_id = lcd_drv->dsi_cnt;
2275         lcd_drv->dsi_cnt++;
2276         lcd->reg_base = res->reg_base[SUNXI_DSI0 + lcd->type_id];
2277 
2278         lcd->mclk = res->mclk[SUNXI_DSI0 + lcd->type_id];
2279         lcd->mclk_bus = res->mclk_bus[SUNXI_DSI0 + lcd->type_id];
2280         lcd->parent_clk = clk_get_parent(lcd->mclk);
2281 #ifdef DSI_VERSION_40
2282         lcd->irq_used = true;
2283 #else
2284         lcd->irq_used = false;
2285 #endif
2286         lcd->irq_no = res->irq_no[SUNXI_DSI0 + lcd->type_id];
2287 #endif
2288     } else if (lcd->type == LCD_IF_LVDS) { /* LVDS */
2289         lcd->type_id = lcd_drv->lvds_cnt;
2290         lcd_drv->lvds_cnt++;
2291         lcd->mclk = res->mclk[SUNXI_LVDS0 + lcd->type_id];
2292         lcd->parent_clk = clk_get_parent(lcd->mclk);
2293         lcd->irq_used = false;
2294     } else if (lcd->type == LCD_IF_HV) { /* RGB */
2295         lcd->type_id = lcd_drv->rgb_cnt;
2296         lcd_drv->rgb_cnt++;
2297         lcd->mclk = res->mclk[SUNXI_RGB0 + lcd->type_id];
2298         lcd->parent_clk = clk_get_parent(lcd->mclk);
2299         lcd->irq_used = false;
2300     } else if (lcd->type == LCD_IF_CPU) { /* CPU */
2301         lcd->type_id = lcd_drv->cpu_cnt;
2302         lcd_drv->cpu_cnt++;
2303         lcd->mclk = res->mclk[SUNXI_CPU0 + lcd->type_id];
2304         lcd->parent_clk = clk_get_parent(lcd->mclk);
2305         lcd->irq_used = false;
2306     } else {
2307         DRM_ERROR("lcd type:%d haven't been Implement\n", lcd->type);
2308         goto lcd_err;
2309     }
2310 
2311 /* sunxi_lcd get a backlight */
2312 
2313     if (lcd->lcd_cfg.lcd_bl_en_used || lcd->panel_para.lcd_pwm_used) {
2314         lcd->use_bl = 1;
2315 #if defined(CONFIG_AW_DRM_BACKLIGHT)
2316         if (sunxi_lcd_backlight_init(lcd) < 0) {
2317             DRM_ERROR("sunxi_lcd_backlight_init failed\n");
2318             goto lcd_err;
2319         }
2320 #endif
2321     }
2322 
2323 /* initial lcd panel */
2324     lcd->panel = sunxi_lcd_get_panel(lcd->panel_para.lcd_model_name);
2325     if (!lcd->panel) {
2326         DRM_ERROR("get panel failed\n");
2327         goto lcd_err;
2328     }
2329 
2330     lcd->panel->func.cfg_panel_info(&lcd->extend_para);
2331 
2332     if (lcd->type == LCD_IF_DSI) {
2333         lcd->funcs = &sunxi_dsi_funcs;
2334     } else if (lcd->type == LCD_IF_LVDS) {
2335         lcd->funcs = &sunxi_lvds_funcs;
2336     }  else if (lcd->type == LCD_IF_HV) {
2337         lcd->funcs = &sunxi_hv_funcs;
2338     }  else if (lcd->type == LCD_IF_CPU) {
2339         // lcd->funcs = &sunxi_cpu_funcs
2340     } else {
2341         DRM_ERROR("lcd type:%d haven't been Implement\n", lcd->type);
2342         goto lcd_err;
2343     }
2344 
2345 /* increase lcd count */
2346     lcd_drv->lcd_cnt++;
2347 
2348     DRM_INFO("[SUNXI-LCD]lcd%d probe end\n", lcd->id);
2349     return 0;
2350 
2351 lcd_err:
2352     // lcd_drv->lcd_cnt++
2353     DRM_ERROR("probe failed\n");
2354     return -EINVAL;
2355 }
2356 
sunxi_lcd_remove(struct platform_device * pdev)2357 static int sunxi_lcd_remove(struct platform_device *pdev)
2358 {
2359 #if defined(CONFIG_AW_DRM_BACKLIGHT)
2360     struct sunxi_lcd *lcd;
2361     int i = 0, lcd_cnt;
2362 
2363     lcd_cnt = sunxi_lcd_get_count();
2364     for (i = 0; i < lcd_cnt; i++) {
2365         lcd = sunxi_lcd_get_lcd(i);
2366         sunxi_lcd_backlight_remove(lcd);
2367     }
2368 
2369     sunxi_backlight_drv_exit();
2370 #endif
2371 
2372     return 0;
2373 }
2374 
2375 
2376 static const struct of_device_id sunxi_lcd_match[] = {
2377     { .compatible = "allwinner,sunxi-lcd", },
2378     { .compatible = "allwinner,sunxi-lcd0", },
2379     { .compatible = "allwinner,sunxi-lcd1", },
2380 
2381     /* generally, we at most use two lcd at the same time.
2382      * but if you want to use more, and use these config below, and
2383      * set lcd configs in sys_config.fex
2384      */
2385     /*
2386     { .compatible = "allwinner,sunxi-lcd2", },
2387     { .compatible = "allwinner,sunxi-lcd3", },
2388      */
2389     {},
2390 };
2391 
2392 struct platform_driver sunxi_lcd_platform_driver = {
2393     .probe = sunxi_lcd_probe,
2394     .remove = sunxi_lcd_remove,
2395     .driver = {
2396            .name = "lcd",
2397            .owner = THIS_MODULE,
2398            .of_match_table = sunxi_lcd_match,
2399     },
2400 };
2401 
sunxi_lcd_module_init(void)2402 int sunxi_lcd_module_init(void)
2403 {
2404     int ret = 0, err;
2405     struct drv_model_info *drv_model;
2406 
2407     DRM_INFO("[SUNXI-LCD]sunxi_lcd_module_init\n");
2408 
2409     lcd_drv = kzalloc(sizeof(struct sunxi_lcd_drv), GFP_KERNEL);
2410     if (!lcd_drv) {
2411         DRM_ERROR("can NOT allocate memory for lcd_drv\n");
2412         goto lcd_err;
2413     }
2414     drv_model = &lcd_drv->drv_model;
2415 
2416     if (alloc_chrdev_region(&drv_model->devid, 0, 1, "lcd") < 0) {
2417         DRM_ERROR("alloc_chrdev_region failed\n");
2418         goto lcd_err;
2419     }
2420 
2421     drv_model->cdev = cdev_alloc();
2422     if (!drv_model->cdev) {
2423         DRM_ERROR("cdev_alloc failed\n");
2424         goto lcd_err;
2425     }
2426 
2427     cdev_init(drv_model->cdev, NULL);
2428     drv_model->cdev->owner = THIS_MODULE;
2429     err = cdev_add(drv_model->cdev, drv_model->devid, 1);
2430     if (err) {
2431         DRM_ERROR("cdev_add major number:%d failed\n",
2432                         MAJOR(drv_model->devid));
2433         goto lcd_err;
2434     }
2435 
2436     drv_model->sysclass = class_create(THIS_MODULE, "lcd");
2437     if (IS_ERR(drv_model->sysclass)) {
2438         DRM_ERROR("create class error\n");
2439         goto lcd_err;
2440     }
2441 
2442     drv_model->dev = device_create(drv_model->sysclass, NULL,
2443                     drv_model->devid, NULL, "lcd");
2444     if (!drv_model->dev) {
2445         DRM_ERROR("device_create failed\n");
2446         goto lcd_err;
2447     }
2448 
2449     ret = platform_driver_register(&sunxi_lcd_platform_driver);
2450     if (ret) {
2451         DRM_ERROR("platform_driver_register failed\n");
2452         goto lcd_err;
2453     }
2454 
2455     ret = sysfs_create_group(&drv_model->dev->kobj,
2456                     &lcd_attribute_group);
2457     if (ret < 0) {
2458         DRM_ERROR("sysfs_create_file fail!\n");
2459         goto lcd_err;
2460     }
2461 
2462     DRM_INFO("[SUNXI-LCD]sunxi_lcd_module_init end\n\n");
2463     return 0;
2464 
2465 lcd_err:
2466     DRM_ERROR("sunxi_lcd_module_init failed\n");
2467     kfree(lcd_drv);
2468     return -EINVAL;
2469 }
2470 
sunxi_lcd_module_exit(void)2471 void sunxi_lcd_module_exit(void)
2472 {
2473     struct drv_model_info  *drv_model;
2474 
2475     DRM_INFO("[SUNXI-LCD]sunxi_lcd_module_exit\n");
2476     platform_driver_unregister(&sunxi_lcd_platform_driver);
2477 
2478     drv_model = &lcd_drv->drv_model;
2479     device_destroy(drv_model->sysclass, drv_model->devid);
2480     class_destroy(drv_model->sysclass);
2481 
2482     cdev_del(drv_model->cdev);
2483     if (lcd_drv)
2484         kfree(lcd_drv);
2485 }
2486 
2487