diff options
author | Jagan Teki <jagan@amarulasolutions.com> | 2018-05-07 13:03:30 +0530 |
---|---|---|
committer | Jagan Teki <jagan@amarulasolutions.com> | 2018-05-28 16:40:43 +0530 |
commit | 5f646bf1d7d0b22eefec3c22d5c9c94c6eb79228 (patch) | |
tree | e2924375f365069679ecb292933d9a426c662164 /drivers/phy | |
parent | bafe5e3061497a52023b24b50b1104f0da880fed (diff) |
phy: sun4i-usb: Add A83T USB PHY config
Unlike, other Allwinner SUN4I Phy supporting SOC, A83T has
2 USB PHY's and second one is HSIC. So phy control need to
configure to handle these HSIC and SIDDQ requirement.
Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
Acked-by: Jun Nie <jun.nie@linaro.org>
Diffstat (limited to 'drivers/phy')
-rw-r--r-- | drivers/phy/allwinner/phy-sun4i-usb.c | 85 |
1 files changed, 68 insertions, 17 deletions
diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c index de0a59a32c6..01782ac97cd 100644 --- a/drivers/phy/allwinner/phy-sun4i-usb.c +++ b/drivers/phy/allwinner/phy-sun4i-usb.c @@ -53,9 +53,19 @@ #define SUNXI_AHB_INCRX_ALIGN_EN BIT(8) #define SUNXI_ULPI_BYPASS_EN BIT(0) +/* A83T specific control bits for PHY0 */ +#define PHY_CTL_VBUSVLDEXT BIT(5) +#define PHY_CTL_SIDDQ BIT(3) + +/* A83T specific control bits for PHY2 HSIC */ +#define SUNXI_EHCI_HS_FORCE BIT(20) +#define SUNXI_HSIC_CONNECT_INT BIT(16) +#define SUNXI_HSIC BIT(1) + #define MAX_PHYS 4 enum sun4i_usb_phy_type { + sun8i_a83t_phy, sun8i_h3_phy, sun8i_v3s_phy, sun50i_a64_phy, @@ -92,13 +102,20 @@ struct sun4i_usb_phy_info { .gpio_vbus = CONFIG_USB2_VBUS_PIN, .gpio_vbus_det = NULL, .gpio_id_det = NULL, +#ifdef CONFIG_MACH_SUN8I_A83T + .rst_mask = (CCM_USB_CTRL_HSIC_RST | CCM_USB_CTRL_HSIC_CLK | + CCM_USB_CTRL_12M_CLK), +#else .rst_mask = (CCM_USB_CTRL_PHY2_RST | CCM_USB_CTRL_PHY2_CLK), +#endif }, { .gpio_vbus = CONFIG_USB3_VBUS_PIN, .gpio_vbus_det = NULL, .gpio_id_det = NULL, +#ifdef CONFIG_MACH_SUN6I .rst_mask = (CCM_USB_CTRL_PHY3_RST | CCM_USB_CTRL_PHY3_CLK), +#endif }, }; @@ -166,9 +183,10 @@ static void sun4i_usb_phy_write(struct phy *phy, u32 addr, u32 data, int len) } } -static void sun4i_usb_phy_passby(struct sun4i_usb_phy_plat *usb_phy, - bool enable) +static void sun4i_usb_phy_passby(struct phy *phy, bool enable) { + struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev); + struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id]; u32 bits, reg_value; if (!usb_phy->pmu) @@ -176,6 +194,12 @@ static void sun4i_usb_phy_passby(struct sun4i_usb_phy_plat *usb_phy, bits = SUNXI_AHB_ICHR8_EN | SUNXI_AHB_INCR4_BURST_EN | SUNXI_AHB_INCRX_ALIGN_EN | SUNXI_ULPI_BYPASS_EN; + + /* A83T USB2 is HSIC */ + if (data->cfg->type == sun8i_a83t_phy && usb_phy->id == 2) + bits |= SUNXI_EHCI_HS_FORCE | SUNXI_HSIC_CONNECT_INT | + SUNXI_HSIC; + reg_value = readl(usb_phy->pmu); if (enable) @@ -244,25 +268,36 @@ static int sun4i_usb_phy_init(struct phy *phy) setbits_le32(&data->ccm->usb_clk_cfg, usb_phy->rst_mask); - if (usb_phy->pmu && data->cfg->enable_pmu_unk1) { - val = readl(usb_phy->pmu + REG_PMU_UNK1); - writel(val & ~2, usb_phy->pmu + REG_PMU_UNK1); - } + if (data->cfg->type == sun8i_a83t_phy) { + if (phy->id == 0) { + val = readl(data->base + data->cfg->phyctl_offset); + val |= PHY_CTL_VBUSVLDEXT; + val &= ~PHY_CTL_SIDDQ; + writel(val, data->base + data->cfg->phyctl_offset); + } + } else { + if (usb_phy->pmu && data->cfg->enable_pmu_unk1) { + val = readl(usb_phy->pmu + REG_PMU_UNK1); + writel(val & ~2, usb_phy->pmu + REG_PMU_UNK1); + } - if (usb_phy->id == 0) - sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN, PHY_RES45_CAL_DATA, - PHY_RES45_CAL_LEN); + if (usb_phy->id == 0) + sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN, + PHY_RES45_CAL_DATA, + PHY_RES45_CAL_LEN); - /* Adjust PHY's magnitude and rate */ - sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, PHY_TX_MAGNITUDE | - PHY_TX_RATE, PHY_TX_AMPLITUDE_LEN); + /* Adjust PHY's magnitude and rate */ + sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, + PHY_TX_MAGNITUDE | PHY_TX_RATE, + PHY_TX_AMPLITUDE_LEN); - /* Disconnect threshold adjustment */ - sun4i_usb_phy_write(phy, PHY_DISCON_TH_SEL, data->cfg->disc_thresh, - PHY_DISCON_TH_LEN); + /* Disconnect threshold adjustment */ + sun4i_usb_phy_write(phy, PHY_DISCON_TH_SEL, + data->cfg->disc_thresh, PHY_DISCON_TH_LEN); + } if (usb_phy->id != 0) - sun4i_usb_phy_passby(usb_phy, true); + sun4i_usb_phy_passby(phy, true); sun4i_usb_phy0_reroute(data, true); @@ -274,7 +309,16 @@ static int sun4i_usb_phy_exit(struct phy *phy) struct sun4i_usb_phy_data *data = dev_get_priv(phy->dev); struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id]; - sun4i_usb_phy_passby(usb_phy, false); + if (phy->id == 0) { + if (data->cfg->type == sun8i_a83t_phy) { + void __iomem *phyctl = data->base + + data->cfg->phyctl_offset; + + writel(readl(phyctl) | PHY_CTL_SIDDQ, phyctl); + } + } + + sun4i_usb_phy_passby(phy, false); clrbits_le32(&data->ccm->usb_clk_cfg, usb_phy->rst_mask); @@ -416,6 +460,12 @@ static int sun4i_usb_phy_probe(struct udevice *dev) return 0; } +static const struct sun4i_usb_phy_cfg sun8i_a83t_cfg = { + .num_phys = 3, + .type = sun8i_a83t_phy, + .phyctl_offset = REG_PHYCTL_A33, +}; + static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = { .num_phys = 4, .type = sun8i_h3_phy, @@ -444,6 +494,7 @@ static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = { }; static const struct udevice_id sun4i_usb_phy_ids[] = { + { .compatible = "allwinner,sun8i-a83t-usb-phy", .data = (ulong)&sun8i_a83t_cfg }, { .compatible = "allwinner,sun8i-h3-usb-phy", .data = (ulong)&sun8i_h3_cfg }, { .compatible = "allwinner,sun8i-v3s-usb-phy", .data = (ulong)&sun8i_v3s_cfg }, { .compatible = "allwinner,sun50i-a64-usb-phy", .data = (ulong)&sun50i_a64_cfg}, |