NanoPayload

stage2/jzlcd.c

100:d57753b57162
2016-01-25 Paul Boddie Added 16bpp support, fixed/improved dual panel support, handled apparent framebuffer positioning limitations and line positioning constraints. Removed old test code in the LCD demonstration. stage2-non-pic
     1 /*     2  * JzRISC LCD controller     3  *     4  * Copyright (C) Xiangfu Liu <xiangfu@sharism.cc>     5  * Copyright (C) 2015, 2016 Paul Boddie <paul@boddie.org.uk>     6  *     7  * This program is free software; you can redistribute it and/or     8  * modify it under the terms of the GNU General Public License as     9  * published by the Free Software Foundation; either version 2 of    10  * the License, or (at your option) any later version.    11  *    12  * This program is distributed in the hope that it will be useful,    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the    15  * GNU General Public License for more details.    16  *    17  * You should have received a copy of the GNU General Public License    18  * along with this program; if not, write to the Free Software    19  * Foundation, Inc., 51 Franklin Street, Fifth Floor,    20  * Boston, MA  02110-1301, USA    21  */    22     23 #include "sdram.h"    24 #include "jzlcd.h"    25 #include "cpu.h"    26 #include "board.h"    27     28 #define align2(n) (n)=((((n)+1)>>1)<<1)    29 #define align4(n) (n)=((((n)+3)>>2)<<2)    30 #define align8(n) (n)=((((n)+7)>>3)<<3)    31     32 extern struct jzfb_info jzfb;    33 extern vidinfo_t panel_info;    34     35 static unsigned short lcd_get_panels()    36 {    37 	return ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL) ||    38 		((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) ? 2 : 1;    39 }    40     41 static unsigned long lcd_get_size(vidinfo_t *vid)    42 {    43 	/* Lines must be aligned to a word boundary. */    44 	unsigned long line_length = ALIGN((vid->vl_col * NBITS(vid->vl_bpix)) / 8, sizeof(u32));    45         return line_length * vid->vl_row;    46 }    47     48 static unsigned long lcd_get_aligned_size(vidinfo_t *vid)    49 {    50 	/* LCD_CTRL_BST_16 requires 16-word alignment. */    51         return ALIGN(lcd_get_size(vid), 16 * sizeof(u32));    52 }    53     54 static unsigned long lcd_get_min_size(vidinfo_t *vid)    55 {    56 	/* Lines must be aligned to a word boundary. */    57 	unsigned long line_length = ALIGN((vid->vl_col * 32) / 8, sizeof(u32));    58         return line_length * vid->vl_row;    59 }    60     61 static unsigned long lcd_get_aligned_min_size(vidinfo_t *vid)    62 {    63 	/* LCD_CTRL_BST_16 requires 16-word alignment. */    64         return ALIGN(lcd_get_min_size(vid), 16 * sizeof(u32));    65 }    66     67 static unsigned long lcd_get_palette_size()    68 {    69 	return 256 * sizeof(u16);    70 }    71     72 static unsigned long lcd_get_aligned_palette_size()    73 {    74 	/* LCD_CTRL_BST_16 requires 16-word alignment. */    75 	return ALIGN(lcd_get_palette_size(), 16 * sizeof(u32));    76 }    77     78 static unsigned long lcd_get_descriptors_size()    79 {    80 	return 3 * sizeof(struct jz_fb_dma_descriptor);    81 }    82     83 static unsigned long lcd_get_total_size(vidinfo_t *vid)    84 {    85 	unsigned long size = lcd_get_aligned_size(vid) * lcd_get_panels();    86 	unsigned long min_size = lcd_get_aligned_min_size(vid);    87     88         /* Round up to nearest full page, or MMU section if defined. */    89 	return ALIGN((size >= min_size ? size : min_size) + lcd_get_aligned_palette_size() + lcd_get_descriptors_size(), PAGE_SIZE);    90 }    91     92 static unsigned long lcd_get_palette(unsigned long addr)    93 {    94         /* Allocate memory at the end of the region for the palette. */    95 	return addr - lcd_get_aligned_palette_size();    96 }    97     98 static unsigned long lcd_get_descriptors(unsigned long addr)    99 {   100         /* Allocate memory before the palette for the descriptor array. */   101 	return lcd_get_palette(addr) - lcd_get_descriptors_size();   102 }   103    104 static unsigned long lcd_get_framebuffer(unsigned long addr, unsigned short panel)   105 {   106         /* Allocate pages for the frame buffer and palette. */   107         return addr - lcd_get_total_size(&panel_info) + (panel * lcd_get_aligned_size(&panel_info));   108 }   109    110 static void jz_lcd_desc_init(vidinfo_t *vid);   111 static int  jz_lcd_hw_init(vidinfo_t *vid);   112    113 unsigned long lcd_ctrl_init()   114 {   115 	struct jz_fb_info *fbi = &panel_info.jz_fb;   116    117 	/* Start from the top of memory and obtain palette and framebuffer regions. */   118    119 	fbi->screen = lcd_get_framebuffer(get_memory_size(), 0);   120 	fbi->palette = lcd_get_palette(get_memory_size());   121    122 	jz_lcd_desc_init(&panel_info);   123 	jz_lcd_hw_init(&panel_info);   124    125 	return fbi->screen;   126 }   127    128 /*   129  * Before enabling the LCD controller, LCD registers should be configured correctly.   130  */   131 void lcd_enable(void)   132 {   133 	REG_LCD_CTRL &= ~(1<<4); /* LCDCTRL.DIS */   134 	REG_LCD_CTRL |= 1<<3;    /* LCDCTRL.ENA*/   135 }   136    137 void lcd_disable(void)   138 {   139 	REG_LCD_CTRL |= (1<<4); /* LCDCTRL.DIS, regular disable */   140 }   141    142 static void jz_lcd_desc_init(vidinfo_t *vid)   143 {   144 	struct jz_fb_dma_descriptor *descriptors;   145 	struct jz_fb_info * fbi;   146    147 	fbi = &vid->jz_fb;   148    149 	/* Allocate space for descriptors before the palette entries. */   150    151 	descriptors = (struct jz_fb_dma_descriptor *) lcd_get_descriptors(get_memory_size());   152 	fbi->dmadesc_fblow = (struct jz_fb_dma_descriptor *) &descriptors[0];   153 	fbi->dmadesc_fbhigh = (struct jz_fb_dma_descriptor *) &descriptors[1];   154 	fbi->dmadesc_palette = (struct jz_fb_dma_descriptor *) &descriptors[2];   155    156 	/* Populate descriptors. */   157    158 	if (lcd_get_panels() == 2)   159 	{   160 		fbi->dmadesc_fblow->fdadr = fbi->dmadesc_fblow;   161 		fbi->dmadesc_fblow->fsadr = lcd_get_framebuffer(get_memory_size(), 1);   162 		fbi->dmadesc_fblow->fidr  = 0;   163 		fbi->dmadesc_fblow->ldcmd = lcd_get_size(vid) / 4 ;   164    165 		fbi->fdadr1 = fbi->dmadesc_fblow; /* only used in dual-panel mode */   166 	}   167    168 	fbi->dmadesc_fbhigh->fsadr = fbi->screen;   169 	fbi->dmadesc_fbhigh->fidr = 0;   170 	fbi->dmadesc_fbhigh->ldcmd =  lcd_get_size(vid) / 4; /* length in words */   171    172 	fbi->dmadesc_palette->fsadr = fbi->palette;   173 	fbi->dmadesc_palette->fidr  = 0;   174 	fbi->dmadesc_palette->ldcmd = (lcd_get_palette_size() / 4) | (1<<28);   175    176 	if (NBITS(vid->vl_bpix) < 12)   177 	{   178 		/* assume any mode with <12 bpp is palette driven */   179 		fbi->dmadesc_palette->fdadr = fbi->dmadesc_fbhigh;   180 		fbi->dmadesc_fbhigh->fdadr = fbi->dmadesc_palette;   181 		/* flips back and forth between pal and fbhigh */   182 		fbi->fdadr0 = fbi->dmadesc_palette;   183 	} else {   184 		/* palette shouldn't be loaded in true-color mode */   185 		fbi->dmadesc_fbhigh->fdadr = fbi->dmadesc_fbhigh;   186 		fbi->fdadr0 = fbi->dmadesc_fbhigh; /* no pal just fbhigh */   187 	}   188    189 	flush_cache_all();   190 }   191    192 static unsigned int jz_lcd_stn_init(unsigned int stnH)   193 {   194 	unsigned int val = 0;   195    196 	switch (jzfb.bpp) {   197 	case 1:   198 		/* val |= LCD_CTRL_PEDN; */   199 	case 2:   200 		val |= LCD_CTRL_FRC_2;   201 		break;   202 	case 4:   203 		val |= LCD_CTRL_FRC_4;   204 		break;   205 	case 8:   206 	default:   207 		val |= LCD_CTRL_FRC_16;   208 		break;   209 	}   210    211 	switch (jzfb.cfg & STN_DAT_PINMASK) {   212 	case STN_DAT_PIN1:   213 		/* Do not adjust the hori-param value. */   214 		break;   215 	case STN_DAT_PIN2:   216 		align2(jzfb.hsw);   217 		align2(jzfb.elw);   218 		align2(jzfb.blw);   219 		break;   220 	case STN_DAT_PIN4:   221 		align4(jzfb.hsw);   222 		align4(jzfb.elw);   223 		align4(jzfb.blw);   224 		break;   225 	case STN_DAT_PIN8:   226 		align8(jzfb.hsw);   227 		align8(jzfb.elw);   228 		align8(jzfb.blw);   229 		break;   230 	}   231    232 	REG_LCD_VSYNC = (0 << 16) | jzfb.vsw;   233 	REG_LCD_HSYNC = ((jzfb.blw+jzfb.w) << 16) | (jzfb.blw+jzfb.w+jzfb.hsw);   234    235 	/* Screen setting */   236 	REG_LCD_VAT = ((jzfb.blw + jzfb.w + jzfb.hsw + jzfb.elw) << 16) | (stnH + jzfb.vsw + jzfb.bfw + jzfb.efw);   237 	REG_LCD_DAH = (jzfb.blw << 16) | (jzfb.blw + jzfb.w);   238 	REG_LCD_DAV = (0 << 16) | (stnH);   239    240 	/* AC BIAs signal */   241 	REG_LCD_PS = (0 << 16) | (stnH+jzfb.vsw+jzfb.efw+jzfb.bfw);   242    243 	return val;   244 }   245    246 static void jz_lcd_tft_init()   247 {   248 	REG_LCD_VSYNC = (0 << 16) | jzfb.vsw;   249 	REG_LCD_HSYNC = (0 << 16) | jzfb.hsw;   250 	REG_LCD_DAV =((jzfb.vsw+jzfb.bfw) << 16) | (jzfb.vsw +jzfb.bfw+jzfb.h);   251 	REG_LCD_DAH = ((jzfb.hsw + jzfb.blw) << 16) | (jzfb.hsw + jzfb.blw + jzfb.w );   252 	REG_LCD_VAT = (((jzfb.blw + jzfb.w + jzfb.elw + jzfb.hsw)) << 16) \   253 		| (jzfb.vsw + jzfb.bfw + jzfb.h + jzfb.efw);   254 }   255    256 static unsigned int jz_lcd_get_pixel_clock()   257 {   258 	unsigned int pclk;   259    260 	/* Derive pixel clock from frame clock. */   261    262 	if ( (jzfb.cfg & MODE_MASK) != MODE_8BIT_SERIAL_TFT) {   263 		pclk = jzfb.fclk * (jzfb.w + jzfb.hsw + jzfb.elw + jzfb.blw) *   264 			(jzfb.h + jzfb.vsw + jzfb.efw + jzfb.bfw);   265 	} else {   266 		/* serial mode: Hsync period = 3*Width_Pixel */   267 		pclk = jzfb.fclk * (jzfb.w*3 + jzfb.hsw + jzfb.elw + jzfb.blw) *   268 			(jzfb.h + jzfb.vsw + jzfb.efw + jzfb.bfw);   269 	}   270    271 	if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_SINGLE) ||   272 	    ((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL))   273 		pclk = (pclk * 3);   274    275 	if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_SINGLE) ||   276 	    ((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) ||   277 	    ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_SINGLE) ||   278 	    ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL))   279 		pclk = pclk >> ((jzfb.cfg & STN_DAT_PINMASK) >> 4);   280    281 	if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) ||   282 	    ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL))   283 		pclk >>= 1;   284    285 	return pclk;   286 }   287    288 static void jz_lcd_set_timing(unsigned int pclk)   289 {   290 	unsigned int val;   291    292 #ifdef CONFIG_CPU_JZ4730   293         val = __cpm_get_pllout() / pclk;   294         REG_CPM_CFCR2 = val - 1;   295         val = pclk * 4 ;   296         if ( val > 150000000 ) {   297                 val = 150000000;   298         }   299         val = __cpm_get_pllout() / val;   300         val--;   301         if ( val > 0xF )   302                 val = 0xF;   303 #else   304 	int pll_div;   305    306 	pll_div = ( REG_CPM_CPCCR & CPM_CPCCR_PCS ); /* clock source,0:pllout/2 1: pllout */   307 	pll_div = pll_div ? 1 : 2 ;   308 	val = ( __cpm_get_pllout()/pll_div ) / pclk;   309 	val--;   310 	if ( val > 0x1ff ) {   311 		val = 0x1ff;   312 	}   313 	__cpm_set_pixdiv(val);   314    315 	val = pclk * 3 ;	/* LCDClock > 2.5*Pixclock */   316 	if ( val > 150000000 ) {   317 		val = 150000000;   318 	}   319 	val = ( __cpm_get_pllout()/pll_div ) / val;   320 	val--;   321 	if ( val > 0x1f ) {   322 		val = 0x1f;   323 	}   324 #endif   325 	__cpm_set_ldiv( val );   326 	REG_CPM_CPCCR |= CPM_CPCCR_CE ; /* update divide */   327 }   328    329 static int jz_lcd_hw_init(vidinfo_t *vid)   330 {   331 	struct jz_fb_info *fbi = &vid->jz_fb;   332 	unsigned int val = 0;   333 	unsigned int pclk = jz_lcd_get_pixel_clock();   334    335 	/* Setting Control register */   336 	switch (jzfb.bpp) {   337 	case 1:   338 		val |= LCD_CTRL_BPP_1;   339 		break;   340 	case 2:   341 		val |= LCD_CTRL_BPP_2;   342 		break;   343 	case 4:   344 		val |= LCD_CTRL_BPP_4;   345 		break;   346 	case 8:   347 		val |= LCD_CTRL_BPP_8;   348 		break;   349 	case 15:   350 		val |= LCD_CTRL_RGB555;   351 	case 16:   352 		val |= LCD_CTRL_BPP_16;   353 		break;   354 #ifndef CONFIG_CPU_JZ4730   355 	case 17 ... 32:   356 		val |= LCD_CTRL_BPP_18_24;	/* target is 4bytes/pixel */   357 		break;   358 #endif   359 	default:   360 		/* printf("jz_lcd.c The BPP %d is not supported\n", jzfb.bpp); */   361 		val |= LCD_CTRL_BPP_16;   362 		break;   363 	}   364    365 	switch (jzfb.cfg & MODE_MASK) {   366 	case MODE_STN_MONO_DUAL:   367 	case MODE_STN_COLOR_DUAL:   368 		val |= jz_lcd_stn_init(jzfb.h >> 1);   369 		break;   370    371 	case MODE_STN_MONO_SINGLE:   372 	case MODE_STN_COLOR_SINGLE:   373 		val |= jz_lcd_stn_init(jzfb.h);   374 		break;   375    376 	case MODE_TFT_GEN:   377 	case MODE_TFT_CASIO:   378 	case MODE_8BIT_SERIAL_TFT:   379 	case MODE_TFT_18BIT:   380 		jz_lcd_tft_init();   381 		break;   382    383 	case MODE_TFT_SAMSUNG:   384 	{   385 		unsigned int total, tp_s, tp_e, ckv_s, ckv_e;   386 		unsigned int rev_s, rev_e, inv_s, inv_e;   387    388 		jz_lcd_tft_init();   389    390 		total = jzfb.blw + jzfb.w + jzfb.elw + jzfb.hsw;   391 		tp_s = jzfb.blw + jzfb.w + 1;   392 		tp_e = tp_s + 1;   393 		/* ckv_s = tp_s - jz_clocks.pixclk/(1000000000/4100); */   394 		ckv_s = tp_s - pclk/(1000000000/4100);   395 		ckv_e = tp_s + total;   396 		rev_s = tp_s - 11;	/* -11.5 clk */   397 		rev_e = rev_s + total;   398 		inv_s = tp_s;   399 		inv_e = inv_s + total;   400 		REG_LCD_CLS = (tp_s << 16) | tp_e;   401 		REG_LCD_PS = (ckv_s << 16) | ckv_e;   402 		REG_LCD_SPL = (rev_s << 16) | rev_e;   403 		REG_LCD_REV = (inv_s << 16) | inv_e;   404 		jzfb.cfg |= STFT_REVHI | STFT_SPLHI;   405 		break;   406 	}   407    408 	case MODE_TFT_SHARP:   409 	{   410 		unsigned int total, cls_s, cls_e, ps_s, ps_e;   411 		unsigned int spl_s, spl_e, rev_s, rev_e;   412    413 		jz_lcd_tft_init();   414    415 		total = jzfb.blw + jzfb.w + jzfb.elw + jzfb.hsw;   416 		spl_s = 1;   417 		spl_e = spl_s + 1;   418 		cls_s = 0;   419 		cls_e = total - 60;	/* > 4us (pclk = 80ns) */   420 		ps_s = cls_s;   421 		ps_e = cls_e;   422 		rev_s = total - 40;	/* > 3us (pclk = 80ns) */   423 		rev_e = rev_s + total;   424 		jzfb.cfg |= STFT_PSHI;    425 		REG_LCD_SPL = (spl_s << 16) | spl_e;   426 		REG_LCD_CLS = (cls_s << 16) | cls_e;   427 		REG_LCD_PS = (ps_s << 16) | ps_e;   428 		REG_LCD_REV = (rev_s << 16) | rev_e;   429 		break;   430 	}   431    432 	default:   433 		break;   434 	}   435    436 	/* Configure the LCD panel */   437    438 	val |= LCD_CTRL_BST_16;		/* Burst Length is 16WORD=64Byte */   439 	val |= LCD_CTRL_OFUP;		/* OutFIFO underrun protect */   440 	REG_LCD_CTRL = val;   441 	REG_LCD_CFG = jzfb.cfg;   442    443 	/* Timing reset. */   444    445 	__cpm_stop_lcd();   446 	jz_lcd_set_timing(pclk);   447 	__cpm_start_lcd();   448 	udelay(1000);   449    450 	/* Configure DMA. */   451    452 	REG_LCD_DA0 = (unsigned long) fbi->fdadr0; /* frame descriptor */   453    454 	if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) ||   455 	    ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL))   456 		REG_LCD_DA1 = (unsigned long) fbi->fdadr1; /* frame descriptor */   457    458 	return 0;   459 }   460    461 void lcd_setcolreg (unsigned short regno, unsigned short red, unsigned short green, unsigned short blue)   462 {   463 }   464    465 void lcd_initcolregs (void)   466 {   467 }