2 * JzRISC lcd controller
4 * xiangfu liu <xiangfu.z@gmail.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of
9 * the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
23 * Fallowing macro may be used:
24 * CONFIG_LCD : LCD support
25 * LCD_BPP : Bits per pixel, 0 = 1, 1 = 2, 2 = 4, 3 = 8
26 * CONFIG_LCD_LOGO : show logo
33 #include <asm/io.h> /* virt_to_phys() */
35 #if defined(CONFIG_LCD) && !defined(CONFIG_SLCD)
37 #if defined(CONFIG_JZ4740)
38 #include <asm/jz4740.h>
45 unsigned int cfg
; /* panel mode and pin usage etc. */
48 unsigned int bpp
; /* bit per pixel */
49 unsigned int fclk
; /* frame clk */
50 unsigned int hsw
; /* hsync width, in pclk */
51 unsigned int vsw
; /* vsync width, in line count */
52 unsigned int elw
; /* end of line, in pclk */
53 unsigned int blw
; /* begin of line, in pclk */
54 unsigned int efw
; /* end of frame, in line count */
55 unsigned int bfw
; /* begin of frame, in line count */
58 static struct jzfb_info jzfb
= {
59 #if defined(CONFIG_NANONOTE)
60 MODE_8BIT_SERIAL_TFT
| PCLK_N
| HSYNC_N
| VSYNC_N
,
61 320, 240, 32, 70, 1, 1, 273, 140, 1, 20
66 /************************************************************************/
68 vidinfo_t panel_info
= {
69 #if defined(CONFIG_JZLCD_FOXCONN_PT035TN01)
74 /*----------------------------------------------------------------------*/
82 * Frame buffer memory information
84 void *lcd_base
; /* Start of framebuffer memory */
85 void *lcd_console_address
; /* Start of console buffer */
90 /*----------------------------------------------------------------------*/
92 void lcd_ctrl_init (void *lcdbase
);
94 void lcd_enable (void);
95 void lcd_disable (void);
97 /*----------------------------------------------------------------------*/
99 static int jz_lcd_init_mem(void *lcdbase
, vidinfo_t
*vid
);
100 static void jz_lcd_desc_init(vidinfo_t
*vid
);
101 static int jz_lcd_hw_init( vidinfo_t
*vid
);
102 extern int flush_cache_all(void);
104 #if LCD_BPP == LCD_COLOR8
105 void lcd_setcolreg (ushort regno
, ushort red
, ushort green
, ushort blue
);
107 #if LCD_BPP == LCD_MONOCHROME
108 void lcd_initcolregs (void);
111 /*-----------------------------------------------------------------------*/
113 void lcd_ctrl_init (void *lcdbase
)
115 __lcd_display_pin_init();
117 jz_lcd_init_mem(lcdbase
, &panel_info
);
118 jz_lcd_desc_init(&panel_info
);
119 jz_lcd_hw_init(&panel_info
);
124 /*----------------------------------------------------------------------*/
125 #if LCD_BPP == LCD_COLOR8
127 lcd_setcolreg (ushort regno
, ushort red
, ushort green
, ushort blue
)
131 /*----------------------------------------------------------------------*/
133 #if LCD_BPP == LCD_MONOCHROME
135 void lcd_initcolregs (void)
141 * Before enabled lcd controller, lcd registers should be configured correctly.
144 void lcd_enable (void)
146 REG_LCD_CTRL
&= ~(1<<4); /* LCDCTRL.DIS */
147 REG_LCD_CTRL
|= 1<<3; /* LCDCTRL.ENA*/
150 void lcd_disable (void)
152 REG_LCD_CTRL
|= (1<<4); /* LCDCTRL.DIS, regular disable */
153 /* REG_LCD_CTRL |= (1<<3); */ /* LCDCTRL.DIS, quikly disable */
156 static int jz_lcd_init_mem(void *lcdbase
, vidinfo_t
*vid
)
158 u_long palette_mem_size
;
159 struct jz_fb_info
*fbi
= &vid
->jz_fb
;
160 int fb_size
= vid
->vl_row
* (vid
->vl_col
* NBITS (vid
->vl_bpix
)) / 8;
162 fbi
->screen
= (u_long
)lcdbase
;
163 fbi
->palette_size
= 256;
164 palette_mem_size
= fbi
->palette_size
* sizeof(u16
);
166 debug("jz_lcd.c palette_mem_size = 0x%08lx\n", (u_long
) palette_mem_size
);
167 /* locate palette and descs at end of page following fb */
168 fbi
->palette
= (u_long
)lcdbase
+ fb_size
+ PAGE_SIZE
- palette_mem_size
;
173 static void jz_lcd_desc_init(vidinfo_t
*vid
)
175 struct jz_fb_info
* fbi
;
177 fbi
->dmadesc_fblow
= (struct jz_fb_dma_descriptor
*)((unsigned int)fbi
->palette
- 3*16);
178 fbi
->dmadesc_fbhigh
= (struct jz_fb_dma_descriptor
*)((unsigned int)fbi
->palette
- 2*16);
179 fbi
->dmadesc_palette
= (struct jz_fb_dma_descriptor
*)((unsigned int)fbi
->palette
- 1*16);
181 #define BYTES_PER_PANEL (vid->vl_col * vid->vl_row * NBITS(vid->vl_bpix) / 8)
183 /* populate descriptors */
184 fbi
->dmadesc_fblow
->fdadr
= virt_to_phys(fbi
->dmadesc_fblow
);
185 fbi
->dmadesc_fblow
->fsadr
= virt_to_phys((void *)(fbi
->screen
+ BYTES_PER_PANEL
));
186 fbi
->dmadesc_fblow
->fidr
= 0;
187 fbi
->dmadesc_fblow
->ldcmd
= BYTES_PER_PANEL
/ 4 ;
189 fbi
->fdadr1
= virt_to_phys(fbi
->dmadesc_fblow
); /* only used in dual-panel mode */
191 fbi
->dmadesc_fbhigh
->fsadr
= virt_to_phys((void *)fbi
->screen
);
192 fbi
->dmadesc_fbhigh
->fidr
= 0;
193 fbi
->dmadesc_fbhigh
->ldcmd
= BYTES_PER_PANEL
/ 4; /* length in word */
195 fbi
->dmadesc_palette
->fsadr
= virt_to_phys((void *)fbi
->palette
);
196 fbi
->dmadesc_palette
->fidr
= 0;
197 fbi
->dmadesc_palette
->ldcmd
= (fbi
->palette_size
* 2)/4 | (1<<28);
199 if( NBITS(vid
->vl_bpix
) < 12)
201 /* assume any mode with <12 bpp is palette driven */
202 fbi
->dmadesc_palette
->fdadr
= virt_to_phys(fbi
->dmadesc_fbhigh
);
203 fbi
->dmadesc_fbhigh
->fdadr
= virt_to_phys(fbi
->dmadesc_palette
);
204 /* flips back and forth between pal and fbhigh */
205 fbi
->fdadr0
= virt_to_phys(fbi
->dmadesc_palette
);
207 /* palette shouldn't be loaded in true-color mode */
208 fbi
->dmadesc_fbhigh
->fdadr
= virt_to_phys((void *)fbi
->dmadesc_fbhigh
);
209 fbi
->fdadr0
= virt_to_phys(fbi
->dmadesc_fbhigh
); /* no pal just fbhigh */
215 static int jz_lcd_hw_init(vidinfo_t
*vid
)
217 struct jz_fb_info
*fbi
= &vid
->jz_fb
;
218 unsigned int val
= 0;
221 #if defined(CONFIG_MIPS_JZ4740)
225 /* Setting Control register */
228 val
|= LCD_CTRL_BPP_1
;
231 val
|= LCD_CTRL_BPP_2
;
234 val
|= LCD_CTRL_BPP_4
;
237 val
|= LCD_CTRL_BPP_8
;
240 val
|= LCD_CTRL_RGB555
;
242 val
|= LCD_CTRL_BPP_16
;
244 #if defined(CONFIG_MIPS_JZ4740)
246 val
|= LCD_CTRL_BPP_18_24
; /* target is 4bytes/pixel */
250 printf("jz_lcd.c The BPP %d is not supported\n", jzfb
.bpp
);
251 val
|= LCD_CTRL_BPP_16
;
255 switch (jzfb
.cfg
& MODE_MASK
) {
256 case MODE_STN_MONO_DUAL
:
257 case MODE_STN_COLOR_DUAL
:
258 case MODE_STN_MONO_SINGLE
:
259 case MODE_STN_COLOR_SINGLE
:
262 /* val |= LCD_CTRL_PEDN; */
264 val
|= LCD_CTRL_FRC_2
;
267 val
|= LCD_CTRL_FRC_4
;
271 val
|= LCD_CTRL_FRC_16
;
277 val
|= LCD_CTRL_BST_16
; /* Burst Length is 16WORD=64Byte */
278 val
|= LCD_CTRL_OFUP
; /* OutFIFO underrun protect */
280 switch (jzfb
.cfg
& MODE_MASK
) {
281 case MODE_STN_MONO_DUAL
:
282 case MODE_STN_COLOR_DUAL
:
283 case MODE_STN_MONO_SINGLE
:
284 case MODE_STN_COLOR_SINGLE
:
285 switch (jzfb
.cfg
& STN_DAT_PINMASK
) {
286 #define align2(n) (n)=((((n)+1)>>1)<<1)
287 #define align4(n) (n)=((((n)+3)>>2)<<2)
288 #define align8(n) (n)=((((n)+7)>>3)<<3)
290 /* Do not adjust the hori-param value. */
313 switch (jzfb
.cfg
& MODE_MASK
) {
314 case MODE_STN_MONO_DUAL
:
315 case MODE_STN_COLOR_DUAL
:
316 case MODE_STN_MONO_SINGLE
:
317 case MODE_STN_COLOR_SINGLE
:
318 if (((jzfb
.cfg
& MODE_MASK
) == MODE_STN_MONO_DUAL
) ||
319 ((jzfb
.cfg
& MODE_MASK
) == MODE_STN_COLOR_DUAL
))
324 REG_LCD_VSYNC
= (0 << 16) | jzfb
.vsw
;
325 REG_LCD_HSYNC
= ((jzfb
.blw
+jzfb
.w
) << 16) | (jzfb
.blw
+jzfb
.w
+jzfb
.hsw
);
328 REG_LCD_VAT
= ((jzfb
.blw
+ jzfb
.w
+ jzfb
.hsw
+ jzfb
.elw
) << 16) | (stnH
+ jzfb
.vsw
+ jzfb
.bfw
+ jzfb
.efw
);
329 REG_LCD_DAH
= (jzfb
.blw
<< 16) | (jzfb
.blw
+ jzfb
.w
);
330 REG_LCD_DAV
= (0 << 16) | (stnH
);
333 REG_LCD_PS
= (0 << 16) | (stnH
+jzfb
.vsw
+jzfb
.efw
+jzfb
.bfw
);
340 case MODE_TFT_SAMSUNG
:
341 case MODE_8BIT_SERIAL_TFT
:
343 REG_LCD_VSYNC
= (0 << 16) | jzfb
.vsw
;
344 REG_LCD_HSYNC
= (0 << 16) | jzfb
.hsw
;
345 #if defined(CONFIG_JZLCD_INNOLUX_AT080TN42)
346 REG_LCD_DAV
= (0 << 16) | ( jzfb
.h
);
348 REG_LCD_DAV
=((jzfb
.vsw
+jzfb
.bfw
) << 16) | (jzfb
.vsw
+jzfb
.bfw
+jzfb
.h
);
349 #endif /*#if defined(CONFIG_JZLCD_INNOLUX_AT080TN42)*/
350 REG_LCD_DAH
= ((jzfb
.hsw
+ jzfb
.blw
) << 16) | (jzfb
.hsw
+ jzfb
.blw
+ jzfb
.w
);
351 REG_LCD_VAT
= (((jzfb
.blw
+ jzfb
.w
+ jzfb
.elw
+ jzfb
.hsw
)) << 16) \
352 | (jzfb
.vsw
+ jzfb
.bfw
+ jzfb
.h
+ jzfb
.efw
);
356 switch (jzfb
.cfg
& MODE_MASK
) {
357 case MODE_TFT_SAMSUNG
:
359 unsigned int total
, tp_s
, tp_e
, ckv_s
, ckv_e
;
360 unsigned int rev_s
, rev_e
, inv_s
, inv_e
;
362 pclk
= val
* (jzfb
.w
+ jzfb
.hsw
+ jzfb
.elw
+ jzfb
.blw
) *
363 (jzfb
.h
+ jzfb
.vsw
+ jzfb
.efw
+ jzfb
.bfw
); /* Pixclk */
365 total
= jzfb
.blw
+ jzfb
.w
+ jzfb
.elw
+ jzfb
.hsw
;
366 tp_s
= jzfb
.blw
+ jzfb
.w
+ 1;
368 /* ckv_s = tp_s - jz_clocks.pixclk/(1000000000/4100); */
369 ckv_s
= tp_s
- pclk
/(1000000000/4100);
370 ckv_e
= tp_s
+ total
;
371 rev_s
= tp_s
- 11; /* -11.5 clk */
372 rev_e
= rev_s
+ total
;
374 inv_e
= inv_s
+ total
;
375 REG_LCD_CLS
= (tp_s
<< 16) | tp_e
;
376 REG_LCD_PS
= (ckv_s
<< 16) | ckv_e
;
377 REG_LCD_SPL
= (rev_s
<< 16) | rev_e
;
378 REG_LCD_REV
= (inv_s
<< 16) | inv_e
;
379 jzfb
.cfg
|= STFT_REVHI
| STFT_SPLHI
;
384 unsigned int total
, cls_s
, cls_e
, ps_s
, ps_e
;
385 unsigned int spl_s
, spl_e
, rev_s
, rev_e
;
386 total
= jzfb
.blw
+ jzfb
.w
+ jzfb
.elw
+ jzfb
.hsw
;
387 #if !defined(CONFIG_JZLCD_INNOLUX_AT080TN42)
391 cls_e
= total
- 60; /* > 4us (pclk = 80ns) */
394 rev_s
= total
- 40; /* > 3us (pclk = 80ns) */
395 rev_e
= rev_s
+ total
;
396 jzfb
.cfg
|= STFT_PSHI
;
397 #else /*#if defined(CONFIG_JZLCD_INNOLUX_AT080TN42)*/
398 spl_s
= total
- 5; /* LD */
400 cls_s
= 32; /* CKV */
406 #endif /*#if defined(CONFIG_JZLCD_INNOLUX_AT080TN42)*/
407 REG_LCD_SPL
= (spl_s
<< 16) | spl_e
;
408 REG_LCD_CLS
= (cls_s
<< 16) | cls_e
;
409 REG_LCD_PS
= (ps_s
<< 16) | ps_e
;
410 REG_LCD_REV
= (rev_s
<< 16) | rev_e
;
417 /* Configure the LCD panel */
418 REG_LCD_CFG
= jzfb
.cfg
;
423 val
= jzfb
.fclk
; /* frame clk */
424 if ( (jzfb
.cfg
& MODE_MASK
) != MODE_8BIT_SERIAL_TFT
) {
425 pclk
= val
* (jzfb
.w
+ jzfb
.hsw
+ jzfb
.elw
+ jzfb
.blw
) *
426 (jzfb
.h
+ jzfb
.vsw
+ jzfb
.efw
+ jzfb
.bfw
); /* Pixclk */
429 /* serial mode: Hsync period = 3*Width_Pixel */
430 pclk
= val
* (jzfb
.w
*3 + jzfb
.hsw
+ jzfb
.elw
+ jzfb
.blw
) *
431 (jzfb
.h
+ jzfb
.vsw
+ jzfb
.efw
+ jzfb
.bfw
); /* Pixclk */
434 if (((jzfb
.cfg
& MODE_MASK
) == MODE_STN_COLOR_SINGLE
) ||
435 ((jzfb
.cfg
& MODE_MASK
) == MODE_STN_COLOR_DUAL
))
438 if (((jzfb
.cfg
& MODE_MASK
) == MODE_STN_COLOR_SINGLE
) ||
439 ((jzfb
.cfg
& MODE_MASK
) == MODE_STN_COLOR_DUAL
) ||
440 ((jzfb
.cfg
& MODE_MASK
) == MODE_STN_MONO_SINGLE
) ||
441 ((jzfb
.cfg
& MODE_MASK
) == MODE_STN_MONO_DUAL
))
442 pclk
= pclk
>> ((jzfb
.cfg
& STN_DAT_PINMASK
) >> 4);
444 if (((jzfb
.cfg
& MODE_MASK
) == MODE_STN_COLOR_DUAL
) ||
445 ((jzfb
.cfg
& MODE_MASK
) == MODE_STN_MONO_DUAL
))
448 pll_div
= ( REG_CPM_CPCCR
& CPM_CPCCR_PCS
); /* clock source,0:pllout/2 1: pllout */
449 pll_div
= pll_div
? 1 : 2 ;
450 val
= ( __cpm_get_pllout()/pll_div
) / pclk
;
453 printf("CPM_LPCDR too large, set it to 0x1ff\n");
456 __cpm_set_pixdiv(val
);
458 val
= pclk
* 3 ; /* LCDClock > 2.5*Pixclock */
459 if ( val
> 150000000 ) {
460 printf("Warning: LCDClock=%d\n, LCDClock must less or equal to 150MHz.\n", val
);
461 printf("Change LCDClock to 150MHz\n");
464 val
= ( __cpm_get_pllout()/pll_div
) / val
;
467 printf("CPM_CPCCR.LDIV too large, set it to 0x1f\n");
470 __cpm_set_ldiv( val
);
471 REG_CPM_CPCCR
|= CPM_CPCCR_CE
; /* update divide */
476 REG_LCD_DA0
= fbi
->fdadr0
; /* frame descripter*/
478 if (((jzfb
.cfg
& MODE_MASK
) == MODE_STN_COLOR_DUAL
) ||
479 ((jzfb
.cfg
& MODE_MASK
) == MODE_STN_MONO_DUAL
))
480 REG_LCD_DA1
= fbi
->fdadr1
; /* frame descripter*/
This page took 0.100499 seconds and 5 git commands to generate.