forked from Minki/linux
2874c5fd28
Based on 1 normalized pattern(s): 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 extracted by the scancode license scanner the SPDX license identifier GPL-2.0-or-later has been chosen to replace the boilerplate/reference in 3029 file(s). Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Allison Randal <allison@lohutok.net> Cc: linux-spdx@vger.kernel.org Link: https://lkml.kernel.org/r/20190527070032.746973796@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
252 lines
6.5 KiB
C
252 lines
6.5 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Freescale 83xx USB SOC setup code
|
|
*
|
|
* Copyright (C) 2007 Freescale Semiconductor, Inc.
|
|
* Author: Li Yang
|
|
*/
|
|
|
|
|
|
#include <linux/stddef.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/of.h>
|
|
|
|
#include <asm/io.h>
|
|
#include <asm/prom.h>
|
|
#include <sysdev/fsl_soc.h>
|
|
|
|
#include "mpc83xx.h"
|
|
|
|
|
|
#ifdef CONFIG_PPC_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, NULL, "fsl-usb2-dr");
|
|
if (np) {
|
|
sccr |= MPC83XX_SCCR_USB_DRCM_11; /* 1:3 */
|
|
|
|
prop = of_get_property(np, "phy_type", NULL);
|
|
port1_is_dr = 1;
|
|
if (prop && (!strcmp(prop, "utmi") ||
|
|
!strcmp(prop, "utmi_wide"))) {
|
|
sicrl |= MPC834X_SICRL_USB0 | MPC834X_SICRL_USB1;
|
|
sicrh |= MPC834X_SICRH_USB_UTMI;
|
|
port0_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;
|
|
port0_is_dr = 1;
|
|
} else {
|
|
sicrl |= MPC834X_SICRL_USB1;
|
|
}
|
|
} else if (prop && !strcmp(prop, "ulpi")) {
|
|
sicrl |= MPC834X_SICRL_USB1;
|
|
} else {
|
|
printk(KERN_WARNING "834x USB PHY type not supported\n");
|
|
}
|
|
of_node_put(np);
|
|
}
|
|
np = of_find_compatible_node(NULL, NULL, "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_PPC_MPC834x */
|
|
|
|
#ifdef CONFIG_PPC_MPC831x
|
|
int mpc831x_usb_cfg(void)
|
|
{
|
|
u32 temp;
|
|
void __iomem *immap, *usb_regs;
|
|
struct device_node *np = NULL;
|
|
struct device_node *immr_node = 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, NULL, "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 */
|
|
immr_node = of_get_parent(np);
|
|
if (immr_node && (of_device_is_compatible(immr_node, "fsl,mpc8315-immr") ||
|
|
of_device_is_compatible(immr_node, "fsl,mpc8308-immr")))
|
|
clrsetbits_be32(immap + MPC83XX_SCCR_OFFS,
|
|
MPC8315_SCCR_USB_MASK,
|
|
MPC8315_SCCR_USB_DRCM_01);
|
|
else
|
|
clrsetbits_be32(immap + MPC83XX_SCCR_OFFS,
|
|
MPC83XX_SCCR_USB_MASK,
|
|
MPC83XX_SCCR_USB_DRCM_11);
|
|
|
|
/* Configure pin mux for ULPI. There is no pin mux for UTMI */
|
|
if (prop && !strcmp(prop, "ulpi")) {
|
|
if (of_device_is_compatible(immr_node, "fsl,mpc8308-immr")) {
|
|
clrsetbits_be32(immap + MPC83XX_SICRH_OFFS,
|
|
MPC8308_SICRH_USB_MASK,
|
|
MPC8308_SICRH_USB_ULPI);
|
|
} else if (of_device_is_compatible(immr_node, "fsl,mpc8315-immr")) {
|
|
clrsetbits_be32(immap + MPC83XX_SICRL_OFFS,
|
|
MPC8315_SICRL_USB_MASK,
|
|
MPC8315_SICRL_USB_ULPI);
|
|
clrsetbits_be32(immap + MPC83XX_SICRH_OFFS,
|
|
MPC8315_SICRH_USB_MASK,
|
|
MPC8315_SICRH_USB_ULPI);
|
|
} else {
|
|
clrsetbits_be32(immap + MPC83XX_SICRL_OFFS,
|
|
MPC831X_SICRL_USB_MASK,
|
|
MPC831X_SICRL_USB_ULPI);
|
|
clrsetbits_be32(immap + MPC83XX_SICRH_OFFS,
|
|
MPC831X_SICRH_USB_MASK,
|
|
MPC831X_SICRH_USB_ULPI);
|
|
}
|
|
}
|
|
|
|
iounmap(immap);
|
|
|
|
of_node_put(immr_node);
|
|
|
|
/* 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, resource_size(&res));
|
|
|
|
/* Using on-chip PHY */
|
|
if (prop && (!strcmp(prop, "utmi_wide") ||
|
|
!strcmp(prop, "utmi"))) {
|
|
u32 refsel;
|
|
|
|
if (of_device_is_compatible(immr_node, "fsl,mpc8308-immr"))
|
|
goto out;
|
|
|
|
if (of_device_is_compatible(immr_node, "fsl,mpc8315-immr"))
|
|
refsel = CONTROL_REFSEL_24MHZ;
|
|
else
|
|
refsel = CONTROL_REFSEL_48MHZ;
|
|
/* Set UTMI_PHY_EN and REFSEL */
|
|
out_be32(usb_regs + FSL_USB2_CONTROL_OFFS,
|
|
CONTROL_UTMI_PHY_EN | refsel);
|
|
/* Using external UPLI PHY */
|
|
} else if (prop && !strcmp(prop, "ulpi")) {
|
|
/* Set PHY_CLK_SEL to ULPI */
|
|
temp = CONTROL_PHY_CLK_SEL_ULPI;
|
|
#ifdef CONFIG_USB_OTG
|
|
/* Set OTG_PORT */
|
|
if (!of_device_is_compatible(immr_node, "fsl,mpc8308-immr")) {
|
|
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;
|
|
}
|
|
|
|
out:
|
|
iounmap(usb_regs);
|
|
of_node_put(np);
|
|
return ret;
|
|
}
|
|
#endif /* CONFIG_PPC_MPC831x */
|
|
|
|
#ifdef CONFIG_PPC_MPC837x
|
|
int mpc837x_usb_cfg(void)
|
|
{
|
|
void __iomem *immap;
|
|
struct device_node *np = NULL;
|
|
const void *prop;
|
|
int ret = 0;
|
|
|
|
np = of_find_compatible_node(NULL, NULL, "fsl-usb2-dr");
|
|
if (!np || !of_device_is_available(np)) {
|
|
of_node_put(np);
|
|
return -ENODEV;
|
|
}
|
|
prop = of_get_property(np, "phy_type", NULL);
|
|
|
|
if (!prop || (strcmp(prop, "ulpi") && strcmp(prop, "serial"))) {
|
|
printk(KERN_WARNING "837x USB PHY type not supported\n");
|
|
of_node_put(np);
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Map IMMR space for pin and clock settings */
|
|
immap = ioremap(get_immrbase(), 0x1000);
|
|
if (!immap) {
|
|
of_node_put(np);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/* Configure clock */
|
|
clrsetbits_be32(immap + MPC83XX_SCCR_OFFS, MPC837X_SCCR_USB_DRCM_11,
|
|
MPC837X_SCCR_USB_DRCM_11);
|
|
|
|
/* Configure pin mux for ULPI/serial */
|
|
clrsetbits_be32(immap + MPC83XX_SICRL_OFFS, MPC837X_SICRL_USB_MASK,
|
|
MPC837X_SICRL_USB_ULPI);
|
|
|
|
iounmap(immap);
|
|
of_node_put(np);
|
|
return ret;
|
|
}
|
|
#endif /* CONFIG_PPC_MPC837x */
|