2 * Copyright (C) 2012 Spreadtrum Communications Inc.
\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
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
16 #include <asm/arch/tiger_lcd.h>
\r
17 #include <asm/arch/dispc_reg.h>
\r
21 #define CONFIG_FB_NO_FMARK /*Jessica for FPGA*/
\r
23 static int32_t dispc_mcu_send_cmd(uint32_t cmd)
\r
25 /* busy wait for ahb fifo full sign's disappearance */
\r
26 while(dispc_read(DISPC_DBI_QUEUE) & (1<<5));
\r
28 dispc_write(cmd, DISPC_DBI_CMD);
\r
33 static int32_t dispc_mcu_send_cmd_data(uint32_t cmd, uint32_t data)
\r
35 /* busy wait for ahb fifo full sign's disappearance */
\r
36 while(dispc_read(DISPC_DBI_QUEUE) & (1<<5));
\r
38 dispc_write(cmd, DISPC_DBI_CMD);
\r
40 /* busy wait for ahb fifo full sign's disappearance */
\r
41 while(dispc_read(DISPC_DBI_QUEUE) & (1<<5));
\r
43 dispc_write(data, DISPC_DBI_DATA);
\r
48 static int32_t dispc_mcu_send_data(uint32_t data)
\r
50 /* busy wait for ahb fifo full sign's disappearance */
\r
51 while(dispc_read(DISPC_DBI_QUEUE) & (1<<5));
\r
53 dispc_write(data, DISPC_DBI_DATA);
\r
58 static uint32_t dispc_mcu_read_data(void)
\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
64 return dispc_read(DISPC_DBI_RDATA);
\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
75 static uint32_t mcu_calc_timing(struct timing_mcu *timing)
\r
78 uint32_t rcss, rlpw, rhpw, wcss, wlpw, whpw;
\r
79 // struct clk * clk = NULL;
\r
82 FB_PRINT("sprdfb: [%s]: Invalid Param\n", __FUNCTION__);
\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
90 FB_PRINT("sprdfb: [%s] clk_rate: 0x%x\n", __FUNCTION__, clk_rate);
\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
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
104 rcss = DBI_CYCLES(timing->rcss);
\r
105 if (rcss > MAX_DBI_RWCSS_TIMING_VALUE) {
\r
106 rcss = MAX_DBI_RWCSS_TIMING_VALUE ;
\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
114 rhpw = DBI_CYCLES (timing->rhpw);
\r
115 if (rhpw > MAX_DBI_RWHPW_TIMING_VALUE) {
\r
116 rhpw = MAX_DBI_RWHPW_TIMING_VALUE ;
\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
124 wlpw = DBI_CYCLES(timing->wlpw);
\r
125 if (wlpw > MAX_DBI_RWLPW_TIMING_VALUE) {
\r
126 wlpw = MAX_DBI_RWLPW_TIMING_VALUE ;
\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
133 whpw = DBI_CYCLES (timing->whpw) ;
\r
135 if (whpw > MAX_DBI_RWHPW_TIMING_VALUE) {
\r
136 whpw = MAX_DBI_RWHPW_TIMING_VALUE ;
\r
139 return (whpw | (wlpw << 6) | (wcss << 12)
\r
140 | (rhpw << 16) |(rlpw << 22) | (rcss << 28));
\r
143 static uint32_t mcu_readid(struct panel_spec *self)
\r
147 /* default id reg is 0 */
\r
148 self->info.mcu->ops->send_cmd(0x0);
\r
150 if(self->info.mcu->bus_width == 8) {
\r
151 id = (self->info.mcu->ops->read_data()) & 0xff;
\r
153 id |= (self->info.mcu->ops->read_data()) & 0xff;
\r
155 id = self->info.mcu->ops->read_data();
\r
161 #ifdef CONFIG_FB_LCD_CS1
\r
163 void mcu_dispc_init_config(struct panel_spec *panel)
\r
165 uint32_t reg_val = 0;
\r
167 FB_PRINT("sprdfb: [%s] for cs1\n", __FUNCTION__);
\r
170 FB_PRINT("sprdfb: [%s] fail.(Invalid Param)\n", __FUNCTION__);
\r
174 if(SPRDFB_PANEL_TYPE_MCU != panel->type){
\r
175 FB_PRINT("sprdfb: [%s] fail.(not mcu panel)\n", __FUNCTION__);
\r
179 /*use dbi as interface*/
\r
180 dispc_set_bits((2<<1), DISPC_CTRL);
\r
182 /* CS1 bus mode [BIT8]: 8080/6800 */
\r
183 switch (panel->info.mcu->bus_mode) {
\r
192 /* CS1 bus width [BIT11:9] */
\r
193 switch (panel->info.mcu->bus_width) {
\r
197 reg_val |= (1 << 9);
\r
200 reg_val |= (2 << 9);
\r
203 reg_val |= (3 << 9) ;
\r
206 reg_val |= (4 << 9);
\r
212 /*CS1 pixel bits [BIT13:12]*/
\r
213 switch (panel->info.mcu->bpp) {
\r
217 reg_val |= (1 << 12) ;
\r
220 reg_val |= (2 << 12);
\r
226 #ifndef CONFIG_FB_NO_FMARK
\r
228 reg_val |= (1 << 16);
\r
229 if(SPRDFB_POLARITY_NEG == panel->info.mcu->te_pol){
\r
230 reg_val |= (1<< 17);
\r
232 dispc_write(panel->info.mcu->te_sync_delay, DISPC_TE_SYNC_DELAY);
\r
235 #ifdef CONFIG_LCD_CS_ALWAYS_LOW
\r
236 /*CS alway low mode*/
\r
237 reg_val |= (1<<21);
\r
239 /*CS not alway low mode*/
\r
243 reg_val |= (1 << 20);
\r
245 dispc_write(reg_val, DISPC_DBI_CTRL);
\r
247 FB_PRINT("sprdfb: [%s] DISPC_DBI_CTRL = %d\n", __FUNCTION__, dispc_read(DISPC_DBI_CTRL));
\r
250 void mcu_dispc_set_timing(struct sprdfb_device *dev, uint32_t type)
\r
252 FB_PRINT("sprdfb: [%s] for cs1, type = %d\n", __FUNCTION__, type);
\r
256 case MCU_LCD_REGISTER_TIMING:
\r
257 dispc_write(dev->panel_timing.mcu_timing[MCU_LCD_REGISTER_TIMING],DISPC_DBI_TIMING1);
\r
260 case MCU_LCD_GRAM_TIMING:
\r
261 dispc_write(dev->panel_timing.mcu_timing[MCU_LCD_GRAM_TIMING],DISPC_DBI_TIMING1);
\r
270 void mcu_dispc_init_config(struct panel_spec *panel)
\r
272 uint32_t reg_val = 0;
\r
274 FB_PRINT("sprdfb: [%s] for cs0\n", __FUNCTION__);
\r
277 FB_PRINT("sprdfb: [%s] fail.(Invalid Param)\n", __FUNCTION__);
\r
281 if(SPRDFB_PANEL_TYPE_MCU != panel->type){
\r
282 FB_PRINT("sprdfb: [%s] fail.(not mcu panel)\n", __FUNCTION__);
\r
286 /*use dbi as interface*/
\r
287 dispc_set_bits((2<<1), DISPC_CTRL);
\r
289 /* CS0 bus mode [BIT0]: 8080/6800 */
\r
290 switch (panel->info.mcu->bus_mode) {
\r
299 /* CS0 bus width [BIT3:1] */
\r
300 switch (panel->info.mcu->bus_width) {
\r
304 reg_val |= (1 << 1);
\r
307 reg_val |= (2 << 1);
\r
310 reg_val |= (3 << 1) ;
\r
313 reg_val |= (4 << 1);
\r
319 /*CS0 pixel bits [BIT5:4]*/
\r
320 switch (panel->info.mcu->bpp) {
\r
324 reg_val |= (1 << 4) ;
\r
327 reg_val |= (2 << 4);
\r
333 #ifndef CONFIG_FB_NO_FMARK
\r
335 reg_val |= (1 << 16);
\r
336 if(SPRDFB_POLARITY_NEG == panel->info.mcu->te_pol){
\r
337 reg_val |= (1<< 17);
\r
339 dispc_write(panel->info.mcu->te_sync_delay, DISPC_TE_SYNC_DELAY);
\r
342 #ifdef CONFIG_LCD_CS_ALWAYS_LOW
\r
343 /*CS alway low mode*/
\r
344 reg_val |= (1<<21);
\r
346 /*CS not alway low mode*/
\r
351 dispc_write(reg_val, DISPC_DBI_CTRL);
\r
353 FB_PRINT("sprdfb: [%s] DISPC_DBI_CTRL = %d\n", __FUNCTION__, dispc_read(DISPC_DBI_CTRL));
\r
356 void mcu_dispc_set_timing(struct sprdfb_device *dev, uint32_t type)
\r
358 FB_PRINT("sprdfb: [%s] for cs0, type = %d\n", __FUNCTION__, type);
\r
362 case MCU_LCD_REGISTER_TIMING:
\r
363 dispc_write(dev->panel_timing.mcu_timing[MCU_LCD_REGISTER_TIMING],DISPC_DBI_TIMING0);
\r
366 case MCU_LCD_GRAM_TIMING:
\r
367 dispc_write(dev->panel_timing.mcu_timing[MCU_LCD_GRAM_TIMING],DISPC_DBI_TIMING0);
\r
375 static int32_t sprdfb_mcu_panel_check(struct panel_spec *panel)
\r
377 struct info_mcu* mcu_info = NULL;
\r
381 FB_PRINT("sprdfb: [%s] fail. (Invalid param)\n", __FUNCTION__);
\r
385 if(SPRDFB_PANEL_TYPE_MCU != panel->type){
\r
386 FB_PRINT("sprdfb: [%s] fail. (not mcu param)\n", __FUNCTION__);
\r
390 mcu_info = panel->info.mcu;
\r
392 FB_PRINT("sprdfb: [%s]: bus width= %d, bpp = %d\n",__FUNCTION__, mcu_info->bus_width, mcu_info->bpp);
\r
394 switch(mcu_info->bus_width){
\r
396 if((16 != mcu_info->bpp) && (24 != mcu_info->bpp)){
\r
401 if(18 != mcu_info->bpp) {
\r
406 if((16 != mcu_info->bpp) && (18 != mcu_info->bpp) &&
\r
407 (24 != mcu_info->bpp)){
\r
412 if(18 != mcu_info->bpp){
\r
417 if(24 != mcu_info->bpp){
\r
427 FB_PRINT("sprdfb: mcu_panel_check return false!\n");
\r
433 static void sprdfb_mcu_panel_mount(struct sprdfb_device *dev)
\r
435 struct timing_mcu* timing = NULL;
\r
437 if((NULL == dev) || (NULL == dev->panel)){
\r
438 FB_PRINT("sprdfb: [%s]: Invalid Param\n", __FUNCTION__);
\r
442 FB_PRINT("sprdfb: [%s]\n",__FUNCTION__);
\r
444 dev->panel_if_type = SPRDFB_PANEL_IF_DBI;
\r
446 dev->panel->info.mcu->ops = &dispc_mcu_ops;
\r
448 if(NULL == dev->panel->ops->panel_readid){
\r
449 dev->panel->ops->panel_readid = mcu_readid;
\r
452 timing = dev->panel->info.mcu->timing;
\r
453 dev->panel_timing.mcu_timing[MCU_LCD_REGISTER_TIMING] = mcu_calc_timing(timing);
\r
455 dev->panel_timing.mcu_timing[MCU_LCD_GRAM_TIMING] = mcu_calc_timing(timing);
\r
458 static void sprdfb_mcu_panel_init(struct sprdfb_device *dev)
\r
460 mcu_dispc_init_config(dev->panel);
\r
461 mcu_dispc_set_timing(dev, MCU_LCD_REGISTER_TIMING);
\r
464 static void sprdfb_mcu_panel_before_refresh(struct sprdfb_device *dev)
\r
466 mcu_dispc_set_timing(dev, MCU_LCD_GRAM_TIMING);
\r
469 static void sprdfb_mcu_panel_after_refresh(struct sprdfb_device *dev)
\r
471 mcu_dispc_set_timing(dev, MCU_LCD_REGISTER_TIMING);
\r
474 struct panel_if_ctrl sprdfb_mcu_ctrl = {
\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