NanoPayload

stage2/jzlcd.c

216:95be7694d999
2017-06-28 Paul Boddie Employ structure member names to make initialisation clearer.
     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     42     43 /* Functions returning region sizes. */    44     45 static unsigned long lcd_get_size(vidinfo_t *vid)    46 {    47 	/* Lines must be aligned to a word boundary. */    48 	unsigned long line_length = ALIGN((vid->vl_col * NBITS(vid->vl_bpix)) / 8, sizeof(u32));    49         return line_length * vid->vl_row;    50 }    51     52 static unsigned long lcd_get_aligned_size(vidinfo_t *vid)    53 {    54 	/* LCD_CTRL_BST_16 requires 16-word alignment. */    55         return ALIGN(lcd_get_size(vid), 16 * sizeof(u32));    56 }    57     58 static unsigned long lcd_get_min_size(vidinfo_t *vid)    59 {    60 	/* Lines must be aligned to a word boundary. */    61 	unsigned long line_length = ALIGN((vid->vl_col * 32) / 8, sizeof(u32));    62         return line_length * vid->vl_row;    63 }    64     65 static unsigned long lcd_get_aligned_min_size(vidinfo_t *vid)    66 {    67 	/* LCD_CTRL_BST_16 requires 16-word alignment. */    68         return ALIGN(lcd_get_min_size(vid), 16 * sizeof(u32));    69 }    70     71 static unsigned long lcd_get_palette_size(vidinfo_t *vid)    72 {    73 	if (NBITS(vid->vl_bpix) < 12)    74 		return NCOLORS(vid->vl_bpix) * sizeof(u16);    75 	else    76 		return 0;    77 }    78     79 static unsigned long lcd_get_aligned_palette_size(vidinfo_t *vid)    80 {    81 	/* LCD_CTRL_BST_16 requires 16-word alignment. */    82 	return ALIGN(lcd_get_palette_size(vid), 16 * sizeof(u32));    83 }    84     85 static unsigned long lcd_get_descriptors_size()    86 {    87 	return 3 * sizeof(struct jz_fb_dma_descriptor);    88 }    89     90 static unsigned long lcd_get_total_size(vidinfo_t *vid)    91 {    92 	unsigned long size = lcd_get_aligned_size(vid) * lcd_get_panels();    93 	unsigned long min_size = lcd_get_aligned_min_size(vid);    94     95         /* Round up to nearest full page, or MMU section if defined. */    96 	return ALIGN((size >= min_size ? size : min_size) + lcd_get_aligned_palette_size(vid) + lcd_get_descriptors_size(), PAGE_SIZE);    97 }    98     99    100    101 /* Functions returning addresses of each data region. */   102    103 static unsigned long lcd_get_palette(unsigned long addr)   104 {   105         /* Allocate memory at the end of the region for the palette. */   106 	return addr - lcd_get_aligned_palette_size(&panel_info);   107 }   108    109 static unsigned long lcd_get_descriptors(unsigned long addr)   110 {   111         /* Allocate memory before the palette for the descriptor array. */   112 	return lcd_get_palette(addr) - lcd_get_descriptors_size();   113 }   114    115 static unsigned long lcd_get_framebuffer(unsigned long addr, unsigned short panel)   116 {   117         /* Allocate pages for the frame buffer and palette. */   118         return addr - lcd_get_total_size(&panel_info) + (panel * lcd_get_aligned_size(&panel_info));   119 }   120    121    122    123 /* Initialisation functions. */   124    125 static void jz_lcd_desc_init(vidinfo_t *vid)   126 {   127 	struct jz_fb_dma_descriptor *descriptors;   128 	struct jz_fb_info * fbi;   129    130 	fbi = &vid->jz_fb;   131    132 	/* Allocate space for descriptors before the palette entries. */   133    134 	descriptors = (struct jz_fb_dma_descriptor *) lcd_get_descriptors(get_memory_size());   135 	fbi->dmadesc_fblow = (struct jz_fb_dma_descriptor *) &descriptors[0];   136 	fbi->dmadesc_fbhigh = (struct jz_fb_dma_descriptor *) &descriptors[1];   137 	fbi->dmadesc_palette = (struct jz_fb_dma_descriptor *) &descriptors[2];   138    139 	/* Populate descriptors. */   140    141 	if (lcd_get_panels() == 2)   142 	{   143 		fbi->dmadesc_fblow->fdadr = fbi->dmadesc_fblow;   144 		fbi->dmadesc_fblow->fsadr = lcd_get_framebuffer(get_memory_size(), 1);   145 		fbi->dmadesc_fblow->fidr  = 0;   146 		fbi->dmadesc_fblow->ldcmd = lcd_get_size(vid) / 4 ;   147    148 		fbi->fdadr1 = fbi->dmadesc_fblow; /* only used in dual-panel mode */   149 	}   150    151 	fbi->dmadesc_fbhigh->fsadr = fbi->screen;   152 	fbi->dmadesc_fbhigh->fidr = 0;   153 	fbi->dmadesc_fbhigh->ldcmd =  lcd_get_size(vid) / 4; /* length in words */   154    155 	if (NBITS(vid->vl_bpix) < 12)   156 	{   157 		fbi->dmadesc_palette->fsadr = fbi->palette;   158 		fbi->dmadesc_palette->fidr  = 0;   159 		fbi->dmadesc_palette->ldcmd = (lcd_get_palette_size(vid) / 4) | (1<<28);   160    161 		/* assume any mode with <12 bpp is palette driven */   162 		fbi->dmadesc_palette->fdadr = fbi->dmadesc_fbhigh;   163 		fbi->dmadesc_fbhigh->fdadr = fbi->dmadesc_palette;   164 		/* flips back and forth between pal and fbhigh */   165 		fbi->fdadr0 = fbi->dmadesc_palette;   166 	} else {   167 		/* palette shouldn't be loaded in true-color mode */   168 		fbi->dmadesc_fbhigh->fdadr = fbi->dmadesc_fbhigh;   169 		fbi->fdadr0 = fbi->dmadesc_fbhigh; /* no pal just fbhigh */   170 	}   171    172 	flush_cache_all();   173 }   174    175 static unsigned int jz_lcd_stn_init(unsigned int stnH)   176 {   177 	unsigned int val = 0;   178    179 	switch (jzfb.bpp) {   180 	case 1:   181 		/* val |= LCD_CTRL_PEDN; */   182 	case 2:   183 		val |= LCD_CTRL_FRC_2;   184 		break;   185 	case 4:   186 		val |= LCD_CTRL_FRC_4;   187 		break;   188 	case 8:   189 	default:   190 		val |= LCD_CTRL_FRC_16;   191 		break;   192 	}   193    194 	switch (jzfb.cfg & STN_DAT_PINMASK) {   195 	case STN_DAT_PIN1:   196 		/* Do not adjust the hori-param value. */   197 		break;   198 	case STN_DAT_PIN2:   199 		align2(jzfb.hsw);   200 		align2(jzfb.elw);   201 		align2(jzfb.blw);   202 		break;   203 	case STN_DAT_PIN4:   204 		align4(jzfb.hsw);   205 		align4(jzfb.elw);   206 		align4(jzfb.blw);   207 		break;   208 	case STN_DAT_PIN8:   209 		align8(jzfb.hsw);   210 		align8(jzfb.elw);   211 		align8(jzfb.blw);   212 		break;   213 	}   214    215 	REG_LCD_VSYNC = (0 << 16) | jzfb.vsw;   216 	REG_LCD_HSYNC = ((jzfb.blw+jzfb.w) << 16) | (jzfb.blw+jzfb.w+jzfb.hsw);   217    218 	/* Screen setting */   219 	REG_LCD_VAT = ((jzfb.blw + jzfb.w + jzfb.hsw + jzfb.elw) << 16) | (stnH + jzfb.vsw + jzfb.bfw + jzfb.efw);   220 	REG_LCD_DAH = (jzfb.blw << 16) | (jzfb.blw + jzfb.w);   221 	REG_LCD_DAV = (0 << 16) | (stnH);   222    223 	/* AC BIAs signal */   224 	REG_LCD_PS = (0 << 16) | (stnH+jzfb.vsw+jzfb.efw+jzfb.bfw);   225    226 	return val;   227 }   228    229 static void jz_lcd_tft_init()   230 {   231 	REG_LCD_VSYNC = (0 << 16) | jzfb.vsw;   232 	REG_LCD_HSYNC = (0 << 16) | jzfb.hsw;   233 	REG_LCD_DAV =((jzfb.vsw+jzfb.bfw) << 16) | (jzfb.vsw +jzfb.bfw+jzfb.h);   234 	REG_LCD_DAH = ((jzfb.hsw + jzfb.blw) << 16) | (jzfb.hsw + jzfb.blw + jzfb.w );   235 	REG_LCD_VAT = (((jzfb.blw + jzfb.w + jzfb.elw + jzfb.hsw)) << 16) \   236 		| (jzfb.vsw + jzfb.bfw + jzfb.h + jzfb.efw);   237 }   238    239 static void jz_lcd_samsung_init(unsigned int pclk)   240 {   241 	unsigned int total, tp_s, tp_e, ckv_s, ckv_e;   242 	unsigned int rev_s, rev_e, inv_s, inv_e;   243    244 	jz_lcd_tft_init();   245    246 	total = jzfb.blw + jzfb.w + jzfb.elw + jzfb.hsw;   247 	tp_s = jzfb.blw + jzfb.w + 1;   248 	tp_e = tp_s + 1;   249 	/* ckv_s = tp_s - jz_clocks.pixclk/(1000000000/4100); */   250 	ckv_s = tp_s - pclk/(1000000000/4100);   251 	ckv_e = tp_s + total;   252 	rev_s = tp_s - 11;	/* -11.5 clk */   253 	rev_e = rev_s + total;   254 	inv_s = tp_s;   255 	inv_e = inv_s + total;   256 	REG_LCD_CLS = (tp_s << 16) | tp_e;   257 	REG_LCD_PS = (ckv_s << 16) | ckv_e;   258 	REG_LCD_SPL = (rev_s << 16) | rev_e;   259 	REG_LCD_REV = (inv_s << 16) | inv_e;   260 	jzfb.cfg |= STFT_REVHI | STFT_SPLHI;   261 }   262    263 static void jz_lcd_sharp_init()   264 {   265 	unsigned int total, cls_s, cls_e, ps_s, ps_e;   266 	unsigned int spl_s, spl_e, rev_s, rev_e;   267    268 	jz_lcd_tft_init();   269    270 	total = jzfb.blw + jzfb.w + jzfb.elw + jzfb.hsw;   271 	spl_s = 1;   272 	spl_e = spl_s + 1;   273 	cls_s = 0;   274 	cls_e = total - 60;	/* > 4us (pclk = 80ns) */   275 	ps_s = cls_s;   276 	ps_e = cls_e;   277 	rev_s = total - 40;	/* > 3us (pclk = 80ns) */   278 	rev_e = rev_s + total;   279 	jzfb.cfg |= STFT_PSHI;    280 	REG_LCD_SPL = (spl_s << 16) | spl_e;   281 	REG_LCD_CLS = (cls_s << 16) | cls_e;   282 	REG_LCD_PS = (ps_s << 16) | ps_e;   283 	REG_LCD_REV = (rev_s << 16) | rev_e;   284 }   285    286 static unsigned int jz_lcd_get_pixel_clock()   287 {   288 	unsigned int pclk;   289    290 	/* Derive pixel clock from frame clock. */   291    292 	if ( (jzfb.cfg & MODE_MASK) != MODE_8BIT_SERIAL_TFT) {   293 		pclk = jzfb.fclk * (jzfb.w + jzfb.hsw + jzfb.elw + jzfb.blw) *   294 			(jzfb.h + jzfb.vsw + jzfb.efw + jzfb.bfw);   295 	} else {   296 		/* serial mode: Hsync period = 3*Width_Pixel */   297 		pclk = jzfb.fclk * (jzfb.w*3 + jzfb.hsw + jzfb.elw + jzfb.blw) *   298 			(jzfb.h + jzfb.vsw + jzfb.efw + jzfb.bfw);   299 	}   300    301 	if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_SINGLE) ||   302 	    ((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL))   303 		pclk = (pclk * 3);   304    305 	if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_SINGLE) ||   306 	    ((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) ||   307 	    ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_SINGLE) ||   308 	    ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL))   309 		pclk = pclk >> ((jzfb.cfg & STN_DAT_PINMASK) >> 4);   310    311 	if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) ||   312 	    ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL))   313 		pclk >>= 1;   314    315 	return pclk;   316 }   317    318 static void jz_lcd_set_timing(unsigned int pclk)   319 {   320 	unsigned int val;   321    322 #ifdef CONFIG_CPU_JZ4730   323         val = __cpm_get_pllout() / pclk;   324         REG_CPM_CFCR2 = val - 1;   325         val = pclk * 4 ;   326         if ( val > 150000000 ) {   327                 val = 150000000;   328         }   329         val = __cpm_get_pllout() / val;   330         val--;   331         if ( val > 0xF )   332                 val = 0xF;   333 #else   334 	int pll_div;   335    336 	pll_div = ( REG_CPM_CPCCR & CPM_CPCCR_PCS ); /* clock source,0:pllout/2 1: pllout */   337 	pll_div = pll_div ? 1 : 2 ;   338 	val = ( __cpm_get_pllout()/pll_div ) / pclk;   339 	val--;   340 	if ( val > 0x1ff ) {   341 		val = 0x1ff;   342 	}   343 	__cpm_set_pixdiv(val);   344    345 	val = pclk * 3 ;	/* LCDClock > 2.5*Pixclock */   346 	if ( val > 150000000 ) {   347 		val = 150000000;   348 	}   349 	val = ( __cpm_get_pllout()/pll_div ) / val;   350 	val--;   351 	if ( val > 0x1f ) {   352 		val = 0x1f;   353 	}   354 #endif   355 	__cpm_set_ldiv( val );   356 	REG_CPM_CPCCR |= CPM_CPCCR_CE ; /* update divide */   357 }   358    359 static int jz_lcd_hw_init(vidinfo_t *vid)   360 {   361 	struct jz_fb_info *fbi = &vid->jz_fb;   362 	unsigned int val = 0;   363 	unsigned int pclk = jz_lcd_get_pixel_clock();   364    365 	/* Setting Control register */   366 	switch (jzfb.bpp) {   367 	case 1:   368 		val |= LCD_CTRL_BPP_1;   369 		break;   370 	case 2:   371 		val |= LCD_CTRL_BPP_2;   372 		break;   373 	case 4:   374 		val |= LCD_CTRL_BPP_4;   375 		break;   376 	case 8:   377 		val |= LCD_CTRL_BPP_8;   378 		break;   379 	case 15:   380 		val |= LCD_CTRL_RGB555;   381 	case 16:   382 		val |= LCD_CTRL_BPP_16;   383 		break;   384 #ifndef CONFIG_CPU_JZ4730   385 	case 17 ... 32:   386 		val |= LCD_CTRL_BPP_18_24;	/* target is 4bytes/pixel */   387 		break;   388 #endif   389 	default:   390 		/* printf("jz_lcd.c The BPP %d is not supported\n", jzfb.bpp); */   391 		val |= LCD_CTRL_BPP_16;   392 		break;   393 	}   394    395 	switch (jzfb.cfg & MODE_MASK) {   396 	case MODE_STN_MONO_DUAL:   397 	case MODE_STN_COLOR_DUAL:   398 		val |= jz_lcd_stn_init(jzfb.h >> 1);   399 		break;   400    401 	case MODE_STN_MONO_SINGLE:   402 	case MODE_STN_COLOR_SINGLE:   403 		val |= jz_lcd_stn_init(jzfb.h);   404 		break;   405    406 	case MODE_TFT_GEN:   407 	case MODE_TFT_CASIO:   408 	case MODE_8BIT_SERIAL_TFT:   409 	case MODE_TFT_18BIT:   410 		jz_lcd_tft_init();   411 		break;   412    413 	case MODE_TFT_SAMSUNG:   414 	{   415 		jz_lcd_samsung_init(pclk);   416 		break;   417 	}   418    419 	case MODE_TFT_SHARP:   420 	{   421 		jz_lcd_sharp_init();   422 		break;   423 	}   424    425 	default:   426 		break;   427 	}   428    429 	/* Configure the LCD panel */   430    431 	val |= LCD_CTRL_BST_16;		/* Burst Length is 16WORD=64Byte */   432 	val |= LCD_CTRL_OFUP;		/* OutFIFO underrun protect */   433 	REG_LCD_CTRL = val;   434 	REG_LCD_CFG = jzfb.cfg;   435    436 	/* Timing reset. */   437    438 	__cpm_stop_lcd();   439 	jz_lcd_set_timing(pclk);   440 	__cpm_start_lcd();   441 	udelay(1000);   442    443 	/* Configure DMA. */   444    445 	REG_LCD_DA0 = (unsigned long) fbi->fdadr0; /* frame descriptor */   446    447 	if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) ||   448 	    ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL))   449 		REG_LCD_DA1 = (unsigned long) fbi->fdadr1; /* frame descriptor */   450    451 	return 0;   452 }   453    454 static inline u8 LCD_CODE(u8 bpp)   455 {          456         u8 code = 0;   457         while (bpp && !(bpp & 1))   458         {          459                 bpp >>= 1;   460                 code += 1;   461         }   462         return code;   463 }   464    465 /* Public operations. */   466    467 void lcd_set_bpp(u8 bpp)   468 {   469 	jzfb.bpp = bpp;   470 	panel_info.vl_bpix = LCD_CODE(bpp);   471 }   472    473 void lcd_enable()   474 {   475 	/* Clear the disable bit and set the enable bit. */   476    477 	REG_LCD_CTRL &= ~(1<<4);	/* LCDCTRL.DIS */   478 	REG_LCD_CTRL |= 1<<3;		/* LCDCTRL.ENA*/   479 }   480    481 void lcd_disable()   482 {   483 	REG_LCD_CTRL |= (1<<4);		/* LCDCTRL.DIS, regular disable */   484 }   485    486 void lcd_quick_disable()   487 {   488 	REG_LCD_CTRL &= ~(1<<4);	/* LCDCTRL.ENA, quick disable */   489 }   490    491 static inline u16 rgb8_to_rgb16(u8 rgb)   492 {   493 	return ((((rgb & 0xe0) >> 5) * 4) << 11) | ((((rgb & 0x1c) >> 2) * 9) << 6) | ((rgb & 0x03) * 10);   494 }   495    496 static inline u16 rgb4_to_rgb16(u8 rgb)   497 {   498 	return ((((rgb & 8) >> 3) * 0x1f) << 11) | ((((rgb & 6) >> 1) * 0x15) << 5) | ((rgb & 1) * 0x1f);   499 }   500    501 static void lcd_init_palette(vidinfo_t *vid)   502 {   503 	u16 *palette = (u16 *) lcd_get_palette(get_memory_size());   504 	u16 *end = (u16 *) palette + NCOLORS(vid->vl_bpix);   505 	u8 value = 0;   506    507 	while (palette < end)   508 	{   509 		switch (vid->vl_bpix)   510 		{   511 			case LCD_COLOR4:   512 			*palette = rgb4_to_rgb16(value);   513 			break;   514    515 			case LCD_COLOR8:   516 			default:   517 			*palette = rgb8_to_rgb16(value);   518 			break;   519 		}   520    521 		value++;   522 		palette++;   523 	}   524 }   525    526 unsigned long lcd_ctrl_init()   527 {   528 	struct jz_fb_info *fbi = &panel_info.jz_fb;   529    530 	/* Start from the top of memory and obtain palette and framebuffer regions. */   531    532 	fbi->screen = lcd_get_framebuffer(get_memory_size(), 0);   533 	fbi->palette = lcd_get_palette(get_memory_size());   534    535 	if (NBITS(panel_info.vl_bpix) < 12)   536 		lcd_init_palette(&panel_info);   537    538 	jz_lcd_desc_init(&panel_info);   539 	jz_lcd_hw_init(&panel_info);   540    541 	return fbi->screen;   542 }