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 }