1 /* 2 * Copyright 2010-2011 Freescale Semiconductor, Inc. 3 * Authors: Timur Tabi <timur@freescale.com> 4 * 5 * FSL DIU Framebuffer driver 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the Free 9 * Software Foundation; either version 2 of the License, or (at your option) 10 * any later version. 11 */ 12 13 #include <common.h> 14 #include <command.h> 15 #include <linux/ctype.h> 16 #include <asm/io.h> 17 #include <stdio_dev.h> 18 #include <video_fb.h> 19 #include "../common/ngpixis.h" 20 #include <fsl_diu_fb.h> 21 22 /* The CTL register is called 'csr' in the ngpixis_t structure */ 23 #define PX_CTL_ALTACC 0x80 24 25 #define PX_BRDCFG0_ELBC_SPI_MASK 0xc0 26 #define PX_BRDCFG0_ELBC_SPI_ELBC 0x00 27 #define PX_BRDCFG0_ELBC_SPI_NULL 0xc0 28 #define PX_BRDCFG0_ELBC_DIU 0x02 29 30 #define PX_BRDCFG1_DVIEN 0x80 31 #define PX_BRDCFG1_DFPEN 0x40 32 #define PX_BRDCFG1_BACKLIGHT 0x20 33 34 #define PMUXCR_ELBCDIU_MASK 0xc0000000 35 #define PMUXCR_ELBCDIU_NOR16 0x80000000 36 #define PMUXCR_ELBCDIU_DIU 0x40000000 37 38 /* 39 * DIU Area Descriptor 40 * 41 * Note that we need to byte-swap the value before it's written to the AD 42 * register. So even though the registers don't look like they're in the same 43 * bit positions as they are on the MPC8610, the same value is written to the 44 * AD register on the MPC8610 and on the P1022. 45 */ 46 #define AD_BYTE_F 0x10000000 47 #define AD_ALPHA_C_SHIFT 25 48 #define AD_BLUE_C_SHIFT 23 49 #define AD_GREEN_C_SHIFT 21 50 #define AD_RED_C_SHIFT 19 51 #define AD_PIXEL_S_SHIFT 16 52 #define AD_COMP_3_SHIFT 12 53 #define AD_COMP_2_SHIFT 8 54 #define AD_COMP_1_SHIFT 4 55 #define AD_COMP_0_SHIFT 0 56 57 /* 58 * Variables used by the DIU/LBC switching code. It's safe to makes these 59 * global, because the DIU requires DDR, so we'll only run this code after 60 * relocation. 61 */ 62 static u8 px_brdcfg0; 63 static u32 pmuxcr; 64 static void *lbc_lcs0_ba; 65 static void *lbc_lcs1_ba; 66 67 void diu_set_pixel_clock(unsigned int pixclock) 68 { 69 ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); 70 unsigned long speed_ccb, temp; 71 u32 pixval; 72 73 speed_ccb = get_bus_freq(0); 74 temp = 1000000000 / pixclock; 75 temp *= 1000; 76 pixval = speed_ccb / temp; 77 debug("DIU pixval = %lu\n", pixval); 78 79 /* Modify PXCLK in GUTS CLKDVDR */ 80 temp = in_be32(&gur->clkdvdr) & 0x2000FFFF; 81 out_be32(&gur->clkdvdr, temp); /* turn off clock */ 82 out_be32(&gur->clkdvdr, temp | 0x80000000 | ((pixval & 0x1F) << 16)); 83 } 84 85 int platform_diu_init(unsigned int xres, unsigned int yres, const char *port) 86 { 87 ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); 88 const char *name; 89 u32 pixel_format; 90 u8 temp; 91 92 /* Save the LBC LCS0 and LCS1 addresses for the DIU mux functions */ 93 lbc_lcs0_ba = (void *)(get_lbc_br(0) & get_lbc_or(0) & 0xFFFF8000); 94 lbc_lcs1_ba = (void *)(get_lbc_br(1) & get_lbc_or(1) & 0xFFFF8000); 95 96 pixel_format = cpu_to_le32(AD_BYTE_F | (3 << AD_ALPHA_C_SHIFT) | 97 (0 << AD_BLUE_C_SHIFT) | (1 << AD_GREEN_C_SHIFT) | 98 (2 << AD_RED_C_SHIFT) | (8 << AD_COMP_3_SHIFT) | 99 (8 << AD_COMP_2_SHIFT) | (8 << AD_COMP_1_SHIFT) | 100 (8 << AD_COMP_0_SHIFT) | (3 << AD_PIXEL_S_SHIFT)); 101 102 temp = in_8(&pixis->brdcfg1); 103 104 if (strncmp(port, "lvds", 4) == 0) { 105 /* Single link LVDS */ 106 temp &= ~PX_BRDCFG1_DVIEN; 107 /* 108 * LVDS also needs backlight enabled, otherwise the display 109 * will be blank. 110 */ 111 temp |= (PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT); 112 name = "Single-Link LVDS"; 113 } else { /* DVI */ 114 /* Enable the DVI port, disable the DFP and the backlight */ 115 temp &= ~(PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT); 116 temp |= PX_BRDCFG1_DVIEN; 117 name = "DVI"; 118 } 119 120 printf("DIU: Switching to %s monitor @ %ux%u\n", name, xres, yres); 121 out_8(&pixis->brdcfg1, temp); 122 123 /* 124 * Enable PIXIS indirect access mode. This is a hack that allows us to 125 * access PIXIS registers even when the LBC pins have been muxed to the 126 * DIU. 127 */ 128 setbits_8(&pixis->csr, PX_CTL_ALTACC); 129 130 /* 131 * Route the LAD pins to the DIU. This will disable access to the eLBC, 132 * which means we won't be able to read/write any NOR flash addresses! 133 */ 134 out_8(lbc_lcs0_ba, offsetof(ngpixis_t, brdcfg0)); 135 px_brdcfg0 = in_8(lbc_lcs1_ba); 136 out_8(lbc_lcs1_ba, px_brdcfg0 | PX_BRDCFG0_ELBC_DIU); 137 138 /* Set PMUXCR to switch the muxed pins from the LBC to the DIU */ 139 clrsetbits_be32(&gur->pmuxcr, PMUXCR_ELBCDIU_MASK, PMUXCR_ELBCDIU_DIU); 140 pmuxcr = in_be32(&gur->pmuxcr); 141 142 return fsl_diu_init(xres, pixel_format, 0); 143 } 144 145 /* 146 * set_mux_to_lbc - disable the DIU so that we can read/write to elbc 147 * 148 * On the Freescale P1022, the DIU video signal and the LBC address/data lines 149 * share the same pins, which means that when the DIU is active (e.g. the 150 * console is on the DVI display), NOR flash cannot be accessed. So we use the 151 * weak accessor feature of the CFI flash code to temporarily switch the pin 152 * mux from DIU to LBC whenever we want to read or write flash. This has a 153 * significant performance penalty, but it's the only way to make it work. 154 * 155 * There are two muxes: one on the chip, and one on the board. The chip mux 156 * controls whether the pins are used for the DIU or the LBC, and it is 157 * set via PMUXCR. The board mux controls whether those signals go to 158 * the video connector or the NOR flash chips, and it is set via the ngPIXIS. 159 */ 160 static int set_mux_to_lbc(void) 161 { 162 ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR; 163 164 /* Switch the muxes only if they're currently set to DIU mode */ 165 if ((in_be32(&gur->pmuxcr) & PMUXCR_ELBCDIU_MASK) != 166 PMUXCR_ELBCDIU_NOR16) { 167 /* 168 * In DIU mode, the PIXIS can only be accessed indirectly 169 * since we can't read/write the LBC directly. 170 */ 171 172 /* Set the board mux to LBC. This will disable the display. */ 173 out_8(lbc_lcs0_ba, offsetof(ngpixis_t, brdcfg0)); 174 px_brdcfg0 = in_8(lbc_lcs1_ba); 175 out_8(lbc_lcs1_ba, (px_brdcfg0 & ~(PX_BRDCFG0_ELBC_SPI_MASK 176 | PX_BRDCFG0_ELBC_DIU)) | PX_BRDCFG0_ELBC_SPI_ELBC); 177 178 /* Disable indirect PIXIS mode */ 179 out_8(lbc_lcs0_ba, offsetof(ngpixis_t, csr)); 180 clrbits_8(lbc_lcs1_ba, PX_CTL_ALTACC); 181 182 /* Set the chip mux to LBC mode, so that writes go to flash. */ 183 out_be32(&gur->pmuxcr, (pmuxcr & ~PMUXCR_ELBCDIU_MASK) | 184 PMUXCR_ELBCDIU_NOR16); 185 in_be32(&gur->pmuxcr); 186 187 return 1; 188 } 189 190 return 0; 191 } 192 193 /* 194 * set_mux_to_diu - re-enable the DIU muxing 195 * 196 * This function restores the chip and board muxing to point to the DIU. 197 */ 198 static void set_mux_to_diu(void) 199 { 200 ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR; 201 202 /* Enable indirect PIXIS mode */ 203 setbits_8(&pixis->csr, PX_CTL_ALTACC); 204 205 /* Set the board mux to DIU. This will enable the display. */ 206 out_8(lbc_lcs0_ba, offsetof(ngpixis_t, brdcfg0)); 207 out_8(lbc_lcs1_ba, px_brdcfg0); 208 in_8(lbc_lcs1_ba); 209 210 /* Set the chip mux to DIU mode. */ 211 out_be32(&gur->pmuxcr, pmuxcr); 212 in_be32(&gur->pmuxcr); 213 } 214 215 /* 216 * pixis_read - board-specific function to read from the PIXIS 217 * 218 * This function overrides the generic pixis_read() function, so that it can 219 * use PIXIS indirect mode if necessary. 220 */ 221 u8 pixis_read(unsigned int reg) 222 { 223 ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR; 224 225 /* Use indirect mode if the mux is currently set to DIU mode */ 226 if ((in_be32(&gur->pmuxcr) & PMUXCR_ELBCDIU_MASK) != 227 PMUXCR_ELBCDIU_NOR16) { 228 out_8(lbc_lcs0_ba, reg); 229 return in_8(lbc_lcs1_ba); 230 } else { 231 void *p = (void *)PIXIS_BASE; 232 233 return in_8(p + reg); 234 } 235 } 236 237 /* 238 * pixis_write - board-specific function to write to the PIXIS 239 * 240 * This function overrides the generic pixis_write() function, so that it can 241 * use PIXIS indirect mode if necessary. 242 */ 243 void pixis_write(unsigned int reg, u8 value) 244 { 245 ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR; 246 247 /* Use indirect mode if the mux is currently set to DIU mode */ 248 if ((in_be32(&gur->pmuxcr) & PMUXCR_ELBCDIU_MASK) != 249 PMUXCR_ELBCDIU_NOR16) { 250 out_8(lbc_lcs0_ba, reg); 251 out_8(lbc_lcs1_ba, value); 252 /* Do a read-back to ensure the write completed */ 253 in_8(lbc_lcs1_ba); 254 } else { 255 void *p = (void *)PIXIS_BASE; 256 257 out_8(p + reg, value); 258 } 259 } 260 261 void pixis_bank_reset(void) 262 { 263 /* 264 * For some reason, a PIXIS bank reset does not work if the PIXIS is 265 * in indirect mode, so switch to direct mode first. 266 */ 267 set_mux_to_lbc(); 268 269 out_8(&pixis->vctl, 0); 270 out_8(&pixis->vctl, 1); 271 272 while (1); 273 } 274 275 #ifdef CONFIG_CFI_FLASH_USE_WEAK_ACCESSORS 276 277 void flash_write8(u8 value, void *addr) 278 { 279 int sw = set_mux_to_lbc(); 280 281 __raw_writeb(value, addr); 282 if (sw) { 283 /* 284 * To ensure the post-write is completed to eLBC, software must 285 * perform a dummy read from one valid address from eLBC space 286 * before changing the eLBC_DIU from NOR mode to DIU mode. 287 * set_mux_to_diu() includes a sync that will ensure the 288 * __raw_readb() completes before it switches the mux. 289 */ 290 __raw_readb(addr); 291 set_mux_to_diu(); 292 } 293 } 294 295 void flash_write16(u16 value, void *addr) 296 { 297 int sw = set_mux_to_lbc(); 298 299 __raw_writew(value, addr); 300 if (sw) { 301 /* 302 * To ensure the post-write is completed to eLBC, software must 303 * perform a dummy read from one valid address from eLBC space 304 * before changing the eLBC_DIU from NOR mode to DIU mode. 305 * set_mux_to_diu() includes a sync that will ensure the 306 * __raw_readb() completes before it switches the mux. 307 */ 308 __raw_readb(addr); 309 set_mux_to_diu(); 310 } 311 } 312 313 void flash_write32(u32 value, void *addr) 314 { 315 int sw = set_mux_to_lbc(); 316 317 __raw_writel(value, addr); 318 if (sw) { 319 /* 320 * To ensure the post-write is completed to eLBC, software must 321 * perform a dummy read from one valid address from eLBC space 322 * before changing the eLBC_DIU from NOR mode to DIU mode. 323 * set_mux_to_diu() includes a sync that will ensure the 324 * __raw_readb() completes before it switches the mux. 325 */ 326 __raw_readb(addr); 327 set_mux_to_diu(); 328 } 329 } 330 331 void flash_write64(u64 value, void *addr) 332 { 333 int sw = set_mux_to_lbc(); 334 uint32_t *p = addr; 335 336 /* 337 * There is no __raw_writeq(), so do the write manually. We don't trust 338 * the compiler, so we use inline assembly. 339 */ 340 __asm__ __volatile__( 341 "stw%U0%X0 %2,%0;\n" 342 "stw%U1%X1 %3,%1;\n" 343 : "=m" (*p), "=m" (*(p + 1)) 344 : "r" ((uint32_t) (value >> 32)), "r" ((uint32_t) (value))); 345 346 if (sw) { 347 /* 348 * To ensure the post-write is completed to eLBC, software must 349 * perform a dummy read from one valid address from eLBC space 350 * before changing the eLBC_DIU from NOR mode to DIU mode. We 351 * read addr+4 because we just wrote to addr+4, so that's how we 352 * maintain execution order. set_mux_to_diu() includes a sync 353 * that will ensure the __raw_readb() completes before it 354 * switches the mux. 355 */ 356 __raw_readb(addr + 4); 357 set_mux_to_diu(); 358 } 359 } 360 361 u8 flash_read8(void *addr) 362 { 363 u8 ret; 364 365 int sw = set_mux_to_lbc(); 366 367 ret = __raw_readb(addr); 368 if (sw) 369 set_mux_to_diu(); 370 371 return ret; 372 } 373 374 u16 flash_read16(void *addr) 375 { 376 u16 ret; 377 378 int sw = set_mux_to_lbc(); 379 380 ret = __raw_readw(addr); 381 if (sw) 382 set_mux_to_diu(); 383 384 return ret; 385 } 386 387 u32 flash_read32(void *addr) 388 { 389 u32 ret; 390 391 int sw = set_mux_to_lbc(); 392 393 ret = __raw_readl(addr); 394 if (sw) 395 set_mux_to_diu(); 396 397 return ret; 398 } 399 400 u64 flash_read64(void *addr) 401 { 402 u64 ret; 403 404 int sw = set_mux_to_lbc(); 405 406 /* There is no __raw_readq(), so do the read manually */ 407 ret = *(volatile u64 *)addr; 408 if (sw) 409 set_mux_to_diu(); 410 411 return ret; 412 } 413 414 #endif 415