1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Axiado eMMC PHY driver 4 * 5 * Copyright (C) 2017 Arasan Chip Systems Inc. 6 * Copyright (C) 2022-2026 Axiado Corporation (or its affiliates). 7 * 8 * Based on Arasan Driver (sdhci-pci-arasan.c) 9 * sdhci-pci-arasan.c - Driver for Arasan PCI Controller with integrated phy. 10 */ 11 #include <linux/bitfield.h> 12 #include <linux/delay.h> 13 #include <linux/io.h> 14 #include <linux/iopoll.h> 15 #include <linux/module.h> 16 #include <linux/of.h> 17 #include <linux/phy/phy.h> 18 #include <linux/platform_device.h> 19 20 /* Arasan eMMC 5.1 - PHY configuration registers */ 21 #define CAP_REG_IN_S1_MSB 0x04 22 #define PHY_CTRL_1 0x38 23 #define PHY_CTRL_2 0x3c 24 #define PHY_CTRL_3 0x40 25 #define STATUS 0x50 26 27 #define DLL_ENBL BIT(26) 28 #define RTRIM_EN BIT(21) 29 #define PDB_ENBL BIT(23) 30 #define RETB_ENBL BIT(1) 31 32 #define REN_STRB BIT(27) 33 #define REN_CMD_EN GENMASK(20, 12) 34 35 /* Pull-UP Enable on CMD Line */ 36 #define PU_CMD_EN GENMASK(11, 3) 37 38 /* Selection value for the optimum delay from 1-32 output tap lines */ 39 #define OTAP_DLY 0x02 40 /* DLL charge pump current trim default [1000] */ 41 #define DLL_TRM_ICP 0x08 42 /* Select the frequency range of DLL Operation */ 43 #define FRQ_SEL 0x01 44 45 #define OTAP_SEL_MASK GENMASK(10, 7) 46 #define DLL_TRM_MASK GENMASK(25, 22) 47 #define DLL_FRQSEL_MASK GENMASK(27, 25) 48 49 #define OTAP_SEL(x) (FIELD_PREP(OTAP_SEL_MASK, x) | OTAPDLY_EN) 50 #define DLL_TRM(x) (FIELD_PREP(DLL_TRM_MASK, x) | DLL_ENBL) 51 #define DLL_FRQSEL(x) FIELD_PREP(DLL_FRQSEL_MASK, x) 52 53 #define OTAPDLY_EN BIT(11) 54 55 #define SEL_DLY_RXCLK BIT(18) 56 #define SEL_DLY_TXCLK BIT(19) 57 58 #define CALDONE_MASK 0x40 59 #define DLL_RDY_MASK 0x1 60 #define MAX_CLK_BUF0 BIT(20) 61 #define MAX_CLK_BUF1 BIT(21) 62 #define MAX_CLK_BUF2 BIT(22) 63 64 #define CLK_MULTIPLIER 0xc008e 65 #define POLL_TIMEOUT_MS 3000 66 #define POLL_DELAY_US 100 67 68 struct axiado_emmc_phy { 69 void __iomem *reg_base; 70 struct device *dev; 71 }; 72 73 static int axiado_emmc_phy_init(struct phy *phy) 74 { 75 struct axiado_emmc_phy *ax_phy = phy_get_drvdata(phy); 76 struct device *dev = ax_phy->dev; 77 u32 val; 78 int ret; 79 80 val = readl(ax_phy->reg_base + PHY_CTRL_1); 81 writel(val | RETB_ENBL | RTRIM_EN, ax_phy->reg_base + PHY_CTRL_1); 82 83 val = readl(ax_phy->reg_base + PHY_CTRL_3); 84 writel(val | PDB_ENBL, ax_phy->reg_base + PHY_CTRL_3); 85 86 ret = readl_poll_timeout(ax_phy->reg_base + STATUS, val, 87 val & CALDONE_MASK, POLL_DELAY_US, 88 POLL_TIMEOUT_MS * 1000); 89 if (ret) { 90 dev_err(dev, "PHY calibration timeout\n"); 91 return ret; 92 } 93 94 val = readl(ax_phy->reg_base + PHY_CTRL_1); 95 writel(val | REN_CMD_EN | PU_CMD_EN, ax_phy->reg_base + PHY_CTRL_1); 96 97 val = readl(ax_phy->reg_base + PHY_CTRL_2); 98 writel(val | REN_STRB, ax_phy->reg_base + PHY_CTRL_2); 99 100 val = readl(ax_phy->reg_base + PHY_CTRL_3); 101 writel(val | MAX_CLK_BUF0 | MAX_CLK_BUF1 | MAX_CLK_BUF2, 102 ax_phy->reg_base + PHY_CTRL_3); 103 104 writel(CLK_MULTIPLIER, ax_phy->reg_base + CAP_REG_IN_S1_MSB); 105 106 val = readl(ax_phy->reg_base + PHY_CTRL_3); 107 writel(val | SEL_DLY_RXCLK | SEL_DLY_TXCLK, 108 ax_phy->reg_base + PHY_CTRL_3); 109 110 return 0; 111 } 112 113 static int axiado_emmc_phy_power_on(struct phy *phy) 114 { 115 struct axiado_emmc_phy *ax_phy = phy_get_drvdata(phy); 116 struct device *dev = ax_phy->dev; 117 u32 val; 118 int ret; 119 120 val = readl(ax_phy->reg_base + PHY_CTRL_1); 121 writel(val | RETB_ENBL, ax_phy->reg_base + PHY_CTRL_1); 122 123 val = readl(ax_phy->reg_base + PHY_CTRL_3); 124 writel(val | PDB_ENBL, ax_phy->reg_base + PHY_CTRL_3); 125 126 val = readl(ax_phy->reg_base + PHY_CTRL_2); 127 writel(val | OTAP_SEL(OTAP_DLY), ax_phy->reg_base + PHY_CTRL_2); 128 129 val = readl(ax_phy->reg_base + PHY_CTRL_1); 130 writel(val | DLL_TRM(DLL_TRM_ICP), ax_phy->reg_base + PHY_CTRL_1); 131 132 val = readl(ax_phy->reg_base + PHY_CTRL_3); 133 writel(val | DLL_FRQSEL(FRQ_SEL), ax_phy->reg_base + PHY_CTRL_3); 134 135 ret = read_poll_timeout(readl, val, val & DLL_RDY_MASK, POLL_DELAY_US, 136 POLL_TIMEOUT_MS * 1000, false, 137 ax_phy->reg_base + STATUS); 138 if (ret) { 139 dev_err(dev, "DLL ready timeout\n"); 140 return ret; 141 } 142 143 return 0; 144 } 145 146 static int axiado_emmc_phy_power_off(struct phy *phy) 147 { 148 struct axiado_emmc_phy *ax_phy = phy_get_drvdata(phy); 149 u32 val; 150 151 val = readl(ax_phy->reg_base + PHY_CTRL_1); 152 val &= ~(DLL_TRM_MASK | DLL_ENBL); 153 writel(val, ax_phy->reg_base + PHY_CTRL_1); 154 155 val = readl(ax_phy->reg_base + PHY_CTRL_3); 156 val &= ~(DLL_FRQSEL_MASK | PDB_ENBL); 157 writel(val, ax_phy->reg_base + PHY_CTRL_3); 158 159 return 0; 160 } 161 162 static const struct phy_ops axiado_emmc_phy_ops = { 163 .init = axiado_emmc_phy_init, 164 .power_on = axiado_emmc_phy_power_on, 165 .power_off = axiado_emmc_phy_power_off, 166 .owner = THIS_MODULE, 167 }; 168 169 static const struct of_device_id axiado_emmc_phy_of_match[] = { 170 { .compatible = "axiado,ax3000-emmc-phy" }, 171 { /* sentinel */ }, 172 }; 173 MODULE_DEVICE_TABLE(of, axiado_emmc_phy_of_match); 174 175 static int axiado_emmc_phy_probe(struct platform_device *pdev) 176 { 177 struct axiado_emmc_phy *ax_phy; 178 struct phy_provider *phy_provider; 179 struct device *dev = &pdev->dev; 180 struct phy *generic_phy; 181 182 if (!dev->of_node) 183 return -ENODEV; 184 185 ax_phy = devm_kzalloc(dev, sizeof(*ax_phy), GFP_KERNEL); 186 if (!ax_phy) 187 return -ENOMEM; 188 189 ax_phy->reg_base = devm_platform_ioremap_resource(pdev, 0); 190 if (IS_ERR(ax_phy->reg_base)) 191 return PTR_ERR(ax_phy->reg_base); 192 193 ax_phy->dev = dev; 194 195 generic_phy = devm_phy_create(dev, dev->of_node, &axiado_emmc_phy_ops); 196 if (IS_ERR(generic_phy)) 197 return dev_err_probe(dev, PTR_ERR(generic_phy), 198 "failed to create PHY\n"); 199 200 phy_set_drvdata(generic_phy, ax_phy); 201 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 202 203 return PTR_ERR_OR_ZERO(phy_provider); 204 } 205 206 static struct platform_driver axiado_emmc_phy_driver = { 207 .probe = axiado_emmc_phy_probe, 208 .driver = { 209 .name = "axiado-emmc-phy", 210 .of_match_table = axiado_emmc_phy_of_match, 211 }, 212 }; 213 module_platform_driver(axiado_emmc_phy_driver); 214 215 MODULE_DESCRIPTION("AX3000 eMMC PHY Driver"); 216 MODULE_AUTHOR("Axiado Corporation"); 217 MODULE_LICENSE("GPL"); 218