Permalink
Browse files

GXL/GXM USB peripheral mode HACK

for dwc2 to initialize properly:
- USB3 PHY registers need to be set to DEVICE mode
- USB2 PHY (usb2_phy1) registers need to be set to DEVICE mode
- USB2 PHY has to be powered on
- according to Yixun we need CLKID_USB1 and CLKID_USB1_DDR_BRIDGE

switching modes can be done inside the usb3_phy with the "dr_mode"
property.

TODO:
- solve all inline TODOs
- create a virtual "mode mux PHY" inside the USB3 PHY code?
- ...?

Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
  • Loading branch information...
xdarklight committed Mar 30, 2018
1 parent ac2c3fc commit c98e8fcb9c403d82503a0c8787198e15604932b1
@@ -44,6 +44,31 @@
phys = <&usb3_phy>, <&usb2_phy0>, <&usb2_phy1>;
};
};
usb1: usb@c9100000 {
compatible = "snps,dwc2";
reg = <0x0 0xc9100000 0x0 0x40000>;
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
/* TODO: only one clock is supported by the dwc2 driver: */
clocks = <&clkc CLKID_USB1>,
<&clkc CLKID_USB1_DDR_BRIDGE>;
clock-names = "otg", "ddr";
#if 0
/*
* TODO: probably doesn't work because we're requesting
* it as shared reset elsewhere.
*/
resets = <&reset RESET_USB_OTG>;
reset-names = "dwc2";
#endif
phys = <&usb3_phy>;
phy-names = "usb2-phy";
dr_mode = "peripheral";
g-rx-fifo-size = <192>;
g-np-tx-fifo-size = <128>;
g-tx-fifo-size = <128 128 16 16 16>;
status = "disabled";
};
};
};
@@ -79,6 +104,9 @@
clock-names = "phy", "peripheral";
resets = <&reset RESET_USB_OTG>, <&reset RESET_USB_OTG>;
reset-names = "phy", "peripheral";
phys = <&usb2_phy1>;
phy-names = "usb2-phy";
dr_mode = "peripheral"; /* NOTE: host or peripheral */
status = "okay";
};
};
@@ -416,3 +416,7 @@
&usb0 {
status = "okay";
};
&usb1 {
status = "okay";
};
@@ -32,6 +32,7 @@ config PHY_MESON_GXL_USB3
depends on USB_SUPPORT
select GENERIC_PHY
select REGMAP_MMIO
select USB_COMMON
help
Enable this to support the Meson USB3 PHY and OTG detection
IP block found in Meson GXL and GXM SoCs.
@@ -14,6 +14,7 @@
#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/platform_device.h>
#include <linux/usb/otg.h>
#define USB_R0 0x00
#define USB_R0_P30_FSEL_MASK GENMASK(5, 0)
@@ -86,6 +87,7 @@ struct phy_meson_gxl_usb3_priv {
struct clk *clk_phy;
struct clk *clk_peripheral;
struct reset_control *reset;
struct phy *usb2_phy;
};
static const struct regmap_config phy_meson_gxl_usb3_regmap_conf = {
@@ -98,6 +100,11 @@ static const struct regmap_config phy_meson_gxl_usb3_regmap_conf = {
static int phy_meson_gxl_usb3_power_on(struct phy *phy)
{
struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
int ret;
ret = phy_power_on(priv->usb2_phy);
if (ret)
return ret;
regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_0,
USB_R5_ID_DIG_EN_0);
@@ -112,6 +119,11 @@ static int phy_meson_gxl_usb3_power_on(struct phy *phy)
static int phy_meson_gxl_usb3_power_off(struct phy *phy)
{
struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
int ret;
ret = phy_power_off(priv->usb2_phy);
if (ret)
return ret;
regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_0, 0);
regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_1, 0);
@@ -122,6 +134,11 @@ static int phy_meson_gxl_usb3_power_off(struct phy *phy)
static int phy_meson_gxl_usb3_set_mode(struct phy *phy, enum phy_mode mode)
{
struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
int ret;
ret = phy_set_mode(priv->usb2_phy, mode);
if (ret)
return ret;
switch (mode) {
case PHY_MODE_USB_HOST:
@@ -168,6 +185,10 @@ static int phy_meson_gxl_usb3_init(struct phy *phy)
if (ret)
goto err_disable_clk_peripheral;
ret = phy_init(priv->usb2_phy);
if (ret)
goto err_disable_clk_peripheral;
regmap_update_bits(priv->regmap, USB_R1,
USB_R1_U3H_FLADJ_30MHZ_REG_MASK,
FIELD_PREP(USB_R1_U3H_FLADJ_30MHZ_REG_MASK, 0x20));
@@ -185,6 +206,11 @@ static int phy_meson_gxl_usb3_init(struct phy *phy)
static int phy_meson_gxl_usb3_exit(struct phy *phy)
{
struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
int ret;
ret = phy_exit(priv->usb2_phy);
if (ret)
return ret;
clk_disable_unprepare(priv->clk_peripheral);
clk_disable_unprepare(priv->clk_phy);
@@ -211,6 +237,7 @@ static int phy_meson_gxl_usb3_probe(struct platform_device *pdev)
struct phy_provider *phy_provider;
void __iomem *base;
int ret;
enum usb_dr_mode dr_mode;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -238,6 +265,10 @@ static int phy_meson_gxl_usb3_probe(struct platform_device *pdev)
if (IS_ERR(priv->reset))
return PTR_ERR(priv->reset);
priv->usb2_phy = devm_phy_optional_get(dev, "usb2-phy");
if (IS_ERR(priv->usb2_phy))
return PTR_ERR(priv->usb2_phy);
/*
* default to host mode as hardware defaults and/or boot-loader
* behavior can result in this PHY starting up in device mode. this
@@ -246,6 +277,10 @@ static int phy_meson_gxl_usb3_probe(struct platform_device *pdev)
*/
priv->mode = PHY_MODE_USB_HOST;
dr_mode = usb_get_dr_mode(dev);
if (dr_mode == USB_DR_MODE_PERIPHERAL)
priv->mode = PHY_MODE_USB_DEVICE;
phy = devm_phy_create(dev, np, &phy_meson_gxl_usb3_ops);
if (IS_ERR(phy)) {
ret = PTR_ERR(phy);

0 comments on commit c98e8fc

Please sign in to comment.