Commit | Line | Data |
---|---|---|
6fa3eb70 S |
1 | #include <linux/string.h> |
2 | ||
3 | #include "lcm_drv.h" | |
4 | #ifndef BUILD_UBOOT | |
5 | #include <linux/kernel.h> ///for printk | |
6 | #endif | |
7 | ||
8 | // --------------------------------------------------------------------------- | |
9 | // Local Constants | |
10 | // --------------------------------------------------------------------------- | |
11 | ||
12 | #define FRAME_WIDTH (320) | |
13 | #define FRAME_HEIGHT (480) | |
14 | #define LCM_ID (0x69) | |
15 | #define REGFLAG_DELAY 0XFE | |
16 | #define REGFLAG_END_OF_TABLE 0xFF // END OF REGISTERS MARKER | |
17 | ||
18 | // --------------------------------------------------------------------------- | |
19 | // Local Variables | |
20 | // --------------------------------------------------------------------------- | |
21 | ||
22 | static LCM_UTIL_FUNCS lcm_util = {0}; | |
23 | ||
24 | #define SET_RESET_PIN(v) (lcm_util.set_reset_pin((v))) | |
25 | ||
26 | #define UDELAY(n) (lcm_util.udelay(n)) | |
27 | #define MDELAY(n) (lcm_util.mdelay(n)) | |
28 | ||
29 | ||
30 | // --------------------------------------------------------------------------- | |
31 | // Local Functions | |
32 | // --------------------------------------------------------------------------- | |
33 | ||
34 | #define dsi_set_cmdq_V2(cmd, count, ppara, force_update) lcm_util.dsi_set_cmdq_V2(cmd, count, ppara, force_update) | |
35 | #define dsi_set_cmdq(pdata, queue_size, force_update) lcm_util.dsi_set_cmdq(pdata, queue_size, force_update) | |
36 | #define wrtie_cmd(cmd) lcm_util.dsi_write_cmd(cmd) | |
37 | #define write_regs(addr, pdata, byte_nums) lcm_util.dsi_write_regs(addr, pdata, byte_nums) | |
38 | #define read_reg(cmd) lcm_util.dsi_dcs_read_lcm_reg(cmd) | |
39 | #define read_reg_v2(cmd, buffer, buffer_size) lcm_util.dsi_dcs_read_lcm_reg_v2(cmd, buffer, buffer_size) | |
40 | ||
41 | static struct LCM_setting_table { | |
42 | unsigned cmd; | |
43 | unsigned char count; | |
44 | unsigned char para_list[64]; | |
45 | }; | |
46 | ||
47 | ||
48 | static struct LCM_setting_table lcm_initialization_setting[] = { | |
49 | ||
50 | /* | |
51 | Note : | |
52 | ||
53 | Data ID will depends on the following rule. | |
54 | ||
55 | count of parameters > 1 => Data ID = 0x39 | |
56 | count of parameters = 1 => Data ID = 0x15 | |
57 | count of parameters = 0 => Data ID = 0x05 | |
58 | ||
59 | Structure Format : | |
60 | ||
61 | {DCS command, count of parameters, {parameter list}} | |
62 | {REGFLAG_DELAY, milliseconds of time, {}}, | |
63 | ||
64 | ... | |
65 | ||
66 | Setting ending by predefined flag | |
67 | ||
68 | {REGFLAG_END_OF_TABLE, 0x00, {}} | |
69 | */ | |
70 | ||
71 | ||
72 | {0xB9, 3, {0xFF, 0x83, 0x69}}, | |
73 | {REGFLAG_DELAY, 10, {}}, | |
74 | ||
75 | {0xB0, 2, {0x01, 0x0B}}, | |
76 | {REGFLAG_DELAY, 10, {}}, | |
77 | ||
78 | {0xB2, 15, {0x00, 0x20, 0x05, 0x05, | |
79 | 0x70, 0x00, 0xFF, 0x00, | |
80 | 0x00, 0x00, 0x00, 0x03, | |
81 | 0x03, 0x00, 0x01}}, | |
82 | {REGFLAG_DELAY, 10, {}}, | |
83 | ||
84 | {0xB4, 5, {0x00, 0x18, 0x80, 0x06, | |
85 | 0x02}}, | |
86 | {REGFLAG_DELAY, 10, {}}, | |
87 | ||
88 | {0xD5, 26, {0x00, 0x04, 0x03, 0x00, | |
89 | 0x01, 0x05, 0x28, 0x70, | |
90 | 0x01, 0x03, 0x00, 0x00, | |
91 | 0x40, 0x06, 0x51, 0x07, | |
92 | 0x00, 0x00, 0x41, 0x06, | |
93 | 0x50, 0x07, 0x07, 0x0F, | |
94 | 0x04, 0x00}}, | |
95 | {REGFLAG_DELAY, 10, {}}, | |
96 | ||
97 | {0xB1, 19, {0x85, 0x00, 0x34, 0x07, | |
98 | 0x00, 0x0f, 0x0f, 0x2A, | |
99 | 0x32, 0x3F, 0x3F, 0x01, | |
100 | 0x3A, 0x01, 0xE6, 0xE6, | |
101 | 0xE6, 0xE6, 0xE6}}, | |
102 | {REGFLAG_DELAY, 10, {}}, | |
103 | ||
104 | ||
105 | {0x3A, 1, {0x07}}, | |
106 | {0xCC, 1, {0x02}}, | |
107 | ||
108 | {0xB6, 2, {0x42, 0x42}}, | |
109 | {REGFLAG_DELAY, 10, {}}, | |
110 | ||
111 | // ENABLE FMARK | |
112 | {0x44, 2, {((FRAME_HEIGHT/2)>>8), ((FRAME_HEIGHT/2)&0xFF)}}, | |
113 | {0x35, 1, {0x00}}, | |
114 | ||
115 | // SET GAMMA | |
116 | {0xE0, 34, {0x00, 0x31, 0x19, 0x38, | |
117 | 0x3D, 0x3F, 0x28, 0x46, | |
118 | 0x07, 0x0D, 0x0E, 0x12, | |
119 | 0x15, 0x12, 0x14, 0x0F, | |
120 | 0x17, 0x00, 0x13, 0x19, | |
121 | 0x38, 0x3D, 0x3F, 0x28, | |
122 | 0x46, 0x07, 0x0D, 0x0E, | |
123 | 0x12, 0x15, 0x12, 0x14, | |
124 | 0x0F, 0x17}}, | |
125 | {REGFLAG_DELAY, 10, {}}, | |
126 | ||
127 | {0xBA, 13, {0x00, 0xA0, 0xC6, 0x00, | |
128 | 0x0A, 0x02, 0x10, 0x30, | |
129 | 0x6F, 0x02, 0x11, 0x18, | |
130 | 0x40}}, | |
131 | ||
132 | // Note | |
133 | // Strongly recommend not to set Sleep out / Display On here. That will cause messed frame to be shown as later the backlight is on. | |
134 | ||
135 | ||
136 | // Setting ending by predefined flag | |
137 | {REGFLAG_END_OF_TABLE, 0x00, {}} | |
138 | }; | |
139 | ||
140 | ||
141 | static struct LCM_setting_table lcm_set_window[] = { | |
142 | {0x2A, 4, {0x00, 0x00, (FRAME_WIDTH>>8), (FRAME_WIDTH&0xFF)}}, | |
143 | {0x2B, 4, {0x00, 0x00, (FRAME_HEIGHT>>8), (FRAME_HEIGHT&0xFF)}}, | |
144 | {REGFLAG_END_OF_TABLE, 0x00, {}} | |
145 | }; | |
146 | ||
147 | ||
148 | static struct LCM_setting_table lcm_sleep_out_setting[] = { | |
149 | // Sleep Out | |
150 | {0x11, 1, {0x00}}, | |
151 | {REGFLAG_DELAY, 120, {}}, | |
152 | ||
153 | // Display ON | |
154 | {0x29, 1, {0x00}}, | |
155 | {REGFLAG_END_OF_TABLE, 0x00, {}} | |
156 | }; | |
157 | ||
158 | ||
159 | static struct LCM_setting_table lcm_deep_sleep_mode_in_setting[] = { | |
160 | // Display off sequence | |
161 | {0x28, 1, {0x00}}, | |
162 | ||
163 | // Sleep Mode On | |
164 | {0x10, 1, {0x00}}, | |
165 | ||
166 | {REGFLAG_END_OF_TABLE, 0x00, {}} | |
167 | }; | |
168 | ||
169 | static struct LCM_setting_table lcm_compare_id_setting[] = { | |
170 | // Display off sequence | |
171 | {0xB9, 3, {0xFF, 0x83, 0x69}}, | |
172 | {REGFLAG_DELAY, 10, {}}, | |
173 | ||
174 | // Sleep Mode On | |
175 | // {0xC3, 1, {0xFF}}, | |
176 | ||
177 | {REGFLAG_END_OF_TABLE, 0x00, {}} | |
178 | }; | |
179 | ||
180 | static struct LCM_setting_table lcm_backlight_level_setting[] = { | |
181 | {0x51, 1, {0xFF}}, | |
182 | {REGFLAG_END_OF_TABLE, 0x00, {}} | |
183 | }; | |
184 | ||
185 | ||
186 | static void push_table(struct LCM_setting_table *table, unsigned int count, unsigned char force_update) | |
187 | { | |
188 | unsigned int i; | |
189 | ||
190 | for(i = 0; i < count; i++) { | |
191 | ||
192 | unsigned cmd; | |
193 | cmd = table[i].cmd; | |
194 | ||
195 | switch (cmd) { | |
196 | ||
197 | case REGFLAG_DELAY : | |
198 | MDELAY(table[i].count); | |
199 | break; | |
200 | ||
201 | case REGFLAG_END_OF_TABLE : | |
202 | break; | |
203 | ||
204 | default: | |
205 | dsi_set_cmdq_V2(cmd, table[i].count, table[i].para_list, force_update); | |
206 | } | |
207 | } | |
208 | ||
209 | } | |
210 | ||
211 | ||
212 | // --------------------------------------------------------------------------- | |
213 | // LCM Driver Implementations | |
214 | // --------------------------------------------------------------------------- | |
215 | ||
216 | static void lcm_set_util_funcs(const LCM_UTIL_FUNCS *util) | |
217 | { | |
218 | memcpy(&lcm_util, util, sizeof(LCM_UTIL_FUNCS)); | |
219 | } | |
220 | ||
221 | ||
222 | static void lcm_get_params(LCM_PARAMS *params) | |
223 | { | |
224 | memset(params, 0, sizeof(LCM_PARAMS)); | |
225 | ||
226 | params->type = LCM_TYPE_DSI; | |
227 | ||
228 | params->width = FRAME_WIDTH; | |
229 | params->height = FRAME_HEIGHT; | |
230 | ||
231 | // enable tearing-free | |
232 | params->dbi.te_mode = LCM_DBI_TE_MODE_VSYNC_ONLY; | |
233 | params->dbi.te_edge_polarity = LCM_POLARITY_RISING; | |
234 | ||
235 | params->dsi.mode = CMD_MODE; | |
236 | ||
237 | // DSI | |
238 | /* Command mode setting */ | |
239 | params->dsi.LANE_NUM = LCM_TWO_LANE; | |
240 | //The following defined the fomat for data coming from LCD engine. | |
241 | params->dsi.data_format.color_order = LCM_COLOR_ORDER_RGB; | |
242 | params->dsi.data_format.trans_seq = LCM_DSI_TRANS_SEQ_MSB_FIRST; | |
243 | params->dsi.data_format.padding = LCM_DSI_PADDING_ON_LSB; | |
244 | params->dsi.data_format.format = LCM_DSI_FORMAT_RGB888; | |
245 | ||
246 | // Highly depends on LCD driver capability. | |
247 | params->dsi.packet_size=256; | |
248 | ||
249 | // Video mode setting | |
250 | params->dsi.PS=LCM_PACKED_PS_24BIT_RGB888; | |
251 | ||
252 | params->dsi.word_count=480*3; | |
253 | params->dsi.vertical_sync_active=2; | |
254 | params->dsi.vertical_backporch=2; | |
255 | params->dsi.vertical_frontporch=2; | |
256 | params->dsi.vertical_active_line=800; | |
257 | ||
258 | params->dsi.line_byte=2180; // 2256 = 752*3 | |
259 | params->dsi.horizontal_sync_active_byte=26; | |
260 | params->dsi.horizontal_backporch_byte=206; | |
261 | params->dsi.horizontal_frontporch_byte=206; | |
262 | params->dsi.rgb_byte=(480*3+6); | |
263 | ||
264 | params->dsi.horizontal_sync_active_word_count=20; | |
265 | params->dsi.horizontal_backporch_word_count=200; | |
266 | params->dsi.horizontal_frontporch_word_count=200; | |
267 | ||
268 | // Bit rate calculation | |
269 | params->dsi.pll_div1=38; // fref=26MHz, fvco=fref*(div1+1) (div1=0~63, fvco=500MHZ~1GHz) | |
270 | params->dsi.pll_div2=1; // div2=0~15: fout=fvo/(2*div2) | |
271 | ||
272 | } | |
273 | ||
274 | ||
275 | static void lcm_init(void) | |
276 | { | |
277 | SET_RESET_PIN(1); | |
278 | SET_RESET_PIN(0); | |
279 | MDELAY(1); | |
280 | SET_RESET_PIN(1); | |
281 | MDELAY(10); | |
282 | ||
283 | push_table(lcm_initialization_setting, sizeof(lcm_initialization_setting) / sizeof(struct LCM_setting_table), 1); | |
284 | } | |
285 | ||
286 | ||
287 | static void lcm_suspend(void) | |
288 | { | |
289 | push_table(lcm_deep_sleep_mode_in_setting, sizeof(lcm_deep_sleep_mode_in_setting) / sizeof(struct LCM_setting_table), 1); | |
290 | } | |
291 | ||
292 | ||
293 | static void lcm_resume(void) | |
294 | { | |
295 | push_table(lcm_sleep_out_setting, sizeof(lcm_sleep_out_setting) / sizeof(struct LCM_setting_table), 1); | |
296 | } | |
297 | ||
298 | ||
299 | static void lcm_update(unsigned int x, unsigned int y, | |
300 | unsigned int width, unsigned int height) | |
301 | { | |
302 | unsigned int x0 = x; | |
303 | unsigned int y0 = y; | |
304 | unsigned int x1 = x0 + width - 1; | |
305 | unsigned int y1 = y0 + height - 1; | |
306 | ||
307 | unsigned char x0_MSB = ((x0>>8)&0xFF); | |
308 | unsigned char x0_LSB = (x0&0xFF); | |
309 | unsigned char x1_MSB = ((x1>>8)&0xFF); | |
310 | unsigned char x1_LSB = (x1&0xFF); | |
311 | unsigned char y0_MSB = ((y0>>8)&0xFF); | |
312 | unsigned char y0_LSB = (y0&0xFF); | |
313 | unsigned char y1_MSB = ((y1>>8)&0xFF); | |
314 | unsigned char y1_LSB = (y1&0xFF); | |
315 | ||
316 | unsigned int data_array[16]; | |
317 | ||
318 | data_array[0]= 0x00053902; | |
319 | data_array[1]= (x1_MSB<<24)|(x0_LSB<<16)|(x0_MSB<<8)|0x2a; | |
320 | data_array[2]= (x1_LSB); | |
321 | data_array[3]= 0x00053902; | |
322 | data_array[4]= (y1_MSB<<24)|(y0_LSB<<16)|(y0_MSB<<8)|0x2b; | |
323 | data_array[5]= (y1_LSB); | |
324 | data_array[6]= 0x002c3909; | |
325 | ||
326 | dsi_set_cmdq(&data_array, 7, 0); | |
327 | ||
328 | } | |
329 | ||
330 | ||
331 | static void lcm_setbacklight(unsigned int level) | |
332 | { | |
333 | // Refresh value of backlight level. | |
334 | lcm_backlight_level_setting[0].para_list[0] = level; | |
335 | ||
336 | push_table(lcm_backlight_level_setting, sizeof(lcm_backlight_level_setting) / sizeof(struct LCM_setting_table), 1); | |
337 | } | |
338 | ||
339 | ||
340 | static void lcm_setpwm(unsigned int divider) | |
341 | { | |
342 | // TBD | |
343 | } | |
344 | ||
345 | ||
346 | static unsigned int lcm_getpwm(unsigned int divider) | |
347 | { | |
348 | // ref freq = 15MHz, B0h setting 0x80, so 80.6% * freq is pwm_clk; | |
349 | // pwm_clk / 255 / 2(lcm_setpwm() 6th params) = pwm_duration = 23706 | |
350 | unsigned int pwm_clk = 23706 / (1<<divider); | |
351 | return pwm_clk; | |
352 | } | |
353 | ||
354 | static unsigned int lcm_compare_id() | |
355 | { | |
356 | unsigned int id = 0; | |
357 | unsigned char buffer[2]; | |
358 | unsigned int array[16]; | |
359 | SET_RESET_PIN(1); //NOTE:should reset LCM firstly | |
360 | SET_RESET_PIN(0); | |
361 | MDELAY(1); | |
362 | SET_RESET_PIN(1); | |
363 | MDELAY(10); | |
364 | ||
365 | push_table(lcm_compare_id_setting, sizeof(lcm_compare_id_setting) / sizeof(struct LCM_setting_table), 1); | |
366 | ||
367 | array[0] = 0x00023700;// read id return two byte,version and id | |
368 | dsi_set_cmdq(array, 1, 1); | |
369 | // id = read_reg(0xF4); | |
370 | read_reg_v2(0xF4, buffer, 2); | |
371 | id = buffer[0]; //we only need ID | |
372 | ||
373 | return (LCM_ID == id)?1:0; | |
374 | } | |
375 | ||
376 | // --------------------------------------------------------------------------- | |
377 | // Get LCM Driver Hooks | |
378 | // --------------------------------------------------------------------------- | |
379 | LCM_DRIVER hx8369_dsi_6575_hvga_lcm_drv = | |
380 | { | |
381 | .name = "hx8369_dsi_6575_hvga", | |
382 | .set_util_funcs = lcm_set_util_funcs, | |
383 | .get_params = lcm_get_params, | |
384 | .init = lcm_init, | |
385 | .suspend = lcm_suspend, | |
386 | .resume = lcm_resume, | |
387 | .update = lcm_update, | |
388 | .set_backlight = lcm_setbacklight, | |
389 | .set_pwm = lcm_setpwm, | |
390 | .get_pwm = lcm_getpwm, | |
391 | .compare_id = lcm_compare_id, | |
392 | }; |