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