From patchwork Mon May 22 17:03:19 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sebastian Reichel X-Patchwork-Id: 13250881 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 bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id C4F98C77B73 for ; Mon, 22 May 2023 17:04:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=p912uCbyUGK+QciZiY9Atit/G3LoOYHpEwgMltrVQbM=; b=mwOCq6eY4QHaMy dNqNK2eJxksDjUa6GTn1AVVZ2JlZCPcYisiDc0WX7H7PgVKq95uC5TrPZN/blfh2/uDtnMII4t5+s POyfaNVwYEDG0vY9G2t3BEdS0dyjUD61w5dk3Yq5gytzH59LlzCm4LzHvhS13IpAbfCRHd4B9f5dY gGJCMlLgJO0f8hfgCFb3mz/lojaHF+r38qwu6Zg2yGKhrodQMxBMmaFSCs3GB8GfmMVl8vURVBkTZ VB3O/ChAAmuMzNHTjvGRWAl1MIr81/6GVpziYD0gWloxYJgvOaol2Avv6m7e1RmfzvXZyp6uOgAdL 0e8mgANH08lNjlCN9DOQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.96 #2 (Red Hat Linux)) id 1q18xF-007IaW-10; Mon, 22 May 2023 17:04:17 +0000 Received: from madras.collabora.co.uk ([46.235.227.172]) by bombadil.infradead.org with esmtps (Exim 4.96 #2 (Red Hat Linux)) id 1q18wl-007IHd-1z; Mon, 22 May 2023 17:03:51 +0000 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 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20230522_100347_919273_2ECD0863 X-CRM114-Status: GOOD ( 24.79 ) X-BeenThere: linux-rockchip@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Upstream kernel work for Rockchip platforms List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "Linux-rockchip" Errors-To: linux-rockchip-bounces+linux-rockchip=archiver.kernel.org@lists.infradead.org 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/rockchip/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 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 }, {} };