Path: blob/master/arch/powerpc/platforms/85xx/p1022_ds.c
10820 views
/*1* P1022DS board specific routines2*3* Authors: Travis Wheatley <[email protected]>4* Dave Liu <[email protected]>5* Timur Tabi <[email protected]>6*7* Copyright 2010 Freescale Semiconductor, Inc.8*9* This file is taken from the Freescale P1022DS BSP, with modifications:10* 2) No AMP support11* 3) No PCI endpoint support12*13* This file is licensed under the terms of the GNU General Public License14* version 2. This program is licensed "as is" without any warranty of any15* kind, whether express or implied.16*/1718#include <linux/pci.h>19#include <linux/of_platform.h>20#include <linux/memblock.h>21#include <asm/div64.h>22#include <asm/mpic.h>23#include <asm/swiotlb.h>2425#include <sysdev/fsl_soc.h>26#include <sysdev/fsl_pci.h>27#include <asm/fsl_guts.h>2829#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)3031/*32* Board-specific initialization of the DIU. This code should probably be33* executed when the DIU is opened, rather than in arch code, but the DIU34* driver does not have a mechanism for this (yet).35*36* This is especially problematic on the P1022DS because the local bus (eLBC)37* and the DIU video signals share the same pins, which means that enabling the38* DIU will disable access to NOR flash.39*/4041/* DIU Pixel Clock bits of the CLKDVDR Global Utilities register */42#define CLKDVDR_PXCKEN 0x8000000043#define CLKDVDR_PXCKINV 0x1000000044#define CLKDVDR_PXCKDLY 0x0600000045#define CLKDVDR_PXCLK_MASK 0x00FF00004647/* Some ngPIXIS register definitions */48#define PX_BRDCFG1_DVIEN 0x8049#define PX_BRDCFG1_DFPEN 0x4050#define PX_BRDCFG1_BACKLIGHT 0x2051#define PX_BRDCFG1_DDCEN 0x105253/*54* DIU Area Descriptor55*56* Note that we need to byte-swap the value before it's written to the AD57* register. So even though the registers don't look like they're in the same58* bit positions as they are on the MPC8610, the same value is written to the59* AD register on the MPC8610 and on the P1022.60*/61#define AD_BYTE_F 0x1000000062#define AD_ALPHA_C_MASK 0x0E00000063#define AD_ALPHA_C_SHIFT 2564#define AD_BLUE_C_MASK 0x0180000065#define AD_BLUE_C_SHIFT 2366#define AD_GREEN_C_MASK 0x0060000067#define AD_GREEN_C_SHIFT 2168#define AD_RED_C_MASK 0x0018000069#define AD_RED_C_SHIFT 1970#define AD_PALETTE 0x0004000071#define AD_PIXEL_S_MASK 0x0003000072#define AD_PIXEL_S_SHIFT 1673#define AD_COMP_3_MASK 0x0000F00074#define AD_COMP_3_SHIFT 1275#define AD_COMP_2_MASK 0x00000F0076#define AD_COMP_2_SHIFT 877#define AD_COMP_1_MASK 0x000000F078#define AD_COMP_1_SHIFT 479#define AD_COMP_0_MASK 0x0000000F80#define AD_COMP_0_SHIFT 08182#define MAKE_AD(alpha, red, blue, green, size, c0, c1, c2, c3) \83cpu_to_le32(AD_BYTE_F | (alpha << AD_ALPHA_C_SHIFT) | \84(blue << AD_BLUE_C_SHIFT) | (green << AD_GREEN_C_SHIFT) | \85(red << AD_RED_C_SHIFT) | (c3 << AD_COMP_3_SHIFT) | \86(c2 << AD_COMP_2_SHIFT) | (c1 << AD_COMP_1_SHIFT) | \87(c0 << AD_COMP_0_SHIFT) | (size << AD_PIXEL_S_SHIFT))8889/**90* p1022ds_get_pixel_format: return the Area Descriptor for a given pixel depth91*92* The Area Descriptor is a 32-bit value that determine which bits in each93* pixel are to be used for each color.94*/95static unsigned int p1022ds_get_pixel_format(unsigned int bits_per_pixel,96int monitor_port)97{98switch (bits_per_pixel) {99case 32:100/* 0x88883316 */101return MAKE_AD(3, 2, 0, 1, 3, 8, 8, 8, 8);102case 24:103/* 0x88082219 */104return MAKE_AD(4, 0, 1, 2, 2, 0, 8, 8, 8);105case 16:106/* 0x65053118 */107return MAKE_AD(4, 2, 1, 0, 1, 5, 6, 5, 0);108default:109pr_err("fsl-diu: unsupported pixel depth %u\n", bits_per_pixel);110return 0;111}112}113114/**115* p1022ds_set_gamma_table: update the gamma table, if necessary116*117* On some boards, the gamma table for some ports may need to be modified.118* This is not the case on the P1022DS, so we do nothing.119*/120static void p1022ds_set_gamma_table(int monitor_port, char *gamma_table_base)121{122}123124/**125* p1022ds_set_monitor_port: switch the output to a different monitor port126*127*/128static void p1022ds_set_monitor_port(int monitor_port)129{130struct device_node *pixis_node;131u8 __iomem *brdcfg1;132133pixis_node = of_find_compatible_node(NULL, NULL, "fsl,p1022ds-pixis");134if (!pixis_node) {135pr_err("p1022ds: missing ngPIXIS node\n");136return;137}138139brdcfg1 = of_iomap(pixis_node, 0);140if (!brdcfg1) {141pr_err("p1022ds: could not map ngPIXIS registers\n");142return;143}144brdcfg1 += 9; /* BRDCFG1 is at offset 9 in the ngPIXIS */145146switch (monitor_port) {147case 0: /* DVI */148/* Enable the DVI port, disable the DFP and the backlight */149clrsetbits_8(brdcfg1, PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT,150PX_BRDCFG1_DVIEN);151break;152case 1: /* Single link LVDS */153/* Enable the DFP port, disable the DVI and the backlight */154clrsetbits_8(brdcfg1, PX_BRDCFG1_DVIEN | PX_BRDCFG1_BACKLIGHT,155PX_BRDCFG1_DFPEN);156break;157default:158pr_err("p1022ds: unsupported monitor port %i\n", monitor_port);159}160}161162/**163* p1022ds_set_pixel_clock: program the DIU's clock164*165* @pixclock: the wavelength, in picoseconds, of the clock166*/167void p1022ds_set_pixel_clock(unsigned int pixclock)168{169struct device_node *guts_np = NULL;170struct ccsr_guts_85xx __iomem *guts;171unsigned long freq;172u64 temp;173u32 pxclk;174175/* Map the global utilities registers. */176guts_np = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts");177if (!guts_np) {178pr_err("p1022ds: missing global utilties device node\n");179return;180}181182guts = of_iomap(guts_np, 0);183of_node_put(guts_np);184if (!guts) {185pr_err("p1022ds: could not map global utilties device\n");186return;187}188189/* Convert pixclock from a wavelength to a frequency */190temp = 1000000000000ULL;191do_div(temp, pixclock);192freq = temp;193194/* pixclk is the ratio of the platform clock to the pixel clock */195pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq);196197/* Disable the pixel clock, and set it to non-inverted and no delay */198clrbits32(&guts->clkdvdr,199CLKDVDR_PXCKEN | CLKDVDR_PXCKDLY | CLKDVDR_PXCLK_MASK);200201/* Enable the clock and set the pxclk */202setbits32(&guts->clkdvdr, CLKDVDR_PXCKEN | (pxclk << 16));203}204205/**206* p1022ds_show_monitor_port: show the current monitor207*208* This function returns a string indicating whether the current monitor is209* set to DVI or LVDS.210*/211ssize_t p1022ds_show_monitor_port(int monitor_port, char *buf)212{213return sprintf(buf, "%c0 - DVI\n%c1 - Single link LVDS\n",214monitor_port == 0 ? '*' : ' ', monitor_port == 1 ? '*' : ' ');215}216217/**218* p1022ds_set_sysfs_monitor_port: set the monitor port for sysfs219*/220int p1022ds_set_sysfs_monitor_port(int val)221{222return val < 2 ? val : 0;223}224225#endif226227void __init p1022_ds_pic_init(void)228{229struct mpic *mpic;230struct resource r;231struct device_node *np;232233np = of_find_node_by_type(NULL, "open-pic");234if (!np) {235pr_err("Could not find open-pic node\n");236return;237}238239if (of_address_to_resource(np, 0, &r)) {240pr_err("Failed to map mpic register space\n");241of_node_put(np);242return;243}244245mpic = mpic_alloc(np, r.start,246MPIC_PRIMARY | MPIC_WANTS_RESET |247MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS |248MPIC_SINGLE_DEST_CPU,2490, 256, " OpenPIC ");250251BUG_ON(mpic == NULL);252of_node_put(np);253254mpic_init(mpic);255}256257#ifdef CONFIG_SMP258void __init mpc85xx_smp_init(void);259#endif260261/*262* Setup the architecture263*/264static void __init p1022_ds_setup_arch(void)265{266#ifdef CONFIG_PCI267struct device_node *np;268#endif269dma_addr_t max = 0xffffffff;270271if (ppc_md.progress)272ppc_md.progress("p1022_ds_setup_arch()", 0);273274#ifdef CONFIG_PCI275for_each_compatible_node(np, "pci", "fsl,p1022-pcie") {276struct resource rsrc;277struct pci_controller *hose;278279of_address_to_resource(np, 0, &rsrc);280281if ((rsrc.start & 0xfffff) == 0x8000)282fsl_add_bridge(np, 1);283else284fsl_add_bridge(np, 0);285286hose = pci_find_hose_for_OF_device(np);287max = min(max, hose->dma_window_base_cur +288hose->dma_window_size);289}290#endif291292#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)293diu_ops.get_pixel_format = p1022ds_get_pixel_format;294diu_ops.set_gamma_table = p1022ds_set_gamma_table;295diu_ops.set_monitor_port = p1022ds_set_monitor_port;296diu_ops.set_pixel_clock = p1022ds_set_pixel_clock;297diu_ops.show_monitor_port = p1022ds_show_monitor_port;298diu_ops.set_sysfs_monitor_port = p1022ds_set_sysfs_monitor_port;299#endif300301#ifdef CONFIG_SMP302mpc85xx_smp_init();303#endif304305#ifdef CONFIG_SWIOTLB306if (memblock_end_of_DRAM() > max) {307ppc_swiotlb_enable = 1;308set_pci_dma_ops(&swiotlb_dma_ops);309ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb;310}311#endif312313pr_info("Freescale P1022 DS reference board\n");314}315316static struct of_device_id __initdata p1022_ds_ids[] = {317{ .type = "soc", },318{ .compatible = "soc", },319{ .compatible = "simple-bus", },320{ .compatible = "gianfar", },321/* So that the DMA channel nodes can be probed individually: */322{ .compatible = "fsl,eloplus-dma", },323{},324};325326static int __init p1022_ds_publish_devices(void)327{328return of_platform_bus_probe(NULL, p1022_ds_ids, NULL);329}330machine_device_initcall(p1022_ds, p1022_ds_publish_devices);331332machine_arch_initcall(p1022_ds, swiotlb_setup_bus_notifier);333334/*335* Called very early, device-tree isn't unflattened336*/337static int __init p1022_ds_probe(void)338{339unsigned long root = of_get_flat_dt_root();340341return of_flat_dt_is_compatible(root, "fsl,p1022ds");342}343344define_machine(p1022_ds) {345.name = "P1022 DS",346.probe = p1022_ds_probe,347.setup_arch = p1022_ds_setup_arch,348.init_IRQ = p1022_ds_pic_init,349#ifdef CONFIG_PCI350.pcibios_fixup_bus = fsl_pcibios_fixup_bus,351#endif352.get_irq = mpic_get_irq,353.restart = fsl_rstcr_restart,354.calibrate_decr = generic_calibrate_decr,355.progress = udbg_progress,356};357358359