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