tizen 2.4 release
[profile/mobile/platform/kernel/u-boot-tm1.git] / drivers / video / sprdfb / lcd / lcd_hx8394d_mipi.c
1 /* drivers/video/sprdfb/lcd_hx8394d_mipi.c
2  *
3  * Support for hx8394d mipi LCD device
4  *
5  * Copyright (C) 2014 Spreadtrum
6  * Author: Haibing.Yang <haibing.yang@spreadtrum.com>
7  *
8  *      The panel info is got from raolihua@trulyopto.cn
9  *              Panel: 5.0HD(720*1280) LG LTPS
10  *              Driver IC: HX8394D
11  *              Interface: MIPI 4LANES
12  *              Test condition: IOVCC=VCC=2.8V
13  *              DATE: 20150105
14  *              Version: 1.0
15  *
16  * This software is licensed under the terms of the GNU General Public
17  * License version 2, as published by the Free Software Foundation, and
18  * may be copied, distributed, and modified under those terms.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  */
25
26 #include <asm/errno.h>
27 #include <asm/arch/sprd_lcd.h>
28 #include "../sprdfb.h"
29
30 #define pr_info printf
31 #define pr_err printf
32 #define pr_debug printf
33 #define u8 unsigned char
34 #define u16 unsigned short
35 #define u32 unsigned int
36 #define usleep_range(time1, time2) udelay(time1)
37 enum {false, true};
38
39 #define MAX_DATA 100
40 #define MAX_RX_PKT_SIZE 0x37
41 #define PANEL_ID_LENGTH 3
42 #define PANEL_RETURN_ID 0x8394
43 #define PANEL_ACTUAL_ID 0x8394
44 #define PANEL_ID_REG 0x04
45 #define PANEL_ID_READ_CNT 3
46 #define PANEL_ID_OFFSET 0
47
48 #define LCM_TAG_SHIFT 24
49 #define LCM_DATA_TYPE_SHIFT 16
50 #define LCM_TAG_MASK ((1 << LCM_DATA_TYPE_SHIFT) - 1)
51
52 #define LCM_TAG_SEND (1 << LCM_TAG_SHIFT)
53 #define LCM_TAG_SLEEP (2 << LCM_TAG_SHIFT)
54
55 #define LCM_SEND(len) (LCM_TAG_SEND | len)
56 #define LCM_SEND_WITH_TYPE(len, type) \
57                 (LCM_TAG_SEND | len | (type << LCM_DATA_TYPE_SHIFT))
58 #define LCM_SLEEP(ms) (LCM_TAG_SLEEP | ms)
59
60 struct panel_cmds {
61         u32 tag;
62         u8 data[MAX_DATA];
63 };
64
65 static struct panel_cmds hx8394d_init_cmds[] = {
66         {
67                 LCM_SEND(06), {04, 0,
68                 0xB9, 0xFF, 0x83, 0x94}
69         },
70         {
71                 LCM_SEND(05), {03, 0,
72                 0xBA,0x33,0x83}
73         },
74         { /* Set power */
75                 LCM_SEND(20), {18, 0,
76                 0xB1, 0x6C, 0x12, 0x12, 0x26, 0x04, 0x11, 0xF1,
77                 0x81, 0x3A, 0x54, 0x23, 0x80, 0xC0, 0xD2, 0x58}
78         },
79         { /* Set display related register */
80                 LCM_SEND(14), {12, 0,
81                 0xB2, 0x00, 0x64, 0x0E, 0x0D, 0x22, 0x1C, 0x08,
82                 0x08, 0x1C, 0x4D, 0x00}
83         },
84         { /* Set panel driving timing */
85                 LCM_SEND(15), {13, 0,
86                 0xB4, 0x00, 0xFF, 0x51, 0x5A, 0x59, 0x5A, 0x03,
87                 0x5A, 0x01, 0x70, 0x01, 0x70}
88         },
89         {LCM_SEND(2), {0xBC, 0x07}},
90         {
91                 LCM_SEND(06), {04, 0,
92                 0xBF, 0x41, 0x0E, 0x01}
93         },
94         { /* Set GIP */
95                 LCM_SEND(40), {38, 0,
96                 0xD3, 0x00, 0x0F, 0x00, 0x40, 0x07, 0x10, 0x00,
97                 0x08, 0x10, 0x08, 0x00, 0x08, 0x54, 0x15, 0x0E,
98                 0x05, 0x0E, 0x02, 0x15, 0x06, 0x05, 0x06, 0x47,
99                 0x44, 0x0A, 0x0A, 0x4B, 0x10, 0x07, 0x07, 0x08,
100                 0x00, 0x00, 0x00, 0x0A, 0x00, 0x01}
101         },
102         { /* Set GIP */
103                 LCM_SEND(47), {45, 0,
104                 0xD5, 0x1A, 0x1A, 0x1B, 0x1B, 0x00, 0x01, 0x02,
105                 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
106                 0x0B, 0x24, 0x25, 0x18, 0x18, 0x26, 0x27, 0x18,
107                 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
108                 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x20,
109                 0x21, 0x18, 0x18, 0x18, 0x18}
110         },
111         { /* Set GIP */
112                 LCM_SEND(47), {45, 0,
113                 0xD6, 0x1A, 0x1A, 0x1B, 0x1B, 0x0B, 0x0A, 0x09,
114                 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
115                 0x00, 0x21, 0x20, 0x58, 0x58, 0x27, 0x26, 0x18,
116                 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
117                 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x25,
118                 0x24, 0x18, 0x18, 0x18, 0x18}
119         },
120         /* SETPANEL CCh: can set normally-white/black panel */
121         {LCM_SEND(2), {0xCC, 0x09}},
122         {
123                 LCM_SEND(5), {3, 0,
124                 0xC0, 0x30, 0x14}
125         },
126         {
127                 LCM_SEND(7), {5, 0,
128                 0xC7, 0x00, 0xC0, 0x40, 0xC0}
129         },
130         {
131                 LCM_SEND(5), {3, 0,
132                 0xB6, 0x6B, 0x6B}
133         },
134         { /* Analog gamma setting */
135                 LCM_SEND(45), {43, 0,
136                 0xE0, 0x00, 0x0A, 0x0F, 0x24, 0x3A, 0x3F, 0x20,
137                 0x3B, 0x08, 0x0D, 0x0E, 0x16, 0x0F, 0x12, 0x15,
138                 0x13, 0x15, 0x09, 0x12, 0x12, 0x18, 0x00, 0x0A,
139                 0x0F, 0x24, 0x3A, 0x3F, 0x20, 0x3B, 0x08, 0x0D,
140                 0x0E, 0x16, 0x0F, 0x12, 0x15, 0x13, 0x15, 0x09,
141                 0x12, 0x12, 0x18}
142         },
143
144         {LCM_SEND(2), {0xBD, 0x00}}, /* BANK: RED */
145         {
146                 LCM_SEND(46), {44, 0,
147                 0xC1, 0x01, 0x00, 0x06, 0x0C, 0x14, 0x1D, 0x27,
148                 0x2F, 0x38, 0x41, 0x49, 0x51, 0x59, 0x61, 0x69,
149                 0x71, 0x79, 0x81, 0x89, 0x91, 0x99, 0xA1, 0xA9,
150                 0xB2, 0xB9, 0xC1, 0xCA, 0xD1, 0xD8, 0xE2, 0xEA,
151                 0xF0, 0xF7, 0xFF, 0x38, 0xFC, 0x3F, 0x0B, 0xC1,
152                 0x13, 0xF1, 0x0D, 0xC0}
153         },
154         {LCM_SEND(2), {0xBD, 0x01}}, /* BANK: GREEN */
155         {
156                 LCM_SEND(45), {43, 0,
157                 0xC1, 0x00, 0x06, 0x0C, 0x14, 0x1D, 0x27, 0x2F,
158                 0x38, 0x41, 0x49, 0x51, 0x59, 0x61, 0x69, 0x71,
159                 0x79, 0x81, 0x89, 0x91, 0x99, 0xA1, 0xA9, 0xB2,
160                 0xB9, 0xC1, 0xCA, 0xD1, 0xD8, 0xE2, 0xEA, 0xF0,
161                 0xF7, 0xFF, 0x38, 0xFC, 0x3F, 0x0B, 0xC1, 0x13,
162                 0xF1, 0x0D, 0xC0}
163         },
164         {LCM_SEND(2), {0xBD, 0x02}}, /* BANK: BLUE */
165         {
166                 LCM_SEND(45), {43, 0,
167                 0xC1, 0x00, 0x06, 0x0C, 0x14, 0x1D, 0x27, 0x2F,
168                 0x38, 0x41, 0x49, 0x51, 0x59, 0x61, 0x69, 0x71,
169                 0x79, 0x81, 0x89, 0x91, 0x99, 0xA1, 0xA9, 0xB2,
170                 0xB9, 0xC1, 0xCA, 0xD1, 0xD8, 0xE2, 0xEA, 0xF0,
171                 0xF7, 0xFF, 0x38, 0xFC, 0x3F, 0x0B, 0xC1, 0x13,
172                 0xF1, 0x0D, 0xC0}
173         },
174
175         /* Set_address_mode (36h): RGB order and source/gate dir */
176         {LCM_SEND(2), {0x36, 0x03}},
177
178         /* sleep out */
179         {LCM_SEND(1), {0x11}},
180         {LCM_SLEEP(120)},
181         {LCM_SEND(1), {0x29}},
182         {LCM_SLEEP(10)},
183 };
184
185 static struct panel_cmds sleep_in[] = {
186         {LCM_SEND(1), {0x28}},
187         {LCM_SLEEP(10)},
188         {LCM_SEND(1), {0x10}},
189         {LCM_SLEEP(120)},
190 };
191
192 static struct panel_cmds sleep_out[] = {
193         {LCM_SEND(1), {0x11}},
194         {LCM_SLEEP(120)},
195         {LCM_SEND(1), {0x29}},
196         {LCM_SLEEP(10)},
197 };
198
199 int sprdfb_dsi_tx_cmds(struct panel_spec *panel,
200                 struct panel_cmds *cmds, u32 cmds_len, u32 back2hs)
201 {
202         int i, time;
203         struct ops_mipi *ops = panel->info.mipi->ops;
204         u16 work_mode = panel->info.mipi->work_mode;
205         u8 write_type = (cmds->tag >> 16) & 0xff;
206
207         pr_info("%s, write data len: %d\n", __func__, cmds_len);
208
209         if (!ops->mipi_set_cmd_mode ||
210                         !ops->mipi_dcs_write ||
211                         !ops->mipi_force_write) {
212                 pr_err("%s: Expected functions are NULL.\n", __func__);
213                 return -EFAULT;
214         }
215
216         ops->mipi_set_cmd_mode();
217
218         for (i = 0; i < cmds_len; i++) {
219                 if (cmds->tag & LCM_TAG_SEND) {
220                         if (write_type)
221                                 ops->mipi_force_write(write_type, cmds->data,
222                                                 cmds->tag & LCM_TAG_MASK);
223                         else
224                                 ops->mipi_dcs_write(cmds->data, cmds->tag & LCM_TAG_MASK);
225                         udelay(20);
226                 } else if (cmds->tag & LCM_TAG_SLEEP) {
227                         time = (cmds->tag & LCM_TAG_MASK) * 1000;
228                         usleep_range(time, time);
229                 }
230                 cmds++;
231         }
232
233         return 0;
234 }
235
236 int sprdfb_dsi_rx_cmds(struct panel_spec *panel,
237                 u8 regs, u16 get_len, u8 *data, u32 back2hs)
238 {
239         int ret;
240         struct ops_mipi *ops = panel->info.mipi->ops;
241         u8 pkt_size[2];
242         u16 work_mode = panel->info.mipi->work_mode;
243
244         pr_info("%s, read data len: %d\n", __func__, get_len);
245         if (!data) {
246                 pr_err("Expected registers or data is NULL.\n");
247                 return -EIO;
248         }
249         if (!ops->mipi_set_cmd_mode ||
250                         !ops->mipi_force_read ||
251                         !ops->mipi_force_write) {
252                 pr_err("%s: Expected functions are NULL.\n", __func__);
253                 return -EFAULT;
254         }
255
256         pkt_size[0] = get_len & 0xff;
257         pkt_size[1] = (get_len >> 8) & 0xff;
258         ops->mipi_set_cmd_mode();
259         ops->mipi_force_write(MAX_RX_PKT_SIZE, pkt_size, sizeof(pkt_size));
260
261         ret = ops->mipi_force_read(regs, get_len, data);
262         if (ret < 0) {
263                 pr_err("%s: dsi read id fail\n", __func__);
264                 return -EINVAL;
265         }
266
267         return 0;
268 }
269
270 int sprdfb_dsi_panel_sleep(struct panel_spec *panel, u8 is_sleep)
271 {
272         int len;
273         struct panel_cmds *sleep_inout;
274
275         if (is_sleep) {
276                 sleep_inout = sleep_in;
277                 len = ARRAY_SIZE(sleep_in);
278         } else {
279                 sleep_inout = sleep_out;
280                 len = ARRAY_SIZE(sleep_out);
281         }
282
283         return sprdfb_dsi_tx_cmds(panel, sleep_inout, len, false);
284 }
285
286 u32 sprdfb_dsi_panel_readid(struct panel_spec *panel)
287 {
288         int i, cnt = PANEL_ID_READ_CNT;
289         u8 regs = PANEL_ID_REG;
290         u8 data[PANEL_ID_LENGTH] = { 0 };
291         u8 id[PANEL_ID_LENGTH] = { 0 };
292
293         i = PANEL_ID_OFFSET;
294         id[i++] = (PANEL_RETURN_ID >> 8) & 0xFF;
295         id[i] = PANEL_RETURN_ID & 0xFF;
296         do {
297                 sprdfb_dsi_rx_cmds(panel, regs, PANEL_ID_LENGTH, data, false);
298                 pr_debug("%s: reading panel id(0x%2x) is ", __func__, regs);
299                 for (i = 0; i < PANEL_ID_LENGTH; ++i) {
300                         pr_debug("0x%2x, ", data[i]);
301                 }
302                 pr_debug("\n");
303                 i = PANEL_ID_OFFSET;
304                 if (data[i] == id[i] && data[i + 1] == id[i + 1])
305                         return PANEL_ACTUAL_ID;
306         } while (cnt-- > 0);
307
308         return 0;
309 }
310
311 static int hx8394d_dsi_panel_init(struct panel_spec *panel)
312 {
313         return sprdfb_dsi_tx_cmds(panel, hx8394d_init_cmds,
314                         ARRAY_SIZE(hx8394d_init_cmds), false);
315 }
316
317 static int hx8394d_dsi_panel_dead(struct panel_spec *panel)
318 {
319
320         return true;
321 }
322
323 static struct panel_operations lcd_hx8394d_mipi_ops = {
324         .panel_init = hx8394d_dsi_panel_init,
325         .panel_readid = sprdfb_dsi_panel_readid,
326         .panel_enter_sleep = sprdfb_dsi_panel_sleep,
327 };
328
329 static struct timing_rgb lcd_hx8394d_mipi_timing = {
330         .hfp = 16, /* unit: pixel */
331         .hbp = 16,
332         .hsync = 10,
333         .vfp = 12, /*unit: line */
334         .vbp = 15,
335         .vsync = 4,
336 };
337
338 static struct info_mipi lcd_hx8394d_mipi_info = {
339         .work_mode  = SPRDFB_MIPI_MODE_VIDEO,
340         .video_bus_width = 24,
341         .lan_number = 4,
342         .phy_feq = 430000,
343         .h_sync_pol = SPRDFB_POLARITY_POS,
344         .v_sync_pol = SPRDFB_POLARITY_POS,
345         .de_pol = SPRDFB_POLARITY_POS,
346         .te_pol = SPRDFB_POLARITY_POS,
347         .color_mode_pol = SPRDFB_POLARITY_POS,
348         .shut_down_pol = SPRDFB_POLARITY_POS,
349         .timing = &lcd_hx8394d_mipi_timing,
350         .ops = NULL,
351 };
352
353 struct panel_spec lcd_hx8394d_mipi_spec = {
354         .width = 720,
355         .height = 1280,
356         .fps = 60,
357         .type = LCD_MODE_DSI,
358         .direction = LCD_DIRECT_NORMAL,
359         .info = {
360                 .mipi = &lcd_hx8394d_mipi_info
361         },
362         .ops = &lcd_hx8394d_mipi_ops,
363 };
364