tizen 2.4 release
[kernel/u-boot-tm1.git] / drivers / video / sprdfb / sprdfb_mcu.c
1 /*\r
2  * Copyright (C) 2012 Spreadtrum Communications Inc.\r
3  *\r
4  */\r
5 \r
6 #include <common.h>\r
7 \r
8 #include <asm/arch/sprd_lcd.h>\r
9 #include <asm/arch/dispc_reg.h>\r
10 \r
11 #include "sprdfb.h"\r
12 \r
13 //#define CONFIG_FB_NO_FMARK    /*Jessica for FPGA*/\r
14 \r
15 static int32_t dispc_mcu_send_cmd(uint32_t cmd)\r
16 {\r
17         int i = 0;\r
18         /* busy wait for ahb fifo full sign's disappearance */\r
19         while(dispc_read(DISPC_DBI_QUEUE) & (1<<5)){\r
20                 if(0x0 == ++i%10000){\r
21                         printf("sprdfb: [%s] warning: busy waiting!\n", __FUNCTION__);\r
22                 }\r
23         }\r
24 \r
25         dispc_write(cmd, DISPC_DBI_CMD);\r
26 \r
27         return 0;\r
28 }\r
29 \r
30 static int32_t dispc_mcu_send_cmd_data(uint32_t cmd, uint32_t data)\r
31 {\r
32         int i = 0;\r
33         /* busy wait for ahb fifo full sign's disappearance */\r
34         while(dispc_read(DISPC_DBI_QUEUE) & (1<<5)){\r
35                 if(0x0 == ++i%10000){\r
36                         printf("sprdfb: [%s] warning: busy waiting!\n", __FUNCTION__);\r
37                 }\r
38         }\r
39 \r
40         dispc_write(cmd, DISPC_DBI_CMD);\r
41 \r
42         i = 0;\r
43         /* busy wait for ahb fifo full sign's disappearance */\r
44         while(dispc_read(DISPC_DBI_QUEUE) & (1<<5)){\r
45                 if(0x0 == ++i%10000){\r
46                         printf("sprdfb: [%s] warning: busy waiting!\n", __FUNCTION__);\r
47                 }\r
48         }\r
49 \r
50         dispc_write(data, DISPC_DBI_DATA);\r
51 \r
52         return 0;\r
53 }\r
54 \r
55 static int32_t dispc_mcu_send_data(uint32_t data)\r
56 {\r
57         int i = 0;\r
58         /* busy wait for ahb fifo full sign's disappearance */\r
59         while(dispc_read(DISPC_DBI_QUEUE) & (1<<5)){\r
60                 if(0x0 == ++i%10000){\r
61                         printf("sprdfb: [%s] warning: busy waiting!\n", __FUNCTION__);\r
62                 }\r
63         }\r
64 \r
65         dispc_write(data, DISPC_DBI_DATA);\r
66 \r
67         return 0;\r
68 }\r
69 \r
70 static uint32_t dispc_mcu_read_data(void)\r
71 {\r
72         int i = 0;\r
73         /* busy wait for ahb fifo full sign's disappearance */\r
74         while(dispc_read(DISPC_DBI_QUEUE) & (1<<5)){\r
75                 if(0x0 == ++i%10000){\r
76                         printf("sprdfb: [%s] warning: busy waiting!\n", __FUNCTION__);\r
77                 }\r
78         }\r
79         dispc_write(1 << 24, DISPC_DBI_DATA);\r
80         udelay(50);\r
81         return dispc_read(DISPC_DBI_RDATA);\r
82 }\r
83 \r
84 static struct ops_mcu dispc_mcu_ops = {\r
85         .send_cmd = dispc_mcu_send_cmd,\r
86         .send_cmd_data = dispc_mcu_send_cmd_data,\r
87         .send_data = dispc_mcu_send_data,\r
88         .read_data = dispc_mcu_read_data,\r
89 };\r
90 \r
91 \r
92 static uint32_t mcu_calc_timing(struct timing_mcu *timing)\r
93 {\r
94         uint32_t  clk_rate;\r
95         uint32_t  rcss, rlpw, rhpw, wcss, wlpw, whpw;\r
96 //      struct clk * clk = NULL;\r
97 \r
98         if(NULL == timing){\r
99                 FB_PRINT("sprdfb: [%s]: Invalid Param\n", __FUNCTION__);\r
100                 return 0;\r
101         }\r
102 \r
103 //      clk_get(NULL,"clk_dispc_dbi");\r
104 //      clk_rate = clk_get_rate(clk) / 1000000;\r
105         clk_rate = 250; // 250 MHz\r
106 \r
107         FB_PRINT("sprdfb: [%s] clk_rate: 0x%x\n", __FUNCTION__, clk_rate);\r
108 \r
109         /********************************************************\r
110         * we assume : t = ? ns, dispc_dbi = ? MHz   so\r
111         *      1ns need cycle  :  dispc_dbi /1000\r
112         *      tns need cycles :  t * dispc_dbi / 1000\r
113         *\r
114         ********************************************************/\r
115 #define MAX_DBI_RWCSS_TIMING_VALUE      15\r
116 #define MAX_DBI_RWLPW_TIMING_VALUE      63\r
117 #define MAX_DBI_RWHPW_TIMING_VALUE      63\r
118 #define DBI_CYCLES(ns) (( (ns) * clk_rate + 1000 - 1)/ 1000)\r
119 \r
120         /* ceiling*/\r
121         rcss = DBI_CYCLES(timing->rcss);\r
122         if (rcss > MAX_DBI_RWCSS_TIMING_VALUE) {\r
123                 rcss = MAX_DBI_RWCSS_TIMING_VALUE ;\r
124         }\r
125 \r
126         rlpw = DBI_CYCLES(timing->rlpw);\r
127         if (rlpw > MAX_DBI_RWLPW_TIMING_VALUE) {\r
128                 rlpw = MAX_DBI_RWLPW_TIMING_VALUE ;\r
129         }\r
130 \r
131         rhpw = DBI_CYCLES (timing->rhpw);\r
132         if (rhpw > MAX_DBI_RWHPW_TIMING_VALUE) {\r
133                 rhpw = MAX_DBI_RWHPW_TIMING_VALUE ;\r
134         }\r
135 \r
136         wcss = DBI_CYCLES(timing->wcss);\r
137         if (wcss > MAX_DBI_RWCSS_TIMING_VALUE) {\r
138                 wcss = MAX_DBI_RWCSS_TIMING_VALUE ;\r
139         }\r
140 \r
141         wlpw = DBI_CYCLES(timing->wlpw);\r
142         if (wlpw > MAX_DBI_RWLPW_TIMING_VALUE) {\r
143                 wlpw = MAX_DBI_RWLPW_TIMING_VALUE ;\r
144         }\r
145 \r
146 #ifndef CONFIG_LCD_CS_ALWAYS_LOW\r
147          /* dispc/lcdc will waste one cycle because CS pulse will use one cycle*/\r
148         whpw = DBI_CYCLES (timing->whpw) - 1;\r
149 #else\r
150         whpw = DBI_CYCLES (timing->whpw) ;\r
151 #endif\r
152         if (whpw > MAX_DBI_RWHPW_TIMING_VALUE) {\r
153                 whpw = MAX_DBI_RWHPW_TIMING_VALUE ;\r
154         }\r
155 \r
156         return (whpw | (wlpw << 6) | (wcss << 12)\r
157                         | (rhpw << 16) |(rlpw << 22) | (rcss << 28));\r
158 }\r
159 \r
160 static uint32_t mcu_readid(struct panel_spec *self)\r
161 {\r
162         uint32_t id = 0;\r
163 \r
164         /* default id reg is 0 */\r
165         self->info.mcu->ops->send_cmd(0x0);\r
166 \r
167         if(self->info.mcu->bus_width == 8) {\r
168                 id = (self->info.mcu->ops->read_data()) & 0xff;\r
169                 id <<= 8;\r
170                 id |= (self->info.mcu->ops->read_data()) & 0xff;\r
171         } else {\r
172                 id = self->info.mcu->ops->read_data();\r
173         }\r
174 \r
175         return id;\r
176 }\r
177 \r
178 #ifdef CONFIG_FB_LCD_CS1\r
179 /*cs1*/\r
180 void mcu_dispc_init_config(struct panel_spec *panel)\r
181 {\r
182         uint32_t reg_val = 0;\r
183 \r
184         FB_PRINT("sprdfb: [%s] for cs1\n", __FUNCTION__);\r
185 \r
186         if(NULL == panel){\r
187                 printf("sprdfb: [%s] fail.(Invalid Param)\n", __FUNCTION__);\r
188                 return;\r
189         }\r
190 \r
191         if(SPRDFB_PANEL_TYPE_MCU != panel->type){\r
192                 printf("sprdfb: [%s] fail.(not  mcu panel)\n", __FUNCTION__);\r
193                 return;\r
194         }\r
195 \r
196         /*use dbi as interface*/\r
197         dispc_set_bits((2<<1), DISPC_CTRL);\r
198 \r
199         /* CS1 bus mode [BIT8]: 8080/6800 */\r
200         switch (panel->info.mcu->bus_mode) {\r
201         case LCD_BUS_8080:\r
202                 break;\r
203         case LCD_BUS_6800:\r
204                 reg_val |= (1<<8);\r
205                 break;\r
206         default:\r
207                 break;\r
208         }\r
209         /* CS1 bus width [BIT11:9] */\r
210         switch (panel->info.mcu->bus_width) {\r
211         case 8:\r
212                 break;\r
213         case 9:\r
214                 reg_val |= (1 << 9);\r
215                 break;\r
216         case 16:\r
217                 reg_val |= (2 << 9);\r
218                 break;\r
219         case 18:\r
220                 reg_val |= (3 << 9) ;\r
221                 break;\r
222         case 24:\r
223                 reg_val |= (4 << 9);\r
224                 break;\r
225         default:\r
226                 break;\r
227         }\r
228 \r
229         /*CS1 pixel bits [BIT13:12]*/\r
230         switch (panel->info.mcu->bpp) {\r
231         case 16:\r
232                 break;\r
233         case 18:\r
234                 reg_val |= (1 << 12) ;\r
235                 break;\r
236         case 24:\r
237                 reg_val |= (2 << 12);\r
238                 break;\r
239         default:\r
240                 break;\r
241         }\r
242 \r
243 #ifndef CONFIG_FB_NO_FMARK\r
244         /*TE enable*/\r
245         reg_val |= (1 << 16);\r
246         if(SPRDFB_POLARITY_NEG == panel->info.mcu->te_pol){\r
247                 reg_val |= (1<< 17);\r
248         }\r
249         dispc_write(panel->info.mcu->te_sync_delay, DISPC_TE_SYNC_DELAY);\r
250 #endif\r
251 \r
252 #ifdef CONFIG_LCD_CS_ALWAYS_LOW\r
253         /*CS alway low mode*/\r
254         reg_val |= (1<<21);\r
255 #else\r
256         /*CS not alway low mode*/\r
257 #endif\r
258 \r
259         /*CS1 selected*/\r
260         reg_val |= (1 << 20);\r
261 \r
262         dispc_write(reg_val, DISPC_DBI_CTRL);\r
263 \r
264         FB_PRINT("sprdfb: [%s] DISPC_DBI_CTRL = %d\n", __FUNCTION__, dispc_read(DISPC_DBI_CTRL));\r
265 }\r
266 \r
267 void mcu_dispc_set_timing(struct sprdfb_device *dev, uint32_t type)\r
268 {\r
269         FB_PRINT("sprdfb: [%s] for cs1, type = %d\n", __FUNCTION__, type);\r
270 \r
271         switch (type)\r
272         {\r
273         case MCU_LCD_REGISTER_TIMING:\r
274                 dispc_write(dev->panel_timing.mcu_timing[MCU_LCD_REGISTER_TIMING],DISPC_DBI_TIMING1);\r
275                 break;\r
276 \r
277         case MCU_LCD_GRAM_TIMING:\r
278                 dispc_write(dev->panel_timing.mcu_timing[MCU_LCD_GRAM_TIMING],DISPC_DBI_TIMING1);\r
279                 break;\r
280         default:\r
281                 break;\r
282         }\r
283 }\r
284 \r
285 #else\r
286 /*cs0*/\r
287 void mcu_dispc_init_config(struct panel_spec *panel)\r
288 {\r
289         uint32_t reg_val = 0;\r
290 \r
291         FB_PRINT("sprdfb: [%s] for cs0\n", __FUNCTION__);\r
292 \r
293         if(NULL == panel){\r
294                 printf("sprdfb: [%s] fail.(Invalid Param)\n", __FUNCTION__);\r
295                 return;\r
296         }\r
297 \r
298         if(SPRDFB_PANEL_TYPE_MCU != panel->type){\r
299                 printf("sprdfb: [%s] fail.(not  mcu panel)\n", __FUNCTION__);\r
300                 return;\r
301         }\r
302 \r
303         /*use dbi as interface*/\r
304         dispc_set_bits((2<<1), DISPC_CTRL);\r
305 \r
306         /* CS0 bus mode [BIT0]: 8080/6800 */\r
307         switch (panel->info.mcu->bus_mode) {\r
308         case LCD_BUS_8080:\r
309                 break;\r
310         case LCD_BUS_6800:\r
311                 reg_val |= 1;\r
312                 break;\r
313         default:\r
314                 break;\r
315         }\r
316         /* CS0 bus width [BIT3:1] */\r
317         switch (panel->info.mcu->bus_width) {\r
318         case 8:\r
319                 break;\r
320         case 9:\r
321                 reg_val |= (1 << 1);\r
322                 break;\r
323         case 16:\r
324                 reg_val |= (2 << 1);\r
325                 break;\r
326         case 18:\r
327                 reg_val |= (3 << 1) ;\r
328                 break;\r
329         case 24:\r
330                 reg_val |= (4 << 1);\r
331                 break;\r
332         default:\r
333                 break;\r
334         }\r
335 \r
336         /*CS0 pixel bits [BIT5:4]*/\r
337         switch (panel->info.mcu->bpp) {\r
338         case 16:\r
339                 break;\r
340         case 18:\r
341                 reg_val |= (1 << 4) ;\r
342                 break;\r
343         case 24:\r
344                 reg_val |= (2 << 4);\r
345                 break;\r
346         default:\r
347                 break;\r
348         }\r
349 \r
350 #ifndef CONFIG_FB_NO_FMARK\r
351         /*TE enable*/\r
352         reg_val |= (1 << 16);\r
353         if(SPRDFB_POLARITY_NEG == panel->info.mcu->te_pol){\r
354                 reg_val |= (1<< 17);\r
355         }\r
356         dispc_write(panel->info.mcu->te_sync_delay, DISPC_TE_SYNC_DELAY);\r
357 #endif\r
358 \r
359 #ifdef CONFIG_LCD_CS_ALWAYS_LOW\r
360         /*CS alway low mode*/\r
361         reg_val |= (1<<21);\r
362 #else\r
363         /*CS not alway low mode*/\r
364 #endif\r
365 \r
366         /*CS0 selected*/\r
367 \r
368         dispc_write(reg_val, DISPC_DBI_CTRL);\r
369 \r
370         FB_PRINT("sprdfb: [%s] DISPC_DBI_CTRL = %d\n", __FUNCTION__, dispc_read(DISPC_DBI_CTRL));\r
371 }\r
372 \r
373 void mcu_dispc_set_timing(struct sprdfb_device *dev, uint32_t type)\r
374 {\r
375         FB_PRINT("sprdfb: [%s] for cs0, type = %d\n", __FUNCTION__, type);\r
376 \r
377         switch (type)\r
378         {\r
379         case MCU_LCD_REGISTER_TIMING:\r
380                 dispc_write(dev->panel_timing.mcu_timing[MCU_LCD_REGISTER_TIMING],DISPC_DBI_TIMING0);\r
381                 break;\r
382 \r
383         case MCU_LCD_GRAM_TIMING:\r
384                 dispc_write(dev->panel_timing.mcu_timing[MCU_LCD_GRAM_TIMING],DISPC_DBI_TIMING0);\r
385                 break;\r
386         default:\r
387                 break;\r
388         }\r
389 }\r
390 #endif\r
391 \r
392 static int32_t sprdfb_mcu_panel_check(struct panel_spec *panel)\r
393 {\r
394         struct info_mcu* mcu_info = NULL;\r
395         uint16_t rval = 1;\r
396 \r
397         if(NULL == panel){\r
398                 printf("sprdfb: [%s] fail. (Invalid param)\n", __FUNCTION__);\r
399                 return 0;\r
400         }\r
401 \r
402         if(SPRDFB_PANEL_TYPE_MCU != panel->type){\r
403                 printf("sprdfb: [%s] fail. (not mcu param)\n", __FUNCTION__);\r
404                 return 0;\r
405         }\r
406 \r
407         mcu_info = panel->info.mcu;\r
408 \r
409         FB_PRINT("sprdfb: [%s]: bus width= %d, bpp = %d\n",__FUNCTION__, mcu_info->bus_width, mcu_info->bpp);\r
410 \r
411         switch(mcu_info->bus_width){\r
412         case 8:\r
413                 if((16 != mcu_info->bpp) && (24 != mcu_info->bpp)){\r
414                         rval = 0;\r
415                 }\r
416                 break;\r
417         case 9:\r
418                 if(18 != mcu_info->bpp) {\r
419                         rval = 0;\r
420                 }\r
421                 break;\r
422         case 16:\r
423                 if((16 != mcu_info->bpp) && (18 != mcu_info->bpp) &&\r
424                         (24 != mcu_info->bpp)){\r
425                         rval = 0;\r
426                 }\r
427                 break;\r
428         case 18:\r
429                 if(18 != mcu_info->bpp){\r
430                         rval = 0;\r
431                 }\r
432                 break;\r
433         case 24:\r
434                 if(24 != mcu_info->bpp){\r
435                         rval = 0;\r
436                 }\r
437                 break;\r
438         default:\r
439                 rval = 0;\r
440                 break;\r
441         }\r
442 \r
443         if(!rval){\r
444                 FB_PRINT("sprdfb: mcu_panel_check return false!\n");\r
445         }\r
446 \r
447         return rval;\r
448 }\r
449 \r
450 static void sprdfb_mcu_panel_mount(struct sprdfb_device *dev)\r
451 {\r
452         struct timing_mcu* timing = NULL;\r
453 \r
454         if((NULL == dev) || (NULL == dev->panel)){\r
455                 printf("sprdfb: [%s]: Invalid Param\n", __FUNCTION__);\r
456                 return;\r
457         }\r
458 \r
459         FB_PRINT("sprdfb: [%s]\n",__FUNCTION__);\r
460 \r
461         dev->panel_if_type = SPRDFB_PANEL_IF_DBI;\r
462 \r
463         dev->panel->info.mcu->ops =  &dispc_mcu_ops;\r
464 \r
465         if(NULL == dev->panel->ops->panel_readid){\r
466                 dev->panel->ops->panel_readid = mcu_readid;\r
467         }\r
468 \r
469         timing = dev->panel->info.mcu->timing;\r
470         dev->panel_timing.mcu_timing[MCU_LCD_REGISTER_TIMING] = mcu_calc_timing(timing);\r
471         timing++;\r
472         dev->panel_timing.mcu_timing[MCU_LCD_GRAM_TIMING] = mcu_calc_timing(timing);\r
473 }\r
474 \r
475 static void sprdfb_mcu_panel_init(struct sprdfb_device *dev)\r
476 {\r
477         mcu_dispc_init_config(dev->panel);\r
478         mcu_dispc_set_timing(dev, MCU_LCD_REGISTER_TIMING);\r
479 }\r
480 \r
481 static void sprdfb_mcu_panel_before_refresh(struct sprdfb_device *dev)\r
482 {\r
483         mcu_dispc_set_timing(dev, MCU_LCD_GRAM_TIMING);\r
484 }\r
485 \r
486 static void sprdfb_mcu_panel_after_refresh(struct sprdfb_device *dev)\r
487 {\r
488         mcu_dispc_set_timing(dev, MCU_LCD_REGISTER_TIMING);\r
489 }\r
490 \r
491 struct panel_if_ctrl sprdfb_mcu_ctrl = {\r
492         .if_name                = "mcu",\r
493         .panel_if_check         = sprdfb_mcu_panel_check,\r
494         .panel_if_mount                 = sprdfb_mcu_panel_mount,\r
495         .panel_if_init          = sprdfb_mcu_panel_init,\r
496         .panel_if_before_refresh        = sprdfb_mcu_panel_before_refresh,\r
497         .panel_if_after_refresh = sprdfb_mcu_panel_after_refresh,\r
498 };\r
499 \r