mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 10:58:48 +09:00
phy: rockchip: inno-usb2: add usb2 phy support for rk3528
This patch add usb2 phy support for rk3528 and modified the rk3568_vbus_detect_control as a universal interface due to more and more platforms may use this interface in the future. Usb2 phy also has one different design for rk3528. It doesn't has commonon control bit, we found that there is a phy inner debug register which can control the pll out. So we can use this register to support phy pll control for rk3528. Add usb2 phy tuning for rk3528: 1. Turn off differential receiver in suspend mode for the otg and host port to save power consumption. 2. Choose the Tx fs/ls data as linestate from TX driver for otg port which uses dwc3 controller to improve fs/ls devices compatibility with long cable. 3. Enable both the otg and host ports phy irq to pmu wakeup source. 4. Set HS eye-height to 400mV for rk3528 Signed-off-by: Jianwei Zheng <jianwei.zheng@rock-chips.com> Change-Id: Ia4a861bccd6a37db4e1ba42cede66a6b07947b5d
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user