usb: sunxi: Switch to use generic-phy
Allwinner USB PHY handling can be done through driver-model generic-phy so add the generic-phy ops to relevant places on host and musb sunxi driver and enable them in respective SOC's. Signed-off-by: Jagan Teki <jagan@amarulasolutions.com> Acked-by: Jun Nie <jun.nie@linaro.org>
This commit is contained in:
parent
aa29b11b3f
commit
dd3228170a
@ -124,6 +124,7 @@ endif
|
||||
config MACH_SUNXI_H3_H5
|
||||
bool
|
||||
select DM_I2C
|
||||
select PHY_SUN4I_USB
|
||||
select SUNXI_DE2
|
||||
select SUNXI_DRAM_DW
|
||||
select SUNXI_DRAM_DW_32BIT
|
||||
@ -138,6 +139,7 @@ config MACH_SUN4I
|
||||
bool "sun4i (Allwinner A10)"
|
||||
select CPU_V7A
|
||||
select ARM_CORTEX_CPU_IS_UP
|
||||
select PHY_SUN4I_USB
|
||||
select DRAM_SUN4I
|
||||
select SUNXI_GEN_SUN4I
|
||||
select SUPPORT_SPL
|
||||
@ -147,6 +149,7 @@ config MACH_SUN5I
|
||||
select CPU_V7A
|
||||
select ARM_CORTEX_CPU_IS_UP
|
||||
select DRAM_SUN4I
|
||||
select PHY_SUN4I_USB
|
||||
select SUNXI_GEN_SUN4I
|
||||
select SUPPORT_SPL
|
||||
imply CONS_INDEX_2 if !DM_SERIAL
|
||||
@ -158,6 +161,7 @@ config MACH_SUN6I
|
||||
select CPU_V7_HAS_VIRT
|
||||
select ARCH_SUPPORT_PSCI
|
||||
select DRAM_SUN6I
|
||||
select PHY_SUN4I_USB
|
||||
select SUN6I_P2WI
|
||||
select SUN6I_PRCM
|
||||
select SUNXI_GEN_SUN6I
|
||||
@ -171,6 +175,7 @@ config MACH_SUN7I
|
||||
select CPU_V7_HAS_VIRT
|
||||
select ARCH_SUPPORT_PSCI
|
||||
select DRAM_SUN4I
|
||||
select PHY_SUN4I_USB
|
||||
select SUNXI_GEN_SUN4I
|
||||
select SUPPORT_SPL
|
||||
select ARMV7_BOOT_SEC_DEFAULT if OLD_SUNXI_KERNEL_COMPAT
|
||||
@ -182,6 +187,7 @@ config MACH_SUN8I_A23
|
||||
select CPU_V7_HAS_VIRT
|
||||
select ARCH_SUPPORT_PSCI
|
||||
select DRAM_SUN8I_A23
|
||||
select PHY_SUN4I_USB
|
||||
select SUNXI_GEN_SUN6I
|
||||
select SUPPORT_SPL
|
||||
select ARMV7_BOOT_SEC_DEFAULT if OLD_SUNXI_KERNEL_COMPAT
|
||||
@ -194,6 +200,7 @@ config MACH_SUN8I_A33
|
||||
select CPU_V7_HAS_VIRT
|
||||
select ARCH_SUPPORT_PSCI
|
||||
select DRAM_SUN8I_A33
|
||||
select PHY_SUN4I_USB
|
||||
select SUNXI_GEN_SUN6I
|
||||
select SUPPORT_SPL
|
||||
select ARMV7_BOOT_SEC_DEFAULT if OLD_SUNXI_KERNEL_COMPAT
|
||||
@ -203,6 +210,7 @@ config MACH_SUN8I_A83T
|
||||
bool "sun8i (Allwinner A83T)"
|
||||
select CPU_V7A
|
||||
select DRAM_SUN8I_A83T
|
||||
select PHY_SUN4I_USB
|
||||
select SUNXI_GEN_SUN6I
|
||||
select MMC_SUNXI_HAS_NEW_MODE
|
||||
select SUPPORT_SPL
|
||||
@ -253,6 +261,7 @@ config MACH_SUN50I
|
||||
bool "sun50i (Allwinner A64)"
|
||||
select ARM64
|
||||
select DM_I2C
|
||||
select PHY_SUN4I_USB
|
||||
select SUNXI_DE2
|
||||
select SUNXI_GEN_SUN6I
|
||||
select SUNXI_HIGH_SRAM
|
||||
|
@ -11,16 +11,14 @@
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/usb_phy.h>
|
||||
#include <asm/io.h>
|
||||
#include <dm.h>
|
||||
#include "ehci.h"
|
||||
#include <generic-phy.h>
|
||||
|
||||
#ifdef CONFIG_SUNXI_GEN_SUN4I
|
||||
#define BASE_DIST 0x8000
|
||||
#define AHB_CLK_DIST 2
|
||||
#else
|
||||
#define BASE_DIST 0x1000
|
||||
#define AHB_CLK_DIST 1
|
||||
#endif
|
||||
|
||||
@ -28,7 +26,7 @@ struct ehci_sunxi_priv {
|
||||
struct ehci_ctrl ehci;
|
||||
struct sunxi_ccm_reg *ccm;
|
||||
int ahb_gate_mask; /* Mask of ahb_gate0 clk gate bits for this hcd */
|
||||
int phy_index; /* Index of the usb-phy attached to this hcd */
|
||||
struct phy phy;
|
||||
};
|
||||
|
||||
static int ehci_usb_probe(struct udevice *dev)
|
||||
@ -38,11 +36,37 @@ static int ehci_usb_probe(struct udevice *dev)
|
||||
struct ehci_hccr *hccr = (struct ehci_hccr *)devfdt_get_addr(dev);
|
||||
struct ehci_hcor *hcor;
|
||||
int extra_ahb_gate_mask = 0;
|
||||
int phys, ret;
|
||||
|
||||
priv->ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
|
||||
if (IS_ERR(priv->ccm))
|
||||
return PTR_ERR(priv->ccm);
|
||||
|
||||
phys = dev_count_phandle_with_args(dev, "phys", "#phy-cells");
|
||||
if (phys < 0) {
|
||||
phys = 0;
|
||||
goto no_phy;
|
||||
}
|
||||
|
||||
ret = generic_phy_get_by_name(dev, "usb", &priv->phy);
|
||||
if (ret) {
|
||||
pr_err("failed to get %s usb PHY\n", dev->name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = generic_phy_init(&priv->phy);
|
||||
if (ret) {
|
||||
pr_err("failed to init %s USB PHY\n", dev->name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = generic_phy_power_on(&priv->phy);
|
||||
if (ret) {
|
||||
pr_err("failed to power on %s USB PHY\n", dev->name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
no_phy:
|
||||
/*
|
||||
* This should go away once we've moved to the driver model for
|
||||
* clocks resp. phys.
|
||||
@ -51,10 +75,8 @@ static int ehci_usb_probe(struct udevice *dev)
|
||||
#if defined(CONFIG_MACH_SUNXI_H3_H5) || defined(CONFIG_MACH_SUN50I)
|
||||
extra_ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_OHCI0;
|
||||
#endif
|
||||
priv->phy_index = ((uintptr_t)hccr - SUNXI_USB1_BASE) / BASE_DIST;
|
||||
priv->ahb_gate_mask <<= priv->phy_index * AHB_CLK_DIST;
|
||||
extra_ahb_gate_mask <<= priv->phy_index * AHB_CLK_DIST;
|
||||
priv->phy_index++; /* Non otg phys start at 1 */
|
||||
priv->ahb_gate_mask <<= phys * AHB_CLK_DIST;
|
||||
extra_ahb_gate_mask <<= phys * AHB_CLK_DIST;
|
||||
|
||||
setbits_le32(&priv->ccm->ahb_gate0,
|
||||
priv->ahb_gate_mask | extra_ahb_gate_mask);
|
||||
@ -63,9 +85,6 @@ static int ehci_usb_probe(struct udevice *dev)
|
||||
priv->ahb_gate_mask | extra_ahb_gate_mask);
|
||||
#endif
|
||||
|
||||
sunxi_usb_phy_init(priv->phy_index);
|
||||
sunxi_usb_phy_power_on(priv->phy_index);
|
||||
|
||||
hcor = (struct ehci_hcor *)((uintptr_t)hccr +
|
||||
HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
|
||||
|
||||
@ -77,12 +96,18 @@ static int ehci_usb_remove(struct udevice *dev)
|
||||
struct ehci_sunxi_priv *priv = dev_get_priv(dev);
|
||||
int ret;
|
||||
|
||||
if (generic_phy_valid(&priv->phy)) {
|
||||
ret = generic_phy_exit(&priv->phy);
|
||||
if (ret) {
|
||||
pr_err("failed to exit %s USB PHY\n", dev->name);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ehci_deregister(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sunxi_usb_phy_exit(priv->phy_index);
|
||||
|
||||
#ifdef CONFIG_SUNXI_GEN_SUN6I
|
||||
clrbits_le32(&priv->ccm->ahb_reset0_cfg, priv->ahb_gate_mask);
|
||||
#endif
|
||||
|
@ -10,17 +10,15 @@
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/usb_phy.h>
|
||||
#include <asm/io.h>
|
||||
#include <dm.h>
|
||||
#include <usb.h>
|
||||
#include "ohci.h"
|
||||
#include <generic-phy.h>
|
||||
|
||||
#ifdef CONFIG_SUNXI_GEN_SUN4I
|
||||
#define BASE_DIST 0x8000
|
||||
#define AHB_CLK_DIST 2
|
||||
#else
|
||||
#define BASE_DIST 0x1000
|
||||
#define AHB_CLK_DIST 1
|
||||
#endif
|
||||
|
||||
@ -29,7 +27,7 @@ struct ohci_sunxi_priv {
|
||||
ohci_t ohci;
|
||||
int ahb_gate_mask; /* Mask of ahb_gate0 clk gate bits for this hcd */
|
||||
int usb_gate_mask; /* Mask of usb_clk_cfg clk gate bits for this hcd */
|
||||
int phy_index; /* Index of the usb-phy attached to this hcd */
|
||||
struct phy phy;
|
||||
};
|
||||
|
||||
static int ohci_usb_probe(struct udevice *dev)
|
||||
@ -38,11 +36,37 @@ static int ohci_usb_probe(struct udevice *dev)
|
||||
struct ohci_sunxi_priv *priv = dev_get_priv(dev);
|
||||
struct ohci_regs *regs = (struct ohci_regs *)devfdt_get_addr(dev);
|
||||
int extra_ahb_gate_mask = 0;
|
||||
int phys, ret;
|
||||
|
||||
priv->ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
|
||||
if (IS_ERR(priv->ccm))
|
||||
return PTR_ERR(priv->ccm);
|
||||
|
||||
phys = dev_count_phandle_with_args(dev, "phys", "#phy-cells");
|
||||
if (phys < 0) {
|
||||
phys = 0;
|
||||
goto no_phy;
|
||||
}
|
||||
|
||||
ret = generic_phy_get_by_name(dev, "usb", &priv->phy);
|
||||
if (ret) {
|
||||
pr_err("failed to get %s usb PHY\n", dev->name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = generic_phy_init(&priv->phy);
|
||||
if (ret) {
|
||||
pr_err("failed to init %s USB PHY\n", dev->name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = generic_phy_power_on(&priv->phy);
|
||||
if (ret) {
|
||||
pr_err("failed to power on %s USB PHY\n", dev->name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
no_phy:
|
||||
bus_priv->companion = true;
|
||||
|
||||
/*
|
||||
@ -54,11 +78,9 @@ static int ohci_usb_probe(struct udevice *dev)
|
||||
extra_ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_EHCI0;
|
||||
#endif
|
||||
priv->usb_gate_mask = CCM_USB_CTRL_OHCI0_CLK;
|
||||
priv->phy_index = ((uintptr_t)regs - (SUNXI_USB1_BASE + 0x400)) / BASE_DIST;
|
||||
priv->ahb_gate_mask <<= priv->phy_index * AHB_CLK_DIST;
|
||||
extra_ahb_gate_mask <<= priv->phy_index * AHB_CLK_DIST;
|
||||
priv->usb_gate_mask <<= priv->phy_index;
|
||||
priv->phy_index++; /* Non otg phys start at 1 */
|
||||
priv->ahb_gate_mask <<= phys * AHB_CLK_DIST;
|
||||
extra_ahb_gate_mask <<= phys * AHB_CLK_DIST;
|
||||
priv->usb_gate_mask <<= phys;
|
||||
|
||||
setbits_le32(&priv->ccm->ahb_gate0,
|
||||
priv->ahb_gate_mask | extra_ahb_gate_mask);
|
||||
@ -68,9 +90,6 @@ static int ohci_usb_probe(struct udevice *dev)
|
||||
priv->ahb_gate_mask | extra_ahb_gate_mask);
|
||||
#endif
|
||||
|
||||
sunxi_usb_phy_init(priv->phy_index);
|
||||
sunxi_usb_phy_power_on(priv->phy_index);
|
||||
|
||||
return ohci_register(dev, regs);
|
||||
}
|
||||
|
||||
@ -79,12 +98,18 @@ static int ohci_usb_remove(struct udevice *dev)
|
||||
struct ohci_sunxi_priv *priv = dev_get_priv(dev);
|
||||
int ret;
|
||||
|
||||
if (generic_phy_valid(&priv->phy)) {
|
||||
ret = generic_phy_exit(&priv->phy);
|
||||
if (ret) {
|
||||
pr_err("failed to exit %s USB PHY\n", dev->name);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ohci_deregister(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sunxi_usb_phy_exit(priv->phy_index);
|
||||
|
||||
#ifdef CONFIG_SUNXI_GEN_SUN6I
|
||||
clrbits_le32(&priv->ccm->ahb_reset0_cfg, priv->ahb_gate_mask);
|
||||
#endif
|
||||
|
@ -1,9 +1,6 @@
|
||||
#include <common.h>
|
||||
#include <console.h>
|
||||
#include <watchdog.h>
|
||||
#ifdef CONFIG_ARCH_SUNXI
|
||||
#include <asm/arch/usb_phy.h>
|
||||
#endif
|
||||
#include <linux/errno.h>
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
|
@ -17,10 +17,11 @@
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <generic-phy.h>
|
||||
#include <phy-sun4i-usb.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/gpio.h>
|
||||
#include <asm/arch/usb_phy.h>
|
||||
#include <asm-generic/gpio.h>
|
||||
#include <dm/lists.h>
|
||||
#include <dm/root.h>
|
||||
@ -86,6 +87,7 @@ struct sunxi_glue {
|
||||
struct sunxi_ccm_reg *ccm;
|
||||
struct sunxi_musb_config *cfg;
|
||||
struct device dev;
|
||||
struct phy *phy;
|
||||
};
|
||||
#define to_sunxi_glue(d) container_of(d, struct sunxi_glue, dev)
|
||||
|
||||
@ -218,6 +220,7 @@ static bool enabled = false;
|
||||
|
||||
static int sunxi_musb_enable(struct musb *musb)
|
||||
{
|
||||
struct sunxi_glue *glue = to_sunxi_glue(musb->controller);
|
||||
int ret;
|
||||
|
||||
pr_debug("%s():\n", __func__);
|
||||
@ -232,17 +235,23 @@ static int sunxi_musb_enable(struct musb *musb)
|
||||
musb_writeb(musb->mregs, USBC_REG_o_VEND0, 0);
|
||||
|
||||
if (is_host_enabled(musb)) {
|
||||
ret = sunxi_usb_phy_vbus_detect(0);
|
||||
ret = sun4i_usb_phy_vbus_detect(glue->phy);
|
||||
if (ret == 1) {
|
||||
printf("A charger is plugged into the OTG: ");
|
||||
return -ENODEV;
|
||||
}
|
||||
ret = sunxi_usb_phy_id_detect(0);
|
||||
|
||||
ret = sun4i_usb_phy_id_detect(glue->phy);
|
||||
if (ret == 1) {
|
||||
printf("No host cable detected: ");
|
||||
return -ENODEV;
|
||||
}
|
||||
sunxi_usb_phy_power_on(0); /* port power on */
|
||||
|
||||
ret = generic_phy_power_on(glue->phy);
|
||||
if (ret) {
|
||||
pr_err("failed to power on USB PHY\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
USBC_ForceVbusValidToHigh(musb->mregs);
|
||||
@ -253,13 +262,21 @@ static int sunxi_musb_enable(struct musb *musb)
|
||||
|
||||
static void sunxi_musb_disable(struct musb *musb)
|
||||
{
|
||||
struct sunxi_glue *glue = to_sunxi_glue(musb->controller);
|
||||
int ret;
|
||||
|
||||
pr_debug("%s():\n", __func__);
|
||||
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
if (is_host_enabled(musb))
|
||||
sunxi_usb_phy_power_off(0); /* port power off */
|
||||
if (is_host_enabled(musb)) {
|
||||
ret = generic_phy_power_off(glue->phy);
|
||||
if (ret) {
|
||||
pr_err("failed to power off USB PHY\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
USBC_ForceVbusValidToLow(musb->mregs);
|
||||
mdelay(200); /* Wait for the current session to timeout */
|
||||
@ -270,9 +287,16 @@ static void sunxi_musb_disable(struct musb *musb)
|
||||
static int sunxi_musb_init(struct musb *musb)
|
||||
{
|
||||
struct sunxi_glue *glue = to_sunxi_glue(musb->controller);
|
||||
int ret;
|
||||
|
||||
pr_debug("%s():\n", __func__);
|
||||
|
||||
ret = generic_phy_init(glue->phy);
|
||||
if (ret) {
|
||||
pr_err("failed to init USB PHY\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
musb->isr = sunxi_musb_interrupt;
|
||||
|
||||
setbits_le32(&glue->ccm->ahb_gate0, BIT(AHB_GATE_OFFSET_USB0));
|
||||
@ -286,8 +310,6 @@ static int sunxi_musb_init(struct musb *musb)
|
||||
BIT(glue->cfg->rst_bit));
|
||||
#endif
|
||||
|
||||
sunxi_usb_phy_init(0);
|
||||
|
||||
USBC_ConfigFIFO_Base();
|
||||
USBC_EnableDpDmPullUp(musb->mregs);
|
||||
USBC_EnableIdPullUp(musb->mregs);
|
||||
@ -383,6 +405,7 @@ static int musb_usb_probe(struct udevice *dev)
|
||||
struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
|
||||
struct musb_hdrc_platform_data pdata;
|
||||
void *base = dev_read_addr_ptr(dev);
|
||||
struct phy phy;
|
||||
int ret;
|
||||
|
||||
if (!base)
|
||||
@ -396,6 +419,13 @@ static int musb_usb_probe(struct udevice *dev)
|
||||
if (IS_ERR(glue->ccm))
|
||||
return PTR_ERR(glue->ccm);
|
||||
|
||||
ret = generic_phy_get_by_name(dev, "usb", &phy);
|
||||
if (ret) {
|
||||
pr_err("failed to get usb PHY\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
glue->phy = &phy;
|
||||
priv->desc_before_addr = true;
|
||||
|
||||
memset(&pdata, 0, sizeof(pdata));
|
||||
@ -426,10 +456,18 @@ static int musb_usb_remove(struct udevice *dev)
|
||||
{
|
||||
struct sunxi_glue *glue = dev_get_priv(dev);
|
||||
struct musb_host_data *host = &glue->mdata;
|
||||
int ret;
|
||||
|
||||
if (generic_phy_valid(glue->phy)) {
|
||||
ret = generic_phy_exit(glue->phy);
|
||||
if (ret) {
|
||||
pr_err("failed to exit %s USB PHY\n", dev->name);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
musb_stop(host->host);
|
||||
|
||||
sunxi_usb_phy_exit(0);
|
||||
#ifdef CONFIG_SUNXI_GEN_SUN6I
|
||||
clrbits_le32(&glue->ccm->ahb_reset0_cfg, BIT(AHB_GATE_OFFSET_USB0));
|
||||
if (glue->cfg->rst_bit)
|
||||
|
Loading…
Reference in New Issue
Block a user