This is a patchset which makes away with the .bind() controller indexing
workaround which was broken since before v2021.04, and then adds PHY
support and MX8M support on top of that. Better add it into the release
early to get as much testing as possible done, because this really does
a lot of changes to the ehci-mx6 driver.
This commit is contained in:
Tom Rini 2021-04-18 08:46:58 -04:00
commit c6ae5e9869
12 changed files with 466 additions and 184 deletions

View File

@ -39,7 +39,7 @@
};
usbphy: phy {
compatible = "nop-phy";
compatible = "usb-nop-xceiv";
#phy-cells = <0>;
};

View File

@ -4,6 +4,8 @@
*/
#include <dt-bindings/clock/imx8mm-clock.h>
#include <dt-bindings/power/imx8mm-power.h>
#include <dt-bindings/reset/imx8mq-reset.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
@ -241,6 +243,7 @@
};
usbphynop1: usbphynop1 {
#phy-cells = <0>;
compatible = "usb-nop-xceiv";
clocks = <&clk IMX8MM_CLK_USB_PHY_REF>;
assigned-clocks = <&clk IMX8MM_CLK_USB_PHY_REF>;
@ -249,6 +252,7 @@
};
usbphynop2: usbphynop2 {
#phy-cells = <0>;
compatible = "usb-nop-xceiv";
clocks = <&clk IMX8MM_CLK_USB_PHY_REF>;
assigned-clocks = <&clk IMX8MM_CLK_USB_PHY_REF>;
@ -590,6 +594,75 @@
interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
#reset-cells = <1>;
};
gpc: gpc@303a0000 {
compatible = "fsl,imx8mm-gpc";
reg = <0x303a0000 0x10000>;
interrupt-parent = <&gic>;
interrupt-controller;
#interrupt-cells = <3>;
pgc {
#address-cells = <1>;
#size-cells = <0>;
pgc_hsiomix: power-domain@0 {
#power-domain-cells = <0>;
reg = <IMX8MM_POWER_DOMAIN_HSIOMIX>;
clocks = <&clk IMX8MM_CLK_USB_BUS>;
};
pgc_pcie: power-domain@1 {
#power-domain-cells = <0>;
reg = <IMX8MM_POWER_DOMAIN_PCIE>;
power-domains = <&pgc_hsiomix>;
};
pgc_otg1: power-domain@2 {
#power-domain-cells = <0>;
reg = <IMX8MM_POWER_DOMAIN_OTG1>;
power-domains = <&pgc_hsiomix>;
};
pgc_otg2: power-domain@3 {
#power-domain-cells = <0>;
reg = <IMX8MM_POWER_DOMAIN_OTG2>;
power-domains = <&pgc_hsiomix>;
};
pgc_gpumix: power-domain@4 {
#power-domain-cells = <0>;
reg = <IMX8MM_POWER_DOMAIN_GPUMIX>;
clocks = <&clk IMX8MM_CLK_GPU_BUS_ROOT>,
<&clk IMX8MM_CLK_GPU_AHB>;
};
pgc_gpu: power-domain@5 {
#power-domain-cells = <0>;
reg = <IMX8MM_POWER_DOMAIN_GPU>;
clocks = <&clk IMX8MM_CLK_GPU_AHB>,
<&clk IMX8MM_CLK_GPU_BUS_ROOT>,
<&clk IMX8MM_CLK_GPU2D_ROOT>,
<&clk IMX8MM_CLK_GPU3D_ROOT>;
resets = <&src IMX8MQ_RESET_GPU_RESET>;
power-domains = <&pgc_gpumix>;
};
dispmix_pd: power-domain@10 {
#power-domain-cells = <0>;
reg = <IMX8MM_POWER_DOMAIN_DISPMIX>;
clocks = <&clk IMX8MM_CLK_DISP_ROOT>,
<&clk IMX8MM_CLK_DISP_AXI_ROOT>,
<&clk IMX8MM_CLK_DISP_APB_ROOT>;
};
mipi_pd: power-domain@11 {
#power-domain-cells = <0>;
reg = <IMX8MM_POWER_DOMAIN_MIPI>;
power-domains = <&dispmix_pd>;
};
};
};
};
aips2: bus@30400000 {
@ -936,8 +1009,9 @@
clock-names = "usb1_ctrl_root_clk";
assigned-clocks = <&clk IMX8MM_CLK_USB_BUS>;
assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_500M>;
fsl,usbphy = <&usbphynop1>;
phys = <&usbphynop1>;
fsl,usbmisc = <&usbmisc1 0>;
power-domains = <&pgc_otg1>;
status = "disabled";
};
@ -955,8 +1029,9 @@
clock-names = "usb1_ctrl_root_clk";
assigned-clocks = <&clk IMX8MM_CLK_USB_BUS>;
assigned-clock-parents = <&clk IMX8MM_SYS_PLL2_500M>;
fsl,usbphy = <&usbphynop2>;
phys = <&usbphynop2>;
fsl,usbmisc = <&usbmisc2 0>;
power-domains = <&pgc_otg2>;
status = "disabled";
};

View File

@ -4,6 +4,8 @@
*/
#include <dt-bindings/clock/imx8mn-clock.h>
#include <dt-bindings/power/imx8mn-power.h>
#include <dt-bindings/reset/imx8mq-reset.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
@ -612,6 +614,54 @@
interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
#reset-cells = <1>;
};
gpc: gpc@303a0000 {
compatible = "fsl,imx8mn-gpc";
reg = <0x303a0000 0x10000>;
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
pgc {
#address-cells = <1>;
#size-cells = <0>;
pgc_hsiomix: power-domain@0 {
#power-domain-cells = <0>;
reg = <IMX8MN_POWER_DOMAIN_HSIOMIX>;
clocks = <&clk IMX8MN_CLK_USB_BUS>;
};
pgc_otg1: power-domain@1 {
#power-domain-cells = <0>;
reg = <IMX8MN_POWER_DOMAIN_OTG1>;
power-domains = <&pgc_hsiomix>;
};
pgc_gpumix: power-domain@2 {
#power-domain-cells = <0>;
reg = <IMX8MN_POWER_DOMAIN_GPUMIX>;
clocks = <&clk IMX8MN_CLK_GPU_CORE_ROOT>,
<&clk IMX8MN_CLK_GPU_SHADER_DIV>,
<&clk IMX8MN_CLK_GPU_BUS_ROOT>,
<&clk IMX8MN_CLK_GPU_AHB>;
resets = <&src IMX8MQ_RESET_GPU_RESET>;
};
dispmix_pd: power-domain@3 {
#power-domain-cells = <0>;
reg = <IMX8MN_POWER_DOMAIN_DISPMIX>;
clocks = <&clk IMX8MN_CLK_DISP_PIXEL_ROOT>,
<&clk IMX8MN_CLK_DISP_AXI_ROOT>,
<&clk IMX8MN_CLK_DISP_APB_ROOT>;
};
mipi_pd: power-domain@4 {
#power-domain-cells = <0>;
reg = <IMX8MN_POWER_DOMAIN_MIPI>;
power-domains = <&dispmix_pd>;
};
};
};
};
aips2: bus@30400000 {
@ -962,8 +1012,9 @@
clock-names = "usb1_ctrl_root_clk";
assigned-clocks = <&clk IMX8MN_CLK_USB_BUS>;
assigned-clock-parents = <&clk IMX8MN_SYS_PLL2_500M>;
fsl,usbphy = <&usbphynop1>;
phys = <&usbphynop1>;
fsl,usbmisc = <&usbmisc1 0>;
power-domains = <&pgc_otg1>;
status = "disabled";
};
@ -1030,6 +1081,7 @@
};
usbphynop1: usbphynop1 {
#phy-cells = <0>;
compatible = "usb-nop-xceiv";
clocks = <&clk IMX8MN_CLK_USB_PHY_REF>;
assigned-clocks = <&clk IMX8MN_CLK_USB_PHY_REF>;

View File

@ -38,7 +38,6 @@
&usb0_phy {
status = "okay";
compatible = "nop-phy";
};
&usb0 {
@ -51,7 +50,6 @@
};
&usb1_phy {
compatible = "nop-phy";
status = "okay";
};

View File

@ -37,7 +37,6 @@ CONFIG_SPL_BOARD_INIT=y
CONFIG_SPL_SEPARATE_BSS=y
CONFIG_SPL_I2C_SUPPORT=y
CONFIG_SPL_POWER_SUPPORT=y
CONFIG_SPL_USB_HOST_SUPPORT=y
CONFIG_SPL_WATCHDOG_SUPPORT=y
CONFIG_SYS_PROMPT="Verdin iMX8MM # "
# CONFIG_BOOTM_NETBSD is not set
@ -50,6 +49,7 @@ CONFIG_CMD_FUSE=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_I2C=y
CONFIG_CMD_MMC=y
CONFIG_CMD_USB=y
CONFIG_CMD_CACHE=y
CONFIG_CMD_UUID=y
CONFIG_CMD_REGULATOR=y
@ -89,6 +89,8 @@ CONFIG_MII=y
CONFIG_PINCTRL=y
CONFIG_SPL_PINCTRL=y
CONFIG_PINCTRL_IMX8M=y
CONFIG_POWER_DOMAIN=y
CONFIG_IMX8M_POWER_DOMAIN=y
CONFIG_DM_PMIC=y
CONFIG_SPL_DM_PMIC_PCA9450=y
CONFIG_DM_PMIC_PFUZE100=y
@ -101,5 +103,9 @@ CONFIG_SPL_SYSRESET=y
CONFIG_SYSRESET_PSCI=y
CONFIG_SYSRESET_WATCHDOG=y
CONFIG_DM_THERMAL=y
CONFIG_USB=y
CONFIG_DM_USB=y
# CONFIG_SPL_DM_USB is not set
CONFIG_USB_EHCI_HCD=y
CONFIG_IMX_WATCHDOG=y
CONFIG_OF_LIBFDT_OVERLAY=y

View File

@ -43,6 +43,7 @@ static int nop_phy_probe(struct udevice *dev)
static const struct udevice_id nop_phy_ids[] = {
{ .compatible = "nop-phy" },
{ .compatible = "usb-nop-xceiv" },
{ }
};

View File

@ -120,6 +120,8 @@ static int imx8m_power_domain_of_to_plat(struct udevice *dev)
static const struct udevice_id imx8m_power_domain_ids[] = {
{ .compatible = "fsl,imx8mq-gpc" },
{ .compatible = "fsl,imx8mm-gpc" },
{ .compatible = "fsl,imx8mn-gpc" },
{ }
};

View File

@ -156,7 +156,9 @@ config USB_EHCI_MX6
config USB_EHCI_MX7
bool "Support for i.MX7 on-chip EHCI USB controller"
depends on ARCH_MX7
depends on ARCH_MX7 || IMX8M
select PHY if IMX8M
select NOP_PHY if IMX8M
default y
---help---
Enables support for the on-chip EHCI controller on i.MX7 SoCs.

View File

@ -5,6 +5,7 @@
*/
#include <common.h>
#include <clk.h>
#include <log.h>
#include <usb.h>
#include <errno.h>
@ -67,49 +68,41 @@ DECLARE_GLOBAL_DATA_PTR;
#define UCMD_RUN_STOP (1 << 0) /* controller run/stop */
#define UCMD_RESET (1 << 1) /* controller reset */
#if defined(CONFIG_MX6) || defined(CONFIG_MX7ULP)
static const unsigned phy_bases[] = {
USB_PHY0_BASE_ADDR,
#if defined(USB_PHY1_BASE_ADDR)
USB_PHY1_BASE_ADDR,
/* If this is not defined, assume MX6/MX7/MX8M SoC default */
#ifndef CONFIG_MXC_USB_PORTSC
#define CONFIG_MXC_USB_PORTSC (PORT_PTS_UTMI | PORT_PTS_PTW)
#endif
/* Base address for this IP block is 0x02184800 */
struct usbnc_regs {
u32 ctrl[4]; /* otg/host1-3 */
u32 uh2_hsic_ctrl;
u32 uh3_hsic_ctrl;
u32 otg_phy_ctrl_0;
u32 uh1_phy_ctrl_0;
u32 reserve1[4];
u32 phy_cfg1;
u32 phy_cfg2;
u32 reserve2;
u32 phy_status;
u32 reserve3[4];
u32 adp_cfg1;
u32 adp_cfg2;
u32 adp_status;
};
static void usb_internal_phy_clock_gate(int index, int on)
#if defined(CONFIG_MX6) && !defined(CONFIG_PHY)
static void usb_power_config_mx6(struct anatop_regs __iomem *anatop,
int anatop_bits_index)
{
void __iomem *phy_reg;
if (index >= ARRAY_SIZE(phy_bases))
return;
phy_reg = (void __iomem *)phy_bases[index];
phy_reg += on ? USBPHY_CTRL_CLR : USBPHY_CTRL_SET;
writel(USBPHY_CTRL_CLKGATE, phy_reg);
}
static void usb_power_config(int index)
{
#if defined(CONFIG_MX7ULP)
struct usbphy_regs __iomem *usbphy =
(struct usbphy_regs __iomem *)USB_PHY0_BASE_ADDR;
if (index > 0)
return;
writel(ANADIG_USB2_CHRG_DETECT_EN_B |
ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B,
&usbphy->usb1_chrg_detect);
scg_enable_usb_pll(true);
#else
struct anatop_regs __iomem *anatop =
(struct anatop_regs __iomem *)ANATOP_BASE_ADDR;
void __iomem *chrg_detect;
void __iomem *pll_480_ctrl_clr;
void __iomem *pll_480_ctrl_set;
switch (index) {
if (!is_mx6())
return;
switch (anatop_bits_index) {
case 0:
chrg_detect = &anatop->usb1_chrg_detect;
pll_480_ctrl_clr = &anatop->usb1_pll_480_ctrl_clr;
@ -142,22 +135,70 @@ static void usb_power_config(int index)
ANADIG_USB2_PLL_480_CTRL_POWER |
ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS,
pll_480_ctrl_set);
}
#else
static void __maybe_unused
usb_power_config_mx6(void *anatop, int anatop_bits_index) { }
#endif
#if defined(CONFIG_MX7) && !defined(CONFIG_PHY)
static void usb_power_config_mx7(struct usbnc_regs *usbnc)
{
void __iomem *phy_cfg2 = (void __iomem *)(&usbnc->phy_cfg2);
if (!is_mx7())
return;
/*
* Clear the ACAENB to enable usb_otg_id detection,
* otherwise it is the ACA detection enabled.
*/
clrbits_le32(phy_cfg2, USBNC_PHYCFG2_ACAENB);
}
#else
static void __maybe_unused
usb_power_config_mx7(void *usbnc) { }
#endif
#if defined(CONFIG_MX7ULP) && !defined(CONFIG_PHY)
static void usb_power_config_mx7ulp(struct usbphy_regs __iomem *usbphy)
{
if (!is_mx7ulp())
return;
writel(ANADIG_USB2_CHRG_DETECT_EN_B |
ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B,
&usbphy->usb1_chrg_detect);
scg_enable_usb_pll(true);
}
#else
static void __maybe_unused
usb_power_config_mx7ulp(void *usbphy) { }
#endif
#if defined(CONFIG_MX6) || defined(CONFIG_MX7ULP)
static const unsigned phy_bases[] = {
USB_PHY0_BASE_ADDR,
#if defined(USB_PHY1_BASE_ADDR)
USB_PHY1_BASE_ADDR,
#endif
};
#if !defined(CONFIG_PHY)
static void usb_internal_phy_clock_gate(void __iomem *phy_reg, int on)
{
phy_reg += on ? USBPHY_CTRL_CLR : USBPHY_CTRL_SET;
writel(USBPHY_CTRL_CLKGATE, phy_reg);
}
/* Return 0 : host node, <>0 : device mode */
static int usb_phy_enable(int index, struct usb_ehci *ehci)
static int usb_phy_enable(struct usb_ehci *ehci, void __iomem *phy_reg)
{
void __iomem *phy_reg;
void __iomem *phy_ctrl;
void __iomem *usb_cmd;
int ret;
if (index >= ARRAY_SIZE(phy_bases))
return 0;
phy_reg = (void __iomem *)phy_bases[index];
phy_ctrl = (void __iomem *)(phy_reg + USBPHY_CTRL);
usb_cmd = (void __iomem *)&ehci->usbcmd;
@ -188,6 +229,7 @@ static int usb_phy_enable(int index, struct usb_ehci *ehci)
return 0;
}
#endif
int usb_phy_mode(int port)
{
@ -206,52 +248,7 @@ int usb_phy_mode(int port)
return USB_INIT_HOST;
}
#if defined(CONFIG_MX7ULP)
struct usbnc_regs {
u32 ctrl1;
u32 ctrl2;
u32 reserve0[2];
u32 hsic_ctrl;
};
#else
/* Base address for this IP block is 0x02184800 */
struct usbnc_regs {
u32 ctrl[4]; /* otg/host1-3 */
u32 uh2_hsic_ctrl;
u32 uh3_hsic_ctrl;
u32 otg_phy_ctrl_0;
u32 uh1_phy_ctrl_0;
};
#endif
#elif defined(CONFIG_MX7)
struct usbnc_regs {
u32 ctrl1;
u32 ctrl2;
u32 reserve1[10];
u32 phy_cfg1;
u32 phy_cfg2;
u32 reserve2;
u32 phy_status;
u32 reserve3[4];
u32 adp_cfg1;
u32 adp_cfg2;
u32 adp_status;
};
static void usb_power_config(int index)
{
struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR +
(0x10000 * index) + USBNC_OFFSET);
void __iomem *phy_cfg2 = (void __iomem *)(&usbnc->phy_cfg2);
/*
* Clear the ACAENB to enable usb_otg_id detection,
* otherwise it is the ACA detection enabled.
*/
clrbits_le32(phy_cfg2, USBNC_PHYCFG2_ACAENB);
}
int usb_phy_mode(int port)
{
struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR +
@ -268,17 +265,9 @@ int usb_phy_mode(int port)
}
#endif
static void usb_oc_config(int index)
static void usb_oc_config(struct usbnc_regs *usbnc, int index)
{
#if defined(CONFIG_MX6)
struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR +
USB_OTHERREGS_OFFSET);
void __iomem *ctrl = (void __iomem *)(&usbnc->ctrl[index]);
#elif defined(CONFIG_MX7) || defined(CONFIG_MX7ULP)
struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR +
(0x10000 * index) + USBNC_OFFSET);
void __iomem *ctrl = (void __iomem *)(&usbnc->ctrl1);
#endif
#if CONFIG_MACH_TYPE == MACH_TYPE_MX6Q_ARM2
/* mx6qarm2 seems to required a different setting*/
@ -297,6 +286,7 @@ static void usb_oc_config(int index)
#endif
}
#if !CONFIG_IS_ENABLED(DM_USB)
/**
* board_usb_phy_mode - override usb phy mode
* @port: usb host/otg port
@ -343,38 +333,26 @@ int __weak board_ehci_power(int port, int on)
return 0;
}
int ehci_mx6_common_init(struct usb_ehci *ehci, int index)
{
int ret;
enable_usboh3_clk(1);
mdelay(1);
/* Do board specific initialization */
ret = board_ehci_hcd_init(index);
if (ret)
return ret;
usb_power_config(index);
usb_oc_config(index);
#if defined(CONFIG_MX6) || defined(CONFIG_MX7ULP)
usb_internal_phy_clock_gate(index, 1);
usb_phy_enable(index, ehci);
#endif
return 0;
}
#if !CONFIG_IS_ENABLED(DM_USB)
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
enum usb_init_type type;
#if defined(CONFIG_MX6)
u32 controller_spacing = 0x200;
#elif defined(CONFIG_MX7) || defined(CONFIG_MX7ULP)
struct anatop_regs __iomem *anatop =
(struct anatop_regs __iomem *)ANATOP_BASE_ADDR;
struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR +
USB_OTHERREGS_OFFSET);
#elif defined(CONFIG_MX7)
u32 controller_spacing = 0x10000;
struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR +
(0x10000 * index) + USBNC_OFFSET);
#elif defined(CONFIG_MX7ULP)
u32 controller_spacing = 0x10000;
struct usbphy_regs __iomem *usbphy =
(struct usbphy_regs __iomem *)USB_PHY0_BASE_ADDR;
struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR +
(0x10000 * index) + USBNC_OFFSET);
#endif
struct usb_ehci *ehci = (struct usb_ehci *)(USB_BASE_ADDR +
(controller_spacing * index));
@ -391,15 +369,38 @@ int ehci_hcd_init(int index, enum usb_init_type init,
}
}
ret = ehci_mx6_common_init(ehci, index);
if (ret)
enable_usboh3_clk(1);
mdelay(1);
/* Do board specific initialization */
ret = board_ehci_hcd_init(index);
if (ret) {
enable_usboh3_clk(0);
return ret;
}
#if defined(CONFIG_MX6)
usb_power_config_mx6(anatop, index);
#elif defined (CONFIG_MX7)
usb_power_config_mx7(usbnc);
#elif defined (CONFIG_MX7ULP)
usb_power_config_mx7ulp(usbphy);
#endif
usb_oc_config(usbnc, index);
#if defined(CONFIG_MX6) || defined(CONFIG_MX7ULP)
if (index < ARRAY_SIZE(phy_bases)) {
usb_internal_phy_clock_gate((void __iomem *)phy_bases[index], 1);
usb_phy_enable(ehci, (void __iomem *)phy_bases[index]);
}
#endif
type = board_usb_phy_mode(index);
if (hccr && hcor) {
*hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
*hcor = (struct ehci_hcor *)((uint32_t)*hccr +
*hccr = (struct ehci_hccr *)((uintptr_t)&ehci->caplength);
*hcor = (struct ehci_hcor *)((uintptr_t)*hccr +
HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
}
@ -428,8 +429,13 @@ struct ehci_mx6_priv_data {
struct ehci_ctrl ctrl;
struct usb_ehci *ehci;
struct udevice *vbus_supply;
struct clk clk;
struct phy phy;
enum usb_init_type init_type;
int portnr;
void __iomem *phy_addr;
void __iomem *misc_addr;
void __iomem *anatop_addr;
};
static int mx6_init_after_reset(struct ehci_ctrl *dev)
@ -437,14 +443,23 @@ static int mx6_init_after_reset(struct ehci_ctrl *dev)
struct ehci_mx6_priv_data *priv = dev->priv;
enum usb_init_type type = priv->init_type;
struct usb_ehci *ehci = priv->ehci;
int ret;
ret = ehci_mx6_common_init(priv->ehci, priv->portnr);
if (ret)
return ret;
#if !defined(CONFIG_PHY)
usb_power_config_mx6(priv->anatop_addr, priv->portnr);
usb_power_config_mx7(priv->misc_addr);
usb_power_config_mx7ulp(priv->phy_addr);
#endif
usb_oc_config(priv->misc_addr, priv->portnr);
#if !defined(CONFIG_PHY) && (defined(CONFIG_MX6) || defined(CONFIG_MX7ULP))
usb_internal_phy_clock_gate(priv->phy_addr, 1);
usb_phy_enable(ehci, priv->phy_addr);
#endif
#if CONFIG_IS_ENABLED(DM_REGULATOR)
if (priv->vbus_supply) {
int ret;
ret = regulator_set_enable(priv->vbus_supply,
(type == USB_INIT_DEVICE) ?
false : true);
@ -541,46 +556,58 @@ static int ehci_usb_of_to_plat(struct udevice *dev)
return 0;
}
static int ehci_usb_bind(struct udevice *dev)
static int mx6_parse_dt_addrs(struct udevice *dev)
{
/*
* TODO:
* This driver is only partly converted to DT probing and still uses
* a tremendous amount of hard-coded addresses. To make things worse,
* the driver depends on specific sequential indexing of controllers,
* from which it derives offsets in the PHY and ANATOP register sets.
*
* Here we attempt to calculate these indexes from DT information as
* well as we can. The USB controllers on all existing iMX6 SoCs
* are placed next to each other, at addresses incremented by 0x200,
* and iMX7 their addresses are shifted by 0x10000.
* Thus, the index is derived from the multiple of 0x200 (0x10000 for
* iMX7) offset from the first controller address.
*
* However, to complete conversion of this driver to DT probing, the
* following has to be done:
* - DM clock framework support for iMX must be implemented
* - usb_power_config() has to be converted to clock framework
* -> Thus, the ad-hoc "index" variable goes away.
* - USB PHY handling has to be factored out into separate driver
* -> Thus, the ad-hoc "index" variable goes away from the PHY
* code, the PHY driver must parse it's address from DT. This
* USB driver must find the PHY driver via DT phandle.
* -> usb_power_config() shall be moved to PHY driver
* With these changes in place, the ad-hoc indexing goes away and
* the driver is fully converted to DT probing.
*/
struct ehci_mx6_priv_data *priv = dev_get_priv(dev);
int phy_off, misc_off;
const void *blob = gd->fdt_blob;
int offset = dev_of_offset(dev);
void *__iomem addr;
int ret, devnump;
/*
* FIXME: This cannot work with the new sequence numbers.
* Please complete the DM conversion.
*
* u32 controller_spacing = is_mx7() ? 0x10000 : 0x200;
* fdt_addr_t addr = devfdt_get_addr_index(dev, 0);
*
* dev->req_seq = (addr - USB_BASE_ADDR) / controller_spacing;
*/
phy_off = fdtdec_lookup_phandle(blob, offset, "fsl,usbphy");
if (phy_off < 0) {
phy_off = fdtdec_lookup_phandle(blob, offset, "phys");
if (phy_off < 0)
return -EINVAL;
}
ret = fdtdec_get_alias_seq(blob, dev->uclass->uc_drv->name,
phy_off, &devnump);
if (ret < 0)
return ret;
misc_off = fdtdec_lookup_phandle(blob, offset, "fsl,usbmisc");
if (misc_off < 0)
return -EINVAL;
addr = (void __iomem *)fdtdec_get_addr(blob, phy_off, "reg");
if ((fdt_addr_t)addr == FDT_ADDR_T_NONE)
return -EINVAL;
priv->phy_addr = addr;
priv->portnr = devnump;
addr = (void __iomem *)fdtdec_get_addr(blob, misc_off, "reg");
if ((fdt_addr_t)addr == FDT_ADDR_T_NONE)
return -EINVAL;
priv->misc_addr = addr;
#if !defined(CONFIG_PHY) && defined(CONFIG_MX6)
int anatop_off;
/* Resolve ANATOP offset through USB PHY node */
anatop_off = fdtdec_lookup_phandle(blob, phy_off, "fsl,anatop");
if (anatop_off < 0)
return -EINVAL;
addr = (void __iomem *)fdtdec_get_addr(blob, anatop_off, "reg");
if ((fdt_addr_t)addr == FDT_ADDR_T_NONE)
return -EINVAL;
priv->anatop_addr = addr;
#endif
return 0;
}
@ -602,19 +629,46 @@ static int ehci_usb_probe(struct udevice *dev)
}
}
ret = mx6_parse_dt_addrs(dev);
if (ret)
return ret;
priv->ehci = ehci;
priv->portnr = dev_seq(dev);
priv->init_type = type;
#if CONFIG_IS_ENABLED(CLK)
ret = clk_get_by_index(dev, 0, &priv->clk);
if (ret < 0)
return ret;
ret = clk_enable(&priv->clk);
if (ret)
return ret;
#else
/* Compatibility with DM_USB and !CLK */
enable_usboh3_clk(1);
mdelay(1);
#endif
#if CONFIG_IS_ENABLED(DM_REGULATOR)
ret = device_get_supply_regulator(dev, "vbus-supply",
&priv->vbus_supply);
if (ret)
debug("%s: No vbus supply\n", dev->name);
#endif
ret = ehci_mx6_common_init(ehci, priv->portnr);
if (ret)
return ret;
#if !defined(CONFIG_PHY)
usb_power_config_mx6(priv->anatop_addr, priv->portnr);
usb_power_config_mx7(priv->misc_addr);
usb_power_config_mx7ulp(priv->phy_addr);
#endif
usb_oc_config(priv->misc_addr, priv->portnr);
#if !defined(CONFIG_PHY) && (defined(CONFIG_MX6) || defined(CONFIG_MX7ULP))
usb_internal_phy_clock_gate(priv->phy_addr, 1);
usb_phy_enable(ehci, priv->phy_addr);
#endif
#if CONFIG_IS_ENABLED(DM_REGULATOR)
if (priv->vbus_supply) {
@ -623,7 +677,7 @@ static int ehci_usb_probe(struct udevice *dev)
false : true);
if (ret && ret != -ENOSYS) {
printf("Error enabling VBUS supply (ret=%i)\n", ret);
return ret;
goto err_clk;
}
}
#endif
@ -636,15 +690,66 @@ static int ehci_usb_probe(struct udevice *dev)
mdelay(10);
hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
hcor = (struct ehci_hcor *)((uint32_t)hccr +
#if defined(CONFIG_PHY)
ret = ehci_setup_phy(dev, &priv->phy, 0);
if (ret)
goto err_regulator;
#endif
hccr = (struct ehci_hccr *)((uintptr_t)&ehci->caplength);
hcor = (struct ehci_hcor *)((uintptr_t)hccr +
HC_LENGTH(ehci_readl(&(hccr)->cr_capbase)));
return ehci_register(dev, hccr, hcor, &mx6_ehci_ops, 0, priv->init_type);
ret = ehci_register(dev, hccr, hcor, &mx6_ehci_ops, 0, priv->init_type);
if (ret)
goto err_phy;
return ret;
err_phy:
#if defined(CONFIG_PHY)
ehci_shutdown_phy(dev, &priv->phy);
err_regulator:
#endif
#if CONFIG_IS_ENABLED(DM_REGULATOR)
if (priv->vbus_supply)
regulator_set_enable(priv->vbus_supply, false);
err_clk:
#endif
#if CONFIG_IS_ENABLED(CLK)
clk_disable(&priv->clk);
#else
/* Compatibility with DM_USB and !CLK */
enable_usboh3_clk(0);
#endif
return ret;
}
int ehci_usb_remove(struct udevice *dev)
{
struct ehci_mx6_priv_data *priv __maybe_unused = dev_get_priv(dev);
ehci_deregister(dev);
#if defined(CONFIG_PHY)
ehci_shutdown_phy(dev, &priv->phy);
#endif
#if CONFIG_IS_ENABLED(DM_REGULATOR)
if (priv->vbus_supply)
regulator_set_enable(priv->vbus_supply, false);
#endif
#if CONFIG_IS_ENABLED(CLK)
clk_disable(&priv->clk);
#endif
return 0;
}
static const struct udevice_id mx6_usb_ids[] = {
{ .compatible = "fsl,imx27-usb" },
{ .compatible = "fsl,imx7d-usb" },
{ }
};
@ -653,9 +758,8 @@ U_BOOT_DRIVER(usb_mx6) = {
.id = UCLASS_USB,
.of_match = mx6_usb_ids,
.of_to_plat = ehci_usb_of_to_plat,
.bind = ehci_usb_bind,
.probe = ehci_usb_probe,
.remove = ehci_deregister,
.remove = ehci_usb_remove,
.ops = &ehci_usb_ops,
.plat_auto = sizeof(struct usb_plat),
.priv_auto = sizeof(struct ehci_mx6_priv_data),

View File

@ -117,5 +117,10 @@
#define FEC_QUIRK_ENET_MAC
#define IMX_FEC_BASE 0x30BE0000
/* USB Configs */
#define CONFIG_EHCI_HCD_INIT_AFTER_RESET
#define CONFIG_MXC_USB_PORTSC (PORT_PTS_UTMI | PORT_PTS_PTW)
#define CONFIG_USB_MAX_CONTROLLER_COUNT 2
#endif /*_VERDIN_IMX8MM_H */

View File

@ -0,0 +1,22 @@
/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
/*
* Copyright (C) 2020 Pengutronix, Lucas Stach <kernel@pengutronix.de>
*/
#ifndef __DT_BINDINGS_IMX8MM_POWER_H__
#define __DT_BINDINGS_IMX8MM_POWER_H__
#define IMX8MM_POWER_DOMAIN_HSIOMIX 0
#define IMX8MM_POWER_DOMAIN_PCIE 1
#define IMX8MM_POWER_DOMAIN_OTG1 2
#define IMX8MM_POWER_DOMAIN_OTG2 3
#define IMX8MM_POWER_DOMAIN_GPUMIX 4
#define IMX8MM_POWER_DOMAIN_GPU 5
#define IMX8MM_POWER_DOMAIN_VPUMIX 6
#define IMX8MM_POWER_DOMAIN_VPUG1 7
#define IMX8MM_POWER_DOMAIN_VPUG2 8
#define IMX8MM_POWER_DOMAIN_VPUH1 9
#define IMX8MM_POWER_DOMAIN_DISPMIX 10
#define IMX8MM_POWER_DOMAIN_MIPI 11
#endif

View File

@ -0,0 +1,15 @@
/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
/*
* Copyright (C) 2020 Compass Electronics Group, LLC
*/
#ifndef __DT_BINDINGS_IMX8MN_POWER_H__
#define __DT_BINDINGS_IMX8MN_POWER_H__
#define IMX8MN_POWER_DOMAIN_HSIOMIX 0
#define IMX8MN_POWER_DOMAIN_OTG1 1
#define IMX8MN_POWER_DOMAIN_GPUMIX 2
#define IMX8MN_POWER_DOMAIN_DISPMIX 3
#define IMX8MN_POWER_DOMAIN_MIPI 4
#endif