130be4c96STimur Tabi /* 230be4c96STimur Tabi * P1022DS board specific routines 330be4c96STimur Tabi * 430be4c96STimur Tabi * Authors: Travis Wheatley <travis.wheatley@freescale.com> 530be4c96STimur Tabi * Dave Liu <daveliu@freescale.com> 630be4c96STimur Tabi * Timur Tabi <timur@freescale.com> 730be4c96STimur Tabi * 830be4c96STimur Tabi * Copyright 2010 Freescale Semiconductor, Inc. 930be4c96STimur Tabi * 1030be4c96STimur Tabi * This file is taken from the Freescale P1022DS BSP, with modifications: 1130be4c96STimur Tabi * 2) No AMP support 1230be4c96STimur Tabi * 3) No PCI endpoint support 1330be4c96STimur Tabi * 1430be4c96STimur Tabi * This file is licensed under the terms of the GNU General Public License 1530be4c96STimur Tabi * version 2. This program is licensed "as is" without any warranty of any 1630be4c96STimur Tabi * kind, whether express or implied. 1730be4c96STimur Tabi */ 1830be4c96STimur Tabi 1930be4c96STimur Tabi #include <linux/pci.h> 2030be4c96STimur Tabi #include <linux/of_platform.h> 212c184cd3STimur Tabi #include <asm/div64.h> 2230be4c96STimur Tabi #include <asm/mpic.h> 2330be4c96STimur Tabi #include <asm/swiotlb.h> 2430be4c96STimur Tabi 2530be4c96STimur Tabi #include <sysdev/fsl_soc.h> 2630be4c96STimur Tabi #include <sysdev/fsl_pci.h> 27ba8438fbSMichael Neuling #include <asm/udbg.h> 282c184cd3STimur Tabi #include <asm/fsl_guts.h> 296bd825f0STimur Tabi #include <asm/fsl_lbc.h> 30582d3e09SKyle Moffett #include "smp.h" 312c184cd3STimur Tabi 32543a07b1SDmitry Eremin-Solenikov #include "mpc85xx.h" 33543a07b1SDmitry Eremin-Solenikov 342c184cd3STimur Tabi #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) 352c184cd3STimur Tabi 366597c713STimur Tabi #define PMUXCR_ELBCDIU_MASK 0xc0000000 376597c713STimur Tabi #define PMUXCR_ELBCDIU_NOR16 0x80000000 386597c713STimur Tabi #define PMUXCR_ELBCDIU_DIU 0x40000000 396597c713STimur Tabi 402c184cd3STimur Tabi /* 412c184cd3STimur Tabi * Board-specific initialization of the DIU. This code should probably be 422c184cd3STimur Tabi * executed when the DIU is opened, rather than in arch code, but the DIU 432c184cd3STimur Tabi * driver does not have a mechanism for this (yet). 442c184cd3STimur Tabi * 452c184cd3STimur Tabi * This is especially problematic on the P1022DS because the local bus (eLBC) 462c184cd3STimur Tabi * and the DIU video signals share the same pins, which means that enabling the 472c184cd3STimur Tabi * DIU will disable access to NOR flash. 482c184cd3STimur Tabi */ 492c184cd3STimur Tabi 502c184cd3STimur Tabi /* DIU Pixel Clock bits of the CLKDVDR Global Utilities register */ 512c184cd3STimur Tabi #define CLKDVDR_PXCKEN 0x80000000 522c184cd3STimur Tabi #define CLKDVDR_PXCKINV 0x10000000 532c184cd3STimur Tabi #define CLKDVDR_PXCKDLY 0x06000000 542c184cd3STimur Tabi #define CLKDVDR_PXCLK_MASK 0x00FF0000 552c184cd3STimur Tabi 562c184cd3STimur Tabi /* Some ngPIXIS register definitions */ 576597c713STimur Tabi #define PX_CTL 3 586597c713STimur Tabi #define PX_BRDCFG0 8 596597c713STimur Tabi #define PX_BRDCFG1 9 606597c713STimur Tabi 616597c713STimur Tabi #define PX_BRDCFG0_ELBC_SPI_MASK 0xc0 626597c713STimur Tabi #define PX_BRDCFG0_ELBC_SPI_ELBC 0x00 636597c713STimur Tabi #define PX_BRDCFG0_ELBC_SPI_NULL 0xc0 646597c713STimur Tabi #define PX_BRDCFG0_ELBC_DIU 0x02 656597c713STimur Tabi 662c184cd3STimur Tabi #define PX_BRDCFG1_DVIEN 0x80 672c184cd3STimur Tabi #define PX_BRDCFG1_DFPEN 0x40 682c184cd3STimur Tabi #define PX_BRDCFG1_BACKLIGHT 0x20 692c184cd3STimur Tabi #define PX_BRDCFG1_DDCEN 0x10 702c184cd3STimur Tabi 716597c713STimur Tabi #define PX_CTL_ALTACC 0x80 726597c713STimur Tabi 732c184cd3STimur Tabi /* 742c184cd3STimur Tabi * DIU Area Descriptor 752c184cd3STimur Tabi * 762c184cd3STimur Tabi * Note that we need to byte-swap the value before it's written to the AD 772c184cd3STimur Tabi * register. So even though the registers don't look like they're in the same 782c184cd3STimur Tabi * bit positions as they are on the MPC8610, the same value is written to the 792c184cd3STimur Tabi * AD register on the MPC8610 and on the P1022. 802c184cd3STimur Tabi */ 812c184cd3STimur Tabi #define AD_BYTE_F 0x10000000 822c184cd3STimur Tabi #define AD_ALPHA_C_MASK 0x0E000000 832c184cd3STimur Tabi #define AD_ALPHA_C_SHIFT 25 842c184cd3STimur Tabi #define AD_BLUE_C_MASK 0x01800000 852c184cd3STimur Tabi #define AD_BLUE_C_SHIFT 23 862c184cd3STimur Tabi #define AD_GREEN_C_MASK 0x00600000 872c184cd3STimur Tabi #define AD_GREEN_C_SHIFT 21 882c184cd3STimur Tabi #define AD_RED_C_MASK 0x00180000 892c184cd3STimur Tabi #define AD_RED_C_SHIFT 19 902c184cd3STimur Tabi #define AD_PALETTE 0x00040000 912c184cd3STimur Tabi #define AD_PIXEL_S_MASK 0x00030000 922c184cd3STimur Tabi #define AD_PIXEL_S_SHIFT 16 932c184cd3STimur Tabi #define AD_COMP_3_MASK 0x0000F000 942c184cd3STimur Tabi #define AD_COMP_3_SHIFT 12 952c184cd3STimur Tabi #define AD_COMP_2_MASK 0x00000F00 962c184cd3STimur Tabi #define AD_COMP_2_SHIFT 8 972c184cd3STimur Tabi #define AD_COMP_1_MASK 0x000000F0 982c184cd3STimur Tabi #define AD_COMP_1_SHIFT 4 992c184cd3STimur Tabi #define AD_COMP_0_MASK 0x0000000F 1002c184cd3STimur Tabi #define AD_COMP_0_SHIFT 0 1012c184cd3STimur Tabi 1022c184cd3STimur Tabi #define MAKE_AD(alpha, red, blue, green, size, c0, c1, c2, c3) \ 1032c184cd3STimur Tabi cpu_to_le32(AD_BYTE_F | (alpha << AD_ALPHA_C_SHIFT) | \ 1042c184cd3STimur Tabi (blue << AD_BLUE_C_SHIFT) | (green << AD_GREEN_C_SHIFT) | \ 1052c184cd3STimur Tabi (red << AD_RED_C_SHIFT) | (c3 << AD_COMP_3_SHIFT) | \ 1062c184cd3STimur Tabi (c2 << AD_COMP_2_SHIFT) | (c1 << AD_COMP_1_SHIFT) | \ 1072c184cd3STimur Tabi (c0 << AD_COMP_0_SHIFT) | (size << AD_PIXEL_S_SHIFT)) 1082c184cd3STimur Tabi 1092c184cd3STimur Tabi /** 1102c184cd3STimur Tabi * p1022ds_get_pixel_format: return the Area Descriptor for a given pixel depth 1112c184cd3STimur Tabi * 1122c184cd3STimur Tabi * The Area Descriptor is a 32-bit value that determine which bits in each 1132c184cd3STimur Tabi * pixel are to be used for each color. 1142c184cd3STimur Tabi */ 1157653aaabSTimur Tabi static u32 p1022ds_get_pixel_format(enum fsl_diu_monitor_port port, 1167653aaabSTimur Tabi unsigned int bits_per_pixel) 1172c184cd3STimur Tabi { 1182c184cd3STimur Tabi switch (bits_per_pixel) { 1192c184cd3STimur Tabi case 32: 1202c184cd3STimur Tabi /* 0x88883316 */ 1212c184cd3STimur Tabi return MAKE_AD(3, 2, 0, 1, 3, 8, 8, 8, 8); 1222c184cd3STimur Tabi case 24: 1232c184cd3STimur Tabi /* 0x88082219 */ 1242c184cd3STimur Tabi return MAKE_AD(4, 0, 1, 2, 2, 0, 8, 8, 8); 1252c184cd3STimur Tabi case 16: 1262c184cd3STimur Tabi /* 0x65053118 */ 1272c184cd3STimur Tabi return MAKE_AD(4, 2, 1, 0, 1, 5, 6, 5, 0); 1282c184cd3STimur Tabi default: 1292c184cd3STimur Tabi pr_err("fsl-diu: unsupported pixel depth %u\n", bits_per_pixel); 1302c184cd3STimur Tabi return 0; 1312c184cd3STimur Tabi } 1322c184cd3STimur Tabi } 1332c184cd3STimur Tabi 1342c184cd3STimur Tabi /** 1352c184cd3STimur Tabi * p1022ds_set_gamma_table: update the gamma table, if necessary 1362c184cd3STimur Tabi * 1372c184cd3STimur Tabi * On some boards, the gamma table for some ports may need to be modified. 1382c184cd3STimur Tabi * This is not the case on the P1022DS, so we do nothing. 1392c184cd3STimur Tabi */ 1407653aaabSTimur Tabi static void p1022ds_set_gamma_table(enum fsl_diu_monitor_port port, 1417653aaabSTimur Tabi char *gamma_table_base) 1422c184cd3STimur Tabi { 1432c184cd3STimur Tabi } 1442c184cd3STimur Tabi 1456bd825f0STimur Tabi struct fsl_law { 1466bd825f0STimur Tabi u32 lawbar; 1476bd825f0STimur Tabi u32 reserved1; 1486bd825f0STimur Tabi u32 lawar; 1496bd825f0STimur Tabi u32 reserved[5]; 1506bd825f0STimur Tabi }; 1516bd825f0STimur Tabi 1526bd825f0STimur Tabi #define LAWBAR_MASK 0x00F00000 1536bd825f0STimur Tabi #define LAWBAR_SHIFT 12 1546bd825f0STimur Tabi 1556bd825f0STimur Tabi #define LAWAR_EN 0x80000000 1566bd825f0STimur Tabi #define LAWAR_TGT_MASK 0x01F00000 1576bd825f0STimur Tabi #define LAW_TRGT_IF_LBC (0x04 << 20) 1586bd825f0STimur Tabi 1596bd825f0STimur Tabi #define LAWAR_MASK (LAWAR_EN | LAWAR_TGT_MASK) 1606bd825f0STimur Tabi #define LAWAR_MATCH (LAWAR_EN | LAW_TRGT_IF_LBC) 1616bd825f0STimur Tabi 1626bd825f0STimur Tabi #define BR_BA 0xFFFF8000 1636bd825f0STimur Tabi 1646bd825f0STimur Tabi /* 1656bd825f0STimur Tabi * Map a BRx value to a physical address 1666bd825f0STimur Tabi * 1676bd825f0STimur Tabi * The localbus BRx registers only store the lower 32 bits of the address. To 1686bd825f0STimur Tabi * obtain the upper four bits, we need to scan the LAW table. The entry which 1696bd825f0STimur Tabi * maps to the localbus will contain the upper four bits. 1706bd825f0STimur Tabi */ 1716bd825f0STimur Tabi static phys_addr_t lbc_br_to_phys(const void *ecm, unsigned int count, u32 br) 1726bd825f0STimur Tabi { 1736bd825f0STimur Tabi #ifndef CONFIG_PHYS_64BIT 1746bd825f0STimur Tabi /* 1756bd825f0STimur Tabi * If we only have 32-bit addressing, then the BRx address *is* the 1766bd825f0STimur Tabi * physical address. 1776bd825f0STimur Tabi */ 1786bd825f0STimur Tabi return br & BR_BA; 1796bd825f0STimur Tabi #else 1806bd825f0STimur Tabi const struct fsl_law *law = ecm + 0xc08; 1816bd825f0STimur Tabi unsigned int i; 1826bd825f0STimur Tabi 1836bd825f0STimur Tabi for (i = 0; i < count; i++) { 1846bd825f0STimur Tabi u64 lawbar = in_be32(&law[i].lawbar); 1856bd825f0STimur Tabi u32 lawar = in_be32(&law[i].lawar); 1866bd825f0STimur Tabi 1876bd825f0STimur Tabi if ((lawar & LAWAR_MASK) == LAWAR_MATCH) 1886bd825f0STimur Tabi /* Extract the upper four bits */ 1896bd825f0STimur Tabi return (br & BR_BA) | ((lawbar & LAWBAR_MASK) << 12); 1906bd825f0STimur Tabi } 1916bd825f0STimur Tabi 1926bd825f0STimur Tabi return 0; 1936bd825f0STimur Tabi #endif 1946bd825f0STimur Tabi } 1956bd825f0STimur Tabi 1962c184cd3STimur Tabi /** 1972c184cd3STimur Tabi * p1022ds_set_monitor_port: switch the output to a different monitor port 1982c184cd3STimur Tabi */ 1997653aaabSTimur Tabi static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port) 2002c184cd3STimur Tabi { 2016597c713STimur Tabi struct device_node *guts_node; 2026bd825f0STimur Tabi struct device_node *lbc_node = NULL; 2036bd825f0STimur Tabi struct device_node *law_node = NULL; 2049cb6abcbSTimur Tabi struct ccsr_guts __iomem *guts; 2056bd825f0STimur Tabi struct fsl_lbc_regs *lbc = NULL; 2066bd825f0STimur Tabi void *ecm = NULL; 2076597c713STimur Tabi u8 __iomem *lbc_lcs0_ba = NULL; 2086597c713STimur Tabi u8 __iomem *lbc_lcs1_ba = NULL; 2096bd825f0STimur Tabi phys_addr_t cs0_addr, cs1_addr; 210896c01cbSTimur Tabi u32 br0, or0, br1, or1; 2116bd825f0STimur Tabi const __be32 *iprop; 2126bd825f0STimur Tabi unsigned int num_laws; 2136597c713STimur Tabi u8 b; 2146597c713STimur Tabi 2156597c713STimur Tabi /* Map the global utilities registers. */ 2166597c713STimur Tabi guts_node = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts"); 2176597c713STimur Tabi if (!guts_node) { 218b6741bc7STim Blechmann pr_err("p1022ds: missing global utilities device node\n"); 2196597c713STimur Tabi return; 2206597c713STimur Tabi } 2216597c713STimur Tabi 2226597c713STimur Tabi guts = of_iomap(guts_node, 0); 2236597c713STimur Tabi if (!guts) { 224b6741bc7STim Blechmann pr_err("p1022ds: could not map global utilities device\n"); 2256597c713STimur Tabi goto exit; 2266597c713STimur Tabi } 2276597c713STimur Tabi 2286bd825f0STimur Tabi lbc_node = of_find_compatible_node(NULL, NULL, "fsl,p1022-elbc"); 2296bd825f0STimur Tabi if (!lbc_node) { 2306bd825f0STimur Tabi pr_err("p1022ds: missing localbus node\n"); 2316597c713STimur Tabi goto exit; 2326597c713STimur Tabi } 2336597c713STimur Tabi 2346bd825f0STimur Tabi lbc = of_iomap(lbc_node, 0); 2356bd825f0STimur Tabi if (!lbc) { 2366bd825f0STimur Tabi pr_err("p1022ds: could not map localbus node\n"); 2376597c713STimur Tabi goto exit; 2386597c713STimur Tabi } 2396597c713STimur Tabi 2406bd825f0STimur Tabi law_node = of_find_compatible_node(NULL, NULL, "fsl,ecm-law"); 2416bd825f0STimur Tabi if (!law_node) { 2426bd825f0STimur Tabi pr_err("p1022ds: missing local access window node\n"); 2436597c713STimur Tabi goto exit; 2446597c713STimur Tabi } 2456597c713STimur Tabi 2466bd825f0STimur Tabi ecm = of_iomap(law_node, 0); 2476bd825f0STimur Tabi if (!ecm) { 2486bd825f0STimur Tabi pr_err("p1022ds: could not map local access window node\n"); 2496bd825f0STimur Tabi goto exit; 2506bd825f0STimur Tabi } 2516bd825f0STimur Tabi 2526bd825f0STimur Tabi iprop = of_get_property(law_node, "fsl,num-laws", 0); 2536bd825f0STimur Tabi if (!iprop) { 2546bd825f0STimur Tabi pr_err("p1022ds: LAW node is missing fsl,num-laws property\n"); 2556bd825f0STimur Tabi goto exit; 2566bd825f0STimur Tabi } 2576bd825f0STimur Tabi num_laws = be32_to_cpup(iprop); 2586bd825f0STimur Tabi 259896c01cbSTimur Tabi /* 260896c01cbSTimur Tabi * Indirect mode requires both BR0 and BR1 to be set to "GPCM", 261896c01cbSTimur Tabi * otherwise writes to these addresses won't actually appear on the 262896c01cbSTimur Tabi * local bus, and so the PIXIS won't see them. 263896c01cbSTimur Tabi * 264896c01cbSTimur Tabi * In FCM mode, writes go to the NAND controller, which does not pass 265896c01cbSTimur Tabi * them to the localbus directly. So we force BR0 and BR1 into GPCM 266896c01cbSTimur Tabi * mode, since we don't care about what's behind the localbus any 267896c01cbSTimur Tabi * more. 268896c01cbSTimur Tabi */ 269896c01cbSTimur Tabi br0 = in_be32(&lbc->bank[0].br); 270896c01cbSTimur Tabi br1 = in_be32(&lbc->bank[1].br); 271896c01cbSTimur Tabi or0 = in_be32(&lbc->bank[0].or); 272896c01cbSTimur Tabi or1 = in_be32(&lbc->bank[1].or); 273896c01cbSTimur Tabi 274896c01cbSTimur Tabi /* Make sure CS0 and CS1 are programmed */ 275896c01cbSTimur Tabi if (!(br0 & BR_V) || !(br1 & BR_V)) { 276896c01cbSTimur Tabi pr_err("p1022ds: CS0 and/or CS1 is not programmed\n"); 277896c01cbSTimur Tabi goto exit; 278896c01cbSTimur Tabi } 279896c01cbSTimur Tabi 280896c01cbSTimur Tabi /* 281896c01cbSTimur Tabi * Use the existing BRx/ORx values if it's already GPCM. Otherwise, 282896c01cbSTimur Tabi * force the values to simple 32KB GPCM windows with the most 283896c01cbSTimur Tabi * conservative timing. 284896c01cbSTimur Tabi */ 285896c01cbSTimur Tabi if ((br0 & BR_MSEL) != BR_MS_GPCM) { 286896c01cbSTimur Tabi br0 = (br0 & BR_BA) | BR_V; 287896c01cbSTimur Tabi or0 = 0xFFFF8000 | 0xFF7; 288896c01cbSTimur Tabi out_be32(&lbc->bank[0].br, br0); 289896c01cbSTimur Tabi out_be32(&lbc->bank[0].or, or0); 290896c01cbSTimur Tabi } 291896c01cbSTimur Tabi if ((br1 & BR_MSEL) != BR_MS_GPCM) { 292896c01cbSTimur Tabi br1 = (br1 & BR_BA) | BR_V; 293896c01cbSTimur Tabi or1 = 0xFFFF8000 | 0xFF7; 294896c01cbSTimur Tabi out_be32(&lbc->bank[1].br, br1); 295896c01cbSTimur Tabi out_be32(&lbc->bank[1].or, or1); 296896c01cbSTimur Tabi } 297896c01cbSTimur Tabi 298896c01cbSTimur Tabi cs0_addr = lbc_br_to_phys(ecm, num_laws, br0); 299896c01cbSTimur Tabi if (!cs0_addr) { 300896c01cbSTimur Tabi pr_err("p1022ds: could not determine physical address for CS0" 301896c01cbSTimur Tabi " (BR0=%08x)\n", br0); 302896c01cbSTimur Tabi goto exit; 303896c01cbSTimur Tabi } 304896c01cbSTimur Tabi cs1_addr = lbc_br_to_phys(ecm, num_laws, br1); 305896c01cbSTimur Tabi if (!cs0_addr) { 306896c01cbSTimur Tabi pr_err("p1022ds: could not determine physical address for CS1" 307896c01cbSTimur Tabi " (BR1=%08x)\n", br1); 308896c01cbSTimur Tabi goto exit; 309896c01cbSTimur Tabi } 3106bd825f0STimur Tabi 3116bd825f0STimur Tabi lbc_lcs0_ba = ioremap(cs0_addr, 1); 312896c01cbSTimur Tabi if (!lbc_lcs0_ba) { 313896c01cbSTimur Tabi pr_err("p1022ds: could not ioremap CS0 address %llx\n", 314896c01cbSTimur Tabi (unsigned long long)cs0_addr); 315896c01cbSTimur Tabi goto exit; 316896c01cbSTimur Tabi } 3176bd825f0STimur Tabi lbc_lcs1_ba = ioremap(cs1_addr, 1); 318896c01cbSTimur Tabi if (!lbc_lcs1_ba) { 319896c01cbSTimur Tabi pr_err("p1022ds: could not ioremap CS1 address %llx\n", 320896c01cbSTimur Tabi (unsigned long long)cs1_addr); 321896c01cbSTimur Tabi goto exit; 322896c01cbSTimur Tabi } 3236bd825f0STimur Tabi 3246597c713STimur Tabi /* Make sure we're in indirect mode first. */ 3256597c713STimur Tabi if ((in_be32(&guts->pmuxcr) & PMUXCR_ELBCDIU_MASK) != 3266597c713STimur Tabi PMUXCR_ELBCDIU_DIU) { 3276597c713STimur Tabi struct device_node *pixis_node; 32831655958STimur Tabi void __iomem *pixis; 3292c184cd3STimur Tabi 3306597c713STimur Tabi pixis_node = 3316597c713STimur Tabi of_find_compatible_node(NULL, NULL, "fsl,p1022ds-fpga"); 3326597c713STimur Tabi if (!pixis_node) { 3336597c713STimur Tabi pr_err("p1022ds: missing pixis node\n"); 3346597c713STimur Tabi goto exit; 3352c184cd3STimur Tabi } 3362c184cd3STimur Tabi 3376597c713STimur Tabi pixis = of_iomap(pixis_node, 0); 3386597c713STimur Tabi of_node_put(pixis_node); 33931655958STimur Tabi if (!pixis) { 3406597c713STimur Tabi pr_err("p1022ds: could not map pixis registers\n"); 3416597c713STimur Tabi goto exit; 3422c184cd3STimur Tabi } 3436597c713STimur Tabi 3446597c713STimur Tabi /* Enable indirect PIXIS mode. */ 3456597c713STimur Tabi setbits8(pixis + PX_CTL, PX_CTL_ALTACC); 3466597c713STimur Tabi iounmap(pixis); 3476597c713STimur Tabi 3486597c713STimur Tabi /* Switch the board mux to the DIU */ 3496597c713STimur Tabi out_8(lbc_lcs0_ba, PX_BRDCFG0); /* BRDCFG0 */ 3506597c713STimur Tabi b = in_8(lbc_lcs1_ba); 3516597c713STimur Tabi b |= PX_BRDCFG0_ELBC_DIU; 3526597c713STimur Tabi out_8(lbc_lcs1_ba, b); 3536597c713STimur Tabi 3546597c713STimur Tabi /* Set the chip mux to DIU mode. */ 3556597c713STimur Tabi clrsetbits_be32(&guts->pmuxcr, PMUXCR_ELBCDIU_MASK, 3566597c713STimur Tabi PMUXCR_ELBCDIU_DIU); 3576597c713STimur Tabi in_be32(&guts->pmuxcr); 3586597c713STimur Tabi } 3596597c713STimur Tabi 3602c184cd3STimur Tabi 3617653aaabSTimur Tabi switch (port) { 3627653aaabSTimur Tabi case FSL_DIU_PORT_DVI: 3632c184cd3STimur Tabi /* Enable the DVI port, disable the DFP and the backlight */ 3646597c713STimur Tabi out_8(lbc_lcs0_ba, PX_BRDCFG1); 3656597c713STimur Tabi b = in_8(lbc_lcs1_ba); 3666597c713STimur Tabi b &= ~(PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT); 3676597c713STimur Tabi b |= PX_BRDCFG1_DVIEN; 3686597c713STimur Tabi out_8(lbc_lcs1_ba, b); 3692c184cd3STimur Tabi break; 3707653aaabSTimur Tabi case FSL_DIU_PORT_LVDS: 3716597c713STimur Tabi /* 3726597c713STimur Tabi * LVDS also needs backlight enabled, otherwise the display 3736597c713STimur Tabi * will be blank. 3746597c713STimur Tabi */ 3752c184cd3STimur Tabi /* Enable the DFP port, disable the DVI and the backlight */ 3766597c713STimur Tabi out_8(lbc_lcs0_ba, PX_BRDCFG1); 3776597c713STimur Tabi b = in_8(lbc_lcs1_ba); 3786597c713STimur Tabi b &= ~PX_BRDCFG1_DVIEN; 3796597c713STimur Tabi b |= PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT; 3806597c713STimur Tabi out_8(lbc_lcs1_ba, b); 3812c184cd3STimur Tabi break; 3822c184cd3STimur Tabi default: 3837653aaabSTimur Tabi pr_err("p1022ds: unsupported monitor port %i\n", port); 3842c184cd3STimur Tabi } 38531655958STimur Tabi 3866597c713STimur Tabi exit: 3876597c713STimur Tabi if (lbc_lcs1_ba) 3886597c713STimur Tabi iounmap(lbc_lcs1_ba); 3896597c713STimur Tabi if (lbc_lcs0_ba) 3906597c713STimur Tabi iounmap(lbc_lcs0_ba); 3916bd825f0STimur Tabi if (lbc) 3926bd825f0STimur Tabi iounmap(lbc); 3936bd825f0STimur Tabi if (ecm) 3946bd825f0STimur Tabi iounmap(ecm); 3956597c713STimur Tabi if (guts) 3966597c713STimur Tabi iounmap(guts); 3976597c713STimur Tabi 3986bd825f0STimur Tabi of_node_put(law_node); 3996bd825f0STimur Tabi of_node_put(lbc_node); 4006597c713STimur Tabi of_node_put(guts_node); 4012c184cd3STimur Tabi } 4022c184cd3STimur Tabi 4032c184cd3STimur Tabi /** 4042c184cd3STimur Tabi * p1022ds_set_pixel_clock: program the DIU's clock 4052c184cd3STimur Tabi * 4062c184cd3STimur Tabi * @pixclock: the wavelength, in picoseconds, of the clock 4072c184cd3STimur Tabi */ 4082c184cd3STimur Tabi void p1022ds_set_pixel_clock(unsigned int pixclock) 4092c184cd3STimur Tabi { 4102c184cd3STimur Tabi struct device_node *guts_np = NULL; 4119cb6abcbSTimur Tabi struct ccsr_guts __iomem *guts; 4122c184cd3STimur Tabi unsigned long freq; 4132c184cd3STimur Tabi u64 temp; 4142c184cd3STimur Tabi u32 pxclk; 4152c184cd3STimur Tabi 4162c184cd3STimur Tabi /* Map the global utilities registers. */ 4172c184cd3STimur Tabi guts_np = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts"); 4182c184cd3STimur Tabi if (!guts_np) { 419b6741bc7STim Blechmann pr_err("p1022ds: missing global utilities device node\n"); 4202c184cd3STimur Tabi return; 4212c184cd3STimur Tabi } 4222c184cd3STimur Tabi 4232c184cd3STimur Tabi guts = of_iomap(guts_np, 0); 4242c184cd3STimur Tabi of_node_put(guts_np); 4252c184cd3STimur Tabi if (!guts) { 426b6741bc7STim Blechmann pr_err("p1022ds: could not map global utilities device\n"); 4272c184cd3STimur Tabi return; 4282c184cd3STimur Tabi } 4292c184cd3STimur Tabi 4302c184cd3STimur Tabi /* Convert pixclock from a wavelength to a frequency */ 4312c184cd3STimur Tabi temp = 1000000000000ULL; 4322c184cd3STimur Tabi do_div(temp, pixclock); 4332c184cd3STimur Tabi freq = temp; 4342c184cd3STimur Tabi 4357b93eccfSTimur Tabi /* 4367b93eccfSTimur Tabi * 'pxclk' is the ratio of the platform clock to the pixel clock. 4377b93eccfSTimur Tabi * This number is programmed into the CLKDVDR register, and the valid 4387b93eccfSTimur Tabi * range of values is 2-255. 4397b93eccfSTimur Tabi */ 4402c184cd3STimur Tabi pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq); 4417b93eccfSTimur Tabi pxclk = clamp_t(u32, pxclk, 2, 255); 4422c184cd3STimur Tabi 4432c184cd3STimur Tabi /* Disable the pixel clock, and set it to non-inverted and no delay */ 4442c184cd3STimur Tabi clrbits32(&guts->clkdvdr, 4452c184cd3STimur Tabi CLKDVDR_PXCKEN | CLKDVDR_PXCKDLY | CLKDVDR_PXCLK_MASK); 4462c184cd3STimur Tabi 4472c184cd3STimur Tabi /* Enable the clock and set the pxclk */ 4482c184cd3STimur Tabi setbits32(&guts->clkdvdr, CLKDVDR_PXCKEN | (pxclk << 16)); 44931655958STimur Tabi 45031655958STimur Tabi iounmap(guts); 4512c184cd3STimur Tabi } 4522c184cd3STimur Tabi 4532c184cd3STimur Tabi /** 4547653aaabSTimur Tabi * p1022ds_valid_monitor_port: set the monitor port for sysfs 4552c184cd3STimur Tabi */ 4567653aaabSTimur Tabi enum fsl_diu_monitor_port 4577653aaabSTimur Tabi p1022ds_valid_monitor_port(enum fsl_diu_monitor_port port) 4582c184cd3STimur Tabi { 4597653aaabSTimur Tabi switch (port) { 4607653aaabSTimur Tabi case FSL_DIU_PORT_DVI: 4617653aaabSTimur Tabi case FSL_DIU_PORT_LVDS: 4627653aaabSTimur Tabi return port; 4637653aaabSTimur Tabi default: 4647653aaabSTimur Tabi return FSL_DIU_PORT_DVI; /* Dual-link LVDS is not supported */ 4652c184cd3STimur Tabi } 4662c184cd3STimur Tabi } 4672c184cd3STimur Tabi 4682c184cd3STimur Tabi #endif 46930be4c96STimur Tabi 47030be4c96STimur Tabi void __init p1022_ds_pic_init(void) 47130be4c96STimur Tabi { 472e55d7f73SKyle Moffett struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | 47330be4c96STimur Tabi MPIC_SINGLE_DEST_CPU, 47430be4c96STimur Tabi 0, 256, " OpenPIC "); 47530be4c96STimur Tabi BUG_ON(mpic == NULL); 47630be4c96STimur Tabi mpic_init(mpic); 47730be4c96STimur Tabi } 47830be4c96STimur Tabi 4794951896aSTimur Tabi #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) 4804951896aSTimur Tabi 4814951896aSTimur Tabi /* TRUE if there is a "video=fslfb" command-line parameter. */ 4824951896aSTimur Tabi static bool fslfb; 4834951896aSTimur Tabi 4844951896aSTimur Tabi /* 4854951896aSTimur Tabi * Search for a "video=fslfb" command-line parameter, and set 'fslfb' to 4864951896aSTimur Tabi * true if we find it. 4874951896aSTimur Tabi * 4884951896aSTimur Tabi * We need to use early_param() instead of __setup() because the normal 4894951896aSTimur Tabi * __setup() gets called to late. However, early_param() gets called very 4904951896aSTimur Tabi * early, before the device tree is unflattened, so all we can do now is set a 4914951896aSTimur Tabi * global variable. Later on, p1022_ds_setup_arch() will use that variable 4924951896aSTimur Tabi * to determine if we need to update the device tree. 4934951896aSTimur Tabi */ 4944951896aSTimur Tabi static int __init early_video_setup(char *options) 4954951896aSTimur Tabi { 4964951896aSTimur Tabi fslfb = (strncmp(options, "fslfb:", 6) == 0); 4974951896aSTimur Tabi 4984951896aSTimur Tabi return 0; 4994951896aSTimur Tabi } 5004951896aSTimur Tabi early_param("video", early_video_setup); 5014951896aSTimur Tabi 5024951896aSTimur Tabi #endif 5034951896aSTimur Tabi 50430be4c96STimur Tabi /* 50530be4c96STimur Tabi * Setup the architecture 50630be4c96STimur Tabi */ 50730be4c96STimur Tabi static void __init p1022_ds_setup_arch(void) 50830be4c96STimur Tabi { 50930be4c96STimur Tabi if (ppc_md.progress) 51030be4c96STimur Tabi ppc_md.progress("p1022_ds_setup_arch()", 0); 51130be4c96STimur Tabi 5122c184cd3STimur Tabi #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) 5132c184cd3STimur Tabi diu_ops.get_pixel_format = p1022ds_get_pixel_format; 5142c184cd3STimur Tabi diu_ops.set_gamma_table = p1022ds_set_gamma_table; 5152c184cd3STimur Tabi diu_ops.set_monitor_port = p1022ds_set_monitor_port; 5162c184cd3STimur Tabi diu_ops.set_pixel_clock = p1022ds_set_pixel_clock; 5177653aaabSTimur Tabi diu_ops.valid_monitor_port = p1022ds_valid_monitor_port; 5184951896aSTimur Tabi 5194951896aSTimur Tabi /* 5206269f258STimur Tabi * Disable the NOR and NAND flash nodes if there is video=fslfb... 5216269f258STimur Tabi * command-line parameter. When the DIU is active, the localbus is 5226269f258STimur Tabi * unavailable, so we have to disable these nodes before the MTD 5236269f258STimur Tabi * driver loads. 5244951896aSTimur Tabi */ 5254951896aSTimur Tabi if (fslfb) { 5264951896aSTimur Tabi struct device_node *np = 5274951896aSTimur Tabi of_find_compatible_node(NULL, NULL, "fsl,p1022-elbc"); 5284951896aSTimur Tabi 5294951896aSTimur Tabi if (np) { 5306269f258STimur Tabi struct device_node *np2; 5316269f258STimur Tabi 5326269f258STimur Tabi of_node_get(np); 5336269f258STimur Tabi np2 = of_find_compatible_node(np, NULL, "cfi-flash"); 5346269f258STimur Tabi if (np2) { 5354951896aSTimur Tabi static struct property nor_status = { 5364951896aSTimur Tabi .name = "status", 5374951896aSTimur Tabi .value = "disabled", 5384951896aSTimur Tabi .length = sizeof("disabled"), 5394951896aSTimur Tabi }; 5404951896aSTimur Tabi 5416269f258STimur Tabi /* 5426269f258STimur Tabi * prom_update_property() is called before 5436269f258STimur Tabi * kmalloc() is available, so the 'new' object 5446269f258STimur Tabi * should be allocated in the global area. 5456269f258STimur Tabi * The easiest way is to do that is to 5466269f258STimur Tabi * allocate one static local variable for each 5476269f258STimur Tabi * call to this function. 5486269f258STimur Tabi */ 5494951896aSTimur Tabi pr_info("p1022ds: disabling %s node", 5506269f258STimur Tabi np2->full_name); 5516269f258STimur Tabi prom_update_property(np2, &nor_status); 5526269f258STimur Tabi of_node_put(np2); 5534951896aSTimur Tabi } 5546269f258STimur Tabi 5556269f258STimur Tabi of_node_get(np); 5566269f258STimur Tabi np2 = of_find_compatible_node(np, NULL, 5576269f258STimur Tabi "fsl,elbc-fcm-nand"); 5586269f258STimur Tabi if (np2) { 5596269f258STimur Tabi static struct property nand_status = { 5606269f258STimur Tabi .name = "status", 5616269f258STimur Tabi .value = "disabled", 5626269f258STimur Tabi .length = sizeof("disabled"), 5636269f258STimur Tabi }; 5646269f258STimur Tabi 5656269f258STimur Tabi pr_info("p1022ds: disabling %s node", 5666269f258STimur Tabi np2->full_name); 5676269f258STimur Tabi prom_update_property(np2, &nand_status); 5686269f258STimur Tabi of_node_put(np2); 5696269f258STimur Tabi } 5706269f258STimur Tabi 5716269f258STimur Tabi of_node_put(np); 5724951896aSTimur Tabi } 5734951896aSTimur Tabi 5744951896aSTimur Tabi } 5754951896aSTimur Tabi 5762c184cd3STimur Tabi #endif 5772c184cd3STimur Tabi 57830be4c96STimur Tabi mpc85xx_smp_init(); 57930be4c96STimur Tabi 580905e75c4SJia Hongtao fsl_pci_assign_primary(); 581905e75c4SJia Hongtao 582905e75c4SJia Hongtao swiotlb_detect_4g(); 58330be4c96STimur Tabi 58430be4c96STimur Tabi pr_info("Freescale P1022 DS reference board\n"); 58530be4c96STimur Tabi } 58630be4c96STimur Tabi 587905e75c4SJia Hongtao machine_arch_initcall(p1022_ds, mpc85xx_common_publish_devices); 58830be4c96STimur Tabi 58930be4c96STimur Tabi machine_arch_initcall(p1022_ds, swiotlb_setup_bus_notifier); 59030be4c96STimur Tabi 59130be4c96STimur Tabi /* 59230be4c96STimur Tabi * Called very early, device-tree isn't unflattened 59330be4c96STimur Tabi */ 59430be4c96STimur Tabi static int __init p1022_ds_probe(void) 59530be4c96STimur Tabi { 59630be4c96STimur Tabi unsigned long root = of_get_flat_dt_root(); 59730be4c96STimur Tabi 59830be4c96STimur Tabi return of_flat_dt_is_compatible(root, "fsl,p1022ds"); 59930be4c96STimur Tabi } 60030be4c96STimur Tabi 60130be4c96STimur Tabi define_machine(p1022_ds) { 60230be4c96STimur Tabi .name = "P1022 DS", 60330be4c96STimur Tabi .probe = p1022_ds_probe, 60430be4c96STimur Tabi .setup_arch = p1022_ds_setup_arch, 60530be4c96STimur Tabi .init_IRQ = p1022_ds_pic_init, 60630be4c96STimur Tabi #ifdef CONFIG_PCI 60730be4c96STimur Tabi .pcibios_fixup_bus = fsl_pcibios_fixup_bus, 60830be4c96STimur Tabi #endif 60930be4c96STimur Tabi .get_irq = mpic_get_irq, 61030be4c96STimur Tabi .restart = fsl_rstcr_restart, 61130be4c96STimur Tabi .calibrate_decr = generic_calibrate_decr, 61230be4c96STimur Tabi .progress = udbg_progress, 61330be4c96STimur Tabi }; 614