From nobody Tue Feb 10 00:59:03 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B2D5AC77B75 for ; Mon, 22 May 2023 17:04:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233487AbjEVREB (ORCPT ); Mon, 22 May 2023 13:04:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56582 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233399AbjEVRDr (ORCPT ); Mon, 22 May 2023 13:03:47 -0400 Received: from madras.collabora.co.uk (madras.collabora.co.uk [IPv6:2a00:1098:0:82:1000:25:2eeb:e5ab]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 88E9B107; Mon, 22 May 2023 10:03:44 -0700 (PDT) Received: from jupiter.universe (dyndsl-091-248-208-162.ewe-ip-backbone.de [91.248.208.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) (Authenticated sender: sre) by madras.collabora.co.uk (Postfix) with ESMTPSA id DDDDB6606E66; Mon, 22 May 2023 18:03:42 +0100 (BST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1684775023; bh=qvhXp2yyvb606B46qr/uSDeu+IWOleW7ERcOlbRxkco=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bUx4pctmb0IcHfBR7qiOhvoWgvVRFwTvXtL5neDQJwasT2hDTX9TyoOC2JMiKbAha FSdhay4iPBIP2TB5b5URbVbxgxlD5XXAzKxDbUB/gqTbzz18XTcH6xlkcCDuQtWS+i C3LXeaQGPs9rtaQiXpf4yArV9yOe6WPnYIdbxW7w3+lW0PTdJVnUQtqc5A4cVNCv60 X8vagK8QfnhIHGawbkMT2v0Os7lMfv11H+JoSdH1A7CZpmAc19EQWZnKgQFnYVq8ME 5IXkZwRS+07XHnGjGbVjYCNptx80hq/f6MXUXZLAhfNJKq8DGPQHhRJLpO9Z2locn4 w6vJUQ4iR+xzA== Received: by jupiter.universe (Postfix, from userid 1000) id 7AF044807E1; Mon, 22 May 2023 19:03:40 +0200 (CEST) From: Sebastian Reichel To: Vinod Koul , Kishon Vijay Abraham I , Rob Herring , Krzysztof Kozlowski Cc: Heiko Stuebner , linux-phy@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-rockchip@lists.infradead.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, Sebastian Reichel , kernel@collabora.com, William Wu Subject: [PATCH v3 2/7] phy: phy-rockchip-inno-usb2: add rk3588 support Date: Mon, 22 May 2023 19:03:19 +0200 Message-Id: <20230522170324.61349-3-sebastian.reichel@collabora.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20230522170324.61349-1-sebastian.reichel@collabora.com> References: <20230522170324.61349-1-sebastian.reichel@collabora.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Add basic support for the USB2 PHY found in the Rockchip RK3588. Co-developed-by: William Wu Signed-off-by: William Wu Signed-off-by: Sebastian Reichel --- drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 226 ++++++++++++++++-- 1 file changed, 211 insertions(+), 15 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/ro= ckchip/phy-rockchip-inno-usb2.c index a0bc10aa7961..2c4683c67a8e 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -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 roc= kchip_usb2phy *rphy) return 0; } =20 +static int rockchip_usb2phy_enable_host_disc_irq(struct rockchip_usb2phy *= rphy, + struct rockchip_usb2phy_port *rport, + bool en) +{ + int ret; + + ret =3D property_enable(rphy->grf, &rport->port_cfg->disfall_clr, true); + if (ret) + return ret; + + ret =3D property_enable(rphy->grf, &rport->port_cfg->disfall_en, en); + if (ret) + return ret; + + ret =3D 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 =3D 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 =3D=3D USB2PHY_PORT_HOST) { + if (rport->port_cfg->disfall_en.offset) { + rport->host_disconnect =3D true; + ret =3D 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 =3D 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 =3D container_of(work, struct rockchip_usb2phy_port, sm_work.work); struct rockchip_usb2phy *rphy =3D dev_get_drvdata(rport->phy->dev.parent); - unsigned int sh =3D 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; =20 @@ -822,18 +864,26 @@ static void rockchip_usb2phy_sm_work(struct work_stru= ct *work) if (ret < 0) goto next_schedule; =20 - ret =3D regmap_read(rphy->grf, rport->port_cfg->utmi_hstdet.offset, &uhd); - if (ret < 0) - goto next_schedule; - - uhd_mask =3D GENMASK(rport->port_cfg->utmi_hstdet.bitend, - rport->port_cfg->utmi_hstdet.bitstart); ul_mask =3D GENMASK(rport->port_cfg->utmi_ls.bitend, rport->port_cfg->utmi_ls.bitstart); =20 - /* stitch on utmi_ls and utmi_hstdet as phy state */ - state =3D ((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 =3D regmap_read(rphy->grf, rport->port_cfg->utmi_hstdet.offset, &uhd= ); + if (ret < 0) + goto next_schedule; + + uhd_mask =3D GENMASK(rport->port_cfg->utmi_hstdet.bitend, + rport->port_cfg->utmi_hstdet.bitstart); + + sh =3D rport->port_cfg->utmi_hstdet.bitend - + rport->port_cfg->utmi_hstdet.bitstart + 1; + /* stitch on utmi_ls and utmi_hstdet as phy state */ + state =3D ((uhd & uhd_mask) >> rport->port_cfg->utmi_hstdet.bitstart) | + (((ul & ul_mask) >> rport->port_cfg->utmi_ls.bitstart) << sh); + } else { + state =3D ((ul & ul_mask) >> rport->port_cfg->utmi_ls.bitstart) << 1 | + rport->host_disconnect; + } =20 switch (state) { case PHY_STATE_HS_ONLINE: @@ -966,6 +1016,31 @@ static irqreturn_t rockchip_usb2phy_otg_mux_irq(int i= rq, void *data) return ret; } =20 +static irqreturn_t rockchip_usb2phy_host_disc_irq(int irq, void *data) +{ + struct rockchip_usb2phy_port *rport =3D data; + struct rockchip_usb2phy *rphy =3D 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 =3D 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 =3D true; + } + + mutex_unlock(&rport->mutex); + + return IRQ_HANDLED; +} + static irqreturn_t rockchip_usb2phy_irq(int irq, void *data) { struct rockchip_usb2phy *rphy =3D data; @@ -978,6 +1053,10 @@ static irqreturn_t rockchip_usb2phy_irq(int irq, void= *data) if (!rport->phy) continue; =20 + if (rport->port_id =3D=3D USB2PHY_PORT_HOST && + rport->port_cfg->disfall_en.offset) + ret |=3D rockchip_usb2phy_host_disc_irq(irq, rport); + switch (rport->port_id) { case USB2PHY_PORT_OTG: if (rport->mode !=3D USB_DR_MODE_HOST && @@ -1233,7 +1312,7 @@ static int rockchip_usb2phy_probe(struct platform_dev= ice *pdev) } =20 /* support address_cells=3D2 */ - if (reg =3D=3D 0) { + if (of_property_count_u32_elems(np, "reg") > 2 && reg =3D=3D 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_d= evice *pdev) =20 /* find out a proper config which can be matched with dt. */ index =3D 0; - while (phy_cfgs[index].reg) { + do { if (phy_cfgs[index].reg =3D=3D reg) { rphy->phy_cfg =3D &phy_cfgs[index]; break; } =20 ++index; - } + } while (phy_cfgs[index].reg); =20 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[] =3D { { /* sentinel */ } }; =20 +static const struct rockchip_usb2phy_cfg rk3588_phy_cfgs[] =3D { + { + .reg =3D 0x0000, + .num_ports =3D 1, + .clkout_ctl =3D { 0x0000, 0, 0, 1, 0 }, + .port_cfgs =3D { + [USB2PHY_PORT_OTG] =3D { + .phy_sus =3D { 0x000c, 11, 11, 0, 1 }, + .bvalid_det_en =3D { 0x0080, 1, 1, 0, 1 }, + .bvalid_det_st =3D { 0x0084, 1, 1, 0, 1 }, + .bvalid_det_clr =3D { 0x0088, 1, 1, 0, 1 }, + .ls_det_en =3D { 0x0080, 0, 0, 0, 1 }, + .ls_det_st =3D { 0x0084, 0, 0, 0, 1 }, + .ls_det_clr =3D { 0x0088, 0, 0, 0, 1 }, + .disfall_en =3D { 0x0080, 6, 6, 0, 1 }, + .disfall_st =3D { 0x0084, 6, 6, 0, 1 }, + .disfall_clr =3D { 0x0088, 6, 6, 0, 1 }, + .disrise_en =3D { 0x0080, 5, 5, 0, 1 }, + .disrise_st =3D { 0x0084, 5, 5, 0, 1 }, + .disrise_clr =3D { 0x0088, 5, 5, 0, 1 }, + .utmi_avalid =3D { 0x00c0, 7, 7, 0, 1 }, + .utmi_bvalid =3D { 0x00c0, 6, 6, 0, 1 }, + .utmi_ls =3D { 0x00c0, 10, 9, 0, 1 }, + } + }, + .chg_det =3D { + .cp_det =3D { 0x00c0, 0, 0, 0, 1 }, + .dcp_det =3D { 0x00c0, 0, 0, 0, 1 }, + .dp_det =3D { 0x00c0, 1, 1, 1, 0 }, + .idm_sink_en =3D { 0x0008, 5, 5, 1, 0 }, + .idp_sink_en =3D { 0x0008, 5, 5, 0, 1 }, + .idp_src_en =3D { 0x0008, 14, 14, 0, 1 }, + .rdm_pdwn_en =3D { 0x0008, 14, 14, 0, 1 }, + .vdm_src_en =3D { 0x0008, 7, 6, 0, 3 }, + .vdp_src_en =3D { 0x0008, 7, 6, 0, 3 }, + }, + }, + { + .reg =3D 0x4000, + .num_ports =3D 1, + .clkout_ctl =3D { 0x0000, 0, 0, 1, 0 }, + .port_cfgs =3D { + [USB2PHY_PORT_OTG] =3D { + .phy_sus =3D { 0x000c, 11, 11, 0, 1 }, + .bvalid_det_en =3D { 0x0080, 1, 1, 0, 1 }, + .bvalid_det_st =3D { 0x0084, 1, 1, 0, 1 }, + .bvalid_det_clr =3D { 0x0088, 1, 1, 0, 1 }, + .ls_det_en =3D { 0x0080, 0, 0, 0, 1 }, + .ls_det_st =3D { 0x0084, 0, 0, 0, 1 }, + .ls_det_clr =3D { 0x0088, 0, 0, 0, 1 }, + .disfall_en =3D { 0x0080, 6, 6, 0, 1 }, + .disfall_st =3D { 0x0084, 6, 6, 0, 1 }, + .disfall_clr =3D { 0x0088, 6, 6, 0, 1 }, + .disrise_en =3D { 0x0080, 5, 5, 0, 1 }, + .disrise_st =3D { 0x0084, 5, 5, 0, 1 }, + .disrise_clr =3D { 0x0088, 5, 5, 0, 1 }, + .utmi_avalid =3D { 0x00c0, 7, 7, 0, 1 }, + .utmi_bvalid =3D { 0x00c0, 6, 6, 0, 1 }, + .utmi_ls =3D { 0x00c0, 10, 9, 0, 1 }, + } + }, + .chg_det =3D { + .cp_det =3D { 0x00c0, 0, 0, 0, 1 }, + .dcp_det =3D { 0x00c0, 0, 0, 0, 1 }, + .dp_det =3D { 0x00c0, 1, 1, 1, 0 }, + .idm_sink_en =3D { 0x0008, 5, 5, 1, 0 }, + .idp_sink_en =3D { 0x0008, 5, 5, 0, 1 }, + .idp_src_en =3D { 0x0008, 14, 14, 0, 1 }, + .rdm_pdwn_en =3D { 0x0008, 14, 14, 0, 1 }, + .vdm_src_en =3D { 0x0008, 7, 6, 0, 3 }, + .vdp_src_en =3D { 0x0008, 7, 6, 0, 3 }, + }, + }, + { + .reg =3D 0x8000, + .num_ports =3D 1, + .clkout_ctl =3D { 0x0000, 0, 0, 1, 0 }, + .port_cfgs =3D { + [USB2PHY_PORT_HOST] =3D { + .phy_sus =3D { 0x0008, 2, 2, 0, 1 }, + .ls_det_en =3D { 0x0080, 0, 0, 0, 1 }, + .ls_det_st =3D { 0x0084, 0, 0, 0, 1 }, + .ls_det_clr =3D { 0x0088, 0, 0, 0, 1 }, + .disfall_en =3D { 0x0080, 6, 6, 0, 1 }, + .disfall_st =3D { 0x0084, 6, 6, 0, 1 }, + .disfall_clr =3D { 0x0088, 6, 6, 0, 1 }, + .disrise_en =3D { 0x0080, 5, 5, 0, 1 }, + .disrise_st =3D { 0x0084, 5, 5, 0, 1 }, + .disrise_clr =3D { 0x0088, 5, 5, 0, 1 }, + .utmi_ls =3D { 0x00c0, 10, 9, 0, 1 }, + } + }, + }, + { + .reg =3D 0xc000, + .num_ports =3D 1, + .clkout_ctl =3D { 0x0000, 0, 0, 1, 0 }, + .port_cfgs =3D { + [USB2PHY_PORT_HOST] =3D { + .phy_sus =3D { 0x0008, 2, 2, 0, 1 }, + .ls_det_en =3D { 0x0080, 0, 0, 0, 1 }, + .ls_det_st =3D { 0x0084, 0, 0, 0, 1 }, + .ls_det_clr =3D { 0x0088, 0, 0, 0, 1 }, + .disfall_en =3D { 0x0080, 6, 6, 0, 1 }, + .disfall_st =3D { 0x0084, 6, 6, 0, 1 }, + .disfall_clr =3D { 0x0088, 6, 6, 0, 1 }, + .disrise_en =3D { 0x0080, 5, 5, 0, 1 }, + .disrise_st =3D { 0x0084, 5, 5, 0, 1 }, + .disrise_clr =3D { 0x0088, 5, 5, 0, 1 }, + .utmi_ls =3D { 0x00c0, 10, 9, 0, 1 }, + } + }, + }, + { /* sentinel */ } +}; + static const struct rockchip_usb2phy_cfg rv1108_phy_cfgs[] =3D { { .reg =3D 0x100, @@ -1714,6 +1909,7 @@ static const struct of_device_id rockchip_usb2phy_dt_= match[] =3D { { .compatible =3D "rockchip,rk3366-usb2phy", .data =3D &rk3366_phy_cfgs }, { .compatible =3D "rockchip,rk3399-usb2phy", .data =3D &rk3399_phy_cfgs }, { .compatible =3D "rockchip,rk3568-usb2phy", .data =3D &rk3568_phy_cfgs }, + { .compatible =3D "rockchip,rk3588-usb2phy", .data =3D &rk3588_phy_cfgs }, { .compatible =3D "rockchip,rv1108-usb2phy", .data =3D &rv1108_phy_cfgs }, {} }; --=20 2.39.2