1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2019 MediaTek Inc. 4 * Author: Stanley Chu <stanley.chu@mediatek.com> 5 */ 6 7 #include <linux/clk.h> 8 #include <linux/delay.h> 9 #include <linux/io.h> 10 #include <linux/module.h> 11 #include <linux/phy/phy.h> 12 #include <linux/platform_device.h> 13 14 /* mphy register and offsets */ 15 #define MP_GLB_DIG_8C 0x008C 16 #define FRC_PLL_ISO_EN BIT(8) 17 #define PLL_ISO_EN BIT(9) 18 #define FRC_FRC_PWR_ON BIT(10) 19 #define PLL_PWR_ON BIT(11) 20 21 #define MP_LN_DIG_RX_9C 0xA09C 22 #define FSM_DIFZ_FRC BIT(18) 23 24 #define MP_LN_DIG_RX_AC 0xA0AC 25 #define FRC_RX_SQ_EN BIT(0) 26 #define RX_SQ_EN BIT(1) 27 28 #define MP_LN_RX_44 0xB044 29 #define FRC_CDR_PWR_ON BIT(17) 30 #define CDR_PWR_ON BIT(18) 31 #define FRC_CDR_ISO_EN BIT(19) 32 #define CDR_ISO_EN BIT(20) 33 34 #define UFSPHY_CLKS_CNT 2 35 36 struct ufs_mtk_phy { 37 struct device *dev; 38 void __iomem *mmio; 39 struct clk_bulk_data clks[UFSPHY_CLKS_CNT]; 40 }; 41 42 static inline u32 mphy_readl(struct ufs_mtk_phy *phy, u32 reg) 43 { 44 return readl(phy->mmio + reg); 45 } 46 47 static inline void mphy_writel(struct ufs_mtk_phy *phy, u32 val, u32 reg) 48 { 49 writel(val, phy->mmio + reg); 50 } 51 52 static void mphy_set_bit(struct ufs_mtk_phy *phy, u32 reg, u32 bit) 53 { 54 u32 val; 55 56 val = mphy_readl(phy, reg); 57 val |= bit; 58 mphy_writel(phy, val, reg); 59 } 60 61 static void mphy_clr_bit(struct ufs_mtk_phy *phy, u32 reg, u32 bit) 62 { 63 u32 val; 64 65 val = mphy_readl(phy, reg); 66 val &= ~bit; 67 mphy_writel(phy, val, reg); 68 } 69 70 static struct ufs_mtk_phy *get_ufs_mtk_phy(struct phy *generic_phy) 71 { 72 return (struct ufs_mtk_phy *)phy_get_drvdata(generic_phy); 73 } 74 75 static int ufs_mtk_phy_clk_init(struct ufs_mtk_phy *phy) 76 { 77 struct device *dev = phy->dev; 78 struct clk_bulk_data *clks = phy->clks; 79 80 clks[0].id = "unipro"; 81 clks[1].id = "mp"; 82 return devm_clk_bulk_get(dev, UFSPHY_CLKS_CNT, clks); 83 } 84 85 static void ufs_mtk_phy_set_active(struct ufs_mtk_phy *phy) 86 { 87 /* release DA_MP_PLL_PWR_ON */ 88 mphy_set_bit(phy, MP_GLB_DIG_8C, PLL_PWR_ON); 89 mphy_clr_bit(phy, MP_GLB_DIG_8C, FRC_FRC_PWR_ON); 90 91 /* release DA_MP_PLL_ISO_EN */ 92 mphy_clr_bit(phy, MP_GLB_DIG_8C, PLL_ISO_EN); 93 mphy_clr_bit(phy, MP_GLB_DIG_8C, FRC_PLL_ISO_EN); 94 95 /* release DA_MP_CDR_PWR_ON */ 96 mphy_set_bit(phy, MP_LN_RX_44, CDR_PWR_ON); 97 mphy_clr_bit(phy, MP_LN_RX_44, FRC_CDR_PWR_ON); 98 99 /* release DA_MP_CDR_ISO_EN */ 100 mphy_clr_bit(phy, MP_LN_RX_44, CDR_ISO_EN); 101 mphy_clr_bit(phy, MP_LN_RX_44, FRC_CDR_ISO_EN); 102 103 /* release DA_MP_RX0_SQ_EN */ 104 mphy_set_bit(phy, MP_LN_DIG_RX_AC, RX_SQ_EN); 105 mphy_clr_bit(phy, MP_LN_DIG_RX_AC, FRC_RX_SQ_EN); 106 107 /* delay 1us to wait DIFZ stable */ 108 udelay(1); 109 110 /* release DIFZ */ 111 mphy_clr_bit(phy, MP_LN_DIG_RX_9C, FSM_DIFZ_FRC); 112 } 113 114 static void ufs_mtk_phy_set_deep_hibern(struct ufs_mtk_phy *phy) 115 { 116 /* force DIFZ */ 117 mphy_set_bit(phy, MP_LN_DIG_RX_9C, FSM_DIFZ_FRC); 118 119 /* force DA_MP_RX0_SQ_EN */ 120 mphy_set_bit(phy, MP_LN_DIG_RX_AC, FRC_RX_SQ_EN); 121 mphy_clr_bit(phy, MP_LN_DIG_RX_AC, RX_SQ_EN); 122 123 /* force DA_MP_CDR_ISO_EN */ 124 mphy_set_bit(phy, MP_LN_RX_44, FRC_CDR_ISO_EN); 125 mphy_set_bit(phy, MP_LN_RX_44, CDR_ISO_EN); 126 127 /* force DA_MP_CDR_PWR_ON */ 128 mphy_set_bit(phy, MP_LN_RX_44, FRC_CDR_PWR_ON); 129 mphy_clr_bit(phy, MP_LN_RX_44, CDR_PWR_ON); 130 131 /* force DA_MP_PLL_ISO_EN */ 132 mphy_set_bit(phy, MP_GLB_DIG_8C, FRC_PLL_ISO_EN); 133 mphy_set_bit(phy, MP_GLB_DIG_8C, PLL_ISO_EN); 134 135 /* force DA_MP_PLL_PWR_ON */ 136 mphy_set_bit(phy, MP_GLB_DIG_8C, FRC_FRC_PWR_ON); 137 mphy_clr_bit(phy, MP_GLB_DIG_8C, PLL_PWR_ON); 138 } 139 140 static int ufs_mtk_phy_power_on(struct phy *generic_phy) 141 { 142 struct ufs_mtk_phy *phy = get_ufs_mtk_phy(generic_phy); 143 int ret; 144 145 ret = clk_bulk_prepare_enable(UFSPHY_CLKS_CNT, phy->clks); 146 if (ret) 147 return ret; 148 149 ufs_mtk_phy_set_active(phy); 150 151 return 0; 152 } 153 154 static int ufs_mtk_phy_power_off(struct phy *generic_phy) 155 { 156 struct ufs_mtk_phy *phy = get_ufs_mtk_phy(generic_phy); 157 158 ufs_mtk_phy_set_deep_hibern(phy); 159 160 clk_bulk_disable_unprepare(UFSPHY_CLKS_CNT, phy->clks); 161 162 return 0; 163 } 164 165 static const struct phy_ops ufs_mtk_phy_ops = { 166 .power_on = ufs_mtk_phy_power_on, 167 .power_off = ufs_mtk_phy_power_off, 168 .owner = THIS_MODULE, 169 }; 170 171 static int ufs_mtk_phy_probe(struct platform_device *pdev) 172 { 173 struct device *dev = &pdev->dev; 174 struct phy *generic_phy; 175 struct phy_provider *phy_provider; 176 struct ufs_mtk_phy *phy; 177 int ret; 178 179 phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); 180 if (!phy) 181 return -ENOMEM; 182 183 phy->mmio = devm_platform_ioremap_resource(pdev, 0); 184 if (IS_ERR(phy->mmio)) 185 return PTR_ERR(phy->mmio); 186 187 phy->dev = dev; 188 189 ret = ufs_mtk_phy_clk_init(phy); 190 if (ret) 191 return ret; 192 193 generic_phy = devm_phy_create(dev, NULL, &ufs_mtk_phy_ops); 194 if (IS_ERR(generic_phy)) 195 return PTR_ERR(generic_phy); 196 197 phy_set_drvdata(generic_phy, phy); 198 199 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 200 201 return PTR_ERR_OR_ZERO(phy_provider); 202 } 203 204 static const struct of_device_id ufs_mtk_phy_of_match[] = { 205 {.compatible = "mediatek,mt8183-ufsphy"}, 206 {}, 207 }; 208 MODULE_DEVICE_TABLE(of, ufs_mtk_phy_of_match); 209 210 static struct platform_driver ufs_mtk_phy_driver = { 211 .probe = ufs_mtk_phy_probe, 212 .driver = { 213 .of_match_table = ufs_mtk_phy_of_match, 214 .name = "ufs_mtk_phy", 215 }, 216 }; 217 module_platform_driver(ufs_mtk_phy_driver); 218 219 MODULE_DESCRIPTION("Universal Flash Storage (UFS) MediaTek MPHY"); 220 MODULE_AUTHOR("Stanley Chu <stanley.chu@mediatek.com>"); 221 MODULE_LICENSE("GPL v2"); 222