diff options
Diffstat (limited to 'arch/powerpc/platforms/83xx/usb.c')
-rw-r--r-- | arch/powerpc/platforms/83xx/usb.c | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/83xx/usb.c b/arch/powerpc/platforms/83xx/usb.c new file mode 100644 index 00000000000..e7fdf013cd3 --- /dev/null +++ b/arch/powerpc/platforms/83xx/usb.c @@ -0,0 +1,181 @@ +/* + * Freescale 83xx USB SOC setup code + * + * Copyright (C) 2007 Freescale Semiconductor, Inc. + * Author: Li Yang + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + + +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/errno.h> + +#include <asm/io.h> +#include <asm/prom.h> +#include <sysdev/fsl_soc.h> + +#include "mpc83xx.h" + + +#ifdef CONFIG_MPC834x +int mpc834x_usb_cfg(void) +{ + unsigned long sccr, sicrl, sicrh; + void __iomem *immap; + struct device_node *np = NULL; + int port0_is_dr = 0, port1_is_dr = 0; + const void *prop, *dr_mode; + + immap = ioremap(get_immrbase(), 0x1000); + if (!immap) + return -ENOMEM; + + /* Read registers */ + /* Note: DR and MPH must use the same clock setting in SCCR */ + sccr = in_be32(immap + MPC83XX_SCCR_OFFS) & ~MPC83XX_SCCR_USB_MASK; + sicrl = in_be32(immap + MPC83XX_SICRL_OFFS) & ~MPC834X_SICRL_USB_MASK; + sicrh = in_be32(immap + MPC83XX_SICRH_OFFS) & ~MPC834X_SICRH_USB_UTMI; + + np = of_find_compatible_node(NULL, "usb", "fsl-usb2-dr"); + if (np) { + sccr |= MPC83XX_SCCR_USB_DRCM_11; /* 1:3 */ + + prop = of_get_property(np, "phy_type", NULL); + if (prop && (!strcmp(prop, "utmi") || + !strcmp(prop, "utmi_wide"))) { + sicrl |= MPC834X_SICRL_USB0 | MPC834X_SICRL_USB1; + sicrh |= MPC834X_SICRH_USB_UTMI; + port1_is_dr = 1; + } else if (prop && !strcmp(prop, "serial")) { + dr_mode = of_get_property(np, "dr_mode", NULL); + if (dr_mode && !strcmp(dr_mode, "otg")) { + sicrl |= MPC834X_SICRL_USB0 | MPC834X_SICRL_USB1; + port1_is_dr = 1; + } else { + sicrl |= MPC834X_SICRL_USB0; + } + } else if (prop && !strcmp(prop, "ulpi")) { + sicrl |= MPC834X_SICRL_USB0; + } else { + printk(KERN_WARNING "834x USB PHY type not supported\n"); + } + port0_is_dr = 1; + of_node_put(np); + } + np = of_find_compatible_node(NULL, "usb", "fsl-usb2-mph"); + if (np) { + sccr |= MPC83XX_SCCR_USB_MPHCM_11; /* 1:3 */ + + prop = of_get_property(np, "port0", NULL); + if (prop) { + if (port0_is_dr) + printk(KERN_WARNING + "834x USB port0 can't be used by both DR and MPH!\n"); + sicrl |= MPC834X_SICRL_USB0; + } + prop = of_get_property(np, "port1", NULL); + if (prop) { + if (port1_is_dr) + printk(KERN_WARNING + "834x USB port1 can't be used by both DR and MPH!\n"); + sicrl |= MPC834X_SICRL_USB1; + } + of_node_put(np); + } + + /* Write back */ + out_be32(immap + MPC83XX_SCCR_OFFS, sccr); + out_be32(immap + MPC83XX_SICRL_OFFS, sicrl); + out_be32(immap + MPC83XX_SICRH_OFFS, sicrh); + + iounmap(immap); + return 0; +} +#endif /* CONFIG_MPC834x */ + +#ifdef CONFIG_PPC_MPC831x +int mpc831x_usb_cfg(void) +{ + u32 temp; + void __iomem *immap, *usb_regs; + struct device_node *np = NULL; + const void *prop; + struct resource res; + int ret = 0; +#ifdef CONFIG_USB_OTG + const void *dr_mode; +#endif + + np = of_find_compatible_node(NULL, "usb", "fsl-usb2-dr"); + if (!np) + return -ENODEV; + prop = of_get_property(np, "phy_type", NULL); + + /* Map IMMR space for pin and clock settings */ + immap = ioremap(get_immrbase(), 0x1000); + if (!immap) { + of_node_put(np); + return -ENOMEM; + } + + /* Configure clock */ + temp = in_be32(immap + MPC83XX_SCCR_OFFS); + temp &= ~MPC83XX_SCCR_USB_MASK; + temp |= MPC83XX_SCCR_USB_DRCM_11; /* 1:3 */ + out_be32(immap + MPC83XX_SCCR_OFFS, temp); + + /* Configure pin mux for ULPI. There is no pin mux for UTMI */ + if (!strcmp(prop, "ulpi")) { + temp = in_be32(immap + MPC83XX_SICRL_OFFS); + temp &= ~MPC831X_SICRL_USB_MASK; + temp |= MPC831X_SICRL_USB_ULPI; + out_be32(immap + MPC83XX_SICRL_OFFS, temp); + + temp = in_be32(immap + MPC83XX_SICRH_OFFS); + temp &= ~MPC831X_SICRH_USB_MASK; + temp |= MPC831X_SICRH_USB_ULPI; + out_be32(immap + MPC83XX_SICRH_OFFS, temp); + } + + iounmap(immap); + + /* Map USB SOC space */ + ret = of_address_to_resource(np, 0, &res); + if (ret) { + of_node_put(np); + return ret; + } + usb_regs = ioremap(res.start, res.end - res.start + 1); + + /* Using on-chip PHY */ + if (!strcmp(prop, "utmi_wide") || + !strcmp(prop, "utmi")) { + /* Set UTMI_PHY_EN, REFSEL to 48MHZ */ + out_be32(usb_regs + FSL_USB2_CONTROL_OFFS, + CONTROL_UTMI_PHY_EN | CONTROL_REFSEL_48MHZ); + /* Using external UPLI PHY */ + } else if (!strcmp(prop, "ulpi")) { + /* Set PHY_CLK_SEL to ULPI */ + temp = CONTROL_PHY_CLK_SEL_ULPI; +#ifdef CONFIG_USB_OTG + /* Set OTG_PORT */ + dr_mode = of_get_property(np, "dr_mode", NULL); + if (dr_mode && !strcmp(dr_mode, "otg")) + temp |= CONTROL_OTG_PORT; +#endif /* CONFIG_USB_OTG */ + out_be32(usb_regs + FSL_USB2_CONTROL_OFFS, temp); + } else { + printk(KERN_WARNING "831x USB PHY type not supported\n"); + ret = -EINVAL; + } + + iounmap(usb_regs); + of_node_put(np); + return ret; +} +#endif /* CONFIG_PPC_MPC831x */ |