1 /* drivers/video/sunxi/disp2/disp/lcd/ST7796S.c
2  *
3  * Copyright (c) 2017 Allwinnertech Co., Ltd.
4  * Author: zhengxiaobin <zhengxiaobin@allwinnertech.com>
5  *
6  * he0801a-068 panel driver
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  *
12  * [lcd0]
13  * lcd_used            = 1
14 
15  * lcd_driver_name     = "st7796s"
16  * lcd_bl_0_percent    = 0
17  * lcd_bl_40_percent   = 23
18  * lcd_bl_100_percent  = 100
19  * lcd_backlight       = 100
20 
21  * lcd_if              = 4
22  * lcd_x               = 240
23  * lcd_y               = 432
24  * lcd_width           = 52
25  * lcd_height          = 52
26  * lcd_dclk_freq       = 18
27 
28  * lcd_pwm_used        = 1
29  * lcd_pwm_ch          = 0
30  * lcd_pwm_freq        = 50000
31  * lcd_pwm_pol         = 1
32  * lcd_pwm_max_limit   = 255
33 
34  * lcd_hbp             = 96
35  * lcd_ht              = 480
36  * lcd_hspw            = 2
37  * lcd_vbp             = 21
38  * lcd_vt              = 514
39  * lcd_vspw            = 2
40 
41  * lcd_dsi_if          = 1
42  * lcd_dsi_lane        = 1
43  * lcd_dsi_format      = 0
44  * lcd_dsi_te          = 1
45  * lcd_dsi_eotp        = 0
46 
47  * lcd_frm             = 0
48  * lcd_io_phase        = 0x0000
49  * lcd_hv_clk_phase    = 0
50  * lcd_hv_sync_polarity= 0
51  * lcd_gamma_en        = 0
52  * lcd_bright_curve_en = 0
53  * lcd_cmap_en         = 0
54 
55  * lcdgamma4iep        = 22
56 
57  * lcd_bl_en           = port:PB03<1><0><default><1>
58  * lcd_power           = "axp233_dc1sw"
59  * lcd_power1           = "axp233_eldo1"
60 
61  * lcd_gpio_0          = port:PB02<1><0><default><0>
62  * lcd_vsync          = port:PD21<2><0><3><default>
63 */
64 #include "st7796s.h"
65 
66 static void lcd_power_on(u32 sel);
67 static void lcd_power_off(u32 sel);
68 static void lcd_bl_open(u32 sel);
69 static void lcd_bl_close(u32 sel);
70 
71 static void lcd_panel_init(u32 sel);
72 static void lcd_panel_exit(u32 sel);
73 
74 #define panel_reset(sel, val) sunxi_lcd_gpio_set_value(sel, 0, val)
75 
lcd_cfg_panel_info(struct panel_extend_para * info)76 static void lcd_cfg_panel_info(struct panel_extend_para *info)
77 {
78     u32 i = 0, j = 0;
79     u32 items;
80     u8 lcd_gamma_tbl[][2] = {
81         {0, 0},     {15, 15},   {30, 30},   {45, 45},   {60, 60},
82         {75, 75},   {90, 90},   {105, 105}, {120, 120}, {135, 135},
83         {150, 150}, {165, 165}, {180, 180}, {195, 195}, {210, 210},
84         {225, 225}, {240, 240}, {255, 255},
85     };
86 
87     u32 lcd_cmap_tbl[2][3][4] = {
88         {
89         {LCD_CMAP_G0, LCD_CMAP_B1, LCD_CMAP_G2, LCD_CMAP_B3},
90         {LCD_CMAP_B0, LCD_CMAP_R1, LCD_CMAP_B2, LCD_CMAP_R3},
91         {LCD_CMAP_R0, LCD_CMAP_G1, LCD_CMAP_R2, LCD_CMAP_G3},
92         },
93         {
94         {LCD_CMAP_B3, LCD_CMAP_G2, LCD_CMAP_B1, LCD_CMAP_G0},
95         {LCD_CMAP_R3, LCD_CMAP_B2, LCD_CMAP_R1, LCD_CMAP_B0},
96         {LCD_CMAP_G3, LCD_CMAP_R2, LCD_CMAP_G1, LCD_CMAP_R0},
97         },
98     };
99 
100     items = sizeof(lcd_gamma_tbl) / 2;
101     for (i = 0; i < items - 1; i++) {
102         u32 num = lcd_gamma_tbl[i + 1][0] - lcd_gamma_tbl[i][0];
103 
104         for (j = 0; j < num; j++) {
105             u32 value = 0;
106 
107             value =
108                 lcd_gamma_tbl[i][1] +
109                 ((lcd_gamma_tbl[i + 1][1] - lcd_gamma_tbl[i][1]) *
110                  j) /
111                 num;
112             info->lcd_gamma_tbl[lcd_gamma_tbl[i][0] + j] =
113                 (value << 16) + (value << 8) + value;
114         }
115     }
116     info->lcd_gamma_tbl[255] = (lcd_gamma_tbl[items - 1][1] << 16) +
117                    (lcd_gamma_tbl[items - 1][1] << 8) +
118                    lcd_gamma_tbl[items - 1][1];
119 
120     memcpy(info->lcd_cmap_tbl, lcd_cmap_tbl, sizeof(lcd_cmap_tbl));
121 }
122 
lcd_open_flow(u32 sel)123 static s32 lcd_open_flow(u32 sel)
124 {
125     LCD_OPEN_FUNC(sel, lcd_power_on, 10);
126     LCD_OPEN_FUNC(sel, lcd_panel_init, 10);
127     LCD_OPEN_FUNC(sel, sunxi_lcd_tcon_enable, 50);
128     LCD_OPEN_FUNC(sel, lcd_bl_open, 0);
129     return 0;
130 }
131 
lcd_close_flow(u32 sel)132 static s32 lcd_close_flow(u32 sel)
133 {
134     LCD_CLOSE_FUNC(sel, lcd_bl_close, 0);
135     LCD_CLOSE_FUNC(sel, lcd_panel_exit, 200);
136     LCD_CLOSE_FUNC(sel, sunxi_lcd_tcon_disable, 0);
137     LCD_CLOSE_FUNC(sel, lcd_power_off, 500);
138 
139     return 0;
140 }
141 
lcd_power_on(u32 sel)142 static void lcd_power_on(u32 sel)
143 {
144     sunxi_lcd_pin_cfg(sel, 1);
145     sunxi_lcd_power_enable(sel, 0);
146     // sunxi_lcd_power_enable(sel, 1);
147     sunxi_lcd_delay_ms(10);
148 
149     panel_reset(sel, 1);
150     sunxi_lcd_delay_ms(50);
151     panel_reset(sel, 0);
152     sunxi_lcd_delay_ms(50);
153     panel_reset(sel, 1);
154     sunxi_lcd_delay_ms(50);
155 }
156 
lcd_power_off(u32 sel)157 static void lcd_power_off(u32 sel)
158 {
159     sunxi_lcd_pin_cfg(sel, 0);
160     sunxi_lcd_delay_ms(20);
161     panel_reset(sel, 0);
162     sunxi_lcd_delay_ms(5);
163     sunxi_lcd_power_disable(sel, 0);
164 }
165 
lcd_bl_open(u32 sel)166 static void lcd_bl_open(u32 sel)
167 {
168     sunxi_lcd_pwm_enable(sel);
169     sunxi_lcd_backlight_enable(sel);
170 }
171 
lcd_bl_close(u32 sel)172 static void lcd_bl_close(u32 sel)
173 {
174     sunxi_lcd_backlight_disable(sel);
175     sunxi_lcd_pwm_disable(sel);
176 }
177 
178 #define REGFLAG_DELAY         0XFF
179 #define REGFLAG_END_OF_TABLE  0xFE   /* END OF REGISTERS MARKER */
180 
181 struct LCM_setting_table {
182     u8 cmd;
183     u32 count;
184     u8 para_list[15];
185 };
186 
187 
188 static struct LCM_setting_table lcm_initialization_setting[] = {
189     {0x11, 1, {0x00} },
190     {REGFLAG_DELAY, 50, {} },
191     {0x36, 1, {0x48} },
192     {0x35, 1, {0x00} },/*te on*/
193     {0x3a, 1, {0x77} },/*24bit/pixel*/
194     {0xf0, 1, {0xc3} },
195     {0xf0, 1, {0x96} },
196     {0xb4, 1, {0x01} },
197     {0xb6, 3, {0xa0, 0x02, 0x3b} },
198     {0xc1, 1, {0x1d} },
199     {0xc2, 1, {0xa7} },
200     {0xc5, 1, {0x23} },
201     {REGFLAG_DELAY, 1, {} },
202     {0xe8, 8, {0x40, 0x8a, 0x00, 0x00, 0x29, 0x19, 0xa5, 0x33} },
203     {0xe0, 14, { 0xf0, 0x03, 0x0a, 0x12, 0x15,
204                0x1d, 0x42, 0x44, 0x50, 0x28, 0x16, 0x15,
205                0x20, 0x21} },
206     {0xe1, 14, { 0xf0, 0x03, 0x0a, 0x12, 0x15,
207                0x1c, 0x42, 0x44, 0x52, 0x28, 0x16, 0x15,
208                0x20, 0x23} },
209     {REGFLAG_DELAY, 1, {} },
210     {0xf0, 1, {0x3c} },
211     {0xf0, 1, {0x69} },
212     {0x29, 1, {0x00} }, /* DSPON */
213     {REGFLAG_DELAY, 1, {} },
214     {REGFLAG_END_OF_TABLE, 0x00, {} }
215 };
216 
lcd_panel_init(u32 sel)217 static void lcd_panel_init(u32 sel)
218 {
219     u32 i = 0;
220 
221     sunxi_lcd_dsi_clk_enable(sel);
222     sunxi_lcd_delay_ms(100);
223 
224     for (i = 0;; i++) {
225         if (lcm_initialization_setting[i].cmd == REGFLAG_END_OF_TABLE)
226             break;
227         else if (lcm_initialization_setting[i].cmd == REGFLAG_DELAY)
228             sunxi_lcd_delay_ms(lcm_initialization_setting[i].count);
229         else {
230             dsi_dcs_wr(0, lcm_initialization_setting[i].cmd,
231                    lcm_initialization_setting[i].para_list,
232                    lcm_initialization_setting[i].count);
233         }
234     }
235 }
236 
lcd_panel_exit(u32 sel)237 static void lcd_panel_exit(u32 sel)
238 {
239     sunxi_lcd_dsi_dcs_write_0para(sel, 0x28);
240     sunxi_lcd_delay_ms(10);
241     sunxi_lcd_dsi_dcs_write_0para(sel, 0x10);
242     sunxi_lcd_delay_ms(10);
243 }
244 
245 /*sel: 0:lcd0; 1:lcd1*/
lcd_user_defined_func(u32 sel,u32 para1,u32 para2,u32 para3)246 static s32 lcd_user_defined_func(u32 sel, u32 para1, u32 para2, u32 para3)
247 {
248     return 0;
249 }
250 
251 struct __lcd_panel st7796s_panel = {
252     /* panel driver name, must mach the name of
253      * lcd_drv_name in sys_config.fex
254      */
255     .name = "st7796s",
256     .func = {
257         .cfg_panel_info = lcd_cfg_panel_info,
258             .cfg_open_flow = lcd_open_flow,
259             .cfg_close_flow = lcd_close_flow,
260             .lcd_user_defined_func = lcd_user_defined_func,
261     },
262 };
263