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