1 /*
2  * Allwinner SoCs display driver.
3  *
4  * Copyright (C) 2016 Allwinner.
5  *
6  * This file is licensed under the terms of the GNU General Public
7  * License version 2.  This program is licensed "as is" without any
8  * warranty of any kind, whether express or implied.
9  */
10 
11 #include "tm_dsi_panel.h"
12 #include "panels.h"
13 
14 extern s32 bsp_disp_get_panel_info(u32 screen_id,
15         struct disp_panel_para *info);
16 static void LCD_power_on(u32 sel);
17 static void LCD_power_off(u32 sel);
18 static void LCD_bl_open(u32 sel);
19 static void LCD_bl_close(u32 sel);
20 
21 static void LCD_panel_init(u32 sel);
22 static void LCD_panel_exit(u32 sel);
23 
24 static u8 const mipi_dcs_pixel_format[4] = {0x77, 0x66, 0x66, 0x55};
25 #define panel_reset(val) sunxi_lcd_gpio_set_value(sel, 1, val)
26 #define power_en(val) sunxi_lcd_gpio_set_value(sel, 0, val)
27 
LCD_cfg_panel_info(struct panel_extend_para * info)28 static void LCD_cfg_panel_info(struct panel_extend_para *info)
29 {
30     u32 i = 0, j = 0;
31     u32 items;
32     u8 lcd_gamma_tbl[][2] = {
33         /*{input value, corrected value} */
34         {0, 0},     {15, 15},   {30, 30},   {45, 45},   {60, 60},
35         {75, 75},   {90, 90},   {105, 105}, {120, 120}, {135, 135},
36         {150, 150}, {165, 165}, {180, 180}, {195, 195}, {210, 210},
37         {225, 225}, {240, 240}, {255, 255},
38     };
39 
40     u32 lcd_cmap_tbl[2][3][4] = {
41         {
42         {LCD_CMAP_G0, LCD_CMAP_B1, LCD_CMAP_G2, LCD_CMAP_B3},
43         {LCD_CMAP_B0, LCD_CMAP_R1, LCD_CMAP_B2, LCD_CMAP_R3},
44         {LCD_CMAP_R0, LCD_CMAP_G1, LCD_CMAP_R2, LCD_CMAP_G3},
45         },
46         {
47         {LCD_CMAP_B3, LCD_CMAP_G2, LCD_CMAP_B1, LCD_CMAP_G0},
48         {LCD_CMAP_R3, LCD_CMAP_B2, LCD_CMAP_R1, LCD_CMAP_B0},
49         {LCD_CMAP_G3, LCD_CMAP_R2, LCD_CMAP_G1, LCD_CMAP_R0},
50         },
51     };
52 
53     items = sizeof(lcd_gamma_tbl) / 2;
54     for (i = 0; i < items - 1; i++) {
55         u32 num = lcd_gamma_tbl[i + 1][0] - lcd_gamma_tbl[i][0];
56 
57         for (j = 0; j < num; j++) {
58             u32 value = 0;
59 
60             value =
61                 lcd_gamma_tbl[i][1] +
62                 ((lcd_gamma_tbl[i + 1][1] - lcd_gamma_tbl[i][1]) *
63                  j) /
64                 num;
65             info->lcd_gamma_tbl[lcd_gamma_tbl[i][0] + j] =
66                 (value << 16) + (value << 8) + value;
67         }
68     }
69     info->lcd_gamma_tbl[255] = (lcd_gamma_tbl[items - 1][1] << 16) +
70                    (lcd_gamma_tbl[items - 1][1] << 8) +
71                    lcd_gamma_tbl[items - 1][1];
72 
73     memcpy(info->lcd_cmap_tbl, lcd_cmap_tbl, sizeof(lcd_cmap_tbl));
74 }
75 
LCD_open_flow(u32 sel)76 static s32 LCD_open_flow(u32 sel)
77 {
78     LCD_OPEN_FUNC(sel, LCD_power_on,
79               100); /* open lcd power, and delay 50ms */
80     LCD_OPEN_FUNC(sel, LCD_panel_init,
81               200); /* open lcd power, than delay 200ms */
82     LCD_OPEN_FUNC(sel, sunxi_lcd_tcon_enable,
83               50); /* open lcd controller, and delay 100ms */
84     LCD_OPEN_FUNC(sel, LCD_bl_open,
85               0); /* open lcd backlight, and delay 0ms */
86 
87     return 0;
88 }
89 
LCD_close_flow(u32 sel)90 static s32 LCD_close_flow(u32 sel)
91 {
92     LCD_CLOSE_FUNC(sel, LCD_bl_close,
93                200); /* close lcd backlight, and delay 0ms */
94     LCD_CLOSE_FUNC(sel, sunxi_lcd_tcon_disable,
95                20); /* close lcd controller, and delay 0ms */
96     LCD_CLOSE_FUNC(sel, LCD_panel_exit,
97                10); /* open lcd power, than delay 200ms */
98     LCD_CLOSE_FUNC(sel, LCD_power_off,
99                500); /* close lcd power, and delay 500ms */
100 
101     return 0;
102 }
103 
LCD_power_on(u32 sel)104 static void LCD_power_on(u32 sel)
105 {
106     sunxi_lcd_pin_cfg(sel, 1);
107     sunxi_lcd_power_enable(sel, 0);
108     sunxi_lcd_delay_ms(5);
109     sunxi_lcd_power_enable(sel, 1);
110     sunxi_lcd_delay_ms(5);
111     sunxi_lcd_power_enable(sel, 2);
112     sunxi_lcd_delay_ms(5);
113     power_en(1);
114     sunxi_lcd_delay_ms(20);
115     panel_reset(0);
116     sunxi_lcd_delay_ms(10);
117     panel_reset(1);
118 }
119 
LCD_power_off(u32 sel)120 static void LCD_power_off(u32 sel)
121 {
122     sunxi_lcd_pin_cfg(sel, 0);
123     power_en(0);
124     sunxi_lcd_delay_ms(20);
125     panel_reset(0);
126     sunxi_lcd_delay_ms(5);
127     sunxi_lcd_power_disable(
128         sel, 2); /* config lcd_power pin to close lcd power2 */
129     sunxi_lcd_delay_ms(5);
130     sunxi_lcd_power_disable(
131         sel, 1); /* config lcd_power pin to close lcd power1 */
132     sunxi_lcd_delay_ms(5);
133     sunxi_lcd_power_disable(
134         sel, 0); /* config lcd_power pin to close lcd power */
135 }
136 
LCD_bl_open(u32 sel)137 static void LCD_bl_open(u32 sel)
138 {
139     sunxi_lcd_pwm_enable(sel);
140     sunxi_lcd_delay_ms(50);
141     sunxi_lcd_backlight_enable(
142         sel); /* config lcd_bl_en pin to open lcd backlight */
143 }
144 
LCD_bl_close(u32 sel)145 static void LCD_bl_close(u32 sel)
146 {
147     sunxi_lcd_backlight_disable(
148         sel); /* config lcd_bl_en pin to close lcd backlight */
149     sunxi_lcd_delay_ms(20);
150     sunxi_lcd_pwm_disable(sel);
151 }
152 
153 #define REGFLAG_DELAY 0XFE
154 #define REGFLAG_END_OF_TABLE 0xFF /* END OF REGISTERS MARKER */
155 
156 struct LCM_setting_table {
157     u8 cmd;
158     u32 count;
159     u8 para_list[64];
160 };
161 
162 /*add panel initialization code*/
163 static struct LCM_setting_table LCM_TM040YVZG31_setting[] = {
164     {0xB9, 3, {0xFF, 0x83, 0x69} },
165     /*Set Power*/
166     {0xB1, 19, {0x01, 0x00, 0x34, 0x0A,
167                  0x00, 0x11, 0x11, 0x2F, 0x37,
168                  0x3F, 0x3F, 0x07, 0x3A, 0x01,
169                  0xE6, 0xE6, 0xE6, 0xE6, 0xE6} },
170     /* set display,0x2B DSI video mode
171      * 0x20 DSI command mod
172      */
173     {0xB2, 15, {0x00, 0x2B, 0x03, 0x03,
174                  0x70, 0x00, 0xFF, 0x00, 0x00,
175                  0x00, 0x00, 0x03, 0x03, 0x00,
176                  0x01} },
177     /*set display 480*800
178      *0x00 column inversion, 0x01 1-dot inversion
179      *0x02 2-dot inversion, 0x3 zig-zag inversion
180      */
181     {0xB4, 5, {0x00, 0x18, 0x70, 0x00, 0x00} },
182     /*Set VCOM*/
183     {0xB6, 2, {0x4a, 0x4a} },
184     /*set enable chopper function*/
185     {0x36, 1, {0x00} },
186     /*set GIP*/
187     {0xD5, 26, {0x00, 0x00, 0x03, 0x37,
188                 0x01, 0x02, 0x00, 0x70, 0x11,
189                 0x13, 0x00, 0x00, 0x60, 0x24,
190                 0x71, 0x35, 0x00, 0x00, 0x60,
191                 0x24, 0x71, 0x35, 0x07, 0x0F,
192                 0x00, 0x04 } },
193     /*R Gamma*/
194     {0xE0, 34, {0x04, 0x1F, 0x25, 0x2B,
195                 0X3E, 0x35, 0x34, 0x4A, 0x08,
196                 0x0E, 0x0F, 0x14, 0x16, 0x14,
197                 0x15, 0x14, 0x1F, 0x04, 0x1F,
198                 0x25, 0x2B, 0x3E, 0x35, 0x34,
199                 0x4A, 0x08, 0x0E, 0x0F, 0x14,
200                 0x16, 0x14, 0x15, 0x14, 0x1F} },
201     {0xCC, 1, {0x02 } },
202     {0x3A, 1, {0x77 } },
203      /*set mipi, 0x11 two lanes, 0x10 one lane*/
204     {0xBA, 13, {0x00, 0xA0, 0xC6, 0x00,
205                 0x0A, 0x00, 0x10, 0x30, 0x6F,
206                 0x02, 0x11, 0x18, 0x40} },
207     /*sleep exit*/
208     {0x11, 0, {0x00 } },
209     {REGFLAG_DELAY, REGFLAG_DELAY, {120} },
210     /*display on*/
211     {0x29, 0, {0x00 } },
212     {REGFLAG_DELAY, REGFLAG_DELAY, {10} },
213     {REGFLAG_END_OF_TABLE, REGFLAG_END_OF_TABLE, {} }
214 };
215 
LCD_panel_init(u32 sel)216 static void LCD_panel_init(u32 sel)
217 {
218     __u32 i;
219     char model_name[25];
220 
221     disp_sys_script_get_item("lcd0", "lcd_model_name",
222         (int *)model_name, 25);
223     sunxi_lcd_dsi_clk_enable(sel);
224     sunxi_lcd_delay_ms(20);
225 
226     for (i = 0;; i++) {
227         if (LCM_TM040YVZG31_setting[i].count == REGFLAG_END_OF_TABLE)
228             break;
229         else if (LCM_TM040YVZG31_setting[i].count == REGFLAG_DELAY)
230             sunxi_lcd_delay_ms(
231                 LCM_TM040YVZG31_setting[i].para_list[0]);
232 #ifdef SUPPORT_DSI
233         else
234             dsi_dcs_wr(sel, LCM_TM040YVZG31_setting[i].cmd,
235                    LCM_TM040YVZG31_setting[i].para_list,
236                    LCM_TM040YVZG31_setting[i].count);
237 #endif
238     }
239 }
240 
LCD_panel_exit(u32 sel)241 static void LCD_panel_exit(u32 sel)
242 {
243     sunxi_lcd_dsi_dcs_write_0para(sel, DSI_DCS_SET_DISPLAY_OFF);
244     sunxi_lcd_delay_ms(20);
245     sunxi_lcd_dsi_dcs_write_0para(sel, DSI_DCS_ENTER_SLEEP_MODE);
246     sunxi_lcd_delay_ms(80);
247 }
248 
249 /* sel: 0:lcd0; 1:lcd1 */
LCD_user_defined_func(u32 sel,u32 para1,u32 para2,u32 para3)250 static s32 LCD_user_defined_func(u32 sel, u32 para1, u32 para2, u32 para3)
251 {
252     return 0;
253 }
254 
255 /* sel: 0:lcd0; 1:lcd1 */
256 /*static s32 LCD_set_bright(u32 sel, u32 bright)*/
257 /*{*/
258     /*sunxi_lcd_dsi_dcs_write_1para(sel,0x51,bright);*/
259     /*return 0;*/
260 /*}*/
261 
262 struct __lcd_panel tm_dsi_panel = {
263     /* panel driver name, must mach the name of
264      * lcd_drv_name in sys_config.fex
265     */
266     .name = "tm_dsi_panel",
267     .func = {
268     .cfg_panel_info = LCD_cfg_panel_info,
269     .cfg_open_flow = LCD_open_flow,
270     .cfg_close_flow = LCD_close_flow,
271     .lcd_user_defined_func = LCD_user_defined_func,
272     /*.set_bright = LCD_set_bright, */
273     },
274 };
275