phy-qcom-apq8064-sata.c (8107B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (c) 2014, The Linux Foundation. All rights reserved. 4 */ 5 6#include <linux/io.h> 7#include <linux/iopoll.h> 8#include <linux/kernel.h> 9#include <linux/module.h> 10#include <linux/of.h> 11#include <linux/time.h> 12#include <linux/delay.h> 13#include <linux/clk.h> 14#include <linux/slab.h> 15#include <linux/platform_device.h> 16#include <linux/phy/phy.h> 17 18/* PHY registers */ 19#define UNIPHY_PLL_REFCLK_CFG 0x000 20#define UNIPHY_PLL_PWRGEN_CFG 0x014 21#define UNIPHY_PLL_GLB_CFG 0x020 22#define UNIPHY_PLL_SDM_CFG0 0x038 23#define UNIPHY_PLL_SDM_CFG1 0x03C 24#define UNIPHY_PLL_SDM_CFG2 0x040 25#define UNIPHY_PLL_SDM_CFG3 0x044 26#define UNIPHY_PLL_SDM_CFG4 0x048 27#define UNIPHY_PLL_SSC_CFG0 0x04C 28#define UNIPHY_PLL_SSC_CFG1 0x050 29#define UNIPHY_PLL_SSC_CFG2 0x054 30#define UNIPHY_PLL_SSC_CFG3 0x058 31#define UNIPHY_PLL_LKDET_CFG0 0x05C 32#define UNIPHY_PLL_LKDET_CFG1 0x060 33#define UNIPHY_PLL_LKDET_CFG2 0x064 34#define UNIPHY_PLL_CAL_CFG0 0x06C 35#define UNIPHY_PLL_CAL_CFG8 0x08C 36#define UNIPHY_PLL_CAL_CFG9 0x090 37#define UNIPHY_PLL_CAL_CFG10 0x094 38#define UNIPHY_PLL_CAL_CFG11 0x098 39#define UNIPHY_PLL_STATUS 0x0C0 40 41#define SATA_PHY_SER_CTRL 0x100 42#define SATA_PHY_TX_DRIV_CTRL0 0x104 43#define SATA_PHY_TX_DRIV_CTRL1 0x108 44#define SATA_PHY_TX_IMCAL0 0x11C 45#define SATA_PHY_TX_IMCAL2 0x124 46#define SATA_PHY_RX_IMCAL0 0x128 47#define SATA_PHY_EQUAL 0x13C 48#define SATA_PHY_OOB_TERM 0x144 49#define SATA_PHY_CDR_CTRL0 0x148 50#define SATA_PHY_CDR_CTRL1 0x14C 51#define SATA_PHY_CDR_CTRL2 0x150 52#define SATA_PHY_CDR_CTRL3 0x154 53#define SATA_PHY_PI_CTRL0 0x168 54#define SATA_PHY_POW_DWN_CTRL0 0x180 55#define SATA_PHY_POW_DWN_CTRL1 0x184 56#define SATA_PHY_TX_DATA_CTRL 0x188 57#define SATA_PHY_ALIGNP 0x1A4 58#define SATA_PHY_TX_IMCAL_STAT 0x1E4 59#define SATA_PHY_RX_IMCAL_STAT 0x1E8 60 61#define UNIPHY_PLL_LOCK BIT(0) 62#define SATA_PHY_TX_CAL BIT(0) 63#define SATA_PHY_RX_CAL BIT(0) 64 65/* default timeout set to 1 sec */ 66#define TIMEOUT_MS 10000 67#define DELAY_INTERVAL_US 100 68 69struct qcom_apq8064_sata_phy { 70 void __iomem *mmio; 71 struct clk *cfg_clk; 72 struct device *dev; 73}; 74 75/* Helper function to do poll and timeout */ 76static int poll_timeout(void __iomem *addr, u32 mask) 77{ 78 u32 val; 79 80 return readl_relaxed_poll_timeout(addr, val, (val & mask), 81 DELAY_INTERVAL_US, TIMEOUT_MS * 1000); 82} 83 84static int qcom_apq8064_sata_phy_init(struct phy *generic_phy) 85{ 86 struct qcom_apq8064_sata_phy *phy = phy_get_drvdata(generic_phy); 87 void __iomem *base = phy->mmio; 88 int ret = 0; 89 90 /* SATA phy initialization */ 91 writel_relaxed(0x01, base + SATA_PHY_SER_CTRL); 92 writel_relaxed(0xB1, base + SATA_PHY_POW_DWN_CTRL0); 93 /* Make sure the power down happens before power up */ 94 mb(); 95 usleep_range(10, 60); 96 97 writel_relaxed(0x01, base + SATA_PHY_POW_DWN_CTRL0); 98 writel_relaxed(0x3E, base + SATA_PHY_POW_DWN_CTRL1); 99 writel_relaxed(0x01, base + SATA_PHY_RX_IMCAL0); 100 writel_relaxed(0x01, base + SATA_PHY_TX_IMCAL0); 101 writel_relaxed(0x02, base + SATA_PHY_TX_IMCAL2); 102 103 /* Write UNIPHYPLL registers to configure PLL */ 104 writel_relaxed(0x04, base + UNIPHY_PLL_REFCLK_CFG); 105 writel_relaxed(0x00, base + UNIPHY_PLL_PWRGEN_CFG); 106 107 writel_relaxed(0x0A, base + UNIPHY_PLL_CAL_CFG0); 108 writel_relaxed(0xF3, base + UNIPHY_PLL_CAL_CFG8); 109 writel_relaxed(0x01, base + UNIPHY_PLL_CAL_CFG9); 110 writel_relaxed(0xED, base + UNIPHY_PLL_CAL_CFG10); 111 writel_relaxed(0x02, base + UNIPHY_PLL_CAL_CFG11); 112 113 writel_relaxed(0x36, base + UNIPHY_PLL_SDM_CFG0); 114 writel_relaxed(0x0D, base + UNIPHY_PLL_SDM_CFG1); 115 writel_relaxed(0xA3, base + UNIPHY_PLL_SDM_CFG2); 116 writel_relaxed(0xF0, base + UNIPHY_PLL_SDM_CFG3); 117 writel_relaxed(0x00, base + UNIPHY_PLL_SDM_CFG4); 118 119 writel_relaxed(0x19, base + UNIPHY_PLL_SSC_CFG0); 120 writel_relaxed(0xE1, base + UNIPHY_PLL_SSC_CFG1); 121 writel_relaxed(0x00, base + UNIPHY_PLL_SSC_CFG2); 122 writel_relaxed(0x11, base + UNIPHY_PLL_SSC_CFG3); 123 124 writel_relaxed(0x04, base + UNIPHY_PLL_LKDET_CFG0); 125 writel_relaxed(0xFF, base + UNIPHY_PLL_LKDET_CFG1); 126 127 writel_relaxed(0x02, base + UNIPHY_PLL_GLB_CFG); 128 /* make sure global config LDO power down happens before power up */ 129 mb(); 130 131 writel_relaxed(0x03, base + UNIPHY_PLL_GLB_CFG); 132 writel_relaxed(0x05, base + UNIPHY_PLL_LKDET_CFG2); 133 134 /* PLL Lock wait */ 135 ret = poll_timeout(base + UNIPHY_PLL_STATUS, UNIPHY_PLL_LOCK); 136 if (ret) { 137 dev_err(phy->dev, "poll timeout UNIPHY_PLL_STATUS\n"); 138 return ret; 139 } 140 141 /* TX Calibration */ 142 ret = poll_timeout(base + SATA_PHY_TX_IMCAL_STAT, SATA_PHY_TX_CAL); 143 if (ret) { 144 dev_err(phy->dev, "poll timeout SATA_PHY_TX_IMCAL_STAT\n"); 145 return ret; 146 } 147 148 /* RX Calibration */ 149 ret = poll_timeout(base + SATA_PHY_RX_IMCAL_STAT, SATA_PHY_RX_CAL); 150 if (ret) { 151 dev_err(phy->dev, "poll timeout SATA_PHY_RX_IMCAL_STAT\n"); 152 return ret; 153 } 154 155 /* SATA phy calibrated succesfully, power up to functional mode */ 156 writel_relaxed(0x3E, base + SATA_PHY_POW_DWN_CTRL1); 157 writel_relaxed(0x01, base + SATA_PHY_RX_IMCAL0); 158 writel_relaxed(0x01, base + SATA_PHY_TX_IMCAL0); 159 160 writel_relaxed(0x00, base + SATA_PHY_POW_DWN_CTRL1); 161 writel_relaxed(0x59, base + SATA_PHY_CDR_CTRL0); 162 writel_relaxed(0x04, base + SATA_PHY_CDR_CTRL1); 163 writel_relaxed(0x00, base + SATA_PHY_CDR_CTRL2); 164 writel_relaxed(0x00, base + SATA_PHY_PI_CTRL0); 165 writel_relaxed(0x00, base + SATA_PHY_CDR_CTRL3); 166 writel_relaxed(0x01, base + SATA_PHY_POW_DWN_CTRL0); 167 168 writel_relaxed(0x11, base + SATA_PHY_TX_DATA_CTRL); 169 writel_relaxed(0x43, base + SATA_PHY_ALIGNP); 170 writel_relaxed(0x04, base + SATA_PHY_OOB_TERM); 171 172 writel_relaxed(0x01, base + SATA_PHY_EQUAL); 173 writel_relaxed(0x09, base + SATA_PHY_TX_DRIV_CTRL0); 174 writel_relaxed(0x09, base + SATA_PHY_TX_DRIV_CTRL1); 175 176 return 0; 177} 178 179static int qcom_apq8064_sata_phy_exit(struct phy *generic_phy) 180{ 181 struct qcom_apq8064_sata_phy *phy = phy_get_drvdata(generic_phy); 182 void __iomem *base = phy->mmio; 183 184 /* Power down PHY */ 185 writel_relaxed(0xF8, base + SATA_PHY_POW_DWN_CTRL0); 186 writel_relaxed(0xFE, base + SATA_PHY_POW_DWN_CTRL1); 187 188 /* Power down PLL block */ 189 writel_relaxed(0x00, base + UNIPHY_PLL_GLB_CFG); 190 191 return 0; 192} 193 194static const struct phy_ops qcom_apq8064_sata_phy_ops = { 195 .init = qcom_apq8064_sata_phy_init, 196 .exit = qcom_apq8064_sata_phy_exit, 197 .owner = THIS_MODULE, 198}; 199 200static int qcom_apq8064_sata_phy_probe(struct platform_device *pdev) 201{ 202 struct qcom_apq8064_sata_phy *phy; 203 struct device *dev = &pdev->dev; 204 struct phy_provider *phy_provider; 205 struct phy *generic_phy; 206 int ret; 207 208 phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); 209 if (!phy) 210 return -ENOMEM; 211 212 phy->mmio = devm_platform_ioremap_resource(pdev, 0); 213 if (IS_ERR(phy->mmio)) 214 return PTR_ERR(phy->mmio); 215 216 generic_phy = devm_phy_create(dev, NULL, &qcom_apq8064_sata_phy_ops); 217 if (IS_ERR(generic_phy)) { 218 dev_err(dev, "%s: failed to create phy\n", __func__); 219 return PTR_ERR(generic_phy); 220 } 221 222 phy->dev = dev; 223 phy_set_drvdata(generic_phy, phy); 224 platform_set_drvdata(pdev, phy); 225 226 phy->cfg_clk = devm_clk_get(dev, "cfg"); 227 if (IS_ERR(phy->cfg_clk)) { 228 dev_err(dev, "Failed to get sata cfg clock\n"); 229 return PTR_ERR(phy->cfg_clk); 230 } 231 232 ret = clk_prepare_enable(phy->cfg_clk); 233 if (ret) 234 return ret; 235 236 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 237 if (IS_ERR(phy_provider)) { 238 clk_disable_unprepare(phy->cfg_clk); 239 dev_err(dev, "%s: failed to register phy\n", __func__); 240 return PTR_ERR(phy_provider); 241 } 242 243 return 0; 244} 245 246static int qcom_apq8064_sata_phy_remove(struct platform_device *pdev) 247{ 248 struct qcom_apq8064_sata_phy *phy = platform_get_drvdata(pdev); 249 250 clk_disable_unprepare(phy->cfg_clk); 251 252 return 0; 253} 254 255static const struct of_device_id qcom_apq8064_sata_phy_of_match[] = { 256 { .compatible = "qcom,apq8064-sata-phy" }, 257 { }, 258}; 259MODULE_DEVICE_TABLE(of, qcom_apq8064_sata_phy_of_match); 260 261static struct platform_driver qcom_apq8064_sata_phy_driver = { 262 .probe = qcom_apq8064_sata_phy_probe, 263 .remove = qcom_apq8064_sata_phy_remove, 264 .driver = { 265 .name = "qcom-apq8064-sata-phy", 266 .of_match_table = qcom_apq8064_sata_phy_of_match, 267 } 268}; 269module_platform_driver(qcom_apq8064_sata_phy_driver); 270 271MODULE_DESCRIPTION("QCOM apq8064 SATA PHY driver"); 272MODULE_LICENSE("GPL v2");