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