1 /* 2 * Copyright 2007, 2010 Freescale Semiconductor, Inc. 3 * York Sun <yorksun@freescale.com> 4 * 5 * FSL DIU Framebuffer driver 6 * 7 * See file CREDITS for list of people who contributed to this 8 * project. 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License as 12 * published by the Free Software Foundation; either version 2 of 13 * the License, or (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 23 * MA 02111-1307 USA 24 */ 25 26 #include <common.h> 27 #include <i2c.h> 28 #include <malloc.h> 29 #include <asm/io.h> 30 31 #include <fsl_diu_fb.h> 32 33 struct fb_videomode { 34 const char *name; /* optional */ 35 unsigned int refresh; /* optional */ 36 unsigned int xres; 37 unsigned int yres; 38 unsigned int pixclock; 39 unsigned int left_margin; 40 unsigned int right_margin; 41 unsigned int upper_margin; 42 unsigned int lower_margin; 43 unsigned int hsync_len; 44 unsigned int vsync_len; 45 unsigned int sync; 46 unsigned int vmode; 47 unsigned int flag; 48 }; 49 50 #define FB_SYNC_VERT_HIGH_ACT 2 /* vertical sync high active */ 51 #define FB_SYNC_COMP_HIGH_ACT 8 /* composite sync high active */ 52 #define FB_VMODE_NONINTERLACED 0 /* non interlaced */ 53 54 /* This setting is used for the ifm pdm360ng with PRIMEVIEW PM070WL3 */ 55 static struct fb_videomode fsl_diu_mode_800 = { 56 .refresh = 60, 57 .xres = 800, 58 .yres = 480, 59 .pixclock = 31250, 60 .left_margin = 86, 61 .right_margin = 42, 62 .upper_margin = 33, 63 .lower_margin = 10, 64 .hsync_len = 128, 65 .vsync_len = 2, 66 .sync = 0, 67 .vmode = FB_VMODE_NONINTERLACED 68 }; 69 70 /* 71 * These parameters give default parameters 72 * for video output 1024x768, 73 * FIXME - change timing to proper amounts 74 * hsync 31.5kHz, vsync 60Hz 75 */ 76 static struct fb_videomode fsl_diu_mode_1024 = { 77 .refresh = 60, 78 .xres = 1024, 79 .yres = 768, 80 .pixclock = 15385, 81 .left_margin = 160, 82 .right_margin = 24, 83 .upper_margin = 29, 84 .lower_margin = 3, 85 .hsync_len = 136, 86 .vsync_len = 6, 87 .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 88 .vmode = FB_VMODE_NONINTERLACED 89 }; 90 91 static struct fb_videomode fsl_diu_mode_1280 = { 92 .name = "1280x1024-60", 93 .refresh = 60, 94 .xres = 1280, 95 .yres = 1024, 96 .pixclock = 9375, 97 .left_margin = 38, 98 .right_margin = 128, 99 .upper_margin = 2, 100 .lower_margin = 7, 101 .hsync_len = 216, 102 .vsync_len = 37, 103 .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 104 .vmode = FB_VMODE_NONINTERLACED 105 }; 106 107 /* 108 * These are the fields of area descriptor(in DDR memory) for every plane 109 */ 110 struct diu_ad { 111 /* Word 0(32-bit) in DDR memory */ 112 unsigned int pix_fmt; /* hard coding pixel format */ 113 /* Word 1(32-bit) in DDR memory */ 114 unsigned int addr; 115 /* Word 2(32-bit) in DDR memory */ 116 unsigned int src_size_g_alpha; 117 /* Word 3(32-bit) in DDR memory */ 118 unsigned int aoi_size; 119 /* Word 4(32-bit) in DDR memory */ 120 unsigned int offset_xyi; 121 /* Word 5(32-bit) in DDR memory */ 122 unsigned int offset_xyd; 123 /* Word 6(32-bit) in DDR memory */ 124 unsigned int ckmax_r:8; 125 unsigned int ckmax_g:8; 126 unsigned int ckmax_b:8; 127 unsigned int res9:8; 128 /* Word 7(32-bit) in DDR memory */ 129 unsigned int ckmin_r:8; 130 unsigned int ckmin_g:8; 131 unsigned int ckmin_b:8; 132 unsigned int res10:8; 133 /* Word 8(32-bit) in DDR memory */ 134 unsigned int next_ad; 135 /* Word 9(32-bit) in DDR memory, just for 64-bit aligned */ 136 unsigned int res1; 137 unsigned int res2; 138 unsigned int res3; 139 }__attribute__ ((packed)); 140 141 /* 142 * DIU register map 143 */ 144 struct diu { 145 unsigned int desc[3]; 146 unsigned int gamma; 147 unsigned int pallete; 148 unsigned int cursor; 149 unsigned int curs_pos; 150 unsigned int diu_mode; 151 unsigned int bgnd; 152 unsigned int bgnd_wb; 153 unsigned int disp_size; 154 unsigned int wb_size; 155 unsigned int wb_mem_addr; 156 unsigned int hsyn_para; 157 unsigned int vsyn_para; 158 unsigned int syn_pol; 159 unsigned int thresholds; 160 unsigned int int_status; 161 unsigned int int_mask; 162 unsigned int colorbar[8]; 163 unsigned int filling; 164 unsigned int plut; 165 } __attribute__ ((packed)); 166 167 struct diu_hw { 168 struct diu *diu_reg; 169 volatile unsigned int mode; /* DIU operation mode */ 170 }; 171 172 struct diu_addr { 173 unsigned char * paddr; /* Virtual address */ 174 unsigned int offset; 175 }; 176 177 /* 178 * Modes of operation of DIU 179 */ 180 #define MFB_MODE0 0 /* DIU off */ 181 #define MFB_MODE1 1 /* All three planes output to display */ 182 #define MFB_MODE2 2 /* Plane 1 to display, 183 * planes 2+3 written back to memory */ 184 #define MFB_MODE3 3 /* All three planes written back to memory */ 185 #define MFB_MODE4 4 /* Color bar generation */ 186 187 #define MAX_CURS 32 188 189 static struct fb_info fsl_fb_info; 190 static struct diu_addr gamma, cursor; 191 static struct diu_ad fsl_diu_fb_ad __attribute__ ((aligned(32))); 192 static struct diu_ad dummy_ad __attribute__ ((aligned(32))); 193 static unsigned char *dummy_fb; 194 static struct diu_hw dr = { 195 .mode = MFB_MODE1, 196 }; 197 198 int fb_enabled = 0; 199 int fb_initialized = 0; 200 const int default_xres = 1280; 201 const int default_pixel_format = 0x88882317; 202 203 static int map_video_memory(struct fb_info *info, unsigned long bytes_align); 204 static void enable_lcdc(void); 205 static void disable_lcdc(void); 206 static int fsl_diu_enable_panel(struct fb_info *info); 207 static int fsl_diu_disable_panel(struct fb_info *info); 208 static int allocate_buf(struct diu_addr *buf, u32 size, u32 bytes_align); 209 void diu_set_pixel_clock(unsigned int pixclock); 210 211 int fsl_diu_init(int xres, unsigned int pixel_format, int gamma_fix) 212 { 213 struct fb_videomode *fsl_diu_mode_db; 214 struct diu_ad *ad = &fsl_diu_fb_ad; 215 struct diu *hw; 216 struct fb_info *info = &fsl_fb_info; 217 struct fb_var_screeninfo *var = &info->var; 218 unsigned char *gamma_table_base; 219 unsigned int i, j; 220 221 debug("Enter fsl_diu_init\n"); 222 dr.diu_reg = (struct diu *) (CONFIG_SYS_DIU_ADDR); 223 hw = (struct diu *) dr.diu_reg; 224 225 disable_lcdc(); 226 227 switch (xres) { 228 case 800: 229 fsl_diu_mode_db = &fsl_diu_mode_800; 230 break; 231 case 1280: 232 fsl_diu_mode_db = &fsl_diu_mode_1280; 233 break; 234 default: 235 fsl_diu_mode_db = &fsl_diu_mode_1024; 236 } 237 238 if (0 == fb_initialized) { 239 allocate_buf(&gamma, 768, 32); 240 debug("gamma is allocated @ 0x%x\n", 241 (unsigned int)gamma.paddr); 242 allocate_buf(&cursor, MAX_CURS * MAX_CURS * 2, 32); 243 debug("curosr is allocated @ 0x%x\n", 244 (unsigned int)cursor.paddr); 245 246 /* create a dummy fb and dummy ad */ 247 dummy_fb = malloc(64); 248 if (NULL == dummy_fb) { 249 printf("Cannot allocate dummy fb\n"); 250 return -1; 251 } 252 dummy_ad.addr = cpu_to_le32((unsigned int)dummy_fb); 253 dummy_ad.pix_fmt = 0x88882317; 254 dummy_ad.src_size_g_alpha = 0x04400000; /* alpha = 0 */ 255 dummy_ad.aoi_size = 0x02000400; 256 dummy_ad.offset_xyi = 0; 257 dummy_ad.offset_xyd = 0; 258 dummy_ad.next_ad = 0; 259 /* Memory allocation for framebuffer */ 260 if (map_video_memory(info, 32)) { 261 printf("Unable to allocate fb memory 1\n"); 262 return -1; 263 } 264 } 265 266 memset(info->screen_base, 0, info->smem_len); 267 268 out_be32(&dr.diu_reg->desc[0], (int)&dummy_ad); 269 out_be32(&dr.diu_reg->desc[1], (int)&dummy_ad); 270 out_be32(&dr.diu_reg->desc[2], (int)&dummy_ad); 271 debug("dummy dr.diu_reg->desc[0] = 0x%x\n", dr.diu_reg->desc[0]); 272 debug("dummy desc[0] = 0x%x\n", hw->desc[0]); 273 274 /* read mode info */ 275 var->xres = fsl_diu_mode_db->xres; 276 var->yres = fsl_diu_mode_db->yres; 277 var->bits_per_pixel = 32; 278 var->pixclock = fsl_diu_mode_db->pixclock; 279 var->left_margin = fsl_diu_mode_db->left_margin; 280 var->right_margin = fsl_diu_mode_db->right_margin; 281 var->upper_margin = fsl_diu_mode_db->upper_margin; 282 var->lower_margin = fsl_diu_mode_db->lower_margin; 283 var->hsync_len = fsl_diu_mode_db->hsync_len; 284 var->vsync_len = fsl_diu_mode_db->vsync_len; 285 var->sync = fsl_diu_mode_db->sync; 286 var->vmode = fsl_diu_mode_db->vmode; 287 info->line_length = var->xres * var->bits_per_pixel / 8; 288 289 ad->pix_fmt = pixel_format; 290 ad->addr = cpu_to_le32((unsigned int)info->screen_base); 291 ad->src_size_g_alpha 292 = cpu_to_le32((var->yres << 12) | var->xres); 293 /* fix me. AOI should not be greater than display size */ 294 ad->aoi_size = cpu_to_le32(( var->yres << 16) | var->xres); 295 ad->offset_xyi = 0; 296 ad->offset_xyd = 0; 297 298 /* Disable chroma keying function */ 299 ad->ckmax_r = 0; 300 ad->ckmax_g = 0; 301 ad->ckmax_b = 0; 302 303 ad->ckmin_r = 255; 304 ad->ckmin_g = 255; 305 ad->ckmin_b = 255; 306 307 gamma_table_base = gamma.paddr; 308 debug("gamma_table_base is allocated @ 0x%x\n", 309 (unsigned int)gamma_table_base); 310 311 /* Prep for DIU init - gamma table */ 312 313 for (i = 0; i <= 2; i++) 314 for (j = 0; j <= 255; j++) 315 *gamma_table_base++ = j; 316 317 if (gamma_fix == 1) { /* fix the gamma */ 318 debug("Fix gamma table\n"); 319 gamma_table_base = gamma.paddr; 320 for (i = 0; i < 256*3; i++) { 321 gamma_table_base[i] = (gamma_table_base[i] << 2) 322 | ((gamma_table_base[i] >> 6) & 0x03); 323 } 324 } 325 326 debug("update-lcdc: HW - %p\n Disabling DIU\n", hw); 327 328 /* Program DIU registers */ 329 330 out_be32(&hw->gamma, (int)gamma.paddr); 331 out_be32(&hw->cursor, (int)cursor.paddr); 332 out_be32(&hw->bgnd, 0x007F7F7F); 333 out_be32(&hw->bgnd_wb, 0); /* BGND_WB */ 334 out_be32(&hw->disp_size, var->yres << 16 | var->xres); /* DISP SIZE */ 335 out_be32(&hw->wb_size, 0); /* WB SIZE */ 336 out_be32(&hw->wb_mem_addr, 0); /* WB MEM ADDR */ 337 out_be32(&hw->hsyn_para, var->left_margin << 22 | /* BP_H */ 338 var->hsync_len << 11 | /* PW_H */ 339 var->right_margin); /* FP_H */ 340 341 out_be32(&hw->vsyn_para, var->upper_margin << 22 | /* BP_V */ 342 var->vsync_len << 11 | /* PW_V */ 343 var->lower_margin); /* FP_V */ 344 345 out_be32(&hw->syn_pol, 0); /* SYNC SIGNALS POLARITY */ 346 out_be32(&hw->thresholds, 0x00037800); /* The Thresholds */ 347 out_be32(&hw->int_status, 0); /* INTERRUPT STATUS */ 348 out_be32(&hw->int_mask, 0); /* INT MASK */ 349 out_be32(&hw->plut, 0x01F5F666); 350 /* Pixel Clock configuration */ 351 debug("DIU pixclock in ps - %d\n", var->pixclock); 352 diu_set_pixel_clock(var->pixclock); 353 354 fb_initialized = 1; 355 356 /* Enable the DIU */ 357 fsl_diu_enable_panel(info); 358 enable_lcdc(); 359 360 return 0; 361 } 362 363 char *fsl_fb_open(struct fb_info **info) 364 { 365 *info = &fsl_fb_info; 366 return fsl_fb_info.screen_base; 367 } 368 369 void fsl_diu_close(void) 370 { 371 struct fb_info *info = &fsl_fb_info; 372 fsl_diu_disable_panel(info); 373 } 374 375 static int fsl_diu_enable_panel(struct fb_info *info) 376 { 377 struct diu *hw = dr.diu_reg; 378 struct diu_ad *ad = &fsl_diu_fb_ad; 379 380 debug("Entered: enable_panel\n"); 381 if (in_be32(&hw->desc[0]) != (unsigned)ad) 382 out_be32(&hw->desc[0], (unsigned)ad); 383 debug("desc[0] = 0x%x\n", hw->desc[0]); 384 return 0; 385 } 386 387 static int fsl_diu_disable_panel(struct fb_info *info) 388 { 389 struct diu *hw = dr.diu_reg; 390 391 debug("Entered: disable_panel\n"); 392 if (in_be32(&hw->desc[0]) != (unsigned)&dummy_ad) 393 out_be32(&hw->desc[0], (unsigned)&dummy_ad); 394 return 0; 395 } 396 397 static int map_video_memory(struct fb_info *info, unsigned long bytes_align) 398 { 399 unsigned long offset; 400 unsigned long mask; 401 402 debug("Entered: map_video_memory\n"); 403 /* allocate maximum 1280*1024 with 32bpp */ 404 info->smem_len = 1280 * 4 *1024 + bytes_align; 405 debug("MAP_VIDEO_MEMORY: smem_len = %d\n", info->smem_len); 406 info->screen_base = malloc(info->smem_len); 407 if (info->screen_base == NULL) { 408 printf("Unable to allocate fb memory\n"); 409 return -1; 410 } 411 info->smem_start = (unsigned int) info->screen_base; 412 mask = bytes_align - 1; 413 offset = (unsigned long)info->screen_base & mask; 414 if (offset) { 415 info->screen_base += (bytes_align - offset); 416 info->smem_len = info->smem_len - (bytes_align - offset); 417 } else 418 info->smem_len = info->smem_len - bytes_align; 419 420 info->screen_size = info->smem_len; 421 422 debug("Allocated fb @ 0x%08lx, size=%d.\n", 423 info->smem_start, info->smem_len); 424 425 return 0; 426 } 427 428 static void enable_lcdc(void) 429 { 430 struct diu *hw = dr.diu_reg; 431 432 debug("Entered: enable_lcdc, fb_enabled = %d\n", fb_enabled); 433 if (!fb_enabled) { 434 out_be32(&hw->diu_mode, dr.mode); 435 fb_enabled++; 436 } 437 debug("diu_mode = %d\n", hw->diu_mode); 438 } 439 440 static void disable_lcdc(void) 441 { 442 struct diu *hw = dr.diu_reg; 443 444 debug("Entered: disable_lcdc, fb_enabled = %d\n", fb_enabled); 445 if (fb_enabled) { 446 out_be32(&hw->diu_mode, 0); 447 fb_enabled = 0; 448 } 449 } 450 451 /* 452 * Align to 64-bit(8-byte), 32-byte, etc. 453 */ 454 static int allocate_buf(struct diu_addr *buf, u32 size, u32 bytes_align) 455 { 456 u32 offset, ssize; 457 u32 mask; 458 459 debug("Entered: allocate_buf\n"); 460 ssize = size + bytes_align; 461 buf->paddr = malloc(ssize); 462 if (!buf->paddr) 463 return -1; 464 465 memset(buf->paddr, 0, ssize); 466 mask = bytes_align - 1; 467 offset = (u32)buf->paddr & mask; 468 if (offset) { 469 buf->offset = bytes_align - offset; 470 buf->paddr = (unsigned char *) ((u32)buf->paddr + offset); 471 } else 472 buf->offset = 0; 473 return 0; 474 } 475 476 #if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE) 477 #include <stdio_dev.h> 478 #include <video_fb.h> 479 /* 480 * The Graphic Device 481 */ 482 static GraphicDevice ctfb; 483 484 void *video_hw_init(void) 485 { 486 struct fb_info *info; 487 488 if (platform_diu_init(&ctfb.winSizeX, &ctfb.winSizeY) < 0) 489 return NULL; 490 491 /* fill in Graphic device struct */ 492 sprintf(ctfb.modeIdent, "%ix%ix%i %ikHz %iHz", 493 ctfb.winSizeX, ctfb.winSizeY, 32, 64, 60); 494 495 ctfb.frameAdrs = (unsigned int)fsl_fb_open(&info); 496 ctfb.plnSizeX = ctfb.winSizeX; 497 ctfb.plnSizeY = ctfb.winSizeY; 498 499 ctfb.gdfBytesPP = 4; 500 ctfb.gdfIndex = GDF_32BIT_X888RGB; 501 502 ctfb.isaBase = 0; 503 ctfb.pciBase = 0; 504 ctfb.memSize = info->screen_size; 505 506 /* Cursor Start Address */ 507 ctfb.dprBase = 0; 508 ctfb.vprBase = 0; 509 ctfb.cprBase = 0; 510 511 return &ctfb; 512 } 513 #endif /* defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE) */ 514