162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * P1022DS board specific routines 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Authors: Travis Wheatley <travis.wheatley@freescale.com> 562306a36Sopenharmony_ci * Dave Liu <daveliu@freescale.com> 662306a36Sopenharmony_ci * Timur Tabi <timur@freescale.com> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Copyright 2010 Freescale Semiconductor, Inc. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * This file is taken from the Freescale P1022DS BSP, with modifications: 1162306a36Sopenharmony_ci * 2) No AMP support 1262306a36Sopenharmony_ci * 3) No PCI endpoint support 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * This file is licensed under the terms of the GNU General Public License 1562306a36Sopenharmony_ci * version 2. This program is licensed "as is" without any warranty of any 1662306a36Sopenharmony_ci * kind, whether express or implied. 1762306a36Sopenharmony_ci */ 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <linux/fsl/guts.h> 2062306a36Sopenharmony_ci#include <linux/pci.h> 2162306a36Sopenharmony_ci#include <linux/of.h> 2262306a36Sopenharmony_ci#include <linux/of_address.h> 2362306a36Sopenharmony_ci#include <asm/div64.h> 2462306a36Sopenharmony_ci#include <asm/mpic.h> 2562306a36Sopenharmony_ci#include <asm/swiotlb.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include <sysdev/fsl_soc.h> 2862306a36Sopenharmony_ci#include <sysdev/fsl_pci.h> 2962306a36Sopenharmony_ci#include <asm/udbg.h> 3062306a36Sopenharmony_ci#include <asm/fsl_lbc.h> 3162306a36Sopenharmony_ci#include "smp.h" 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include "mpc85xx.h" 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define PMUXCR_ELBCDIU_MASK 0xc0000000 3862306a36Sopenharmony_ci#define PMUXCR_ELBCDIU_NOR16 0x80000000 3962306a36Sopenharmony_ci#define PMUXCR_ELBCDIU_DIU 0x40000000 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* 4262306a36Sopenharmony_ci * Board-specific initialization of the DIU. This code should probably be 4362306a36Sopenharmony_ci * executed when the DIU is opened, rather than in arch code, but the DIU 4462306a36Sopenharmony_ci * driver does not have a mechanism for this (yet). 4562306a36Sopenharmony_ci * 4662306a36Sopenharmony_ci * This is especially problematic on the P1022DS because the local bus (eLBC) 4762306a36Sopenharmony_ci * and the DIU video signals share the same pins, which means that enabling the 4862306a36Sopenharmony_ci * DIU will disable access to NOR flash. 4962306a36Sopenharmony_ci */ 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci/* DIU Pixel Clock bits of the CLKDVDR Global Utilities register */ 5262306a36Sopenharmony_ci#define CLKDVDR_PXCKEN 0x80000000 5362306a36Sopenharmony_ci#define CLKDVDR_PXCKINV 0x10000000 5462306a36Sopenharmony_ci#define CLKDVDR_PXCKDLY 0x06000000 5562306a36Sopenharmony_ci#define CLKDVDR_PXCLK_MASK 0x00FF0000 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* Some ngPIXIS register definitions */ 5862306a36Sopenharmony_ci#define PX_CTL 3 5962306a36Sopenharmony_ci#define PX_BRDCFG0 8 6062306a36Sopenharmony_ci#define PX_BRDCFG1 9 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci#define PX_BRDCFG0_ELBC_SPI_MASK 0xc0 6362306a36Sopenharmony_ci#define PX_BRDCFG0_ELBC_SPI_ELBC 0x00 6462306a36Sopenharmony_ci#define PX_BRDCFG0_ELBC_SPI_NULL 0xc0 6562306a36Sopenharmony_ci#define PX_BRDCFG0_ELBC_DIU 0x02 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci#define PX_BRDCFG1_DVIEN 0x80 6862306a36Sopenharmony_ci#define PX_BRDCFG1_DFPEN 0x40 6962306a36Sopenharmony_ci#define PX_BRDCFG1_BACKLIGHT 0x20 7062306a36Sopenharmony_ci#define PX_BRDCFG1_DDCEN 0x10 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci#define PX_CTL_ALTACC 0x80 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* 7562306a36Sopenharmony_ci * DIU Area Descriptor 7662306a36Sopenharmony_ci * 7762306a36Sopenharmony_ci * Note that we need to byte-swap the value before it's written to the AD 7862306a36Sopenharmony_ci * register. So even though the registers don't look like they're in the same 7962306a36Sopenharmony_ci * bit positions as they are on the MPC8610, the same value is written to the 8062306a36Sopenharmony_ci * AD register on the MPC8610 and on the P1022. 8162306a36Sopenharmony_ci */ 8262306a36Sopenharmony_ci#define AD_BYTE_F 0x10000000 8362306a36Sopenharmony_ci#define AD_ALPHA_C_MASK 0x0E000000 8462306a36Sopenharmony_ci#define AD_ALPHA_C_SHIFT 25 8562306a36Sopenharmony_ci#define AD_BLUE_C_MASK 0x01800000 8662306a36Sopenharmony_ci#define AD_BLUE_C_SHIFT 23 8762306a36Sopenharmony_ci#define AD_GREEN_C_MASK 0x00600000 8862306a36Sopenharmony_ci#define AD_GREEN_C_SHIFT 21 8962306a36Sopenharmony_ci#define AD_RED_C_MASK 0x00180000 9062306a36Sopenharmony_ci#define AD_RED_C_SHIFT 19 9162306a36Sopenharmony_ci#define AD_PALETTE 0x00040000 9262306a36Sopenharmony_ci#define AD_PIXEL_S_MASK 0x00030000 9362306a36Sopenharmony_ci#define AD_PIXEL_S_SHIFT 16 9462306a36Sopenharmony_ci#define AD_COMP_3_MASK 0x0000F000 9562306a36Sopenharmony_ci#define AD_COMP_3_SHIFT 12 9662306a36Sopenharmony_ci#define AD_COMP_2_MASK 0x00000F00 9762306a36Sopenharmony_ci#define AD_COMP_2_SHIFT 8 9862306a36Sopenharmony_ci#define AD_COMP_1_MASK 0x000000F0 9962306a36Sopenharmony_ci#define AD_COMP_1_SHIFT 4 10062306a36Sopenharmony_ci#define AD_COMP_0_MASK 0x0000000F 10162306a36Sopenharmony_ci#define AD_COMP_0_SHIFT 0 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci#define MAKE_AD(alpha, red, blue, green, size, c0, c1, c2, c3) \ 10462306a36Sopenharmony_ci cpu_to_le32(AD_BYTE_F | (alpha << AD_ALPHA_C_SHIFT) | \ 10562306a36Sopenharmony_ci (blue << AD_BLUE_C_SHIFT) | (green << AD_GREEN_C_SHIFT) | \ 10662306a36Sopenharmony_ci (red << AD_RED_C_SHIFT) | (c3 << AD_COMP_3_SHIFT) | \ 10762306a36Sopenharmony_ci (c2 << AD_COMP_2_SHIFT) | (c1 << AD_COMP_1_SHIFT) | \ 10862306a36Sopenharmony_ci (c0 << AD_COMP_0_SHIFT) | (size << AD_PIXEL_S_SHIFT)) 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistruct fsl_law { 11162306a36Sopenharmony_ci u32 lawbar; 11262306a36Sopenharmony_ci u32 reserved1; 11362306a36Sopenharmony_ci u32 lawar; 11462306a36Sopenharmony_ci u32 reserved[5]; 11562306a36Sopenharmony_ci}; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci#define LAWBAR_MASK 0x00F00000 11862306a36Sopenharmony_ci#define LAWBAR_SHIFT 12 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci#define LAWAR_EN 0x80000000 12162306a36Sopenharmony_ci#define LAWAR_TGT_MASK 0x01F00000 12262306a36Sopenharmony_ci#define LAW_TRGT_IF_LBC (0x04 << 20) 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci#define LAWAR_MASK (LAWAR_EN | LAWAR_TGT_MASK) 12562306a36Sopenharmony_ci#define LAWAR_MATCH (LAWAR_EN | LAW_TRGT_IF_LBC) 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci#define BR_BA 0xFFFF8000 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci/* 13062306a36Sopenharmony_ci * Map a BRx value to a physical address 13162306a36Sopenharmony_ci * 13262306a36Sopenharmony_ci * The localbus BRx registers only store the lower 32 bits of the address. To 13362306a36Sopenharmony_ci * obtain the upper four bits, we need to scan the LAW table. The entry which 13462306a36Sopenharmony_ci * maps to the localbus will contain the upper four bits. 13562306a36Sopenharmony_ci */ 13662306a36Sopenharmony_cistatic phys_addr_t lbc_br_to_phys(const void *ecm, unsigned int count, u32 br) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci#ifndef CONFIG_PHYS_64BIT 13962306a36Sopenharmony_ci /* 14062306a36Sopenharmony_ci * If we only have 32-bit addressing, then the BRx address *is* the 14162306a36Sopenharmony_ci * physical address. 14262306a36Sopenharmony_ci */ 14362306a36Sopenharmony_ci return br & BR_BA; 14462306a36Sopenharmony_ci#else 14562306a36Sopenharmony_ci const struct fsl_law *law = ecm + 0xc08; 14662306a36Sopenharmony_ci unsigned int i; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci for (i = 0; i < count; i++) { 14962306a36Sopenharmony_ci u64 lawbar = in_be32(&law[i].lawbar); 15062306a36Sopenharmony_ci u32 lawar = in_be32(&law[i].lawar); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci if ((lawar & LAWAR_MASK) == LAWAR_MATCH) 15362306a36Sopenharmony_ci /* Extract the upper four bits */ 15462306a36Sopenharmony_ci return (br & BR_BA) | ((lawbar & LAWBAR_MASK) << 12); 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci return 0; 15862306a36Sopenharmony_ci#endif 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci/** 16262306a36Sopenharmony_ci * p1022ds_set_monitor_port: switch the output to a different monitor port 16362306a36Sopenharmony_ci */ 16462306a36Sopenharmony_cistatic void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci struct device_node *guts_node; 16762306a36Sopenharmony_ci struct device_node *lbc_node = NULL; 16862306a36Sopenharmony_ci struct device_node *law_node = NULL; 16962306a36Sopenharmony_ci struct ccsr_guts __iomem *guts; 17062306a36Sopenharmony_ci struct fsl_lbc_regs *lbc = NULL; 17162306a36Sopenharmony_ci void *ecm = NULL; 17262306a36Sopenharmony_ci u8 __iomem *lbc_lcs0_ba = NULL; 17362306a36Sopenharmony_ci u8 __iomem *lbc_lcs1_ba = NULL; 17462306a36Sopenharmony_ci phys_addr_t cs0_addr, cs1_addr; 17562306a36Sopenharmony_ci u32 br0, or0, br1, or1; 17662306a36Sopenharmony_ci const __be32 *iprop; 17762306a36Sopenharmony_ci unsigned int num_laws; 17862306a36Sopenharmony_ci u8 b; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci /* Map the global utilities registers. */ 18162306a36Sopenharmony_ci guts_node = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts"); 18262306a36Sopenharmony_ci if (!guts_node) { 18362306a36Sopenharmony_ci pr_err("p1022ds: missing global utilities device node\n"); 18462306a36Sopenharmony_ci return; 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci guts = of_iomap(guts_node, 0); 18862306a36Sopenharmony_ci if (!guts) { 18962306a36Sopenharmony_ci pr_err("p1022ds: could not map global utilities device\n"); 19062306a36Sopenharmony_ci goto exit; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci lbc_node = of_find_compatible_node(NULL, NULL, "fsl,p1022-elbc"); 19462306a36Sopenharmony_ci if (!lbc_node) { 19562306a36Sopenharmony_ci pr_err("p1022ds: missing localbus node\n"); 19662306a36Sopenharmony_ci goto exit; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci lbc = of_iomap(lbc_node, 0); 20062306a36Sopenharmony_ci if (!lbc) { 20162306a36Sopenharmony_ci pr_err("p1022ds: could not map localbus node\n"); 20262306a36Sopenharmony_ci goto exit; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci law_node = of_find_compatible_node(NULL, NULL, "fsl,ecm-law"); 20662306a36Sopenharmony_ci if (!law_node) { 20762306a36Sopenharmony_ci pr_err("p1022ds: missing local access window node\n"); 20862306a36Sopenharmony_ci goto exit; 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci ecm = of_iomap(law_node, 0); 21262306a36Sopenharmony_ci if (!ecm) { 21362306a36Sopenharmony_ci pr_err("p1022ds: could not map local access window node\n"); 21462306a36Sopenharmony_ci goto exit; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci iprop = of_get_property(law_node, "fsl,num-laws", NULL); 21862306a36Sopenharmony_ci if (!iprop) { 21962306a36Sopenharmony_ci pr_err("p1022ds: LAW node is missing fsl,num-laws property\n"); 22062306a36Sopenharmony_ci goto exit; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci num_laws = be32_to_cpup(iprop); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci /* 22562306a36Sopenharmony_ci * Indirect mode requires both BR0 and BR1 to be set to "GPCM", 22662306a36Sopenharmony_ci * otherwise writes to these addresses won't actually appear on the 22762306a36Sopenharmony_ci * local bus, and so the PIXIS won't see them. 22862306a36Sopenharmony_ci * 22962306a36Sopenharmony_ci * In FCM mode, writes go to the NAND controller, which does not pass 23062306a36Sopenharmony_ci * them to the localbus directly. So we force BR0 and BR1 into GPCM 23162306a36Sopenharmony_ci * mode, since we don't care about what's behind the localbus any 23262306a36Sopenharmony_ci * more. 23362306a36Sopenharmony_ci */ 23462306a36Sopenharmony_ci br0 = in_be32(&lbc->bank[0].br); 23562306a36Sopenharmony_ci br1 = in_be32(&lbc->bank[1].br); 23662306a36Sopenharmony_ci or0 = in_be32(&lbc->bank[0].or); 23762306a36Sopenharmony_ci or1 = in_be32(&lbc->bank[1].or); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci /* Make sure CS0 and CS1 are programmed */ 24062306a36Sopenharmony_ci if (!(br0 & BR_V) || !(br1 & BR_V)) { 24162306a36Sopenharmony_ci pr_err("p1022ds: CS0 and/or CS1 is not programmed\n"); 24262306a36Sopenharmony_ci goto exit; 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci /* 24662306a36Sopenharmony_ci * Use the existing BRx/ORx values if it's already GPCM. Otherwise, 24762306a36Sopenharmony_ci * force the values to simple 32KB GPCM windows with the most 24862306a36Sopenharmony_ci * conservative timing. 24962306a36Sopenharmony_ci */ 25062306a36Sopenharmony_ci if ((br0 & BR_MSEL) != BR_MS_GPCM) { 25162306a36Sopenharmony_ci br0 = (br0 & BR_BA) | BR_V; 25262306a36Sopenharmony_ci or0 = 0xFFFF8000 | 0xFF7; 25362306a36Sopenharmony_ci out_be32(&lbc->bank[0].br, br0); 25462306a36Sopenharmony_ci out_be32(&lbc->bank[0].or, or0); 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci if ((br1 & BR_MSEL) != BR_MS_GPCM) { 25762306a36Sopenharmony_ci br1 = (br1 & BR_BA) | BR_V; 25862306a36Sopenharmony_ci or1 = 0xFFFF8000 | 0xFF7; 25962306a36Sopenharmony_ci out_be32(&lbc->bank[1].br, br1); 26062306a36Sopenharmony_ci out_be32(&lbc->bank[1].or, or1); 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci cs0_addr = lbc_br_to_phys(ecm, num_laws, br0); 26462306a36Sopenharmony_ci if (!cs0_addr) { 26562306a36Sopenharmony_ci pr_err("p1022ds: could not determine physical address for CS0" 26662306a36Sopenharmony_ci " (BR0=%08x)\n", br0); 26762306a36Sopenharmony_ci goto exit; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci cs1_addr = lbc_br_to_phys(ecm, num_laws, br1); 27062306a36Sopenharmony_ci if (!cs1_addr) { 27162306a36Sopenharmony_ci pr_err("p1022ds: could not determine physical address for CS1" 27262306a36Sopenharmony_ci " (BR1=%08x)\n", br1); 27362306a36Sopenharmony_ci goto exit; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci lbc_lcs0_ba = ioremap(cs0_addr, 1); 27762306a36Sopenharmony_ci if (!lbc_lcs0_ba) { 27862306a36Sopenharmony_ci pr_err("p1022ds: could not ioremap CS0 address %llx\n", 27962306a36Sopenharmony_ci (unsigned long long)cs0_addr); 28062306a36Sopenharmony_ci goto exit; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci lbc_lcs1_ba = ioremap(cs1_addr, 1); 28362306a36Sopenharmony_ci if (!lbc_lcs1_ba) { 28462306a36Sopenharmony_ci pr_err("p1022ds: could not ioremap CS1 address %llx\n", 28562306a36Sopenharmony_ci (unsigned long long)cs1_addr); 28662306a36Sopenharmony_ci goto exit; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci /* Make sure we're in indirect mode first. */ 29062306a36Sopenharmony_ci if ((in_be32(&guts->pmuxcr) & PMUXCR_ELBCDIU_MASK) != 29162306a36Sopenharmony_ci PMUXCR_ELBCDIU_DIU) { 29262306a36Sopenharmony_ci struct device_node *pixis_node; 29362306a36Sopenharmony_ci void __iomem *pixis; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci pixis_node = 29662306a36Sopenharmony_ci of_find_compatible_node(NULL, NULL, "fsl,p1022ds-fpga"); 29762306a36Sopenharmony_ci if (!pixis_node) { 29862306a36Sopenharmony_ci pr_err("p1022ds: missing pixis node\n"); 29962306a36Sopenharmony_ci goto exit; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci pixis = of_iomap(pixis_node, 0); 30362306a36Sopenharmony_ci of_node_put(pixis_node); 30462306a36Sopenharmony_ci if (!pixis) { 30562306a36Sopenharmony_ci pr_err("p1022ds: could not map pixis registers\n"); 30662306a36Sopenharmony_ci goto exit; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci /* Enable indirect PIXIS mode. */ 31062306a36Sopenharmony_ci setbits8(pixis + PX_CTL, PX_CTL_ALTACC); 31162306a36Sopenharmony_ci iounmap(pixis); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci /* Switch the board mux to the DIU */ 31462306a36Sopenharmony_ci out_8(lbc_lcs0_ba, PX_BRDCFG0); /* BRDCFG0 */ 31562306a36Sopenharmony_ci b = in_8(lbc_lcs1_ba); 31662306a36Sopenharmony_ci b |= PX_BRDCFG0_ELBC_DIU; 31762306a36Sopenharmony_ci out_8(lbc_lcs1_ba, b); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* Set the chip mux to DIU mode. */ 32062306a36Sopenharmony_ci clrsetbits_be32(&guts->pmuxcr, PMUXCR_ELBCDIU_MASK, 32162306a36Sopenharmony_ci PMUXCR_ELBCDIU_DIU); 32262306a36Sopenharmony_ci in_be32(&guts->pmuxcr); 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci switch (port) { 32762306a36Sopenharmony_ci case FSL_DIU_PORT_DVI: 32862306a36Sopenharmony_ci /* Enable the DVI port, disable the DFP and the backlight */ 32962306a36Sopenharmony_ci out_8(lbc_lcs0_ba, PX_BRDCFG1); 33062306a36Sopenharmony_ci b = in_8(lbc_lcs1_ba); 33162306a36Sopenharmony_ci b &= ~(PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT); 33262306a36Sopenharmony_ci b |= PX_BRDCFG1_DVIEN; 33362306a36Sopenharmony_ci out_8(lbc_lcs1_ba, b); 33462306a36Sopenharmony_ci break; 33562306a36Sopenharmony_ci case FSL_DIU_PORT_LVDS: 33662306a36Sopenharmony_ci /* 33762306a36Sopenharmony_ci * LVDS also needs backlight enabled, otherwise the display 33862306a36Sopenharmony_ci * will be blank. 33962306a36Sopenharmony_ci */ 34062306a36Sopenharmony_ci /* Enable the DFP port, disable the DVI and the backlight */ 34162306a36Sopenharmony_ci out_8(lbc_lcs0_ba, PX_BRDCFG1); 34262306a36Sopenharmony_ci b = in_8(lbc_lcs1_ba); 34362306a36Sopenharmony_ci b &= ~PX_BRDCFG1_DVIEN; 34462306a36Sopenharmony_ci b |= PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT; 34562306a36Sopenharmony_ci out_8(lbc_lcs1_ba, b); 34662306a36Sopenharmony_ci break; 34762306a36Sopenharmony_ci default: 34862306a36Sopenharmony_ci pr_err("p1022ds: unsupported monitor port %i\n", port); 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ciexit: 35262306a36Sopenharmony_ci if (lbc_lcs1_ba) 35362306a36Sopenharmony_ci iounmap(lbc_lcs1_ba); 35462306a36Sopenharmony_ci if (lbc_lcs0_ba) 35562306a36Sopenharmony_ci iounmap(lbc_lcs0_ba); 35662306a36Sopenharmony_ci if (lbc) 35762306a36Sopenharmony_ci iounmap(lbc); 35862306a36Sopenharmony_ci if (ecm) 35962306a36Sopenharmony_ci iounmap(ecm); 36062306a36Sopenharmony_ci if (guts) 36162306a36Sopenharmony_ci iounmap(guts); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci of_node_put(law_node); 36462306a36Sopenharmony_ci of_node_put(lbc_node); 36562306a36Sopenharmony_ci of_node_put(guts_node); 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci/** 36962306a36Sopenharmony_ci * p1022ds_set_pixel_clock: program the DIU's clock 37062306a36Sopenharmony_ci * 37162306a36Sopenharmony_ci * @pixclock: the wavelength, in picoseconds, of the clock 37262306a36Sopenharmony_ci */ 37362306a36Sopenharmony_civoid p1022ds_set_pixel_clock(unsigned int pixclock) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci struct device_node *guts_np = NULL; 37662306a36Sopenharmony_ci struct ccsr_guts __iomem *guts; 37762306a36Sopenharmony_ci unsigned long freq; 37862306a36Sopenharmony_ci u64 temp; 37962306a36Sopenharmony_ci u32 pxclk; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci /* Map the global utilities registers. */ 38262306a36Sopenharmony_ci guts_np = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts"); 38362306a36Sopenharmony_ci if (!guts_np) { 38462306a36Sopenharmony_ci pr_err("p1022ds: missing global utilities device node\n"); 38562306a36Sopenharmony_ci return; 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci guts = of_iomap(guts_np, 0); 38962306a36Sopenharmony_ci of_node_put(guts_np); 39062306a36Sopenharmony_ci if (!guts) { 39162306a36Sopenharmony_ci pr_err("p1022ds: could not map global utilities device\n"); 39262306a36Sopenharmony_ci return; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci /* Convert pixclock from a wavelength to a frequency */ 39662306a36Sopenharmony_ci temp = 1000000000000ULL; 39762306a36Sopenharmony_ci do_div(temp, pixclock); 39862306a36Sopenharmony_ci freq = temp; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci /* 40162306a36Sopenharmony_ci * 'pxclk' is the ratio of the platform clock to the pixel clock. 40262306a36Sopenharmony_ci * This number is programmed into the CLKDVDR register, and the valid 40362306a36Sopenharmony_ci * range of values is 2-255. 40462306a36Sopenharmony_ci */ 40562306a36Sopenharmony_ci pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq); 40662306a36Sopenharmony_ci pxclk = clamp_t(u32, pxclk, 2, 255); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci /* Disable the pixel clock, and set it to non-inverted and no delay */ 40962306a36Sopenharmony_ci clrbits32(&guts->clkdvdr, 41062306a36Sopenharmony_ci CLKDVDR_PXCKEN | CLKDVDR_PXCKDLY | CLKDVDR_PXCLK_MASK); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci /* Enable the clock and set the pxclk */ 41362306a36Sopenharmony_ci setbits32(&guts->clkdvdr, CLKDVDR_PXCKEN | (pxclk << 16)); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci iounmap(guts); 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci/** 41962306a36Sopenharmony_ci * p1022ds_valid_monitor_port: set the monitor port for sysfs 42062306a36Sopenharmony_ci */ 42162306a36Sopenharmony_cienum fsl_diu_monitor_port 42262306a36Sopenharmony_cip1022ds_valid_monitor_port(enum fsl_diu_monitor_port port) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci switch (port) { 42562306a36Sopenharmony_ci case FSL_DIU_PORT_DVI: 42662306a36Sopenharmony_ci case FSL_DIU_PORT_LVDS: 42762306a36Sopenharmony_ci return port; 42862306a36Sopenharmony_ci default: 42962306a36Sopenharmony_ci return FSL_DIU_PORT_DVI; /* Dual-link LVDS is not supported */ 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci#endif 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_civoid __init p1022_ds_pic_init(void) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | 43862306a36Sopenharmony_ci MPIC_SINGLE_DEST_CPU, 43962306a36Sopenharmony_ci 0, 256, " OpenPIC "); 44062306a36Sopenharmony_ci BUG_ON(mpic == NULL); 44162306a36Sopenharmony_ci mpic_init(mpic); 44262306a36Sopenharmony_ci} 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci/* TRUE if there is a "video=fslfb" command-line parameter. */ 44762306a36Sopenharmony_cistatic bool fslfb; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci/* 45062306a36Sopenharmony_ci * Search for a "video=fslfb" command-line parameter, and set 'fslfb' to 45162306a36Sopenharmony_ci * true if we find it. 45262306a36Sopenharmony_ci * 45362306a36Sopenharmony_ci * We need to use early_param() instead of __setup() because the normal 45462306a36Sopenharmony_ci * __setup() gets called to late. However, early_param() gets called very 45562306a36Sopenharmony_ci * early, before the device tree is unflattened, so all we can do now is set a 45662306a36Sopenharmony_ci * global variable. Later on, p1022_ds_setup_arch() will use that variable 45762306a36Sopenharmony_ci * to determine if we need to update the device tree. 45862306a36Sopenharmony_ci */ 45962306a36Sopenharmony_cistatic int __init early_video_setup(char *options) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci fslfb = (strncmp(options, "fslfb:", 6) == 0); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci return 0; 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ciearly_param("video", early_video_setup); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci#endif 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci/* 47062306a36Sopenharmony_ci * Setup the architecture 47162306a36Sopenharmony_ci */ 47262306a36Sopenharmony_cistatic void __init p1022_ds_setup_arch(void) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci if (ppc_md.progress) 47562306a36Sopenharmony_ci ppc_md.progress("p1022_ds_setup_arch()", 0); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) 47862306a36Sopenharmony_ci diu_ops.set_monitor_port = p1022ds_set_monitor_port; 47962306a36Sopenharmony_ci diu_ops.set_pixel_clock = p1022ds_set_pixel_clock; 48062306a36Sopenharmony_ci diu_ops.valid_monitor_port = p1022ds_valid_monitor_port; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* 48362306a36Sopenharmony_ci * Disable the NOR and NAND flash nodes if there is video=fslfb... 48462306a36Sopenharmony_ci * command-line parameter. When the DIU is active, the localbus is 48562306a36Sopenharmony_ci * unavailable, so we have to disable these nodes before the MTD 48662306a36Sopenharmony_ci * driver loads. 48762306a36Sopenharmony_ci */ 48862306a36Sopenharmony_ci if (fslfb) { 48962306a36Sopenharmony_ci struct device_node *np = 49062306a36Sopenharmony_ci of_find_compatible_node(NULL, NULL, "fsl,p1022-elbc"); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci if (np) { 49362306a36Sopenharmony_ci struct device_node *np2; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci of_node_get(np); 49662306a36Sopenharmony_ci np2 = of_find_compatible_node(np, NULL, "cfi-flash"); 49762306a36Sopenharmony_ci if (np2) { 49862306a36Sopenharmony_ci static struct property nor_status = { 49962306a36Sopenharmony_ci .name = "status", 50062306a36Sopenharmony_ci .value = "disabled", 50162306a36Sopenharmony_ci .length = sizeof("disabled"), 50262306a36Sopenharmony_ci }; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci /* 50562306a36Sopenharmony_ci * of_update_property() is called before 50662306a36Sopenharmony_ci * kmalloc() is available, so the 'new' object 50762306a36Sopenharmony_ci * should be allocated in the global area. 50862306a36Sopenharmony_ci * The easiest way is to do that is to 50962306a36Sopenharmony_ci * allocate one static local variable for each 51062306a36Sopenharmony_ci * call to this function. 51162306a36Sopenharmony_ci */ 51262306a36Sopenharmony_ci pr_info("p1022ds: disabling %pOF node", 51362306a36Sopenharmony_ci np2); 51462306a36Sopenharmony_ci of_update_property(np2, &nor_status); 51562306a36Sopenharmony_ci of_node_put(np2); 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci of_node_get(np); 51962306a36Sopenharmony_ci np2 = of_find_compatible_node(np, NULL, 52062306a36Sopenharmony_ci "fsl,elbc-fcm-nand"); 52162306a36Sopenharmony_ci if (np2) { 52262306a36Sopenharmony_ci static struct property nand_status = { 52362306a36Sopenharmony_ci .name = "status", 52462306a36Sopenharmony_ci .value = "disabled", 52562306a36Sopenharmony_ci .length = sizeof("disabled"), 52662306a36Sopenharmony_ci }; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci pr_info("p1022ds: disabling %pOF node", 52962306a36Sopenharmony_ci np2); 53062306a36Sopenharmony_ci of_update_property(np2, &nand_status); 53162306a36Sopenharmony_ci of_node_put(np2); 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci of_node_put(np); 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci#endif 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci mpc85xx_smp_init(); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci fsl_pci_assign_primary(); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci swiotlb_detect_4g(); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci pr_info("Freescale P1022 DS reference board\n"); 54862306a36Sopenharmony_ci} 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_cimachine_arch_initcall(p1022_ds, mpc85xx_common_publish_devices); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_cidefine_machine(p1022_ds) { 55362306a36Sopenharmony_ci .name = "P1022 DS", 55462306a36Sopenharmony_ci .compatible = "fsl,p1022ds", 55562306a36Sopenharmony_ci .setup_arch = p1022_ds_setup_arch, 55662306a36Sopenharmony_ci .init_IRQ = p1022_ds_pic_init, 55762306a36Sopenharmony_ci#ifdef CONFIG_PCI 55862306a36Sopenharmony_ci .pcibios_fixup_bus = fsl_pcibios_fixup_bus, 55962306a36Sopenharmony_ci .pcibios_fixup_phb = fsl_pcibios_fixup_phb, 56062306a36Sopenharmony_ci#endif 56162306a36Sopenharmony_ci .get_irq = mpic_get_irq, 56262306a36Sopenharmony_ci .progress = udbg_progress, 56362306a36Sopenharmony_ci}; 564