tizen 2.4 release
[kernel/u-boot-tm1.git] / drivers / video / sprdfb / sprdfb_dispc.c
1 /******************************************************************************
2  ** File Name:    sprdfb_dispc.c                                            *
3  ** Author:                                                           *
4  ** DATE:                                                           *
5  ** Copyright:    2005 Spreatrum, Incoporated. All Rights Reserved.           *
6  ** Description:                                                            *
7  ******************************************************************************/
8 /******************************************************************************
9  **                   Edit    History                                         *
10  **---------------------------------------------------------------------------*
11  ** DATE          NAME            DESCRIPTION                                 *
12  **
13  ******************************************************************************/
14
15 #include <common.h>
16
17 #include "sprdfb.h"
18 #include "sprdfb_chip_common.h"
19
20 #define SPRDFB_DPI_CLOCK_SRC (384000000)
21
22 static uint16_t         is_first_frame = 1;
23
24 extern void sprdfb_panel_before_refresh(struct sprdfb_device *dev);
25 extern void sprdfb_panel_after_refresh(struct sprdfb_device *dev);
26 extern void sprdfb_panel_invalidate(struct panel_spec *self);
27 extern void sprdfb_panel_invalidate_rect(struct panel_spec *self,
28                                 uint16_t left, uint16_t top,
29                                 uint16_t right, uint16_t bottom);
30
31 static void __raw_bits_and(unsigned int v, unsigned int a)
32 {
33         __raw_writel((__raw_readl(a) & v), a);
34 }
35
36 /* dispc soft reset */
37 static void dispc_reset(void)
38 {
39         FB_PRINT("sprdfb:[%s]\n",__FUNCTION__);
40         __raw_writel(__raw_readl(DISPC_AHB_SOFT_RST) | (BIT_DISPC_SOFT_RST), DISPC_AHB_SOFT_RST);
41         udelay(10);
42         __raw_writel(__raw_readl(DISPC_AHB_SOFT_RST) & (~(BIT_DISPC_SOFT_RST)), DISPC_AHB_SOFT_RST);
43 }
44
45 static inline void dispc_set_bg_color(uint32_t bg_color)
46 {
47         FB_PRINT("sprdfb:[%s]\n",__FUNCTION__);
48
49         dispc_write(bg_color, DISPC_BG_COLOR);
50 }
51
52 static inline void dispc_set_osd_ck(uint32_t ck_color)
53 {
54         FB_PRINT("sprdfb:[%s]\n",__FUNCTION__);
55
56         dispc_write(ck_color, DISPC_OSD_CK);
57 }
58
59 static void dispc_dithering_enable(uint16_t enable)
60 {
61         FB_PRINT("sprdfb:[%s]\n",__FUNCTION__);
62
63         if(enable){
64                 dispc_set_bits((1<<6), DISPC_CTRL);
65         }else{
66                 dispc_clear_bits((1<<6), DISPC_CTRL);
67         }
68 }
69
70 static void dispc_set_exp_mode(uint16_t exp_mode)
71 {
72         uint32_t reg_val = dispc_read(DISPC_CTRL);
73
74         FB_PRINT("sprdfb:[%s]\n",__FUNCTION__);
75
76         reg_val &= ~(0x3 << 16);
77         reg_val |= (exp_mode << 16);
78         dispc_write(reg_val, DISPC_CTRL);
79 }
80
81 static void dispc_module_enable(void)
82 {
83         FB_PRINT("sprdfb:[%s]\n",__FUNCTION__);
84
85         /*dispc module enable */
86         dispc_write((1<<0), DISPC_CTRL);
87
88         /*disable dispc INT*/
89         dispc_write(0x0, DISPC_INT_EN);
90
91         /* clear dispc INT */
92         dispc_write(0x1F, DISPC_INT_CLR);
93 }
94
95 static inline int32_t  dispc_set_disp_size(struct sprdfb_device *dev)
96 {
97         uint32_t reg_val;
98
99         FB_PRINT("sprdfb:[%s]\n",__FUNCTION__);
100
101         reg_val = (dev->panel->width& 0xfff) | ((dev->panel->height & 0xfff ) << 16);
102         dispc_write(reg_val, DISPC_SIZE_XY);
103
104         return 0;
105 }
106
107 static void dispc_layer_init(struct sprdfb_device *dev)
108 {
109         uint32_t reg_val = 0;
110
111         FB_PRINT("sprdfb:[%s]\n",__FUNCTION__);
112
113         dispc_clear_bits((1<<0),DISPC_IMG_CTRL);
114         dispc_clear_bits((1<<0),DISPC_OSD_CTRL);
115
116         /******************* OSD layer setting **********************/
117
118         /*enable OSD layer*/
119         reg_val |= (1 << 0);
120
121         /*disable  color key */
122
123         /* alpha mode select  - block alpha*/
124         reg_val |= (1 << 2);
125
126         /* data format */
127         /* RGB565 */
128         reg_val |= (5 << 4);
129         /* B2B3B0B1 */
130         reg_val |= (2 << 8);
131
132         dispc_write(reg_val, DISPC_OSD_CTRL);
133
134         /* OSD layer alpha value */
135         dispc_write(0xff, DISPC_OSD_ALPHA);
136
137         /* OSD layer size */
138 #ifdef CONFIG_FB_LOW_RES_SIMU
139         if((0 != dev->display_width) && (0 != dev->display_height)){
140                 reg_val = ( dev->display_width& 0xfff) | ((dev->display_height & 0xfff ) << 16);
141         }else
142  #endif 
143         reg_val = ( dev->panel->width& 0xfff) | ((dev->panel->height & 0xfff ) << 16);
144         dispc_write(reg_val, DISPC_OSD_SIZE_XY);
145
146         /* OSD layer start position */
147         dispc_write(0, DISPC_OSD_DISP_XY);
148
149         /* OSD layer pitch */
150 #ifdef CONFIG_FB_LOW_RES_SIMU
151         if((0 != dev->display_width) && (0 != dev->display_height)){
152                 reg_val = ( dev->display_width & 0xfff) ;
153         }else
154  #endif 
155         reg_val = ( dev->panel->width & 0xfff) ;        
156         dispc_write(reg_val, DISPC_OSD_PITCH);
157
158         /*OSD base address*/
159         dispc_write(dev->smem_start, DISPC_OSD_BASE_ADDR);
160
161         /* OSD color_key value */
162         dispc_set_osd_ck(0x0);
163
164         /* DISPC workplane size */
165         dispc_set_disp_size(dev);
166
167         FB_PRINT("DISPC_OSD_CTRL: 0x%x\n", dispc_read(DISPC_OSD_CTRL));
168         FB_PRINT("DISPC_OSD_ALPHA: 0x%x\n", dispc_read(DISPC_OSD_ALPHA));
169         FB_PRINT("DISPC_OSD_SIZE_XY: 0x%x\n", dispc_read(DISPC_OSD_SIZE_XY));
170         FB_PRINT("DISPC_OSD_DISP_XY: 0x%x\n", dispc_read(DISPC_OSD_DISP_XY));
171         FB_PRINT("DISPC_OSD_PITCH: 0x%x\n", dispc_read(DISPC_OSD_PITCH));
172         FB_PRINT("DISPC_OSD_BASE_ADDR: 0x%x\n", dispc_read(DISPC_OSD_BASE_ADDR));
173 }
174
175 static void dispc_update_clock(struct sprdfb_device *dev)
176 {
177         uint32_t hpixels, vlines, need_clock, dividor;
178
179         struct panel_spec* panel = dev->panel;
180         struct info_mipi * mipi = panel->info.mipi;
181         struct info_rgb* rgb = panel->info.rgb;
182
183         FB_PRINT("sprdfb:[%s]\n", __FUNCTION__);
184
185         if(0 == panel->fps){
186                 printf("sprdfb: No panel->fps specified!\n");
187                 return;
188         }
189
190         if(SPRDFB_PANEL_IF_DPI == dev->panel_if_type){
191                 if(LCD_MODE_DSI == dev->panel->type ){
192                         hpixels = panel->width + mipi->timing->hsync + mipi->timing->hbp + mipi->timing->hfp;
193                         vlines = panel->height + mipi->timing->vsync + mipi->timing->vbp + mipi->timing->vfp;
194                 }else if(LCD_MODE_RGB == dev->panel->type || dev->panel->type == LCD_MODE_LVDS){
195                         hpixels = panel->width + rgb->timing->hsync + rgb->timing->hbp + rgb->timing->hfp;
196                         vlines = panel->height + rgb->timing->vsync + rgb->timing->vbp + rgb->timing->vfp;
197                 }else{
198                         printf("sprdfb:[%s] unexpected panel type!(%d)\n", __FUNCTION__, dev->panel->type);
199                         return;
200                 }
201
202                 need_clock = hpixels * vlines * panel->fps;
203                 dividor = SPRDFB_DPI_CLOCK_SRC/need_clock;
204                 if(SPRDFB_DPI_CLOCK_SRC - dividor*need_clock > (need_clock/2) ) {
205                         dividor += 1;
206                 }
207                 if((dividor<1) || (dividor > 0x100)){
208                         printf("sprdfb:[%s]: Invliad dividor(%d)!Not update dpi clock!\n", __FUNCTION__, dividor);
209                         return;
210                 }
211
212                 dev->dpi_clock = SPRDFB_DPI_CLOCK_SRC / dividor;
213                 dispc_dpi_clk_set(DISPC_DPI_SEL_DEFAULT, (dividor-1));
214
215                 printf("sprdfb:[%s] need_clock = %d, dividor = %d, dpi_clock = %d\n", __FUNCTION__, need_clock, dividor, dev->dpi_clock);
216         }
217         dispc_print_clk();
218
219 }
220
221
222 #if defined(CONFIG_SPX15) || defined(CONFIG_SPX30G)
223 //#define GSP_IOMMU_WORKAROUND1
224 #endif
225
226 #ifdef GSP_IOMMU_WORKAROUND1
227
228 static void cycle_delay(uint32_t delay)
229 {
230         while(delay--);
231 }
232
233 /*
234 func:gsp_iommu_workaround
235 desc:dolphin IOMMU workaround, configure GSP-IOMMU CTL REG before dispc_emc enable,
236      including config IO base addr and enable gsp-iommu
237 warn:when dispc_emc disabled, reading ctl or entry register will hung up AHB bus .
238      only 4-writting operations are allowed to exeute, over 4 ops will also hung uo AHB bus
239      GSP module soft reset is not allowed , beacause it will clear gsp-iommu-ctrl register
240 */
241 static void gsp_iommu_workaround(void)
242 {
243         uint32_t emc_en_cfg = 0;
244         uint32_t gsp_en_cfg = 0;
245         #define REG_WRITE(reg,value)    (*(volatile uint32_t*)reg = value)
246 #ifdef CONFIG_SPX30G //tshark
247         #define GSP_MMU_CTRL_BASE               (0x21408000)
248 #else//defined(CONFIG_SPX15) //dolphin
249         #define GSP_MMU_CTRL_BASE               (0x21404000)
250 #endif
251
252         emc_en_cfg = __raw_readl(DISPC_EMC_EN);
253         gsp_en_cfg = __raw_readl(DISPC_AHB_EN);
254         printf("ytc:gsp_iommu_workaround: emc_eb_cfg:%x; gsp_eb_cfg:%x;\n", emc_en_cfg, gsp_en_cfg);
255         REG_WRITE(DISPC_EMC_EN,emc_en_cfg & (~0x800)); // disable emc clk
256         REG_WRITE(DISPC_AHB_EN,gsp_en_cfg | 0x8); // enable gsp
257         cycle_delay(5); // delay for a while
258         REG_WRITE(GSP_MMU_CTRL_BASE,0x10000001);//set iova base as 0x10000000, and enable gsp_iommu
259         cycle_delay(5); // delay for a while
260         printf("ytc:gsp_iommu_workaround: %x, gsp_eb_cfg: %x\n", __raw_readl(DISPC_EMC_EN), __raw_readl(DISPC_AHB_EN));
261         REG_WRITE(DISPC_AHB_EN,gsp_en_cfg); // restore gsp
262         REG_WRITE(DISPC_EMC_EN,emc_en_cfg); // restore emc clk
263 }
264
265 #endif
266 static int32_t sprdfb_dispc_early_init(struct sprdfb_device *dev)
267 {
268         FB_PRINT("sprdfb:[%s]\n", __FUNCTION__);
269
270         dispc_pll_clk_set(DISPC_PLL_SEL_DEFAULT, 0);
271         dispc_dbi_clk_set(DISPC_DBI_SEL_DEFAULT, 0);
272         dispc_dpi_clk_set(DISPC_DPI_SEL_DEFAULT, DISPC_DPI_DIV_DEFAULT);
273         
274         dev->dpi_clock = SPRDFB_DPI_CLOCK_SRC /(DISPC_DPI_DIV_DEFAULT + 1);
275
276
277         __raw_bits_or(BIT_DISPC_CORE_EN, DISPC_CORE_EN);  //core_clock_en
278 #ifdef GSP_IOMMU_WORKAROUND1
279         gsp_iommu_workaround();
280 #endif
281         __raw_bits_or(BIT_DISPC_EMC_EN, DISPC_EMC_EN);  //matrix clock en
282
283         __raw_bits_or(BIT_DISPC_AHB_EN, DISPC_AHB_EN);//enable DISPC clock
284
285         FB_PRINT("sprdfb:DISPC_CORE_EN:%x \n",__raw_readl(DISPC_CORE_EN));
286         FB_PRINT("sprdfb:DISPC_EMC_EN:%x \n",__raw_readl(DISPC_EMC_EN));
287         FB_PRINT("sprdfb:DISPC_AHB_EN:%x \n",__raw_readl(DISPC_AHB_EN));
288
289
290
291
292         dispc_reset();
293         dispc_module_enable();
294         is_first_frame = 1;
295
296         return 0;
297 }
298
299
300 static int32_t sprdfb_dispc_init(struct sprdfb_device *dev)
301 {
302         FB_PRINT("sprdfb:[%s]\n",__FUNCTION__);
303
304         /*set bg color*/
305 //      dispc_set_bg_color(0xFFFFFFFF);
306         dispc_set_bg_color(0x0);
307         /*enable dithering*/
308         dispc_dithering_enable(1);
309         /*use MSBs as img exp mode*/
310         dispc_set_exp_mode(0x0);
311
312         dispc_layer_init(dev);
313
314 //      dispc_update_clock(dev);
315
316         if(SPRDFB_PANEL_IF_DPI == dev->panel_if_type){
317                 if(is_first_frame){
318                         /*set dpi register update only with SW*/
319                         dispc_set_bits((1<<4), DISPC_DPI_CTRL);
320                 }else{
321                         /*set dpi register update with SW & VSYNC*/
322                         dispc_clear_bits((1<<4), DISPC_DPI_CTRL);
323                 }
324                 /*enable dispc update done INT*/
325 //              dispc_write((1<<4), DISPC_INT_EN);
326         }else{
327                 /* enable dispc DONE  INT*/
328 //              dispc_write((1<<0), DISPC_INT_EN);
329         }
330 #if defined CONFIG_SC8830 || (defined CONFIG_SC9630)
331                 {/*for debug*/
332                         int32_t i;
333                         for(i=0x20800000;i<0x208000c0;i+=16){
334                                 FB_PRINT("sprdfb: %x: 0x%x, 0x%x, 0x%x, 0x%x\n", i, __raw_readl(i), __raw_readl(i+4), __raw_readl(i+8), __raw_readl(i+12));
335                         }
336                         FB_PRINT("**************************************\n");
337                 }
338 #endif
339         return 0;
340 }
341
342 static int32_t sprdfb_dispc_uninit(struct sprdfb_device *dev)
343 {
344         FB_PRINT("sprdfb:[%s]\n",__FUNCTION__);
345
346         __raw_bits_and(~(BIT_DISPC_AHB_EN), DISPC_AHB_EN);
347
348         return 0;
349 }
350
351 static int32_t sprdfb_dispc_refresh (struct sprdfb_device *dev)
352 {
353         uint32_t i;
354
355         printf("sprdfb:[%s]\n",__FUNCTION__);
356
357         if(SPRDFB_PANEL_IF_DPI != dev->panel_if_type){
358                 sprdfb_panel_invalidate(dev->panel);
359         }
360
361         sprdfb_panel_before_refresh(dev);
362
363         if(SPRDFB_PANEL_IF_DPI == dev->panel_if_type){
364                 /*dpi register update*/
365                 dispc_set_bits((1<<5), DISPC_DPI_CTRL);
366                 if(is_first_frame){
367                         udelay(30);
368                         /*dpi register update with SW and VSync*/
369                         dispc_clear_bits((1<<4), DISPC_DPI_CTRL);
370                         /* start refresh */
371                         dispc_set_bits((1 << 4), DISPC_CTRL);
372                         is_first_frame = 0;
373                 }else{
374                         for(i=0;i<1000;i++){
375                                 if(!(dispc_read(DISPC_INT_RAW) & (0x10))){
376                                         udelay(100);
377                                 }else{
378                                         break;
379                                 }
380                         }
381                         if(i >= 1000){
382                                 printf("sprdfb:[%s] wait dispc update  int time out!! (0x%x)\n", __FUNCTION__, dispc_read(DISPC_INT_RAW));
383                         }else{
384                                 FB_PRINT("sprdfb:[%s] got dispc update int (0x%x)\n", __FUNCTION__, dispc_read(DISPC_INT_RAW));
385                         }
386                         dispc_set_bits((1<<5), DISPC_INT_CLR);
387                    }
388         }else{
389                 /* start refresh */
390                 dispc_set_bits((1 << 4), DISPC_CTRL);
391                 for(i=0;i<500;i++){
392                         if(0x1 != (dispc_read(DISPC_INT_RAW) & (1<<0))){
393                                 udelay(1000);
394                         }else{
395                                 break;
396                         }
397                 }
398                 if(i >= 1000){
399                         printf("sprdfb:[%s] wait dispc done int time out!! (0x%x)\n", __FUNCTION__, dispc_read(DISPC_INT_RAW));
400                 }else{
401                         FB_PRINT("sprdfb:[%s] got dispc done int (0x%x)\n", __FUNCTION__, dispc_read(DISPC_INT_RAW));
402                 }
403                 dispc_set_bits((1<<0), DISPC_INT_CLR);
404         }
405
406         sprdfb_panel_after_refresh(dev);
407
408         return 0;
409 }
410
411 struct display_ctrl sprdfb_dispc_ctrl = {
412         .name           = "dispc",
413         .early_init             = sprdfb_dispc_early_init,
414         .init                   = sprdfb_dispc_init,
415         .uninit         = sprdfb_dispc_uninit,
416         .refresh                = sprdfb_dispc_refresh,
417         .update_clk     = dispc_update_clock,
418 };
419