12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 20dde1a1dSScott Wood /* 30dde1a1dSScott Wood * Embedded Planet EP8248E support 40dde1a1dSScott Wood * 50dde1a1dSScott Wood * Copyright 2007 Freescale Semiconductor, Inc. 60dde1a1dSScott Wood * Author: Scott Wood <scottwood@freescale.com> 70dde1a1dSScott Wood */ 80dde1a1dSScott Wood 90dde1a1dSScott Wood #include <linux/init.h> 100dde1a1dSScott Wood #include <linux/interrupt.h> 110dde1a1dSScott Wood #include <linux/fsl_devices.h> 120dde1a1dSScott Wood #include <linux/mdio-bitbang.h> 13fd84f0eeSGrant Likely #include <linux/of_mdio.h> 145a0e3ad6STejun Heo #include <linux/slab.h> 150dde1a1dSScott Wood #include <linux/of_platform.h> 16*81d7cac4SRob Herring #include <linux/platform_device.h> 170dde1a1dSScott Wood 180dde1a1dSScott Wood #include <asm/io.h> 190dde1a1dSScott Wood #include <asm/cpm2.h> 200dde1a1dSScott Wood #include <asm/udbg.h> 210dde1a1dSScott Wood #include <asm/machdep.h> 220dde1a1dSScott Wood #include <asm/time.h> 230dde1a1dSScott Wood #include <asm/mpc8260.h> 240dde1a1dSScott Wood 250dde1a1dSScott Wood #include <sysdev/fsl_soc.h> 260dde1a1dSScott Wood #include <sysdev/cpm2_pic.h> 270dde1a1dSScott Wood 280dde1a1dSScott Wood #include "pq2.h" 290dde1a1dSScott Wood 300dde1a1dSScott Wood static u8 __iomem *ep8248e_bcsr; 310dde1a1dSScott Wood static struct device_node *ep8248e_bcsr_node; 320dde1a1dSScott Wood 330dde1a1dSScott Wood #define BCSR7_SCC2_ENABLE 0x10 340dde1a1dSScott Wood 350dde1a1dSScott Wood #define BCSR8_PHY1_ENABLE 0x80 360dde1a1dSScott Wood #define BCSR8_PHY1_POWER 0x40 370dde1a1dSScott Wood #define BCSR8_PHY2_ENABLE 0x20 380dde1a1dSScott Wood #define BCSR8_PHY2_POWER 0x10 390dde1a1dSScott Wood #define BCSR8_MDIO_READ 0x04 400dde1a1dSScott Wood #define BCSR8_MDIO_CLOCK 0x02 410dde1a1dSScott Wood #define BCSR8_MDIO_DATA 0x01 420dde1a1dSScott Wood 430dde1a1dSScott Wood #define BCSR9_USB_ENABLE 0x80 440dde1a1dSScott Wood #define BCSR9_USB_POWER 0x40 450dde1a1dSScott Wood #define BCSR9_USB_HOST 0x20 460dde1a1dSScott Wood #define BCSR9_USB_FULL_SPEED_TARGET 0x10 470dde1a1dSScott Wood 480dde1a1dSScott Wood static void __init ep8248e_pic_init(void) 490dde1a1dSScott Wood { 500dde1a1dSScott Wood struct device_node *np = of_find_compatible_node(NULL, NULL, "fsl,pq2-pic"); 510dde1a1dSScott Wood if (!np) { 520dde1a1dSScott Wood printk(KERN_ERR "PIC init: can not find cpm-pic node\n"); 530dde1a1dSScott Wood return; 540dde1a1dSScott Wood } 550dde1a1dSScott Wood 560dde1a1dSScott Wood cpm2_pic_init(np); 570dde1a1dSScott Wood of_node_put(np); 580dde1a1dSScott Wood } 590dde1a1dSScott Wood 600dde1a1dSScott Wood static void ep8248e_set_mdc(struct mdiobb_ctrl *ctrl, int level) 610dde1a1dSScott Wood { 620dde1a1dSScott Wood if (level) 630dde1a1dSScott Wood setbits8(&ep8248e_bcsr[8], BCSR8_MDIO_CLOCK); 640dde1a1dSScott Wood else 650dde1a1dSScott Wood clrbits8(&ep8248e_bcsr[8], BCSR8_MDIO_CLOCK); 660dde1a1dSScott Wood 670dde1a1dSScott Wood /* Read back to flush the write. */ 680dde1a1dSScott Wood in_8(&ep8248e_bcsr[8]); 690dde1a1dSScott Wood } 700dde1a1dSScott Wood 710dde1a1dSScott Wood static void ep8248e_set_mdio_dir(struct mdiobb_ctrl *ctrl, int output) 720dde1a1dSScott Wood { 730dde1a1dSScott Wood if (output) 740dde1a1dSScott Wood clrbits8(&ep8248e_bcsr[8], BCSR8_MDIO_READ); 750dde1a1dSScott Wood else 760dde1a1dSScott Wood setbits8(&ep8248e_bcsr[8], BCSR8_MDIO_READ); 770dde1a1dSScott Wood 780dde1a1dSScott Wood /* Read back to flush the write. */ 790dde1a1dSScott Wood in_8(&ep8248e_bcsr[8]); 800dde1a1dSScott Wood } 810dde1a1dSScott Wood 820dde1a1dSScott Wood static void ep8248e_set_mdio_data(struct mdiobb_ctrl *ctrl, int data) 830dde1a1dSScott Wood { 840dde1a1dSScott Wood if (data) 850dde1a1dSScott Wood setbits8(&ep8248e_bcsr[8], BCSR8_MDIO_DATA); 860dde1a1dSScott Wood else 870dde1a1dSScott Wood clrbits8(&ep8248e_bcsr[8], BCSR8_MDIO_DATA); 880dde1a1dSScott Wood 890dde1a1dSScott Wood /* Read back to flush the write. */ 900dde1a1dSScott Wood in_8(&ep8248e_bcsr[8]); 910dde1a1dSScott Wood } 920dde1a1dSScott Wood 930dde1a1dSScott Wood static int ep8248e_get_mdio_data(struct mdiobb_ctrl *ctrl) 940dde1a1dSScott Wood { 950dde1a1dSScott Wood return in_8(&ep8248e_bcsr[8]) & BCSR8_MDIO_DATA; 960dde1a1dSScott Wood } 970dde1a1dSScott Wood 980dde1a1dSScott Wood static const struct mdiobb_ops ep8248e_mdio_ops = { 990dde1a1dSScott Wood .set_mdc = ep8248e_set_mdc, 1000dde1a1dSScott Wood .set_mdio_dir = ep8248e_set_mdio_dir, 1010dde1a1dSScott Wood .set_mdio_data = ep8248e_set_mdio_data, 1020dde1a1dSScott Wood .get_mdio_data = ep8248e_get_mdio_data, 1030dde1a1dSScott Wood .owner = THIS_MODULE, 1040dde1a1dSScott Wood }; 1050dde1a1dSScott Wood 1060dde1a1dSScott Wood static struct mdiobb_ctrl ep8248e_mdio_ctrl = { 1070dde1a1dSScott Wood .ops = &ep8248e_mdio_ops, 1080dde1a1dSScott Wood }; 1090dde1a1dSScott Wood 110cad5cef6SGreg Kroah-Hartman static int ep8248e_mdio_probe(struct platform_device *ofdev) 1110dde1a1dSScott Wood { 1120dde1a1dSScott Wood struct mii_bus *bus; 1130dde1a1dSScott Wood struct resource res; 1140dde1a1dSScott Wood struct device_node *node; 115fd84f0eeSGrant Likely int ret; 1160dde1a1dSScott Wood 11761c7a080SGrant Likely node = of_get_parent(ofdev->dev.of_node); 1180dde1a1dSScott Wood of_node_put(node); 1190dde1a1dSScott Wood if (node != ep8248e_bcsr_node) 1200dde1a1dSScott Wood return -ENODEV; 1210dde1a1dSScott Wood 12261c7a080SGrant Likely ret = of_address_to_resource(ofdev->dev.of_node, 0, &res); 1230dde1a1dSScott Wood if (ret) 1240dde1a1dSScott Wood return ret; 1250dde1a1dSScott Wood 1260dde1a1dSScott Wood bus = alloc_mdio_bitbang(&ep8248e_mdio_ctrl); 1270dde1a1dSScott Wood if (!bus) 1280dde1a1dSScott Wood return -ENOMEM; 1290dde1a1dSScott Wood 1300dde1a1dSScott Wood bus->name = "ep8248e-mdio-bitbang"; 13118ee49ddSLennert Buytenhek bus->parent = &ofdev->dev; 1329d9326d3SAndy Fleming snprintf(bus->id, MII_BUS_ID_SIZE, "%x", res.start); 1330dde1a1dSScott Wood 13461c7a080SGrant Likely ret = of_mdiobus_register(bus, ofdev->dev.of_node); 13558459a4eSRoel Kluin if (ret) 136e7f4dc35SAndrew Lunn goto err_free_bus; 13758459a4eSRoel Kluin 13858459a4eSRoel Kluin return 0; 13958459a4eSRoel Kluin err_free_bus: 14058459a4eSRoel Kluin free_mdio_bitbang(bus); 14158459a4eSRoel Kluin return ret; 1420dde1a1dSScott Wood } 1430dde1a1dSScott Wood 144a454dc50SGrant Likely static int ep8248e_mdio_remove(struct platform_device *ofdev) 1450dde1a1dSScott Wood { 1460dde1a1dSScott Wood BUG(); 1470dde1a1dSScott Wood return 0; 1480dde1a1dSScott Wood } 1490dde1a1dSScott Wood 1500dde1a1dSScott Wood static const struct of_device_id ep8248e_mdio_match[] = { 1510dde1a1dSScott Wood { 1520dde1a1dSScott Wood .compatible = "fsl,ep8248e-mdio-bitbang", 1530dde1a1dSScott Wood }, 1540dde1a1dSScott Wood {}, 1550dde1a1dSScott Wood }; 1560dde1a1dSScott Wood 15700006124SGrant Likely static struct platform_driver ep8248e_mdio_driver = { 1580dde1a1dSScott Wood .driver = { 1590dde1a1dSScott Wood .name = "ep8248e-mdio-bitbang", 1604018294bSGrant Likely .of_match_table = ep8248e_mdio_match, 1610dde1a1dSScott Wood }, 1620dde1a1dSScott Wood .probe = ep8248e_mdio_probe, 1630dde1a1dSScott Wood .remove = ep8248e_mdio_remove, 1640dde1a1dSScott Wood }; 1650dde1a1dSScott Wood 1660dde1a1dSScott Wood struct cpm_pin { 1670dde1a1dSScott Wood int port, pin, flags; 1680dde1a1dSScott Wood }; 1690dde1a1dSScott Wood 1700dde1a1dSScott Wood static __initdata struct cpm_pin ep8248e_pins[] = { 1710dde1a1dSScott Wood /* SMC1 */ 1720dde1a1dSScott Wood {2, 4, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 1730dde1a1dSScott Wood {2, 5, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, 1740dde1a1dSScott Wood 1750dde1a1dSScott Wood /* SCC1 */ 1760dde1a1dSScott Wood {2, 14, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 1770dde1a1dSScott Wood {2, 15, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 1780dde1a1dSScott Wood {3, 29, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, 1790dde1a1dSScott Wood {3, 30, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, 1800dde1a1dSScott Wood {3, 31, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 1810dde1a1dSScott Wood 1820dde1a1dSScott Wood /* FCC1 */ 1830dde1a1dSScott Wood {0, 14, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 1840dde1a1dSScott Wood {0, 15, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 1850dde1a1dSScott Wood {0, 16, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 1860dde1a1dSScott Wood {0, 17, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 1870dde1a1dSScott Wood {0, 18, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, 1880dde1a1dSScott Wood {0, 19, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, 1890dde1a1dSScott Wood {0, 20, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, 1900dde1a1dSScott Wood {0, 21, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, 1910dde1a1dSScott Wood {0, 26, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, 1920dde1a1dSScott Wood {0, 27, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, 1930dde1a1dSScott Wood {0, 28, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, 1940dde1a1dSScott Wood {0, 29, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, 1950dde1a1dSScott Wood {0, 30, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, 1960dde1a1dSScott Wood {0, 31, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, 1970dde1a1dSScott Wood {2, 21, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 1980dde1a1dSScott Wood {2, 22, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 1990dde1a1dSScott Wood 2000dde1a1dSScott Wood /* FCC2 */ 2010dde1a1dSScott Wood {1, 18, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2020dde1a1dSScott Wood {1, 19, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2030dde1a1dSScott Wood {1, 20, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2040dde1a1dSScott Wood {1, 21, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2050dde1a1dSScott Wood {1, 22, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, 2060dde1a1dSScott Wood {1, 23, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, 2070dde1a1dSScott Wood {1, 24, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, 2080dde1a1dSScott Wood {1, 25, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, 2090dde1a1dSScott Wood {1, 26, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2100dde1a1dSScott Wood {1, 27, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2110dde1a1dSScott Wood {1, 28, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2120dde1a1dSScott Wood {1, 29, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, 2130dde1a1dSScott Wood {1, 30, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2140dde1a1dSScott Wood {1, 31, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, 2150dde1a1dSScott Wood {2, 18, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2160dde1a1dSScott Wood {2, 19, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2170dde1a1dSScott Wood 2180dde1a1dSScott Wood /* I2C */ 2190dde1a1dSScott Wood {4, 14, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, 2200dde1a1dSScott Wood {4, 15, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, 2210dde1a1dSScott Wood 2220dde1a1dSScott Wood /* USB */ 2230dde1a1dSScott Wood {2, 10, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2240dde1a1dSScott Wood {2, 11, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2250dde1a1dSScott Wood {2, 20, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, 2260dde1a1dSScott Wood {2, 24, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2270dde1a1dSScott Wood {3, 23, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, 2280dde1a1dSScott Wood {3, 24, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, 2290dde1a1dSScott Wood {3, 25, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, 2300dde1a1dSScott Wood }; 2310dde1a1dSScott Wood 2320dde1a1dSScott Wood static void __init init_ioports(void) 2330dde1a1dSScott Wood { 2340dde1a1dSScott Wood int i; 2350dde1a1dSScott Wood 2360dde1a1dSScott Wood for (i = 0; i < ARRAY_SIZE(ep8248e_pins); i++) { 2370dde1a1dSScott Wood const struct cpm_pin *pin = &ep8248e_pins[i]; 2380dde1a1dSScott Wood cpm2_set_pin(pin->port, pin->pin, pin->flags); 2390dde1a1dSScott Wood } 2400dde1a1dSScott Wood 2410dde1a1dSScott Wood cpm2_smc_clk_setup(CPM_CLK_SMC1, CPM_BRG7); 2420dde1a1dSScott Wood cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_RX); 2430dde1a1dSScott Wood cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_TX); 2440dde1a1dSScott Wood cpm2_clk_setup(CPM_CLK_SCC3, CPM_CLK8, CPM_CLK_TX); /* USB */ 2450dde1a1dSScott Wood cpm2_clk_setup(CPM_CLK_FCC1, CPM_CLK11, CPM_CLK_RX); 2460dde1a1dSScott Wood cpm2_clk_setup(CPM_CLK_FCC1, CPM_CLK10, CPM_CLK_TX); 2470dde1a1dSScott Wood cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK13, CPM_CLK_RX); 2480dde1a1dSScott Wood cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK14, CPM_CLK_TX); 2490dde1a1dSScott Wood } 2500dde1a1dSScott Wood 2510dde1a1dSScott Wood static void __init ep8248e_setup_arch(void) 2520dde1a1dSScott Wood { 2530dde1a1dSScott Wood if (ppc_md.progress) 2540dde1a1dSScott Wood ppc_md.progress("ep8248e_setup_arch()", 0); 2550dde1a1dSScott Wood 2560dde1a1dSScott Wood cpm2_reset(); 2570dde1a1dSScott Wood 2580dde1a1dSScott Wood /* When this is set, snooping CPM DMA from RAM causes 2590dde1a1dSScott Wood * machine checks. See erratum SIU18. 2600dde1a1dSScott Wood */ 2610dde1a1dSScott Wood clrbits32(&cpm2_immr->im_siu_conf.siu_82xx.sc_bcr, MPC82XX_BCR_PLDP); 2620dde1a1dSScott Wood 2630dde1a1dSScott Wood ep8248e_bcsr_node = 2640dde1a1dSScott Wood of_find_compatible_node(NULL, NULL, "fsl,ep8248e-bcsr"); 2650dde1a1dSScott Wood if (!ep8248e_bcsr_node) { 2660dde1a1dSScott Wood printk(KERN_ERR "No bcsr in device tree\n"); 2670dde1a1dSScott Wood return; 2680dde1a1dSScott Wood } 2690dde1a1dSScott Wood 2700dde1a1dSScott Wood ep8248e_bcsr = of_iomap(ep8248e_bcsr_node, 0); 2710dde1a1dSScott Wood if (!ep8248e_bcsr) { 2720dde1a1dSScott Wood printk(KERN_ERR "Cannot map BCSR registers\n"); 2730dde1a1dSScott Wood of_node_put(ep8248e_bcsr_node); 2740dde1a1dSScott Wood ep8248e_bcsr_node = NULL; 2750dde1a1dSScott Wood return; 2760dde1a1dSScott Wood } 2770dde1a1dSScott Wood 2780dde1a1dSScott Wood setbits8(&ep8248e_bcsr[7], BCSR7_SCC2_ENABLE); 2790dde1a1dSScott Wood setbits8(&ep8248e_bcsr[8], BCSR8_PHY1_ENABLE | BCSR8_PHY1_POWER | 2800dde1a1dSScott Wood BCSR8_PHY2_ENABLE | BCSR8_PHY2_POWER); 2810dde1a1dSScott Wood 2820dde1a1dSScott Wood init_ioports(); 2830dde1a1dSScott Wood 2840dde1a1dSScott Wood if (ppc_md.progress) 2850dde1a1dSScott Wood ppc_md.progress("ep8248e_setup_arch(), finish", 0); 2860dde1a1dSScott Wood } 2870dde1a1dSScott Wood 288ce6d73c9SUwe Kleine-König static const struct of_device_id of_bus_ids[] __initconst = { 2890dde1a1dSScott Wood { .compatible = "simple-bus", }, 2900dde1a1dSScott Wood { .compatible = "fsl,ep8248e-bcsr", }, 2910dde1a1dSScott Wood {}, 2920dde1a1dSScott Wood }; 2930dde1a1dSScott Wood 2940dde1a1dSScott Wood static int __init declare_of_platform_devices(void) 2950dde1a1dSScott Wood { 2960dde1a1dSScott Wood of_platform_bus_probe(NULL, of_bus_ids, NULL); 29749bf9279SAndrey Smirnov 29849bf9279SAndrey Smirnov if (IS_ENABLED(CONFIG_MDIO_BITBANG)) 29900006124SGrant Likely platform_driver_register(&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 define_machine(ep8248e) 3060dde1a1dSScott Wood { 3070dde1a1dSScott Wood .name = "Embedded Planet EP8248E", 3081c96fcdeSChristophe Leroy .compatible = "fsl,ep8248e", 3090dde1a1dSScott Wood .setup_arch = ep8248e_setup_arch, 3100dde1a1dSScott Wood .init_IRQ = ep8248e_pic_init, 3110dde1a1dSScott Wood .get_irq = cpm2_get_irq, 3120dde1a1dSScott Wood .restart = pq2_restart, 3130dde1a1dSScott Wood .progress = udbg_progress, 3140dde1a1dSScott Wood }; 315