diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index 66e5e10c0321..72b8deb151d2 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -208,7 +208,9 @@ struct rockchip_usb2phy_port_cfg { * @num_ports: specify how many ports that the phy has. * @phy_tuning: phy default parameters tuning. * @vbus_detect: vbus voltage level detection function. - * @clkout_ctl: keep on/turn off output clk of phy. + * @clkout_ctl: keep on/turn off output clk of phy via commonon bit. + * @clkout_ctl_phy: keep on/turn off output clk of phy via phy inner + * debug register. * @ls_filter_con: set linestate filter time. * @port_cfgs: usb-phy port configurations. * @ls_filter_con: set linestate filter time. @@ -218,8 +220,11 @@ struct rockchip_usb2phy_cfg { unsigned int reg; unsigned int num_ports; int (*phy_tuning)(struct rockchip_usb2phy *rphy); - int (*vbus_detect)(struct rockchip_usb2phy *rphy, bool en); + int (*vbus_detect)(struct rockchip_usb2phy *rphy, + const struct usb2phy_reg *vbus_det_en, + bool en); struct usb2phy_reg clkout_ctl; + struct usb2phy_reg clkout_ctl_phy; struct usb2phy_reg ls_filter_con; const struct rockchip_usb2phy_port_cfg port_cfgs[USB2PHY_NUM_PORTS]; const struct rockchip_chg_det_reg chg_det; @@ -376,6 +381,29 @@ static inline bool property_enabled(struct regmap *base, return tmp == reg->enable; } +static inline void phy_property_enable(void __iomem *base, + const struct usb2phy_reg *reg, bool en) +{ + unsigned int val, tmp; + + val = readl(base + reg->offset); + tmp = en ? reg->enable : reg->disable; + val &= ~GENMASK(reg->bitend, reg->bitstart); + val |= tmp << reg->bitstart; + writel(val, base + reg->offset); +} + +static inline bool phy_property_enabled(void __iomem *base, + const struct usb2phy_reg *reg) +{ + unsigned int orig, tmp; + unsigned int mask = GENMASK(reg->bitend, reg->bitstart); + + orig = readl(base + reg->offset); + tmp = (orig & mask) >> reg->bitstart; + return tmp == reg->enable; +} + static inline void phy_clear_bits(void __iomem *reg, u32 bits) { u32 tmp = readl(reg); @@ -431,7 +459,14 @@ static int rockchip_usb2phy_clk480m_prepare(struct clk_hw *hw) int ret; /* turn on 480m clk output if it is off */ - if (!property_enabled(base, &rphy->phy_cfg->clkout_ctl)) { + if (rphy->phy_cfg->clkout_ctl_phy.enable) { + if (!phy_property_enabled(rphy->phy_base, &rphy->phy_cfg->clkout_ctl_phy)) { + phy_property_enable(rphy->phy_base, &rphy->phy_cfg->clkout_ctl_phy, true); + + /* waiting for the clk become stable */ + usleep_range(1200, 1300); + } + } else if (!property_enabled(base, &rphy->phy_cfg->clkout_ctl)) { ret = property_enable(base, &rphy->phy_cfg->clkout_ctl, true); if (ret) return ret; @@ -450,7 +485,10 @@ static void rockchip_usb2phy_clk480m_unprepare(struct clk_hw *hw) struct regmap *base = get_reg_base(rphy); /* turn off 480m clk output */ - property_enable(base, &rphy->phy_cfg->clkout_ctl, false); + if (rphy->phy_cfg->clkout_ctl_phy.enable) + phy_property_enable(rphy->phy_base, &rphy->phy_cfg->clkout_ctl_phy, false); + else + property_enable(base, &rphy->phy_cfg->clkout_ctl, false); } static int rockchip_usb2phy_clk480m_prepared(struct clk_hw *hw) @@ -459,7 +497,10 @@ static int rockchip_usb2phy_clk480m_prepared(struct clk_hw *hw) container_of(hw, struct rockchip_usb2phy, clk480m_hw); struct regmap *base = get_reg_base(rphy); - return property_enabled(base, &rphy->phy_cfg->clkout_ctl); + if (rphy->phy_cfg->clkout_ctl_phy.enable) + return phy_property_enabled(rphy->phy_base, &rphy->phy_cfg->clkout_ctl_phy); + else + return property_enabled(base, &rphy->phy_cfg->clkout_ctl); } static unsigned long @@ -1011,7 +1052,8 @@ static int rockchip_usb2phy_set_mode(struct phy *phy, } if (rphy->phy_cfg->vbus_detect) - rphy->phy_cfg->vbus_detect(rphy, vbus_det_en); + rphy->phy_cfg->vbus_detect(rphy, &rport->port_cfg->vbus_det_en, + vbus_det_en); else ret = property_enable(rphy->grf, &rport->port_cfg->vbus_det_en, vbus_det_en); @@ -2666,6 +2708,31 @@ static int rk3399_usb2phy_tuning(struct rockchip_usb2phy *rphy) return ret; } +static int rk3528_usb2phy_tuning(struct rockchip_usb2phy *rphy) +{ + int ret = 0; + + /* Turn off otg port differential receiver in suspend mode */ + phy_clear_bits(rphy->phy_base + 0x30, BIT(2)); + + /* Turn off host port differential receiver in suspend mode */ + phy_clear_bits(rphy->phy_base + 0x430, BIT(2)); + + /* Set otg port HS eye height to 400mv(default is 450mv) */ + phy_update_bits(rphy->phy_base + 0x30, GENMASK(6, 4), (0x00 << 4)); + + /* Set host port HS eye height to 400mv(default is 450mv) */ + phy_update_bits(rphy->phy_base + 0x430, GENMASK(6, 4), (0x00 << 4)); + + /* Choose the Tx fs/ls data as linestate from TX driver for otg port */ + phy_update_bits(rphy->phy_base + 0x94, GENMASK(6, 3), (0x03 << 3)); + + /* Enable otg and host ports phy irq to pmu wakeup source */ + ret |= regmap_write(rphy->grf, 0x80004, 0x00030003); + + return ret; +} + static int rk3568_usb2phy_tuning(struct rockchip_usb2phy *rphy) { int ret = 0; @@ -2734,14 +2801,16 @@ static int rv1106_usb2phy_tuning(struct rockchip_usb2phy *rphy) return 0; } -static int rk3568_vbus_detect_control(struct rockchip_usb2phy *rphy, bool en) +static int rockchip_usb2phy_vbus_det_control(struct rockchip_usb2phy *rphy, + const struct usb2phy_reg *vbus_det_en, + bool en) { if (en) { /* Enable vbus voltage level detection function */ - phy_clear_bits(rphy->phy_base + 0x3c, BIT(7)); + phy_clear_bits(rphy->phy_base + vbus_det_en->offset, BIT(7)); } else { /* Disable vbus voltage level detection function */ - phy_set_bits(rphy->phy_base + 0x3c, BIT(7)); + phy_set_bits(rphy->phy_base + vbus_det_en->offset, BIT(7)); } return 0; @@ -3477,12 +3546,66 @@ static const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = { { /* sentinel */ } }; +static const struct rockchip_usb2phy_cfg rk3528_phy_cfgs[] = { + { + .reg = 0xffdf0000, + .num_ports = 2, + .phy_tuning = rk3528_usb2phy_tuning, + .vbus_detect = rockchip_usb2phy_vbus_det_control, + .clkout_ctl_phy = { 0x041c, 7, 2, 0, 0x27 }, + .port_cfgs = { + [USB2PHY_PORT_OTG] = { + .phy_sus = { 0x6004c, 8, 0, 0, 0x1d1 }, + .bvalid_det_en = { 0x60074, 2, 2, 0, 1 }, + .bvalid_det_st = { 0x60078, 2, 2, 0, 1 }, + .bvalid_det_clr = { 0x6007c, 2, 2, 0, 1 }, + .iddig_output = { 0x6004c, 10, 10, 0, 1 }, + .iddig_en = { 0x6004c, 9, 9, 0, 1 }, + .idfall_det_en = { 0x60074, 5, 5, 0, 1 }, + .idfall_det_st = { 0x60078, 5, 5, 0, 1 }, + .idfall_det_clr = { 0x6007c, 5, 5, 0, 1 }, + .idrise_det_en = { 0x60074, 4, 4, 0, 1 }, + .idrise_det_st = { 0x60078, 4, 4, 0, 1 }, + .idrise_det_clr = { 0x6007c, 4, 4, 0, 1 }, + .ls_det_en = { 0x60074, 0, 0, 0, 1 }, + .ls_det_st = { 0x60078, 0, 0, 0, 1 }, + .ls_det_clr = { 0x6007c, 0, 0, 0, 1 }, + .utmi_avalid = { 0x6006c, 1, 1, 0, 1 }, + .utmi_bvalid = { 0x6006c, 0, 0, 0, 1 }, + .utmi_iddig = { 0x6006c, 6, 6, 0, 1 }, + .utmi_ls = { 0x6006c, 5, 4, 0, 1 }, + .vbus_det_en = { 0x003c, 7, 7, 0, 1 }, + }, + [USB2PHY_PORT_HOST] = { + .phy_sus = { 0x6005c, 8, 0, 0x1d2, 0x1d1 }, + .ls_det_en = { 0x60090, 0, 0, 0, 1 }, + .ls_det_st = { 0x60094, 0, 0, 0, 1 }, + .ls_det_clr = { 0x60098, 0, 0, 0, 1 }, + .utmi_ls = { 0x6006c, 13, 12, 0, 1 }, + .utmi_hstdet = { 0x6006c, 15, 15, 0, 1 } + } + }, + .chg_det = { + .chg_mode = { 0x6004c, 8, 0, 0, 0x1d7 }, + .cp_det = { 0x6006c, 19, 19, 0, 1 }, + .dcp_det = { 0x6006c, 18, 18, 0, 1 }, + .dp_det = { 0x6006c, 20, 20, 0, 1 }, + .idm_sink_en = { 0x60058, 1, 1, 0, 1 }, + .idp_sink_en = { 0x60058, 0, 0, 0, 1 }, + .idp_src_en = { 0x60058, 2, 2, 0, 1 }, + .rdm_pdwn_en = { 0x60058, 3, 3, 0, 1 }, + .vdm_src_en = { 0x60058, 5, 5, 0, 1 }, + .vdp_src_en = { 0x60058, 4, 4, 0, 1 }, + }, + } +}; + static const struct rockchip_usb2phy_cfg rk3568_phy_cfgs[] = { { .reg = 0xfe8a0000, .num_ports = 2, .phy_tuning = rk3568_usb2phy_tuning, - .vbus_detect = rk3568_vbus_detect_control, + .vbus_detect = rockchip_usb2phy_vbus_det_control, .clkout_ctl = { 0x0008, 4, 4, 1, 0 }, .ls_filter_con = { 0x0040, 19, 0, 0x30100, 0x00020 }, .port_cfgs = { @@ -3509,6 +3632,7 @@ static const struct rockchip_usb2phy_cfg rk3568_phy_cfgs[] = { .utmi_bvalid = { 0x00c0, 9, 9, 0, 1 }, .utmi_iddig = { 0x00c0, 6, 6, 0, 1 }, .utmi_ls = { 0x00c0, 5, 4, 0, 1 }, + .vbus_det_en = { 0x003c, 7, 7, 0, 1 }, }, [USB2PHY_PORT_HOST] = { /* Select suspend control from controller */ @@ -3833,6 +3957,9 @@ static const struct of_device_id rockchip_usb2phy_dt_match[] = { #ifdef CONFIG_CPU_RK3399 { .compatible = "rockchip,rk3399-usb2phy", .data = &rk3399_phy_cfgs }, #endif +#ifdef CONFIG_CPU_RK3528 + { .compatible = "rockchip,rk3528-usb2phy", .data = &rk3528_phy_cfgs }, +#endif #ifdef CONFIG_CPU_RK3568 { .compatible = "rockchip,rk3568-usb2phy", .data = &rk3568_phy_cfgs }, #endif