usb: dwc3: meson-g12a: add support for GXL and GXM SoCs

In order to add support for the Amlogic GXL/GXM USB Glue, this adds
the corresponding :
- PHY names
- clock names
- USB2 PHY init and mode set
- regmap setup

Reviewed-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Signed-off-by: Felipe Balbi <balbi@kernel.org>
This commit is contained in:
Neil Armstrong 2020-04-16 14:19:05 +02:00 committed by Felipe Balbi
parent df7e374581
commit a9fc15e0fd
1 changed files with 101 additions and 1 deletions

View File

@ -101,6 +101,11 @@
#define PHY_COUNT 3
#define USB2_OTG_PHY 1
static struct clk_bulk_data meson_gxl_clocks[] = {
{ .id = "usb_ctrl" },
{ .id = "ddr" },
};
static struct clk_bulk_data meson_g12a_clocks[] = {
{ .id = NULL },
};
@ -111,6 +116,10 @@ static struct clk_bulk_data meson_a1_clocks[] = {
{ .id = "xtal_usb_ctrl" },
};
static const char *meson_gxm_phy_names[] = {
"usb2-phy0", "usb2-phy1", "usb2-phy2",
};
static const char *meson_g12a_phy_names[] = {
"usb2-phy0", "usb2-phy1", "usb3-phy0",
};
@ -145,16 +154,25 @@ struct dwc3_meson_g12a_drvdata {
int (*usb_post_init)(struct dwc3_meson_g12a *priv);
};
static int dwc3_meson_gxl_setup_regmaps(struct dwc3_meson_g12a *priv,
void __iomem *base);
static int dwc3_meson_g12a_setup_regmaps(struct dwc3_meson_g12a *priv,
void __iomem *base);
static int dwc3_meson_g12a_usb2_init_phy(struct dwc3_meson_g12a *priv, int i,
enum phy_mode mode);
enum phy_mode mode);
static int dwc3_meson_gxl_usb2_init_phy(struct dwc3_meson_g12a *priv, int i,
enum phy_mode mode);
static int dwc3_meson_g12a_set_phy_mode(struct dwc3_meson_g12a *priv,
int i, enum phy_mode mode);
static int dwc3_meson_gxl_set_phy_mode(struct dwc3_meson_g12a *priv,
int i, enum phy_mode mode);
static int dwc3_meson_g12a_usb_init(struct dwc3_meson_g12a *priv);
static int dwc3_meson_gxl_usb_init(struct dwc3_meson_g12a *priv);
static int dwc3_meson_gxl_usb_post_init(struct dwc3_meson_g12a *priv);
/*
* For GXL and GXM SoCs:
@ -169,6 +187,34 @@ static int dwc3_meson_g12a_usb_init(struct dwc3_meson_g12a *priv);
* reset to recover usage of the port.
*/
static struct dwc3_meson_g12a_drvdata gxl_drvdata = {
.otg_switch_supported = true,
.otg_phy_host_port_disable = true,
.clks = meson_gxl_clocks,
.num_clks = ARRAY_SIZE(meson_g12a_clocks),
.phy_names = meson_a1_phy_names,
.num_phys = ARRAY_SIZE(meson_a1_phy_names),
.setup_regmaps = dwc3_meson_gxl_setup_regmaps,
.usb2_init_phy = dwc3_meson_gxl_usb2_init_phy,
.set_phy_mode = dwc3_meson_gxl_set_phy_mode,
.usb_init = dwc3_meson_gxl_usb_init,
.usb_post_init = dwc3_meson_gxl_usb_post_init,
};
static struct dwc3_meson_g12a_drvdata gxm_drvdata = {
.otg_switch_supported = true,
.otg_phy_host_port_disable = true,
.clks = meson_gxl_clocks,
.num_clks = ARRAY_SIZE(meson_g12a_clocks),
.phy_names = meson_gxm_phy_names,
.num_phys = ARRAY_SIZE(meson_gxm_phy_names),
.setup_regmaps = dwc3_meson_gxl_setup_regmaps,
.usb2_init_phy = dwc3_meson_gxl_usb2_init_phy,
.set_phy_mode = dwc3_meson_gxl_set_phy_mode,
.usb_init = dwc3_meson_gxl_usb_init,
.usb_post_init = dwc3_meson_gxl_usb_post_init,
};
static struct dwc3_meson_g12a_drvdata g12a_drvdata = {
.otg_switch_supported = true,
.clks = meson_g12a_clocks,
@ -209,6 +255,21 @@ struct dwc3_meson_g12a {
const struct dwc3_meson_g12a_drvdata *drvdata;
};
static int dwc3_meson_gxl_set_phy_mode(struct dwc3_meson_g12a *priv,
int i, enum phy_mode mode)
{
return phy_set_mode(priv->phys[i], mode);
}
static int dwc3_meson_gxl_usb2_init_phy(struct dwc3_meson_g12a *priv, int i,
enum phy_mode mode)
{
/* On GXL PHY must be started in device mode for DWC2 init */
return priv->drvdata->set_phy_mode(priv, i,
(i == USB2_OTG_PHY) ? PHY_MODE_USB_DEVICE
: PHY_MODE_USB_HOST);
}
static int dwc3_meson_g12a_set_phy_mode(struct dwc3_meson_g12a *priv,
int i, enum phy_mode mode)
{
@ -559,6 +620,18 @@ static int dwc3_meson_g12a_otg_init(struct platform_device *pdev,
return 0;
}
static int dwc3_meson_gxl_setup_regmaps(struct dwc3_meson_g12a *priv,
void __iomem *base)
{
/* GXL controls the PHY mode in the PHY registers unlike G12A */
priv->usb_glue_regmap = devm_regmap_init_mmio(priv->dev, base,
&phy_meson_g12a_usb_glue_regmap_conf);
if (IS_ERR(priv->usb_glue_regmap))
return PTR_ERR(priv->usb_glue_regmap);
return 0;
}
static int dwc3_meson_g12a_setup_regmaps(struct dwc3_meson_g12a *priv,
void __iomem *base)
{
@ -599,6 +672,25 @@ static int dwc3_meson_g12a_usb_init(struct dwc3_meson_g12a *priv)
return dwc3_meson_g12a_usb_init_glue(priv, priv->otg_phy_mode);
}
static int dwc3_meson_gxl_usb_init(struct dwc3_meson_g12a *priv)
{
return dwc3_meson_g12a_usb_init_glue(priv, PHY_MODE_USB_DEVICE);
}
static int dwc3_meson_gxl_usb_post_init(struct dwc3_meson_g12a *priv)
{
int ret;
ret = priv->drvdata->set_phy_mode(priv, USB2_OTG_PHY,
priv->otg_phy_mode);
if (ret)
return ret;
dwc3_meson_g12a_usb_otg_apply_mode(priv, priv->otg_phy_mode);
return 0;
}
static int dwc3_meson_g12a_probe(struct platform_device *pdev)
{
struct dwc3_meson_g12a *priv;
@ -830,6 +922,14 @@ static const struct dev_pm_ops dwc3_meson_g12a_dev_pm_ops = {
};
static const struct of_device_id dwc3_meson_g12a_match[] = {
{
.compatible = "amlogic,meson-gxl-usb-ctrl",
.data = &gxl_drvdata,
},
{
.compatible = "amlogic,meson-gxm-usb-ctrl",
.data = &gxm_drvdata,
},
{
.compatible = "amlogic,meson-g12a-usb-ctrl",
.data = &g12a_drvdata,