From a9fc15e0fd78ac57535c2e4fcddfafd9df32e37a Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 16 Apr 2020 14:19:05 +0200 Subject: 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 Signed-off-by: Neil Armstrong Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-meson-g12a.c | 102 ++++++++++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-) (limited to 'drivers/usb/dwc3') diff --git a/drivers/usb/dwc3/dwc3-meson-g12a.c b/drivers/usb/dwc3/dwc3-meson-g12a.c index b4d728c4a051..bd744e82cad4 100644 --- a/drivers/usb/dwc3/dwc3-meson-g12a.c +++ b/drivers/usb/dwc3/dwc3-meson-g12a.c @@ -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, -- cgit v1.2.3