mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2025-11-25 04:31:29 +01:00
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>
This commit is contained in:
parent
bafe5e3061
commit
5f646bf1d7
@ -53,9 +53,19 @@
|
|||||||
#define SUNXI_AHB_INCRX_ALIGN_EN BIT(8)
|
#define SUNXI_AHB_INCRX_ALIGN_EN BIT(8)
|
||||||
#define SUNXI_ULPI_BYPASS_EN BIT(0)
|
#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
|
#define MAX_PHYS 4
|
||||||
|
|
||||||
enum sun4i_usb_phy_type {
|
enum sun4i_usb_phy_type {
|
||||||
|
sun8i_a83t_phy,
|
||||||
sun8i_h3_phy,
|
sun8i_h3_phy,
|
||||||
sun8i_v3s_phy,
|
sun8i_v3s_phy,
|
||||||
sun50i_a64_phy,
|
sun50i_a64_phy,
|
||||||
@ -92,13 +102,20 @@ struct sun4i_usb_phy_info {
|
|||||||
.gpio_vbus = CONFIG_USB2_VBUS_PIN,
|
.gpio_vbus = CONFIG_USB2_VBUS_PIN,
|
||||||
.gpio_vbus_det = NULL,
|
.gpio_vbus_det = NULL,
|
||||||
.gpio_id_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),
|
.rst_mask = (CCM_USB_CTRL_PHY2_RST | CCM_USB_CTRL_PHY2_CLK),
|
||||||
|
#endif
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.gpio_vbus = CONFIG_USB3_VBUS_PIN,
|
.gpio_vbus = CONFIG_USB3_VBUS_PIN,
|
||||||
.gpio_vbus_det = NULL,
|
.gpio_vbus_det = NULL,
|
||||||
.gpio_id_det = NULL,
|
.gpio_id_det = NULL,
|
||||||
|
#ifdef CONFIG_MACH_SUN6I
|
||||||
.rst_mask = (CCM_USB_CTRL_PHY3_RST | CCM_USB_CTRL_PHY3_CLK),
|
.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,
|
static void sun4i_usb_phy_passby(struct phy *phy, bool enable)
|
||||||
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;
|
u32 bits, reg_value;
|
||||||
|
|
||||||
if (!usb_phy->pmu)
|
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 |
|
bits = SUNXI_AHB_ICHR8_EN | SUNXI_AHB_INCR4_BURST_EN |
|
||||||
SUNXI_AHB_INCRX_ALIGN_EN | SUNXI_ULPI_BYPASS_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);
|
reg_value = readl(usb_phy->pmu);
|
||||||
|
|
||||||
if (enable)
|
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);
|
setbits_le32(&data->ccm->usb_clk_cfg, usb_phy->rst_mask);
|
||||||
|
|
||||||
|
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) {
|
if (usb_phy->pmu && data->cfg->enable_pmu_unk1) {
|
||||||
val = readl(usb_phy->pmu + REG_PMU_UNK1);
|
val = readl(usb_phy->pmu + REG_PMU_UNK1);
|
||||||
writel(val & ~2, usb_phy->pmu + REG_PMU_UNK1);
|
writel(val & ~2, usb_phy->pmu + REG_PMU_UNK1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usb_phy->id == 0)
|
if (usb_phy->id == 0)
|
||||||
sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN, PHY_RES45_CAL_DATA,
|
sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN,
|
||||||
|
PHY_RES45_CAL_DATA,
|
||||||
PHY_RES45_CAL_LEN);
|
PHY_RES45_CAL_LEN);
|
||||||
|
|
||||||
/* Adjust PHY's magnitude and rate */
|
/* Adjust PHY's magnitude and rate */
|
||||||
sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, PHY_TX_MAGNITUDE |
|
sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE,
|
||||||
PHY_TX_RATE, PHY_TX_AMPLITUDE_LEN);
|
PHY_TX_MAGNITUDE | PHY_TX_RATE,
|
||||||
|
PHY_TX_AMPLITUDE_LEN);
|
||||||
|
|
||||||
/* Disconnect threshold adjustment */
|
/* Disconnect threshold adjustment */
|
||||||
sun4i_usb_phy_write(phy, PHY_DISCON_TH_SEL, data->cfg->disc_thresh,
|
sun4i_usb_phy_write(phy, PHY_DISCON_TH_SEL,
|
||||||
PHY_DISCON_TH_LEN);
|
data->cfg->disc_thresh, PHY_DISCON_TH_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
if (usb_phy->id != 0)
|
if (usb_phy->id != 0)
|
||||||
sun4i_usb_phy_passby(usb_phy, true);
|
sun4i_usb_phy_passby(phy, true);
|
||||||
|
|
||||||
sun4i_usb_phy0_reroute(data, 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_data *data = dev_get_priv(phy->dev);
|
||||||
struct sun4i_usb_phy_plat *usb_phy = &data->usb_phy[phy->id];
|
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);
|
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;
|
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 = {
|
static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = {
|
||||||
.num_phys = 4,
|
.num_phys = 4,
|
||||||
.type = sun8i_h3_phy,
|
.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[] = {
|
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-h3-usb-phy", .data = (ulong)&sun8i_h3_cfg },
|
||||||
{ .compatible = "allwinner,sun8i-v3s-usb-phy", .data = (ulong)&sun8i_v3s_cfg },
|
{ .compatible = "allwinner,sun8i-v3s-usb-phy", .data = (ulong)&sun8i_v3s_cfg },
|
||||||
{ .compatible = "allwinner,sun50i-a64-usb-phy", .data = (ulong)&sun50i_a64_cfg},
|
{ .compatible = "allwinner,sun50i-a64-usb-phy", .data = (ulong)&sun50i_a64_cfg},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user