1 /* 2 * P1022DS board specific routines 3 * 4 * Authors: Travis Wheatley <travis.wheatley@freescale.com> 5 * Dave Liu <daveliu@freescale.com> 6 * Timur Tabi <timur@freescale.com> 7 * 8 * Copyright 2010 Freescale Semiconductor, Inc. 9 * 10 * This file is taken from the Freescale P1022DS BSP, with modifications: 11 * 2) No AMP support 12 * 3) No PCI endpoint support 13 * 14 * This file is licensed under the terms of the GNU General Public License 15 * version 2. This program is licensed "as is" without any warranty of any 16 * kind, whether express or implied. 17 */ 18 19 #include <linux/pci.h> 20 #include <linux/of_platform.h> 21 #include <linux/memblock.h> 22 #include <asm/div64.h> 23 #include <asm/mpic.h> 24 #include <asm/swiotlb.h> 25 26 #include <sysdev/fsl_soc.h> 27 #include <sysdev/fsl_pci.h> 28 #include <asm/udbg.h> 29 #include <asm/fsl_guts.h> 30 #include "smp.h" 31 32 #include "mpc85xx.h" 33 34 #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) 35 36 #define PMUXCR_ELBCDIU_MASK 0xc0000000 37 #define PMUXCR_ELBCDIU_NOR16 0x80000000 38 #define PMUXCR_ELBCDIU_DIU 0x40000000 39 40 /* 41 * Board-specific initialization of the DIU. This code should probably be 42 * executed when the DIU is opened, rather than in arch code, but the DIU 43 * driver does not have a mechanism for this (yet). 44 * 45 * This is especially problematic on the P1022DS because the local bus (eLBC) 46 * and the DIU video signals share the same pins, which means that enabling the 47 * DIU will disable access to NOR flash. 48 */ 49 50 /* DIU Pixel Clock bits of the CLKDVDR Global Utilities register */ 51 #define CLKDVDR_PXCKEN 0x80000000 52 #define CLKDVDR_PXCKINV 0x10000000 53 #define CLKDVDR_PXCKDLY 0x06000000 54 #define CLKDVDR_PXCLK_MASK 0x00FF0000 55 56 /* Some ngPIXIS register definitions */ 57 #define PX_CTL 3 58 #define PX_BRDCFG0 8 59 #define PX_BRDCFG1 9 60 61 #define PX_BRDCFG0_ELBC_SPI_MASK 0xc0 62 #define PX_BRDCFG0_ELBC_SPI_ELBC 0x00 63 #define PX_BRDCFG0_ELBC_SPI_NULL 0xc0 64 #define PX_BRDCFG0_ELBC_DIU 0x02 65 66 #define PX_BRDCFG1_DVIEN 0x80 67 #define PX_BRDCFG1_DFPEN 0x40 68 #define PX_BRDCFG1_BACKLIGHT 0x20 69 #define PX_BRDCFG1_DDCEN 0x10 70 71 #define PX_CTL_ALTACC 0x80 72 73 /* 74 * DIU Area Descriptor 75 * 76 * Note that we need to byte-swap the value before it's written to the AD 77 * register. So even though the registers don't look like they're in the same 78 * bit positions as they are on the MPC8610, the same value is written to the 79 * AD register on the MPC8610 and on the P1022. 80 */ 81 #define AD_BYTE_F 0x10000000 82 #define AD_ALPHA_C_MASK 0x0E000000 83 #define AD_ALPHA_C_SHIFT 25 84 #define AD_BLUE_C_MASK 0x01800000 85 #define AD_BLUE_C_SHIFT 23 86 #define AD_GREEN_C_MASK 0x00600000 87 #define AD_GREEN_C_SHIFT 21 88 #define AD_RED_C_MASK 0x00180000 89 #define AD_RED_C_SHIFT 19 90 #define AD_PALETTE 0x00040000 91 #define AD_PIXEL_S_MASK 0x00030000 92 #define AD_PIXEL_S_SHIFT 16 93 #define AD_COMP_3_MASK 0x0000F000 94 #define AD_COMP_3_SHIFT 12 95 #define AD_COMP_2_MASK 0x00000F00 96 #define AD_COMP_2_SHIFT 8 97 #define AD_COMP_1_MASK 0x000000F0 98 #define AD_COMP_1_SHIFT 4 99 #define AD_COMP_0_MASK 0x0000000F 100 #define AD_COMP_0_SHIFT 0 101 102 #define MAKE_AD(alpha, red, blue, green, size, c0, c1, c2, c3) \ 103 cpu_to_le32(AD_BYTE_F | (alpha << AD_ALPHA_C_SHIFT) | \ 104 (blue << AD_BLUE_C_SHIFT) | (green << AD_GREEN_C_SHIFT) | \ 105 (red << AD_RED_C_SHIFT) | (c3 << AD_COMP_3_SHIFT) | \ 106 (c2 << AD_COMP_2_SHIFT) | (c1 << AD_COMP_1_SHIFT) | \ 107 (c0 << AD_COMP_0_SHIFT) | (size << AD_PIXEL_S_SHIFT)) 108 109 /** 110 * p1022ds_get_pixel_format: return the Area Descriptor for a given pixel depth 111 * 112 * The Area Descriptor is a 32-bit value that determine which bits in each 113 * pixel are to be used for each color. 114 */ 115 static u32 p1022ds_get_pixel_format(enum fsl_diu_monitor_port port, 116 unsigned int bits_per_pixel) 117 { 118 switch (bits_per_pixel) { 119 case 32: 120 /* 0x88883316 */ 121 return MAKE_AD(3, 2, 0, 1, 3, 8, 8, 8, 8); 122 case 24: 123 /* 0x88082219 */ 124 return MAKE_AD(4, 0, 1, 2, 2, 0, 8, 8, 8); 125 case 16: 126 /* 0x65053118 */ 127 return MAKE_AD(4, 2, 1, 0, 1, 5, 6, 5, 0); 128 default: 129 pr_err("fsl-diu: unsupported pixel depth %u\n", bits_per_pixel); 130 return 0; 131 } 132 } 133 134 /** 135 * p1022ds_set_gamma_table: update the gamma table, if necessary 136 * 137 * On some boards, the gamma table for some ports may need to be modified. 138 * This is not the case on the P1022DS, so we do nothing. 139 */ 140 static void p1022ds_set_gamma_table(enum fsl_diu_monitor_port port, 141 char *gamma_table_base) 142 { 143 } 144 145 /** 146 * p1022ds_set_monitor_port: switch the output to a different monitor port 147 * 148 */ 149 static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port) 150 { 151 struct device_node *guts_node; 152 struct device_node *indirect_node = NULL; 153 struct ccsr_guts __iomem *guts; 154 u8 __iomem *lbc_lcs0_ba = NULL; 155 u8 __iomem *lbc_lcs1_ba = NULL; 156 u8 b; 157 158 /* Map the global utilities registers. */ 159 guts_node = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts"); 160 if (!guts_node) { 161 pr_err("p1022ds: missing global utilties device node\n"); 162 return; 163 } 164 165 guts = of_iomap(guts_node, 0); 166 if (!guts) { 167 pr_err("p1022ds: could not map global utilties device\n"); 168 goto exit; 169 } 170 171 indirect_node = of_find_compatible_node(NULL, NULL, 172 "fsl,p1022ds-indirect-pixis"); 173 if (!indirect_node) { 174 pr_err("p1022ds: missing pixis indirect mode node\n"); 175 goto exit; 176 } 177 178 lbc_lcs0_ba = of_iomap(indirect_node, 0); 179 if (!lbc_lcs0_ba) { 180 pr_err("p1022ds: could not map localbus chip select 0\n"); 181 goto exit; 182 } 183 184 lbc_lcs1_ba = of_iomap(indirect_node, 1); 185 if (!lbc_lcs1_ba) { 186 pr_err("p1022ds: could not map localbus chip select 1\n"); 187 goto exit; 188 } 189 190 /* Make sure we're in indirect mode first. */ 191 if ((in_be32(&guts->pmuxcr) & PMUXCR_ELBCDIU_MASK) != 192 PMUXCR_ELBCDIU_DIU) { 193 struct device_node *pixis_node; 194 void __iomem *pixis; 195 196 pixis_node = 197 of_find_compatible_node(NULL, NULL, "fsl,p1022ds-fpga"); 198 if (!pixis_node) { 199 pr_err("p1022ds: missing pixis node\n"); 200 goto exit; 201 } 202 203 pixis = of_iomap(pixis_node, 0); 204 of_node_put(pixis_node); 205 if (!pixis) { 206 pr_err("p1022ds: could not map pixis registers\n"); 207 goto exit; 208 } 209 210 /* Enable indirect PIXIS mode. */ 211 setbits8(pixis + PX_CTL, PX_CTL_ALTACC); 212 iounmap(pixis); 213 214 /* Switch the board mux to the DIU */ 215 out_8(lbc_lcs0_ba, PX_BRDCFG0); /* BRDCFG0 */ 216 b = in_8(lbc_lcs1_ba); 217 b |= PX_BRDCFG0_ELBC_DIU; 218 out_8(lbc_lcs1_ba, b); 219 220 /* Set the chip mux to DIU mode. */ 221 clrsetbits_be32(&guts->pmuxcr, PMUXCR_ELBCDIU_MASK, 222 PMUXCR_ELBCDIU_DIU); 223 in_be32(&guts->pmuxcr); 224 } 225 226 227 switch (port) { 228 case FSL_DIU_PORT_DVI: 229 /* Enable the DVI port, disable the DFP and the backlight */ 230 out_8(lbc_lcs0_ba, PX_BRDCFG1); 231 b = in_8(lbc_lcs1_ba); 232 b &= ~(PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT); 233 b |= PX_BRDCFG1_DVIEN; 234 out_8(lbc_lcs1_ba, b); 235 break; 236 case FSL_DIU_PORT_LVDS: 237 /* 238 * LVDS also needs backlight enabled, otherwise the display 239 * will be blank. 240 */ 241 /* Enable the DFP port, disable the DVI and the backlight */ 242 out_8(lbc_lcs0_ba, PX_BRDCFG1); 243 b = in_8(lbc_lcs1_ba); 244 b &= ~PX_BRDCFG1_DVIEN; 245 b |= PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT; 246 out_8(lbc_lcs1_ba, b); 247 break; 248 default: 249 pr_err("p1022ds: unsupported monitor port %i\n", port); 250 } 251 252 exit: 253 if (lbc_lcs1_ba) 254 iounmap(lbc_lcs1_ba); 255 if (lbc_lcs0_ba) 256 iounmap(lbc_lcs0_ba); 257 if (guts) 258 iounmap(guts); 259 260 of_node_put(indirect_node); 261 of_node_put(guts_node); 262 } 263 264 /** 265 * p1022ds_set_pixel_clock: program the DIU's clock 266 * 267 * @pixclock: the wavelength, in picoseconds, of the clock 268 */ 269 void p1022ds_set_pixel_clock(unsigned int pixclock) 270 { 271 struct device_node *guts_np = NULL; 272 struct ccsr_guts __iomem *guts; 273 unsigned long freq; 274 u64 temp; 275 u32 pxclk; 276 277 /* Map the global utilities registers. */ 278 guts_np = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts"); 279 if (!guts_np) { 280 pr_err("p1022ds: missing global utilties device node\n"); 281 return; 282 } 283 284 guts = of_iomap(guts_np, 0); 285 of_node_put(guts_np); 286 if (!guts) { 287 pr_err("p1022ds: could not map global utilties device\n"); 288 return; 289 } 290 291 /* Convert pixclock from a wavelength to a frequency */ 292 temp = 1000000000000ULL; 293 do_div(temp, pixclock); 294 freq = temp; 295 296 /* 297 * 'pxclk' is the ratio of the platform clock to the pixel clock. 298 * This number is programmed into the CLKDVDR register, and the valid 299 * range of values is 2-255. 300 */ 301 pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq); 302 pxclk = clamp_t(u32, pxclk, 2, 255); 303 304 /* Disable the pixel clock, and set it to non-inverted and no delay */ 305 clrbits32(&guts->clkdvdr, 306 CLKDVDR_PXCKEN | CLKDVDR_PXCKDLY | CLKDVDR_PXCLK_MASK); 307 308 /* Enable the clock and set the pxclk */ 309 setbits32(&guts->clkdvdr, CLKDVDR_PXCKEN | (pxclk << 16)); 310 311 iounmap(guts); 312 } 313 314 /** 315 * p1022ds_valid_monitor_port: set the monitor port for sysfs 316 */ 317 enum fsl_diu_monitor_port 318 p1022ds_valid_monitor_port(enum fsl_diu_monitor_port port) 319 { 320 switch (port) { 321 case FSL_DIU_PORT_DVI: 322 case FSL_DIU_PORT_LVDS: 323 return port; 324 default: 325 return FSL_DIU_PORT_DVI; /* Dual-link LVDS is not supported */ 326 } 327 } 328 329 #endif 330 331 void __init p1022_ds_pic_init(void) 332 { 333 struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | 334 MPIC_SINGLE_DEST_CPU, 335 0, 256, " OpenPIC "); 336 BUG_ON(mpic == NULL); 337 mpic_init(mpic); 338 } 339 340 #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) 341 342 /* 343 * Disables a node in the device tree. 344 * 345 * This function is called before kmalloc() is available, so the 'new' object 346 * should be allocated in the global area. The easiest way is to do that is 347 * to allocate one static local variable for each call to this function. 348 */ 349 static void __init disable_one_node(struct device_node *np, struct property *new) 350 { 351 struct property *old; 352 353 old = of_find_property(np, new->name, NULL); 354 if (old) 355 prom_update_property(np, new, old); 356 else 357 prom_add_property(np, new); 358 } 359 360 /* TRUE if there is a "video=fslfb" command-line parameter. */ 361 static bool fslfb; 362 363 /* 364 * Search for a "video=fslfb" command-line parameter, and set 'fslfb' to 365 * true if we find it. 366 * 367 * We need to use early_param() instead of __setup() because the normal 368 * __setup() gets called to late. However, early_param() gets called very 369 * early, before the device tree is unflattened, so all we can do now is set a 370 * global variable. Later on, p1022_ds_setup_arch() will use that variable 371 * to determine if we need to update the device tree. 372 */ 373 static int __init early_video_setup(char *options) 374 { 375 fslfb = (strncmp(options, "fslfb:", 6) == 0); 376 377 return 0; 378 } 379 early_param("video", early_video_setup); 380 381 #endif 382 383 /* 384 * Setup the architecture 385 */ 386 static void __init p1022_ds_setup_arch(void) 387 { 388 #ifdef CONFIG_PCI 389 struct device_node *np; 390 #endif 391 dma_addr_t max = 0xffffffff; 392 393 if (ppc_md.progress) 394 ppc_md.progress("p1022_ds_setup_arch()", 0); 395 396 #ifdef CONFIG_PCI 397 for_each_compatible_node(np, "pci", "fsl,p1022-pcie") { 398 struct resource rsrc; 399 struct pci_controller *hose; 400 401 of_address_to_resource(np, 0, &rsrc); 402 403 if ((rsrc.start & 0xfffff) == 0x8000) 404 fsl_add_bridge(np, 1); 405 else 406 fsl_add_bridge(np, 0); 407 408 hose = pci_find_hose_for_OF_device(np); 409 max = min(max, hose->dma_window_base_cur + 410 hose->dma_window_size); 411 } 412 #endif 413 414 #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) 415 diu_ops.get_pixel_format = p1022ds_get_pixel_format; 416 diu_ops.set_gamma_table = p1022ds_set_gamma_table; 417 diu_ops.set_monitor_port = p1022ds_set_monitor_port; 418 diu_ops.set_pixel_clock = p1022ds_set_pixel_clock; 419 diu_ops.valid_monitor_port = p1022ds_valid_monitor_port; 420 421 /* 422 * Disable the NOR flash node if there is video=fslfb... command-line 423 * parameter. When the DIU is active, NOR flash is unavailable, so we 424 * have to disable the node before the MTD driver loads. 425 */ 426 if (fslfb) { 427 struct device_node *np = 428 of_find_compatible_node(NULL, NULL, "fsl,p1022-elbc"); 429 430 if (np) { 431 np = of_find_compatible_node(np, NULL, "cfi-flash"); 432 if (np) { 433 static struct property nor_status = { 434 .name = "status", 435 .value = "disabled", 436 .length = sizeof("disabled"), 437 }; 438 439 pr_info("p1022ds: disabling %s node", 440 np->full_name); 441 disable_one_node(np, &nor_status); 442 of_node_put(np); 443 } 444 } 445 446 } 447 448 #endif 449 450 mpc85xx_smp_init(); 451 452 #ifdef CONFIG_SWIOTLB 453 if (memblock_end_of_DRAM() > max) { 454 ppc_swiotlb_enable = 1; 455 set_pci_dma_ops(&swiotlb_dma_ops); 456 ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb; 457 } 458 #endif 459 460 pr_info("Freescale P1022 DS reference board\n"); 461 } 462 463 machine_device_initcall(p1022_ds, mpc85xx_common_publish_devices); 464 465 machine_arch_initcall(p1022_ds, swiotlb_setup_bus_notifier); 466 467 /* 468 * Called very early, device-tree isn't unflattened 469 */ 470 static int __init p1022_ds_probe(void) 471 { 472 unsigned long root = of_get_flat_dt_root(); 473 474 return of_flat_dt_is_compatible(root, "fsl,p1022ds"); 475 } 476 477 define_machine(p1022_ds) { 478 .name = "P1022 DS", 479 .probe = p1022_ds_probe, 480 .setup_arch = p1022_ds_setup_arch, 481 .init_IRQ = p1022_ds_pic_init, 482 #ifdef CONFIG_PCI 483 .pcibios_fixup_bus = fsl_pcibios_fixup_bus, 484 #endif 485 .get_irq = mpic_get_irq, 486 .restart = fsl_rstcr_restart, 487 .calibrate_decr = generic_calibrate_decr, 488 .progress = udbg_progress, 489 }; 490