tizen 2.4 release
[profile/mobile/platform/kernel/u-boot-tm1.git] / drivers / video / sprdfb / sprdfb_rgb.c
1 /*\r
2  * Copyright (C) 2012 Spreadtrum Communications Inc.\r
3  */\r
4 #include <common.h>\r
5 \r
6 #include <asm/arch/sprd_lcd.h>\r
7 #include <asm/arch/dispc_reg.h>\r
8 \r
9 #include "sprdfb_chip_common.h"\r
10 #include "sprdfb.h"\r
11 \r
12 extern struct ops_i2c sprdfb_i2c_ops;\r
13 extern struct ops_spi sprdfb_spi_ops;\r
14 \r
15 extern uint16_t sprdfb_i2c_init(struct sprdfb_device *dev);\r
16 extern uint16_t sprdfb_i2c_uninit(struct sprdfb_device *dev);\r
17 extern uint16_t sprdfb_spi_init(struct sprdfb_device *dev);\r
18 extern uint16_t sprdfb_spi_uninit(struct sprdfb_device *dev);\r
19 \r
20 \r
21 static uint32_t rgb_readid(struct panel_spec *self)\r
22 {\r
23         uint32_t id = 0;\r
24         struct info_rgb *rgb = self->info.rgb;\r
25 \r
26         /* default id reg is 0 */\r
27         if(SPRDFB_RGB_BUS_TYPE_I2C == rgb->cmd_bus_mode){\r
28                 rgb->bus_info.i2c->ops->i2c_read_16bits(rgb->bus_info.i2c->i2c_addr , 0x0, FALSE, &id, FALSE);\r
29         }else{\r
30                 rgb->bus_info.spi->ops->spi_send_cmd(0x0);\r
31                 rgb->bus_info.spi->ops->spi_read(&id);\r
32         }\r
33 \r
34         return id;\r
35 }\r
36 \r
37 static void rgb_dispc_init_config(struct panel_spec *panel)\r
38 {\r
39         uint32_t reg_val = 0;\r
40 \r
41         FB_PRINT("sprdfb: [%s]\n", __FUNCTION__);\r
42 \r
43         if(NULL == panel){\r
44                 printf("sprdfb: [%s] fail.(Invalid Param)\n", __FUNCTION__);\r
45                 return;\r
46         }\r
47 \r
48         if(SPRDFB_PANEL_TYPE_RGB != panel->type && SPRDFB_PANEL_TYPE_LVDS != panel->type){\r
49                 printf("sprdfb: [%s] fail.(not  rgb panel)\n", __FUNCTION__);\r
50                 return;\r
51         }\r
52 \r
53         /*use dpi as interface*/\r
54         dispc_clear_bits((3<<1), DISPC_CTRL);\r
55 \r
56         /*h sync pol*/\r
57         if(SPRDFB_POLARITY_NEG == panel->info.rgb->h_sync_pol){\r
58                 reg_val |= (1<<0);\r
59         }\r
60 \r
61         /*v sync pol*/\r
62         if(SPRDFB_POLARITY_NEG == panel->info.rgb->v_sync_pol){\r
63                 reg_val |= (1<<1);\r
64         }\r
65 \r
66         /*de sync pol*/\r
67         if(SPRDFB_POLARITY_NEG == panel->info.rgb->de_pol){\r
68                 reg_val |= (1<<2);\r
69         }\r
70 \r
71         /*always run mode*/\r
72         reg_val &= ~ (1<<3);\r
73 \r
74         /*dpi bits*/\r
75         switch(panel->info.rgb->video_bus_width){\r
76         case 16:\r
77                 break;\r
78         case 18:\r
79                 reg_val |= (1 << 6);\r
80                 break;\r
81         case 24:\r
82                 reg_val |= (2 << 6);\r
83                 break;\r
84         default:\r
85                 break;\r
86         }\r
87 \r
88         dispc_write(reg_val, DISPC_DPI_CTRL);\r
89 \r
90         FB_PRINT("sprdfb: [%s] DISPC_DPI_CTRL = %d\n", __FUNCTION__, dispc_read(DISPC_DPI_CTRL));\r
91 }\r
92 \r
93 static void rgb_dispc_set_timing(struct sprdfb_device *dev)\r
94 {\r
95         FB_PRINT("sprdfb: [%s]\n", __FUNCTION__);\r
96 \r
97         dispc_write(dev->panel_timing.rgb_timing[RGB_LCD_H_TIMING], DISPC_DPI_H_TIMING);\r
98         dispc_write(dev->panel_timing.rgb_timing[RGB_LCD_V_TIMING], DISPC_DPI_V_TIMING);\r
99 }\r
100 \r
101 uint32_t rgb_calc_h_timing(struct timing_rgb *timing)\r
102 {\r
103 #if 0\r
104         uint32_t  clk_rate;\r
105         uint32_t  hsync, hbp, hfp;\r
106 //      struct clk * clk = NULL;\r
107 \r
108         if(NULL == timing){\r
109                 FB_PRINT("sprdfb: [%s]: Invalid Param\n", __FUNCTION__);\r
110                 return 0;\r
111         }\r
112 \r
113 //      clk_get(NULL,"clk_dispc_dpi");\r
114 //      clk_rate = clk_get_rate(clk) / 1000000;\r
115         clk_rate = 250; // 250 MHz\r
116 \r
117         FB_PRINT("sprdfb: [%s] clk_rate: 0x%x\n", __FUNCTION__, clk_rate);\r
118 \r
119 /********************************************************\r
120         * we assume : t = ? ns, dispc_dpi = ? MHz   so\r
121         *      1ns need cycle  :  dispc_dpi /1000\r
122         *      tns need cycles :  t * dispc_dpi / 1000\r
123         *\r
124         ********************************************************/\r
125 #define MAX_DPI_HSYNC_TIMING_VALUE      255\r
126 #define MAX_DPI_HBP_TIMING_VALUE        4095\r
127 #define MAX_DPI_HFP_TIMING_VALUE        4095\r
128 #define DPI_CYCLES(ns) (( (ns) * clk_rate + 1000 - 1)/ 1000)\r
129 \r
130         /* ceiling*/\r
131         hsync = DPI_CYCLES(timing->hsync);\r
132         if (hsync > MAX_DPI_HSYNC_TIMING_VALUE) {\r
133                 hsync = MAX_DPI_HSYNC_TIMING_VALUE ;\r
134         }\r
135 \r
136         hbp = DPI_CYCLES(timing->hbp);\r
137         if (hbp > MAX_DPI_HSYNC_TIMING_VALUE) {\r
138                 hbp = MAX_DPI_HSYNC_TIMING_VALUE ;\r
139         }\r
140 \r
141         hfp = DPI_CYCLES (timing->hfp);\r
142         if (hfp > MAX_DPI_HFP_TIMING_VALUE) {\r
143                 hfp = MAX_DPI_HFP_TIMING_VALUE ;\r
144         }\r
145 \r
146         return (hsync | (hbp << 8) | (hfp << 20));\r
147 #else\r
148         return  (timing->hsync | (timing->hbp << 8) | (timing->hfp << 20));\r
149 #endif\r
150 }\r
151 \r
152 \r
153 uint32_t rgb_calc_v_timing(struct timing_rgb *timing)\r
154 {\r
155         return (timing->vsync| (timing->vbp << 8) | (timing->vfp << 20));\r
156 }\r
157 \r
158 static int32_t sprdfb_rgb_panel_check(struct panel_spec *panel)\r
159 {\r
160         if(NULL == panel){\r
161                 printf("sprdfb: [%s] fail. (Invalid param)\n", __FUNCTION__);\r
162                 return 0;\r
163         }\r
164 \r
165         if(SPRDFB_PANEL_TYPE_RGB != panel->type && SPRDFB_PANEL_TYPE_LVDS != panel->type){\r
166                 printf("sprdfb: [%s] fail. (not rgb param)\n", __FUNCTION__);\r
167                 return 0;\r
168         }\r
169 \r
170         FB_PRINT("sprdfb: [%s]\n",__FUNCTION__);\r
171 \r
172         return 1;\r
173 }\r
174 \r
175 static void sprdfb_rgb_panel_mount(struct sprdfb_device *dev)\r
176 {\r
177         if((NULL == dev) || (NULL == dev->panel)){\r
178                 printf("sprdfb: [%s]: Invalid Param\n", __FUNCTION__);\r
179                 return;\r
180         }\r
181 \r
182         FB_PRINT("sprdfb: [%s]\n",__FUNCTION__);\r
183 \r
184         dev->panel_if_type = SPRDFB_PANEL_IF_DPI;\r
185 \r
186         if(SPRDFB_RGB_BUS_TYPE_I2C == dev->panel->info.rgb->cmd_bus_mode){\r
187                 dev->panel->info.rgb->bus_info.i2c->ops = &sprdfb_i2c_ops;\r
188         }else{\r
189                 dev->panel->info.rgb->bus_info.spi->ops = &sprdfb_spi_ops;\r
190         }\r
191 \r
192         if(NULL == dev->panel->ops->panel_readid){\r
193                 dev->panel->ops->panel_readid = rgb_readid;\r
194         }\r
195 \r
196         dev->panel_timing.rgb_timing[RGB_LCD_H_TIMING] = rgb_calc_h_timing(dev->panel->info.rgb->timing);\r
197         dev->panel_timing.rgb_timing[RGB_LCD_V_TIMING] = rgb_calc_v_timing(dev->panel->info.rgb->timing);\r
198 }\r
199 \r
200 static void sprdfb_rgb_panel_init(struct sprdfb_device *dev)\r
201 {\r
202         if(SPRDFB_RGB_BUS_TYPE_I2C == dev->panel->info.rgb->cmd_bus_mode){\r
203                 sprdfb_i2c_init(dev);\r
204         }else if(SPRDFB_RGB_BUS_TYPE_SPI == dev->panel->info.rgb->cmd_bus_mode) {\r
205                 sprdfb_spi_init(dev);\r
206         }\r
207         rgb_dispc_init_config(dev->panel);\r
208         rgb_dispc_set_timing(dev);\r
209 \r
210         dispc_set_bits((1 << 4), DISPC_CTRL);   //rgb panel need to out put clock before init\r
211         udelay(1200);\r
212         dispc_clear_bits((1 << 4), DISPC_CTRL);\r
213 \r
214 #ifdef SPRDFB_SUPPORT_LVDS_PANEL\r
215         if (dev->panel->type == SPRDFB_PANEL_TYPE_LVDS) {\r
216                 /* The following register is used for the actual SharkL Chip tape-out */\r
217                 printf("sprdfb: [%s]: Now initialize host LVDS mode\n", __FUNCTION__);\r
218                 /* bit[16] clk from LVDS TX (need set when in LVDS mode) */\r
219                 __raw_writel((1 << 16), REG_AP_CLK_DISPC0_DPI_CFG);\r
220                 /* 0xa4, bit[0]: LVDS AP select */\r
221                 /* 0x3060, bit[0]: LVDS TX power down (active '1') */\r
222                 __raw_writel((1 << 0), REG_PMU_APB_LVDSDIS_PLL_REL_CFG);\r
223                 __raw_writel((1 << 0), REG_AON_APB_LVDS_CFG);\r
224 \r
225                 /* '0': R/G/B[1:0] sent by lan3; '1': RGB[7:6] sent by lan3 */\r
226                 dispc_set_bits((1 << 21), DISPC_LVDS_CTRL);\r
227         }\r
228 #endif\r
229 }\r
230 \r
231 static void sprdfb_rgb_panel_uninit(struct sprdfb_device *dev)\r
232 {\r
233         if(SPRDFB_RGB_BUS_TYPE_I2C == dev->panel->info.rgb->cmd_bus_mode){\r
234                 sprdfb_i2c_uninit(dev);\r
235         }else if(SPRDFB_RGB_BUS_TYPE_SPI == dev->panel->info.rgb->cmd_bus_mode) {\r
236                 sprdfb_spi_uninit(dev);\r
237         }\r
238 }\r
239 \r
240 struct panel_if_ctrl sprdfb_rgb_ctrl = {\r
241         .if_name                = "rgb",\r
242         .panel_if_check         = sprdfb_rgb_panel_check,\r
243         .panel_if_mount                 = sprdfb_rgb_panel_mount,\r
244         .panel_if_init          = sprdfb_rgb_panel_init,\r
245         .panel_if_uninit                = sprdfb_rgb_panel_uninit,\r
246         .panel_if_before_refresh        = NULL,\r
247         .panel_if_after_refresh = NULL,\r
248 };\r
249 \r
250 \r