1 /* 2 * Ben NanoNote LCD initialisation, based on uboot-xburst and xburst-tools. 3 * 4 * Copyright (C) 2001-2002 Wolfgang Denk, DENX Software Engineering, <wd@denx.de> 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 modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation, either version 3 of the License, or 10 * (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, see <http://www.gnu.org/licenses/>. 19 */ 20 21 #include "board-display.h" 22 23 #include "lcd.h" 24 #include "jzlcd.h" 25 #include "sdram.h" 26 #include "cpu.h" 27 #include "board.h" 28 29 extern vidinfo_t panel_info; 30 static uint32_t lcd_base; 31 32 33 34 static uint16_t get_line_length() 35 { 36 return ALIGN((panel_info.jz_fb->w * panel_info.jz_fb->bpp) / 8, sizeof(uint32_t)); 37 } 38 39 static uint32_t *get_pixel32(uint16_t h, uint16_t v) 40 { 41 return (uint32_t *) (lcd_base + v * get_line_length()) + h; 42 } 43 44 static uint16_t *get_pixel16(uint16_t h, uint16_t v) 45 { 46 return (uint16_t *) (lcd_base + v * get_line_length()) + h; 47 } 48 49 static uint8_t *get_pixel8(uint16_t h, uint16_t v) 50 { 51 return (uint8_t *) (lcd_base + v * get_line_length()) + h; 52 } 53 54 static uint8_t *get_pixel4(uint16_t h, uint16_t v) 55 { 56 return (uint8_t *) (lcd_base + v * get_line_length()) + h / 2; 57 } 58 59 static inline uint16_t div(uint16_t num, uint16_t denom, uint16_t scale) 60 { 61 return (scale * num) / denom; 62 } 63 64 static uint32_t pixel(uint8_t r, uint8_t g, uint8_t b, uint8_t rmax, uint8_t gmax, uint8_t bmax, uint8_t rshift, uint8_t gshift, uint8_t bshift) 65 { 66 return (div(r, 255, rmax) << rshift) | (div(g, 255, gmax) << gshift) | (div(b, 255, bmax) << bshift); 67 } 68 69 uint32_t get_bitmap_value(uint16_t x, uint32_t value) 70 { 71 return (value >> (((panel_info.jz_fb->w - 1 - x) * 32) / panel_info.jz_fb->w)) % 2 ? 0xffffffff : 0; 72 } 73 74 static void get_colour(uint16_t h, uint16_t v, uint8_t rgb[], uint16_t pixel_type) 75 { 76 uint16_t v_max = panel_info.jz_fb->h - 1; 77 uint16_t h_max = panel_info.jz_fb->w - 1; 78 79 rgb[(pixel_type - 1) % 3] = div(h, h_max, 255); 80 rgb[pixel_type % 3] = div(v, v_max, 255); 81 rgb[(pixel_type + 1) % 3] = (rgb[0] + rgb[1]) / 2; 82 } 83 84 static void set_pixel32(uint16_t h, uint16_t v, uint32_t value) 85 { 86 uint32_t *pix = get_pixel32(h, v); 87 *pix = value; 88 } 89 90 static void set_pixel16_565(uint16_t h, uint16_t v, uint32_t value) 91 { 92 uint16_t *pix = get_pixel16(h, v); 93 *pix = (uint16_t) value; 94 } 95 96 static void set_pixel8(uint16_t h, uint16_t v, uint32_t value) 97 { 98 uint8_t *pix = get_pixel8(h, v); 99 *pix = (uint8_t) value; 100 } 101 102 static void set_pixel4(uint16_t h, uint16_t v, uint32_t value) 103 { 104 uint8_t *pix = get_pixel4(h, v); 105 uint8_t mask = h & 1 ? 0xf0 : 0x0f; 106 *pix = (*pix & mask) | ((uint8_t) value); 107 } 108 109 void set_pixel(uint16_t h, uint16_t v, uint32_t value) 110 { 111 switch (panel_info.jz_fb->bpp) 112 { 113 case 32: 114 set_pixel32(h, v, value); 115 break; 116 117 case 8: 118 set_pixel8(h, v, value); 119 break; 120 121 case 4: 122 set_pixel4(h, v, value); 123 break; 124 125 case 16: 126 default: 127 set_pixel16_565(h, v, value); 128 break; 129 } 130 } 131 static void test_pixel32(uint16_t h, uint16_t v, uint16_t pixel_type) 132 { 133 uint8_t rgb[3]; 134 135 get_colour(h, v, rgb, pixel_type); 136 set_pixel32(h, v, pixel(rgb[0], rgb[1], rgb[2], 255, 255, 255, 16, 8, 0) | get_bitmap_value(h, pixel_type)); 137 } 138 139 static void test_pixel16_565(uint16_t h, uint16_t v, uint16_t pixel_type) 140 { 141 uint8_t rgb[3]; 142 143 get_colour(h, v, rgb, pixel_type); 144 set_pixel16_565(h, v, pixel(rgb[0], rgb[1], rgb[2], 31, 63, 31, 11, 5, 0) | get_bitmap_value(h, pixel_type)); 145 } 146 147 static void test_pixel8(uint16_t h, uint16_t v, uint16_t pixel_type) 148 { 149 uint8_t rgb[3]; 150 151 get_colour(h, v, rgb, pixel_type); 152 set_pixel8(h, v, pixel(rgb[0], rgb[1], rgb[2], 7, 7, 3, 5, 2, 0) | get_bitmap_value(h, pixel_type)); 153 } 154 155 static void test_pixel4(uint16_t h, uint16_t v, uint16_t pixel_type) 156 { 157 uint8_t rgb[3]; 158 159 get_colour(h, v, rgb, pixel_type); 160 set_pixel4(h, v, pixel(rgb[0], rgb[1], rgb[2], 1, 2, 1, 3, 1, 0) | get_bitmap_value(h, pixel_type)); 161 } 162 163 void test_pixel(uint16_t h, uint16_t v, uint16_t pixel_type) 164 { 165 switch (panel_info.jz_fb->bpp) 166 { 167 case 32: 168 test_pixel32(h, v, pixel_type); 169 break; 170 171 case 8: 172 test_pixel8(h, v, pixel_type); 173 break; 174 175 case 4: 176 test_pixel4(h, v, pixel_type); 177 break; 178 179 case 16: 180 default: 181 test_pixel16_565(h, v, pixel_type); 182 break; 183 } 184 } 185 186 void clear_pixel32(uint16_t h, uint16_t v) 187 { 188 uint32_t *pix = get_pixel32(h, v); 189 *pix = 0; 190 } 191 192 void clear_pixel16(uint16_t h, uint16_t v) 193 { 194 uint16_t *pix = get_pixel16(h, v); 195 *pix = 0; 196 } 197 198 void clear_pixel8(uint16_t h, uint16_t v) 199 { 200 uint8_t *pix = get_pixel8(h, v); 201 *pix = 0; 202 } 203 204 void clear_pixel4(uint16_t h, uint16_t v) 205 { 206 uint8_t *pix = get_pixel4(h, v); 207 uint8_t mask = h & 1 ? 0xf0 : 0x0f; 208 *pix = *pix & mask; 209 } 210 211 void clear_pixel(uint16_t h, uint16_t v) 212 { 213 switch (panel_info.jz_fb->bpp) 214 { 215 case 32: 216 clear_pixel32(h, v); 217 break; 218 219 case 8: 220 clear_pixel8(h, v); 221 break; 222 223 case 4: 224 clear_pixel4(h, v); 225 break; 226 227 case 16: 228 default: 229 clear_pixel16(h, v); 230 break; 231 } 232 } 233 234 void test_pattern() 235 { 236 uint16_t v_max = panel_info.jz_fb->h; 237 uint16_t h_max = panel_info.jz_fb->w; 238 uint16_t v, h; 239 240 for (v = 0; v < v_max; v += 1) { 241 for (h = 0; h < h_max; h += 1) { 242 test_pixel(h, v, 1); 243 } 244 } 245 } 246 247 void lcd_clear(uint32_t lcd_base) 248 { 249 uint16_t v_max = panel_info.jz_fb->h; 250 uint16_t h_max = panel_info.jz_fb->w; 251 uint16_t v, h; 252 uint32_t *pix = (uint32_t *)lcd_base; 253 254 for (v = 0; v < v_max; v += 1) { 255 for (h = 0; h < h_max; h += 1) { 256 *pix++ = 0; 257 } 258 } 259 } 260 261 262 263 /* LCD initialisation. */ 264 265 #ifdef CONFIG_CPU_JZ4730 266 void jz4730_set_lcd_frequencies(uint32_t pclk, uint8_t ratio) 267 { 268 uint32_t val; 269 270 val = __cpm_get_pllout() / pclk; 271 REG_CPM_CFCR2 = val - 1; 272 val = pclk * ratio; 273 274 if (val > 150000000) { 275 val = 150000000; 276 } 277 278 val = __cpm_get_pllout() / val; 279 val--; 280 281 if (val > 0xF) 282 val = 0xF; 283 284 __cpm_set_ldiv(val); 285 REG_CPM_CPCCR = REG_CPM_CPCCR | CPM_CPCCR_CE; /* update divide */ 286 } 287 #else 288 void jz4740_set_lcd_frequencies(uint32_t pclk, uint8_t ratio) 289 { 290 uint32_t val; 291 int pll_div; 292 293 pll_div = REG_CPM_CPCCR & CPM_CPCCR_PCS; /* clock source,0:pllout/2 1: pllout */ 294 pll_div = pll_div ? 1 : 2; 295 val = (__cpm_get_pllout() / pll_div) / pclk; 296 val--; 297 298 if ( val > 0x1ff ) { 299 val = 0x1ff; 300 } 301 302 __cpm_set_pixdiv(val); 303 304 val = pclk * ratio; /* LCDClock > 2.5*Pixclock */ 305 306 if ( val > 150000000 ) { 307 val = 150000000; 308 } 309 310 val = (__cpm_get_pllout() / pll_div) / val; 311 val--; 312 313 if (val > 0x1f) 314 val = 0x1f; 315 316 __cpm_set_ldiv(val); 317 REG_CPM_CPCCR = REG_CPM_CPCCR | CPM_CPCCR_CE; /* update divide */ 318 } 319 #endif 320 321 void lcd_set_timing(vidinfo_t *vid) 322 { 323 uint32_t pclk = jz4740_lcd_get_pixel_clock(vid); 324 325 __cpm_stop_lcd(); 326 327 #ifdef CONFIG_CPU_JZ4730 328 jz4730_set_lcd_frequencies(pclk, 4); 329 #else 330 jz4740_set_lcd_frequencies(pclk, 3); 331 #endif 332 333 __cpm_start_lcd(); 334 udelay(1000); 335 } 336 337 static void lcd_display_pin_init() 338 { 339 __lcd_display_pin_init(); 340 } 341 342 static void lcd_display_on() 343 { 344 __lcd_display_on(); 345 } 346 347 static void lcd_set_bpp(uint8_t bpp) 348 { 349 jz4740_lcd_set_bpp(bpp, &panel_info); 350 } 351 352 static void lcd_enable() 353 { 354 jz4740_lcd_enable(&panel_info); 355 } 356 357 static void lcd_disable() 358 { 359 jz4740_lcd_disable(&panel_info); 360 } 361 362 static void lcd_quick_disable() 363 { 364 jz4740_lcd_quick_disable(&panel_info); 365 } 366 367 uint32_t lcd_ctrl_init() 368 { 369 vidinfo_t *vid = &panel_info; 370 struct jz_mem_info *fbi = &vid->jz_mem; 371 void *fb_vaddr; 372 373 /* Start from the top of memory and obtain the framebuffer region. */ 374 375 fb_vaddr = (void *) (get_memory_size() - jz4740_lcd_get_total_size(vid)); 376 377 jz4740_lcd_ctrl_init((void *) LCD_BASE_KSEG1, fb_vaddr, vid); 378 flush_cache_all(); 379 jz4740_lcd_hw_init(vid); 380 lcd_set_timing(vid); 381 jz4740_lcd_dma_init(vid); 382 383 return fbi->screen; 384 } 385 386 void lcd_init() 387 { 388 lcd_display_pin_init(); 389 lcd_display_on(); 390 391 /* Initialise the member here since the address is otherwise invalid. */ 392 393 panel_info.jz_fb = (struct jzfb_info *) ((uint32_t) panel_info.jz_fb & ~0x80000000); 394 395 lcd_base = lcd_ctrl_init(); 396 lcd_clear(lcd_base); 397 lcd_enable(); 398 }