10dde1a1dSScott Wood /* 20dde1a1dSScott Wood * Embedded Planet EP8248E support 30dde1a1dSScott Wood * 40dde1a1dSScott Wood * Copyright 2007 Freescale Semiconductor, Inc. 50dde1a1dSScott Wood * Author: Scott Wood <scottwood@freescale.com> 60dde1a1dSScott Wood * 70dde1a1dSScott Wood * This program is free software; you can redistribute it and/or modify it 80dde1a1dSScott Wood * under the terms of the GNU General Public License as published by the 90dde1a1dSScott Wood * Free Software Foundation; either version 2 of the License, or (at your 100dde1a1dSScott Wood * option) any later version. 110dde1a1dSScott Wood */ 120dde1a1dSScott Wood 130dde1a1dSScott Wood #include <linux/init.h> 140dde1a1dSScott Wood #include <linux/interrupt.h> 150dde1a1dSScott Wood #include <linux/fsl_devices.h> 160dde1a1dSScott Wood #include <linux/mdio-bitbang.h> 170dde1a1dSScott Wood #include <linux/of_platform.h> 180dde1a1dSScott Wood 190dde1a1dSScott Wood #include <asm/io.h> 200dde1a1dSScott Wood #include <asm/cpm2.h> 210dde1a1dSScott Wood #include <asm/udbg.h> 220dde1a1dSScott Wood #include <asm/machdep.h> 230dde1a1dSScott Wood #include <asm/time.h> 240dde1a1dSScott Wood #include <asm/mpc8260.h> 250dde1a1dSScott Wood #include <asm/prom.h> 260dde1a1dSScott Wood 270dde1a1dSScott Wood #include <sysdev/fsl_soc.h> 280dde1a1dSScott Wood #include <sysdev/cpm2_pic.h> 290dde1a1dSScott Wood 300dde1a1dSScott Wood #include "pq2.h" 310dde1a1dSScott Wood 320dde1a1dSScott Wood static u8 __iomem *ep8248e_bcsr; 330dde1a1dSScott Wood static struct device_node *ep8248e_bcsr_node; 340dde1a1dSScott Wood 350dde1a1dSScott Wood #define BCSR7_SCC2_ENABLE 0x10 360dde1a1dSScott Wood 370dde1a1dSScott Wood #define BCSR8_PHY1_ENABLE 0x80 380dde1a1dSScott Wood #define BCSR8_PHY1_POWER 0x40 390dde1a1dSScott Wood #define BCSR8_PHY2_ENABLE 0x20 400dde1a1dSScott Wood #define BCSR8_PHY2_POWER 0x10 410dde1a1dSScott Wood #define BCSR8_MDIO_READ 0x04 420dde1a1dSScott Wood #define BCSR8_MDIO_CLOCK 0x02 430dde1a1dSScott Wood #define BCSR8_MDIO_DATA 0x01 440dde1a1dSScott Wood 450dde1a1dSScott Wood #define BCSR9_USB_ENABLE 0x80 460dde1a1dSScott Wood #define BCSR9_USB_POWER 0x40 470dde1a1dSScott Wood #define BCSR9_USB_HOST 0x20 480dde1a1dSScott Wood #define BCSR9_USB_FULL_SPEED_TARGET 0x10 490dde1a1dSScott Wood 500dde1a1dSScott Wood static void __init ep8248e_pic_init(void) 510dde1a1dSScott Wood { 520dde1a1dSScott Wood struct device_node *np = of_find_compatible_node(NULL, NULL, "fsl,pq2-pic"); 530dde1a1dSScott Wood if (!np) { 540dde1a1dSScott Wood printk(KERN_ERR "PIC init: can not find cpm-pic node\n"); 550dde1a1dSScott Wood return; 560dde1a1dSScott Wood } 570dde1a1dSScott Wood 580dde1a1dSScott Wood cpm2_pic_init(np); 590dde1a1dSScott Wood of_node_put(np); 600dde1a1dSScott Wood } 610dde1a1dSScott Wood 620dde1a1dSScott Wood static void ep8248e_set_mdc(struct mdiobb_ctrl *ctrl, int level) 630dde1a1dSScott Wood { 640dde1a1dSScott Wood if (level) 650dde1a1dSScott Wood setbits8(&ep8248e_bcsr[8], BCSR8_MDIO_CLOCK); 660dde1a1dSScott Wood else 670dde1a1dSScott Wood clrbits8(&ep8248e_bcsr[8], BCSR8_MDIO_CLOCK); 680dde1a1dSScott Wood 690dde1a1dSScott Wood /* Read back to flush the write. */ 700dde1a1dSScott Wood in_8(&ep8248e_bcsr[8]); 710dde1a1dSScott Wood } 720dde1a1dSScott Wood 730dde1a1dSScott Wood static void ep8248e_set_mdio_dir(struct mdiobb_ctrl *ctrl, int output) 740dde1a1dSScott Wood { 750dde1a1dSScott Wood if (output) 760dde1a1dSScott Wood clrbits8(&ep8248e_bcsr[8], BCSR8_MDIO_READ); 770dde1a1dSScott Wood else 780dde1a1dSScott Wood setbits8(&ep8248e_bcsr[8], BCSR8_MDIO_READ); 790dde1a1dSScott Wood 800dde1a1dSScott Wood /* Read back to flush the write. */ 810dde1a1dSScott Wood in_8(&ep8248e_bcsr[8]); 820dde1a1dSScott Wood } 830dde1a1dSScott Wood 840dde1a1dSScott Wood static void ep8248e_set_mdio_data(struct mdiobb_ctrl *ctrl, int data) 850dde1a1dSScott Wood { 860dde1a1dSScott Wood if (data) 870dde1a1dSScott Wood setbits8(&ep8248e_bcsr[8], BCSR8_MDIO_DATA); 880dde1a1dSScott Wood else 890dde1a1dSScott Wood clrbits8(&ep8248e_bcsr[8], BCSR8_MDIO_DATA); 900dde1a1dSScott Wood 910dde1a1dSScott Wood /* Read back to flush the write. */ 920dde1a1dSScott Wood in_8(&ep8248e_bcsr[8]); 930dde1a1dSScott Wood } 940dde1a1dSScott Wood 950dde1a1dSScott Wood static int ep8248e_get_mdio_data(struct mdiobb_ctrl *ctrl) 960dde1a1dSScott Wood { 970dde1a1dSScott Wood return in_8(&ep8248e_bcsr[8]) & BCSR8_MDIO_DATA; 980dde1a1dSScott Wood } 990dde1a1dSScott Wood 1000dde1a1dSScott Wood static const struct mdiobb_ops ep8248e_mdio_ops = { 1010dde1a1dSScott Wood .set_mdc = ep8248e_set_mdc, 1020dde1a1dSScott Wood .set_mdio_dir = ep8248e_set_mdio_dir, 1030dde1a1dSScott Wood .set_mdio_data = ep8248e_set_mdio_data, 1040dde1a1dSScott Wood .get_mdio_data = ep8248e_get_mdio_data, 1050dde1a1dSScott Wood .owner = THIS_MODULE, 1060dde1a1dSScott Wood }; 1070dde1a1dSScott Wood 1080dde1a1dSScott Wood static struct mdiobb_ctrl ep8248e_mdio_ctrl = { 1090dde1a1dSScott Wood .ops = &ep8248e_mdio_ops, 1100dde1a1dSScott Wood }; 1110dde1a1dSScott Wood 1120dde1a1dSScott Wood static int __devinit ep8248e_mdio_probe(struct of_device *ofdev, 1130dde1a1dSScott Wood const struct of_device_id *match) 1140dde1a1dSScott Wood { 1150dde1a1dSScott Wood struct mii_bus *bus; 1160dde1a1dSScott Wood struct resource res; 1170dde1a1dSScott Wood struct device_node *node; 1180dde1a1dSScott Wood int ret, i; 1190dde1a1dSScott Wood 1200dde1a1dSScott Wood node = of_get_parent(ofdev->node); 1210dde1a1dSScott Wood of_node_put(node); 1220dde1a1dSScott Wood if (node != ep8248e_bcsr_node) 1230dde1a1dSScott Wood return -ENODEV; 1240dde1a1dSScott Wood 1250dde1a1dSScott Wood ret = of_address_to_resource(ofdev->node, 0, &res); 1260dde1a1dSScott Wood if (ret) 1270dde1a1dSScott Wood return ret; 1280dde1a1dSScott Wood 1290dde1a1dSScott Wood bus = alloc_mdio_bitbang(&ep8248e_mdio_ctrl); 1300dde1a1dSScott Wood if (!bus) 1310dde1a1dSScott Wood return -ENOMEM; 1320dde1a1dSScott Wood 1330dde1a1dSScott Wood bus->phy_mask = 0; 1340dde1a1dSScott Wood bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); 1350dde1a1dSScott Wood 1360dde1a1dSScott Wood for (i = 0; i < PHY_MAX_ADDR; i++) 1370dde1a1dSScott Wood bus->irq[i] = -1; 1380dde1a1dSScott Wood 1390dde1a1dSScott Wood bus->name = "ep8248e-mdio-bitbang"; 140*18ee49ddSLennert Buytenhek bus->parent = &ofdev->dev; 1419d9326d3SAndy Fleming snprintf(bus->id, MII_BUS_ID_SIZE, "%x", res.start); 1420dde1a1dSScott Wood 1430dde1a1dSScott Wood return mdiobus_register(bus); 1440dde1a1dSScott Wood } 1450dde1a1dSScott Wood 1460dde1a1dSScott Wood static int ep8248e_mdio_remove(struct of_device *ofdev) 1470dde1a1dSScott Wood { 1480dde1a1dSScott Wood BUG(); 1490dde1a1dSScott Wood return 0; 1500dde1a1dSScott Wood } 1510dde1a1dSScott Wood 1520dde1a1dSScott Wood static const struct of_device_id ep8248e_mdio_match[] = { 1530dde1a1dSScott Wood { 1540dde1a1dSScott Wood .compatible = "fsl,ep8248e-mdio-bitbang", 1550dde1a1dSScott Wood }, 1560dde1a1dSScott Wood {}, 1570dde1a1dSScott Wood }; 1580dde1a1dSScott Wood 1590dde1a1dSScott Wood static struct of_platform_driver ep8248e_mdio_driver = { 1600dde1a1dSScott Wood .driver = { 1610dde1a1dSScott Wood .name = "ep8248e-mdio-bitbang", 1620dde1a1dSScott Wood }, 1630dde1a1dSScott Wood .match_table = ep8248e_mdio_match, 1640dde1a1dSScott Wood .probe = ep8248e_mdio_probe, 1650dde1a1dSScott Wood .remove = ep8248e_mdio_remove, 1660dde1a1dSScott Wood }; 1670dde1a1dSScott Wood 1680dde1a1dSScott Wood struct cpm_pin { 1690dde1a1dSScott Wood int port, pin, flags; 1700dde1a1dSScott Wood }; 1710dde1a1dSScott Wood 1720dde1a1dSScott Wood static __initdata struct cpm_pin ep8248e_pins[] = { 1730dde1a1dSScott Wood /* SMC1 */ 1740dde1a1dSScott Wood {2, 4, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 1750dde1a1dSScott Wood {2, 5, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, 1760dde1a1dSScott Wood 1770dde1a1dSScott Wood /* SCC1 */ 1780dde1a1dSScott Wood {2, 14, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 1790dde1a1dSScott Wood {2, 15, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 1800dde1a1dSScott Wood {3, 29, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, 1810dde1a1dSScott Wood {3, 30, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, 1820dde1a1dSScott Wood {3, 31, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 1830dde1a1dSScott Wood 1840dde1a1dSScott Wood /* FCC1 */ 1850dde1a1dSScott Wood {0, 14, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 1860dde1a1dSScott Wood {0, 15, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 1870dde1a1dSScott Wood {0, 16, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 1880dde1a1dSScott Wood {0, 17, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 1890dde1a1dSScott Wood {0, 18, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, 1900dde1a1dSScott Wood {0, 19, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, 1910dde1a1dSScott Wood {0, 20, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, 1920dde1a1dSScott Wood {0, 21, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, 1930dde1a1dSScott Wood {0, 26, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, 1940dde1a1dSScott Wood {0, 27, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, 1950dde1a1dSScott Wood {0, 28, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, 1960dde1a1dSScott Wood {0, 29, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, 1970dde1a1dSScott Wood {0, 30, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, 1980dde1a1dSScott Wood {0, 31, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, 1990dde1a1dSScott Wood {2, 21, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2000dde1a1dSScott Wood {2, 22, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2010dde1a1dSScott Wood 2020dde1a1dSScott Wood /* FCC2 */ 2030dde1a1dSScott Wood {1, 18, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2040dde1a1dSScott Wood {1, 19, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2050dde1a1dSScott Wood {1, 20, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2060dde1a1dSScott Wood {1, 21, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2070dde1a1dSScott Wood {1, 22, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, 2080dde1a1dSScott Wood {1, 23, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, 2090dde1a1dSScott Wood {1, 24, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, 2100dde1a1dSScott Wood {1, 25, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, 2110dde1a1dSScott Wood {1, 26, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2120dde1a1dSScott Wood {1, 27, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2130dde1a1dSScott Wood {1, 28, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2140dde1a1dSScott Wood {1, 29, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, 2150dde1a1dSScott Wood {1, 30, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2160dde1a1dSScott Wood {1, 31, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, 2170dde1a1dSScott Wood {2, 18, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2180dde1a1dSScott Wood {2, 19, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2190dde1a1dSScott Wood 2200dde1a1dSScott Wood /* I2C */ 2210dde1a1dSScott Wood {4, 14, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, 2220dde1a1dSScott Wood {4, 15, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, 2230dde1a1dSScott Wood 2240dde1a1dSScott Wood /* USB */ 2250dde1a1dSScott Wood {2, 10, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2260dde1a1dSScott Wood {2, 11, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2270dde1a1dSScott Wood {2, 20, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, 2280dde1a1dSScott Wood {2, 24, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2290dde1a1dSScott Wood {3, 23, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, 2300dde1a1dSScott Wood {3, 24, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, 2310dde1a1dSScott Wood {3, 25, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2320dde1a1dSScott Wood }; 2330dde1a1dSScott Wood 2340dde1a1dSScott Wood static void __init init_ioports(void) 2350dde1a1dSScott Wood { 2360dde1a1dSScott Wood int i; 2370dde1a1dSScott Wood 2380dde1a1dSScott Wood for (i = 0; i < ARRAY_SIZE(ep8248e_pins); i++) { 2390dde1a1dSScott Wood const struct cpm_pin *pin = &ep8248e_pins[i]; 2400dde1a1dSScott Wood cpm2_set_pin(pin->port, pin->pin, pin->flags); 2410dde1a1dSScott Wood } 2420dde1a1dSScott Wood 2430dde1a1dSScott Wood cpm2_smc_clk_setup(CPM_CLK_SMC1, CPM_BRG7); 2440dde1a1dSScott Wood cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_RX); 2450dde1a1dSScott Wood cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_TX); 2460dde1a1dSScott Wood cpm2_clk_setup(CPM_CLK_SCC3, CPM_CLK8, CPM_CLK_TX); /* USB */ 2470dde1a1dSScott Wood cpm2_clk_setup(CPM_CLK_FCC1, CPM_CLK11, CPM_CLK_RX); 2480dde1a1dSScott Wood cpm2_clk_setup(CPM_CLK_FCC1, CPM_CLK10, CPM_CLK_TX); 2490dde1a1dSScott Wood cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK13, CPM_CLK_RX); 2500dde1a1dSScott Wood cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK14, CPM_CLK_TX); 2510dde1a1dSScott Wood } 2520dde1a1dSScott Wood 2530dde1a1dSScott Wood static void __init ep8248e_setup_arch(void) 2540dde1a1dSScott Wood { 2550dde1a1dSScott Wood if (ppc_md.progress) 2560dde1a1dSScott Wood ppc_md.progress("ep8248e_setup_arch()", 0); 2570dde1a1dSScott Wood 2580dde1a1dSScott Wood cpm2_reset(); 2590dde1a1dSScott Wood 2600dde1a1dSScott Wood /* When this is set, snooping CPM DMA from RAM causes 2610dde1a1dSScott Wood * machine checks. See erratum SIU18. 2620dde1a1dSScott Wood */ 2630dde1a1dSScott Wood clrbits32(&cpm2_immr->im_siu_conf.siu_82xx.sc_bcr, MPC82XX_BCR_PLDP); 2640dde1a1dSScott Wood 2650dde1a1dSScott Wood ep8248e_bcsr_node = 2660dde1a1dSScott Wood of_find_compatible_node(NULL, NULL, "fsl,ep8248e-bcsr"); 2670dde1a1dSScott Wood if (!ep8248e_bcsr_node) { 2680dde1a1dSScott Wood printk(KERN_ERR "No bcsr in device tree\n"); 2690dde1a1dSScott Wood return; 2700dde1a1dSScott Wood } 2710dde1a1dSScott Wood 2720dde1a1dSScott Wood ep8248e_bcsr = of_iomap(ep8248e_bcsr_node, 0); 2730dde1a1dSScott Wood if (!ep8248e_bcsr) { 2740dde1a1dSScott Wood printk(KERN_ERR "Cannot map BCSR registers\n"); 2750dde1a1dSScott Wood of_node_put(ep8248e_bcsr_node); 2760dde1a1dSScott Wood ep8248e_bcsr_node = NULL; 2770dde1a1dSScott Wood return; 2780dde1a1dSScott Wood } 2790dde1a1dSScott Wood 2800dde1a1dSScott Wood setbits8(&ep8248e_bcsr[7], BCSR7_SCC2_ENABLE); 2810dde1a1dSScott Wood setbits8(&ep8248e_bcsr[8], BCSR8_PHY1_ENABLE | BCSR8_PHY1_POWER | 2820dde1a1dSScott Wood BCSR8_PHY2_ENABLE | BCSR8_PHY2_POWER); 2830dde1a1dSScott Wood 2840dde1a1dSScott Wood init_ioports(); 2850dde1a1dSScott Wood 2860dde1a1dSScott Wood if (ppc_md.progress) 2870dde1a1dSScott Wood ppc_md.progress("ep8248e_setup_arch(), finish", 0); 2880dde1a1dSScott Wood } 2890dde1a1dSScott Wood 2900dde1a1dSScott Wood static __initdata struct of_device_id of_bus_ids[] = { 2910dde1a1dSScott Wood { .compatible = "simple-bus", }, 2920dde1a1dSScott Wood { .compatible = "fsl,ep8248e-bcsr", }, 2930dde1a1dSScott Wood {}, 2940dde1a1dSScott Wood }; 2950dde1a1dSScott Wood 2960dde1a1dSScott Wood static int __init declare_of_platform_devices(void) 2970dde1a1dSScott Wood { 2980dde1a1dSScott Wood of_platform_bus_probe(NULL, of_bus_ids, NULL); 2990dde1a1dSScott Wood of_register_platform_driver(&ep8248e_mdio_driver); 3000dde1a1dSScott Wood 3010dde1a1dSScott Wood return 0; 3020dde1a1dSScott Wood } 3030dde1a1dSScott Wood machine_device_initcall(ep8248e, declare_of_platform_devices); 3040dde1a1dSScott Wood 3050dde1a1dSScott Wood /* 3060dde1a1dSScott Wood * Called very early, device-tree isn't unflattened 3070dde1a1dSScott Wood */ 3080dde1a1dSScott Wood static int __init ep8248e_probe(void) 3090dde1a1dSScott Wood { 3100dde1a1dSScott Wood unsigned long root = of_get_flat_dt_root(); 3110dde1a1dSScott Wood return of_flat_dt_is_compatible(root, "fsl,ep8248e"); 3120dde1a1dSScott Wood } 3130dde1a1dSScott Wood 3140dde1a1dSScott Wood define_machine(ep8248e) 3150dde1a1dSScott Wood { 3160dde1a1dSScott Wood .name = "Embedded Planet EP8248E", 3170dde1a1dSScott Wood .probe = ep8248e_probe, 3180dde1a1dSScott Wood .setup_arch = ep8248e_setup_arch, 3190dde1a1dSScott Wood .init_IRQ = ep8248e_pic_init, 3200dde1a1dSScott Wood .get_irq = cpm2_get_irq, 3210dde1a1dSScott Wood .calibrate_decr = generic_calibrate_decr, 3220dde1a1dSScott Wood .restart = pq2_restart, 3230dde1a1dSScott Wood .progress = udbg_progress, 3240dde1a1dSScott Wood }; 325