From patchwork Sat Mar 16 05:04:46 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stanley Chu X-Patchwork-Id: 10855775 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 581211390 for ; Sat, 16 Mar 2019 05:06:13 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 383122ABEE for ; Sat, 16 Mar 2019 05:06:13 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2C57F2AC3E; Sat, 16 Mar 2019 05:06:13 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED,UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 47F412AC3D for ; Sat, 16 Mar 2019 05:06:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=JTO0og6jgc4pC6wept5r7aHuDyVlhtG96i+6VkIRfBw=; b=FJhGV/ZwPR3K24 Bjl3FMXRDfJdcouHKzbrcpc2Dcl0TytMsMk54AF/1ysfHR8sIuAI3pAb1ldVKbjyMgWLWqrrimTIf 0dQTXfEmMAotbNHMB8+n3DEFR+v5Z74Af4ywv7PLsbPQfQULSZ3BinaG+zPsSNyFgbF7x0SmVpoYK OQxVT1HFSva719xNEo59m2AUg4D5C3Q5Xj1ASFkGa1v7S9sEGG2AakSkMOLHnMSmXLjoTixnczlUk 8+6xtj3PPMCI2/wYlSjVm7mq96Bu3r1YI8IUDT5I0JL31pfljmZvzNIDwdP/wRODvuEO3fLSuGz+q EivwON9OqJFqPu/IBjJQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1h51WA-0007tE-Po; Sat, 16 Mar 2019 05:05:58 +0000 Received: from mailgw02.mediatek.com ([216.200.240.185]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1h51W6-0007oH-NK for linux-mediatek@lists.infradead.org; Sat, 16 Mar 2019 05:05:56 +0000 X-UUID: 6f7cf146e42242ec95fc52134133a012-20190315 X-UUID: 6f7cf146e42242ec95fc52134133a012-20190315 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw02.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLS) with ESMTP id 2138700865; Fri, 15 Mar 2019 21:05:43 -0800 Received: from MTKMBS01N1.mediatek.inc (172.21.101.68) by MTKMBS62DR.mediatek.inc (172.29.94.18) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Fri, 15 Mar 2019 22:05:42 -0700 Received: from mtkcas09.mediatek.inc (172.21.101.178) by mtkmbs01n1.mediatek.inc (172.21.101.68) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Sat, 16 Mar 2019 13:05:34 +0800 Received: from mtkswgap22.mediatek.inc (172.21.77.33) by mtkcas09.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1395.4 via Frontend Transport; Sat, 16 Mar 2019 13:05:35 +0800 From: Stanley Chu To: , , , , , , , , , , , Subject: [PATCH v6 6/7] phy: mediatek: Add UFS M-PHY driver Date: Sat, 16 Mar 2019 13:04:46 +0800 Message-ID: <1552712687-20186-8-git-send-email-stanley.chu@mediatek.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1552712687-20186-1-git-send-email-stanley.chu@mediatek.com> References: <1552712687-20186-1-git-send-email-stanley.chu@mediatek.com> MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190315_220554_770741_46E016A9 X-CRM114-Status: GOOD ( 13.24 ) X-BeenThere: linux-mediatek@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: chun-hung.wu@mediatek.com, kuohong.wang@mediatek.com, matthias.bgg@gmail.com, linux-mediatek@lists.infradead.org, liwei213@huawei.com, vivek.gautam@codeaurora.org, subhashj@codeaurora.org, Stanley Chu , peter.wang@mediatek.com Sender: "Linux-mediatek" Errors-To: linux-mediatek-bounces+patchwork-linux-mediatek=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP Add UFS M-PHY driver on MediaTek chipsets. Signed-off-by: Stanley Chu Reviewed-by: Chunfeng Yun --- drivers/phy/mediatek/Kconfig | 10 ++ drivers/phy/mediatek/Makefile | 1 + drivers/phy/mediatek/phy-mtk-ufs.c | 245 +++++++++++++++++++++++++++++ 3 files changed, 256 insertions(+) create mode 100644 drivers/phy/mediatek/phy-mtk-ufs.c diff --git a/drivers/phy/mediatek/Kconfig b/drivers/phy/mediatek/Kconfig index 8857d00b3c65..b5a89dbd3fe7 100644 --- a/drivers/phy/mediatek/Kconfig +++ b/drivers/phy/mediatek/Kconfig @@ -13,6 +13,16 @@ config PHY_MTK_TPHY multi-ports is first version, otherwise is second veriosn, so you can easily distinguish them by banks layout. +config PHY_MTK_UFS + tristate "MediaTek UFS M-PHY driver" + depends on ARCH_MEDIATEK && OF + select GENERIC_PHY + help + Support for UFS M-PHY on MediaTek chipsets. + Enable this to provide vendor-specific probing, + initialization, power on and power off flow of + specified M-PHYs. + config PHY_MTK_XSPHY tristate "MediaTek XS-PHY Driver" depends on ARCH_MEDIATEK && OF diff --git a/drivers/phy/mediatek/Makefile b/drivers/phy/mediatek/Makefile index ee49edc97ee9..08a8e6a97b1e 100644 --- a/drivers/phy/mediatek/Makefile +++ b/drivers/phy/mediatek/Makefile @@ -4,4 +4,5 @@ # obj-$(CONFIG_PHY_MTK_TPHY) += phy-mtk-tphy.o +obj-$(CONFIG_PHY_MTK_UFS) += phy-mtk-ufs.o obj-$(CONFIG_PHY_MTK_XSPHY) += phy-mtk-xsphy.o diff --git a/drivers/phy/mediatek/phy-mtk-ufs.c b/drivers/phy/mediatek/phy-mtk-ufs.c new file mode 100644 index 000000000000..9a80a76d7990 --- /dev/null +++ b/drivers/phy/mediatek/phy-mtk-ufs.c @@ -0,0 +1,245 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 MediaTek Inc. + * Author: Stanley Chu + */ + +#include +#include +#include +#include +#include +#include + +/* mphy register and offsets */ +#define MP_GLB_DIG_8C 0x008C +#define FRC_PLL_ISO_EN BIT(8) +#define PLL_ISO_EN BIT(9) +#define FRC_FRC_PWR_ON BIT(10) +#define PLL_PWR_ON BIT(11) + +#define MP_LN_DIG_RX_9C 0xA09C +#define FSM_DIFZ_FRC BIT(18) + +#define MP_LN_DIG_RX_AC 0xA0AC +#define FRC_RX_SQ_EN BIT(0) +#define RX_SQ_EN BIT(1) + +#define MP_LN_RX_44 0xB044 +#define FRC_CDR_PWR_ON BIT(17) +#define CDR_PWR_ON BIT(18) +#define FRC_CDR_ISO_EN BIT(19) +#define CDR_ISO_EN BIT(20) + +struct ufs_mtk_phy { + struct device *dev; + void __iomem *mmio; + struct clk *mp_clk; + struct clk *unipro_clk; +}; + +static inline u32 mphy_readl(struct ufs_mtk_phy *phy, u32 reg) +{ + return readl(phy->mmio + reg); +} + +static inline void mphy_writel(struct ufs_mtk_phy *phy, u32 val, u32 reg) +{ + writel(val, phy->mmio + reg); +} + +static void mphy_set_bit(struct ufs_mtk_phy *phy, u32 reg, u32 bit) +{ + u32 val; + + val = mphy_readl(phy, reg); + val |= bit; + mphy_writel(phy, val, reg); +} + +static void mphy_clr_bit(struct ufs_mtk_phy *phy, u32 reg, u32 bit) +{ + u32 val; + + val = mphy_readl(phy, reg); + val &= ~bit; + mphy_writel(phy, val, reg); +} + +static struct ufs_mtk_phy *get_ufs_mtk_phy(struct phy *generic_phy) +{ + return (struct ufs_mtk_phy *)phy_get_drvdata(generic_phy); +} + +static int ufs_mtk_phy_clk_init(struct ufs_mtk_phy *phy) +{ + struct device *dev = phy->dev; + + phy->unipro_clk = devm_clk_get(dev, "unipro"); + if (IS_ERR(phy->unipro_clk)) { + dev_err(dev, "failed to get clock: unipro"); + return PTR_ERR(phy->unipro_clk); + } + + phy->mp_clk = devm_clk_get(dev, "mp"); + if (IS_ERR(phy->mp_clk)) { + dev_err(dev, "failed to get clock: mp"); + return PTR_ERR(phy->mp_clk); + } + + return 0; +} + +static void ufs_mtk_phy_set_active(struct ufs_mtk_phy *phy) +{ + /* release DA_MP_PLL_PWR_ON */ + mphy_set_bit(phy, MP_GLB_DIG_8C, PLL_PWR_ON); + mphy_clr_bit(phy, MP_GLB_DIG_8C, FRC_FRC_PWR_ON); + + /* release DA_MP_PLL_ISO_EN */ + mphy_clr_bit(phy, MP_GLB_DIG_8C, PLL_ISO_EN); + mphy_clr_bit(phy, MP_GLB_DIG_8C, FRC_PLL_ISO_EN); + + /* release DA_MP_CDR_PWR_ON */ + mphy_set_bit(phy, MP_LN_RX_44, CDR_PWR_ON); + mphy_clr_bit(phy, MP_LN_RX_44, FRC_CDR_PWR_ON); + + /* release DA_MP_CDR_ISO_EN */ + mphy_clr_bit(phy, MP_LN_RX_44, CDR_ISO_EN); + mphy_clr_bit(phy, MP_LN_RX_44, FRC_CDR_ISO_EN); + + /* release DA_MP_RX0_SQ_EN */ + mphy_set_bit(phy, MP_LN_DIG_RX_AC, RX_SQ_EN); + mphy_clr_bit(phy, MP_LN_DIG_RX_AC, FRC_RX_SQ_EN); + + /* delay 1us to wait DIFZ stable */ + udelay(1); + + /* release DIFZ */ + mphy_clr_bit(phy, MP_LN_DIG_RX_9C, FSM_DIFZ_FRC); +} + +static void ufs_mtk_phy_set_deep_hibern(struct ufs_mtk_phy *phy) +{ + /* force DIFZ */ + mphy_set_bit(phy, MP_LN_DIG_RX_9C, FSM_DIFZ_FRC); + + /* force DA_MP_RX0_SQ_EN */ + mphy_set_bit(phy, MP_LN_DIG_RX_AC, FRC_RX_SQ_EN); + mphy_clr_bit(phy, MP_LN_DIG_RX_AC, RX_SQ_EN); + + /* force DA_MP_CDR_ISO_EN */ + mphy_set_bit(phy, MP_LN_RX_44, FRC_CDR_ISO_EN); + mphy_set_bit(phy, MP_LN_RX_44, CDR_ISO_EN); + + /* force DA_MP_CDR_PWR_ON */ + mphy_set_bit(phy, MP_LN_RX_44, FRC_CDR_PWR_ON); + mphy_clr_bit(phy, MP_LN_RX_44, CDR_PWR_ON); + + /* force DA_MP_PLL_ISO_EN */ + mphy_set_bit(phy, MP_GLB_DIG_8C, FRC_PLL_ISO_EN); + mphy_set_bit(phy, MP_GLB_DIG_8C, PLL_ISO_EN); + + /* force DA_MP_PLL_PWR_ON */ + mphy_set_bit(phy, MP_GLB_DIG_8C, FRC_FRC_PWR_ON); + mphy_clr_bit(phy, MP_GLB_DIG_8C, PLL_PWR_ON); +} + +static int ufs_mtk_phy_power_on(struct phy *generic_phy) +{ + struct ufs_mtk_phy *phy = get_ufs_mtk_phy(generic_phy); + int ret; + + ret = clk_prepare_enable(phy->unipro_clk); + if (ret) { + dev_err(phy->dev, "unipro_clk enable failed %d\n", ret); + goto out; + } + + ret = clk_prepare_enable(phy->mp_clk); + if (ret) { + dev_err(phy->dev, "mp_clk enable failed %d\n", ret); + goto out_unprepare_unipro_clk; + } + + ufs_mtk_phy_set_active(phy); + + return 0; + +out_unprepare_unipro_clk: + clk_disable_unprepare(phy->unipro_clk); +out: + return ret; +} + +static int ufs_mtk_phy_power_off(struct phy *generic_phy) +{ + struct ufs_mtk_phy *phy = get_ufs_mtk_phy(generic_phy); + + ufs_mtk_phy_set_deep_hibern(phy); + + clk_disable_unprepare(phy->unipro_clk); + clk_disable_unprepare(phy->mp_clk); + + return 0; +} + +static const struct phy_ops ufs_mtk_phy_ops = { + .power_on = ufs_mtk_phy_power_on, + .power_off = ufs_mtk_phy_power_off, + .owner = THIS_MODULE, +}; + +static int ufs_mtk_phy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct phy *generic_phy; + struct phy_provider *phy_provider; + struct resource *res; + struct ufs_mtk_phy *phy; + int ret; + + phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); + if (!phy) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + phy->mmio = devm_ioremap_resource(dev, res); + if (IS_ERR(phy->mmio)) + return PTR_ERR(phy->mmio); + + phy->dev = dev; + + ret = ufs_mtk_phy_clk_init(phy); + if (ret) + return ret; + + generic_phy = devm_phy_create(dev, NULL, &ufs_mtk_phy_ops); + if (IS_ERR(generic_phy)) + return PTR_ERR(generic_phy); + + phy_set_drvdata(generic_phy, phy); + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct of_device_id ufs_mtk_phy_of_match[] = { + {.compatible = "mediatek,mt8183-ufsphy"}, + {}, +}; +MODULE_DEVICE_TABLE(of, ufs_mtk_phy_of_match); + +static struct platform_driver ufs_mtk_phy_driver = { + .probe = ufs_mtk_phy_probe, + .driver = { + .of_match_table = ufs_mtk_phy_of_match, + .name = "ufs_mtk_phy", + }, +}; +module_platform_driver(ufs_mtk_phy_driver); + +MODULE_DESCRIPTION("Universal Flash Storage (UFS) MediaTek MPHY"); +MODULE_AUTHOR("Stanley Chu "); +MODULE_LICENSE("GPL v2");