OSDN Git Service

usb: dwc3: meson-g12a: add support for GXL and GXM SoCs
authorNeil Armstrong <narmstrong@baylibre.com>
Thu, 16 Apr 2020 12:19:05 +0000 (14:19 +0200)
committerFelipe Balbi <balbi@kernel.org>
Mon, 25 May 2020 08:09:38 +0000 (11:09 +0300)
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>
drivers/usb/dwc3/dwc3-meson-g12a.c

index b4d728c..bd744e8 100644 (file)
 #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;
@@ -831,6 +923,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,
        },