phy: phy-rockchip-inno-usb2: add rk3588 support
Add basic support for the USB2 PHY found in the Rockchip RK3588. Co-developed-by: William Wu <william.wu@rock-chips.com> Signed-off-by: William Wu <william.wu@rock-chips.com> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com> Link: https://lore.kernel.org/r/20230522170324.61349-3-sebastian.reichel@collabora.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
This commit is contained in:
parent
cb240921ec
commit
3a7db8e9ed
@ -116,6 +116,12 @@ struct rockchip_chg_det_reg {
|
||||
* @bvalid_det_en: vbus valid rise detection enable register.
|
||||
* @bvalid_det_st: vbus valid rise detection status register.
|
||||
* @bvalid_det_clr: vbus valid rise detection clear register.
|
||||
* @disfall_en: host disconnect fall edge detection enable.
|
||||
* @disfall_st: host disconnect fall edge detection state.
|
||||
* @disfall_clr: host disconnect fall edge detection clear.
|
||||
* @disrise_en: host disconnect rise edge detection enable.
|
||||
* @disrise_st: host disconnect rise edge detection state.
|
||||
* @disrise_clr: host disconnect rise edge detection clear.
|
||||
* @id_det_en: id detection enable register.
|
||||
* @id_det_st: id detection state register.
|
||||
* @id_det_clr: id detection clear register.
|
||||
@ -133,6 +139,12 @@ struct rockchip_usb2phy_port_cfg {
|
||||
struct usb2phy_reg bvalid_det_en;
|
||||
struct usb2phy_reg bvalid_det_st;
|
||||
struct usb2phy_reg bvalid_det_clr;
|
||||
struct usb2phy_reg disfall_en;
|
||||
struct usb2phy_reg disfall_st;
|
||||
struct usb2phy_reg disfall_clr;
|
||||
struct usb2phy_reg disrise_en;
|
||||
struct usb2phy_reg disrise_st;
|
||||
struct usb2phy_reg disrise_clr;
|
||||
struct usb2phy_reg id_det_en;
|
||||
struct usb2phy_reg id_det_st;
|
||||
struct usb2phy_reg id_det_clr;
|
||||
@ -168,6 +180,7 @@ struct rockchip_usb2phy_cfg {
|
||||
* @port_id: flag for otg port or host port.
|
||||
* @suspended: phy suspended flag.
|
||||
* @vbus_attached: otg device vbus status.
|
||||
* @host_disconnect: usb host disconnect status.
|
||||
* @bvalid_irq: IRQ number assigned for vbus valid rise detection.
|
||||
* @id_irq: IRQ number assigned for ID pin detection.
|
||||
* @ls_irq: IRQ number assigned for linestate detection.
|
||||
@ -187,6 +200,7 @@ struct rockchip_usb2phy_port {
|
||||
unsigned int port_id;
|
||||
bool suspended;
|
||||
bool vbus_attached;
|
||||
bool host_disconnect;
|
||||
int bvalid_irq;
|
||||
int id_irq;
|
||||
int ls_irq;
|
||||
@ -405,6 +419,27 @@ static int rockchip_usb2phy_extcon_register(struct rockchip_usb2phy *rphy)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rockchip_usb2phy_enable_host_disc_irq(struct rockchip_usb2phy *rphy,
|
||||
struct rockchip_usb2phy_port *rport,
|
||||
bool en)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = property_enable(rphy->grf, &rport->port_cfg->disfall_clr, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = property_enable(rphy->grf, &rport->port_cfg->disfall_en, en);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = property_enable(rphy->grf, &rport->port_cfg->disrise_clr, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return property_enable(rphy->grf, &rport->port_cfg->disrise_en, en);
|
||||
}
|
||||
|
||||
static int rockchip_usb2phy_init(struct phy *phy)
|
||||
{
|
||||
struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
|
||||
@ -449,6 +484,15 @@ static int rockchip_usb2phy_init(struct phy *phy)
|
||||
dev_dbg(&rport->phy->dev, "mode %d\n", rport->mode);
|
||||
}
|
||||
} else if (rport->port_id == USB2PHY_PORT_HOST) {
|
||||
if (rport->port_cfg->disfall_en.offset) {
|
||||
rport->host_disconnect = true;
|
||||
ret = rockchip_usb2phy_enable_host_disc_irq(rphy, rport, true);
|
||||
if (ret) {
|
||||
dev_err(rphy->dev, "failed to enable disconnect irq\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* clear linestate and enable linestate detect irq */
|
||||
ret = property_enable(rphy->grf,
|
||||
&rport->port_cfg->ls_det_clr, true);
|
||||
@ -810,9 +854,7 @@ static void rockchip_usb2phy_sm_work(struct work_struct *work)
|
||||
struct rockchip_usb2phy_port *rport =
|
||||
container_of(work, struct rockchip_usb2phy_port, sm_work.work);
|
||||
struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);
|
||||
unsigned int sh = rport->port_cfg->utmi_hstdet.bitend -
|
||||
rport->port_cfg->utmi_hstdet.bitstart + 1;
|
||||
unsigned int ul, uhd, state;
|
||||
unsigned int sh, ul, uhd, state;
|
||||
unsigned int ul_mask, uhd_mask;
|
||||
int ret;
|
||||
|
||||
@ -822,18 +864,26 @@ static void rockchip_usb2phy_sm_work(struct work_struct *work)
|
||||
if (ret < 0)
|
||||
goto next_schedule;
|
||||
|
||||
ret = regmap_read(rphy->grf, rport->port_cfg->utmi_hstdet.offset, &uhd);
|
||||
if (ret < 0)
|
||||
goto next_schedule;
|
||||
|
||||
uhd_mask = GENMASK(rport->port_cfg->utmi_hstdet.bitend,
|
||||
rport->port_cfg->utmi_hstdet.bitstart);
|
||||
ul_mask = GENMASK(rport->port_cfg->utmi_ls.bitend,
|
||||
rport->port_cfg->utmi_ls.bitstart);
|
||||
|
||||
/* stitch on utmi_ls and utmi_hstdet as phy state */
|
||||
state = ((uhd & uhd_mask) >> rport->port_cfg->utmi_hstdet.bitstart) |
|
||||
(((ul & ul_mask) >> rport->port_cfg->utmi_ls.bitstart) << sh);
|
||||
if (rport->port_cfg->utmi_hstdet.offset) {
|
||||
ret = regmap_read(rphy->grf, rport->port_cfg->utmi_hstdet.offset, &uhd);
|
||||
if (ret < 0)
|
||||
goto next_schedule;
|
||||
|
||||
uhd_mask = GENMASK(rport->port_cfg->utmi_hstdet.bitend,
|
||||
rport->port_cfg->utmi_hstdet.bitstart);
|
||||
|
||||
sh = rport->port_cfg->utmi_hstdet.bitend -
|
||||
rport->port_cfg->utmi_hstdet.bitstart + 1;
|
||||
/* stitch on utmi_ls and utmi_hstdet as phy state */
|
||||
state = ((uhd & uhd_mask) >> rport->port_cfg->utmi_hstdet.bitstart) |
|
||||
(((ul & ul_mask) >> rport->port_cfg->utmi_ls.bitstart) << sh);
|
||||
} else {
|
||||
state = ((ul & ul_mask) >> rport->port_cfg->utmi_ls.bitstart) << 1 |
|
||||
rport->host_disconnect;
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case PHY_STATE_HS_ONLINE:
|
||||
@ -966,6 +1016,31 @@ static irqreturn_t rockchip_usb2phy_otg_mux_irq(int irq, void *data)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t rockchip_usb2phy_host_disc_irq(int irq, void *data)
|
||||
{
|
||||
struct rockchip_usb2phy_port *rport = data;
|
||||
struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);
|
||||
|
||||
if (!property_enabled(rphy->grf, &rport->port_cfg->disfall_st) &&
|
||||
!property_enabled(rphy->grf, &rport->port_cfg->disrise_st))
|
||||
return IRQ_NONE;
|
||||
|
||||
mutex_lock(&rport->mutex);
|
||||
|
||||
/* clear disconnect fall or rise detect irq pending status */
|
||||
if (property_enabled(rphy->grf, &rport->port_cfg->disfall_st)) {
|
||||
property_enable(rphy->grf, &rport->port_cfg->disfall_clr, true);
|
||||
rport->host_disconnect = false;
|
||||
} else if (property_enabled(rphy->grf, &rport->port_cfg->disrise_st)) {
|
||||
property_enable(rphy->grf, &rport->port_cfg->disrise_clr, true);
|
||||
rport->host_disconnect = true;
|
||||
}
|
||||
|
||||
mutex_unlock(&rport->mutex);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t rockchip_usb2phy_irq(int irq, void *data)
|
||||
{
|
||||
struct rockchip_usb2phy *rphy = data;
|
||||
@ -978,6 +1053,10 @@ static irqreturn_t rockchip_usb2phy_irq(int irq, void *data)
|
||||
if (!rport->phy)
|
||||
continue;
|
||||
|
||||
if (rport->port_id == USB2PHY_PORT_HOST &&
|
||||
rport->port_cfg->disfall_en.offset)
|
||||
ret |= rockchip_usb2phy_host_disc_irq(irq, rport);
|
||||
|
||||
switch (rport->port_id) {
|
||||
case USB2PHY_PORT_OTG:
|
||||
if (rport->mode != USB_DR_MODE_HOST &&
|
||||
@ -1233,7 +1312,7 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
/* support address_cells=2 */
|
||||
if (reg == 0) {
|
||||
if (of_property_count_u32_elems(np, "reg") > 2 && reg == 0) {
|
||||
if (of_property_read_u32_index(np, "reg", 1, ®)) {
|
||||
dev_err(dev, "the reg property is not assigned in %pOFn node\n",
|
||||
np);
|
||||
@ -1254,14 +1333,14 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev)
|
||||
|
||||
/* find out a proper config which can be matched with dt. */
|
||||
index = 0;
|
||||
while (phy_cfgs[index].reg) {
|
||||
do {
|
||||
if (phy_cfgs[index].reg == reg) {
|
||||
rphy->phy_cfg = &phy_cfgs[index];
|
||||
break;
|
||||
}
|
||||
|
||||
++index;
|
||||
}
|
||||
} while (phy_cfgs[index].reg);
|
||||
|
||||
if (!rphy->phy_cfg) {
|
||||
dev_err(dev, "no phy-config can be matched with %pOFn node\n",
|
||||
@ -1664,6 +1743,122 @@ static const struct rockchip_usb2phy_cfg rk3568_phy_cfgs[] = {
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static const struct rockchip_usb2phy_cfg rk3588_phy_cfgs[] = {
|
||||
{
|
||||
.reg = 0x0000,
|
||||
.num_ports = 1,
|
||||
.clkout_ctl = { 0x0000, 0, 0, 1, 0 },
|
||||
.port_cfgs = {
|
||||
[USB2PHY_PORT_OTG] = {
|
||||
.phy_sus = { 0x000c, 11, 11, 0, 1 },
|
||||
.bvalid_det_en = { 0x0080, 1, 1, 0, 1 },
|
||||
.bvalid_det_st = { 0x0084, 1, 1, 0, 1 },
|
||||
.bvalid_det_clr = { 0x0088, 1, 1, 0, 1 },
|
||||
.ls_det_en = { 0x0080, 0, 0, 0, 1 },
|
||||
.ls_det_st = { 0x0084, 0, 0, 0, 1 },
|
||||
.ls_det_clr = { 0x0088, 0, 0, 0, 1 },
|
||||
.disfall_en = { 0x0080, 6, 6, 0, 1 },
|
||||
.disfall_st = { 0x0084, 6, 6, 0, 1 },
|
||||
.disfall_clr = { 0x0088, 6, 6, 0, 1 },
|
||||
.disrise_en = { 0x0080, 5, 5, 0, 1 },
|
||||
.disrise_st = { 0x0084, 5, 5, 0, 1 },
|
||||
.disrise_clr = { 0x0088, 5, 5, 0, 1 },
|
||||
.utmi_avalid = { 0x00c0, 7, 7, 0, 1 },
|
||||
.utmi_bvalid = { 0x00c0, 6, 6, 0, 1 },
|
||||
.utmi_ls = { 0x00c0, 10, 9, 0, 1 },
|
||||
}
|
||||
},
|
||||
.chg_det = {
|
||||
.cp_det = { 0x00c0, 0, 0, 0, 1 },
|
||||
.dcp_det = { 0x00c0, 0, 0, 0, 1 },
|
||||
.dp_det = { 0x00c0, 1, 1, 1, 0 },
|
||||
.idm_sink_en = { 0x0008, 5, 5, 1, 0 },
|
||||
.idp_sink_en = { 0x0008, 5, 5, 0, 1 },
|
||||
.idp_src_en = { 0x0008, 14, 14, 0, 1 },
|
||||
.rdm_pdwn_en = { 0x0008, 14, 14, 0, 1 },
|
||||
.vdm_src_en = { 0x0008, 7, 6, 0, 3 },
|
||||
.vdp_src_en = { 0x0008, 7, 6, 0, 3 },
|
||||
},
|
||||
},
|
||||
{
|
||||
.reg = 0x4000,
|
||||
.num_ports = 1,
|
||||
.clkout_ctl = { 0x0000, 0, 0, 1, 0 },
|
||||
.port_cfgs = {
|
||||
[USB2PHY_PORT_OTG] = {
|
||||
.phy_sus = { 0x000c, 11, 11, 0, 1 },
|
||||
.bvalid_det_en = { 0x0080, 1, 1, 0, 1 },
|
||||
.bvalid_det_st = { 0x0084, 1, 1, 0, 1 },
|
||||
.bvalid_det_clr = { 0x0088, 1, 1, 0, 1 },
|
||||
.ls_det_en = { 0x0080, 0, 0, 0, 1 },
|
||||
.ls_det_st = { 0x0084, 0, 0, 0, 1 },
|
||||
.ls_det_clr = { 0x0088, 0, 0, 0, 1 },
|
||||
.disfall_en = { 0x0080, 6, 6, 0, 1 },
|
||||
.disfall_st = { 0x0084, 6, 6, 0, 1 },
|
||||
.disfall_clr = { 0x0088, 6, 6, 0, 1 },
|
||||
.disrise_en = { 0x0080, 5, 5, 0, 1 },
|
||||
.disrise_st = { 0x0084, 5, 5, 0, 1 },
|
||||
.disrise_clr = { 0x0088, 5, 5, 0, 1 },
|
||||
.utmi_avalid = { 0x00c0, 7, 7, 0, 1 },
|
||||
.utmi_bvalid = { 0x00c0, 6, 6, 0, 1 },
|
||||
.utmi_ls = { 0x00c0, 10, 9, 0, 1 },
|
||||
}
|
||||
},
|
||||
.chg_det = {
|
||||
.cp_det = { 0x00c0, 0, 0, 0, 1 },
|
||||
.dcp_det = { 0x00c0, 0, 0, 0, 1 },
|
||||
.dp_det = { 0x00c0, 1, 1, 1, 0 },
|
||||
.idm_sink_en = { 0x0008, 5, 5, 1, 0 },
|
||||
.idp_sink_en = { 0x0008, 5, 5, 0, 1 },
|
||||
.idp_src_en = { 0x0008, 14, 14, 0, 1 },
|
||||
.rdm_pdwn_en = { 0x0008, 14, 14, 0, 1 },
|
||||
.vdm_src_en = { 0x0008, 7, 6, 0, 3 },
|
||||
.vdp_src_en = { 0x0008, 7, 6, 0, 3 },
|
||||
},
|
||||
},
|
||||
{
|
||||
.reg = 0x8000,
|
||||
.num_ports = 1,
|
||||
.clkout_ctl = { 0x0000, 0, 0, 1, 0 },
|
||||
.port_cfgs = {
|
||||
[USB2PHY_PORT_HOST] = {
|
||||
.phy_sus = { 0x0008, 2, 2, 0, 1 },
|
||||
.ls_det_en = { 0x0080, 0, 0, 0, 1 },
|
||||
.ls_det_st = { 0x0084, 0, 0, 0, 1 },
|
||||
.ls_det_clr = { 0x0088, 0, 0, 0, 1 },
|
||||
.disfall_en = { 0x0080, 6, 6, 0, 1 },
|
||||
.disfall_st = { 0x0084, 6, 6, 0, 1 },
|
||||
.disfall_clr = { 0x0088, 6, 6, 0, 1 },
|
||||
.disrise_en = { 0x0080, 5, 5, 0, 1 },
|
||||
.disrise_st = { 0x0084, 5, 5, 0, 1 },
|
||||
.disrise_clr = { 0x0088, 5, 5, 0, 1 },
|
||||
.utmi_ls = { 0x00c0, 10, 9, 0, 1 },
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
.reg = 0xc000,
|
||||
.num_ports = 1,
|
||||
.clkout_ctl = { 0x0000, 0, 0, 1, 0 },
|
||||
.port_cfgs = {
|
||||
[USB2PHY_PORT_HOST] = {
|
||||
.phy_sus = { 0x0008, 2, 2, 0, 1 },
|
||||
.ls_det_en = { 0x0080, 0, 0, 0, 1 },
|
||||
.ls_det_st = { 0x0084, 0, 0, 0, 1 },
|
||||
.ls_det_clr = { 0x0088, 0, 0, 0, 1 },
|
||||
.disfall_en = { 0x0080, 6, 6, 0, 1 },
|
||||
.disfall_st = { 0x0084, 6, 6, 0, 1 },
|
||||
.disfall_clr = { 0x0088, 6, 6, 0, 1 },
|
||||
.disrise_en = { 0x0080, 5, 5, 0, 1 },
|
||||
.disrise_st = { 0x0084, 5, 5, 0, 1 },
|
||||
.disrise_clr = { 0x0088, 5, 5, 0, 1 },
|
||||
.utmi_ls = { 0x00c0, 10, 9, 0, 1 },
|
||||
}
|
||||
},
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static const struct rockchip_usb2phy_cfg rv1108_phy_cfgs[] = {
|
||||
{
|
||||
.reg = 0x100,
|
||||
@ -1714,6 +1909,7 @@ static const struct of_device_id rockchip_usb2phy_dt_match[] = {
|
||||
{ .compatible = "rockchip,rk3366-usb2phy", .data = &rk3366_phy_cfgs },
|
||||
{ .compatible = "rockchip,rk3399-usb2phy", .data = &rk3399_phy_cfgs },
|
||||
{ .compatible = "rockchip,rk3568-usb2phy", .data = &rk3568_phy_cfgs },
|
||||
{ .compatible = "rockchip,rk3588-usb2phy", .data = &rk3588_phy_cfgs },
|
||||
{ .compatible = "rockchip,rv1108-usb2phy", .data = &rv1108_phy_cfgs },
|
||||
{}
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user