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/kernel.h> 8 #include <linux/module.h> 9 #include <linux/of.h> 10 #include <linux/of_address.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 struct qcom_ipq806x_sata_phy { 19 void __iomem *mmio; 20 struct clk *cfg_clk; 21 struct device *dev; 22 }; 23 24 #define __set(v, a, b) (((v) << (b)) & GENMASK(a, b)) 25 26 #define SATA_PHY_P0_PARAM0 0x200 27 #define SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN3(x) __set(x, 17, 12) 28 #define SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN3_MASK GENMASK(17, 12) 29 #define SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN2(x) __set(x, 11, 6) 30 #define SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN2_MASK GENMASK(11, 6) 31 #define SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN1(x) __set(x, 5, 0) 32 #define SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN1_MASK GENMASK(5, 0) 33 34 #define SATA_PHY_P0_PARAM1 0x204 35 #define SATA_PHY_P0_PARAM1_RESERVED_BITS31_21(x) __set(x, 31, 21) 36 #define SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN3(x) __set(x, 20, 14) 37 #define SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN3_MASK GENMASK(20, 14) 38 #define SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN2(x) __set(x, 13, 7) 39 #define SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN2_MASK GENMASK(13, 7) 40 #define SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN1(x) __set(x, 6, 0) 41 #define SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN1_MASK GENMASK(6, 0) 42 43 #define SATA_PHY_P0_PARAM2 0x208 44 #define SATA_PHY_P0_PARAM2_RX_EQ(x) __set(x, 20, 18) 45 #define SATA_PHY_P0_PARAM2_RX_EQ_MASK GENMASK(20, 18) 46 47 #define SATA_PHY_P0_PARAM3 0x20C 48 #define SATA_PHY_SSC_EN 0x8 49 #define SATA_PHY_P0_PARAM4 0x210 50 #define SATA_PHY_REF_SSP_EN 0x2 51 #define SATA_PHY_RESET 0x1 52 53 static int qcom_ipq806x_sata_phy_init(struct phy *generic_phy) 54 { 55 struct qcom_ipq806x_sata_phy *phy = phy_get_drvdata(generic_phy); 56 u32 reg; 57 58 /* Setting SSC_EN to 1 */ 59 reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM3); 60 reg = reg | SATA_PHY_SSC_EN; 61 writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM3); 62 63 reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM0) & 64 ~(SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN3_MASK | 65 SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN2_MASK | 66 SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN1_MASK); 67 reg |= SATA_PHY_P0_PARAM0_P0_TX_PREEMPH_GEN3(0xf); 68 writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM0); 69 70 reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM1) & 71 ~(SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN3_MASK | 72 SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN2_MASK | 73 SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN1_MASK); 74 reg |= SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN3(0x55) | 75 SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN2(0x55) | 76 SATA_PHY_P0_PARAM1_P0_TX_AMPLITUDE_GEN1(0x55); 77 writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM1); 78 79 reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM2) & 80 ~SATA_PHY_P0_PARAM2_RX_EQ_MASK; 81 reg |= SATA_PHY_P0_PARAM2_RX_EQ(0x3); 82 writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM2); 83 84 /* Setting PHY_RESET to 1 */ 85 reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM4); 86 reg = reg | SATA_PHY_RESET; 87 writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM4); 88 89 /* Setting REF_SSP_EN to 1 */ 90 reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM4); 91 reg = reg | SATA_PHY_REF_SSP_EN | SATA_PHY_RESET; 92 writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM4); 93 94 /* make sure all changes complete before we let the PHY out of reset */ 95 mb(); 96 97 /* sleep for max. 50us more to combine processor wakeups */ 98 usleep_range(20, 20 + 50); 99 100 /* Clearing PHY_RESET to 0 */ 101 reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM4); 102 reg = reg & ~SATA_PHY_RESET; 103 writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM4); 104 105 return 0; 106 } 107 108 static int qcom_ipq806x_sata_phy_exit(struct phy *generic_phy) 109 { 110 struct qcom_ipq806x_sata_phy *phy = phy_get_drvdata(generic_phy); 111 u32 reg; 112 113 /* Setting PHY_RESET to 1 */ 114 reg = readl_relaxed(phy->mmio + SATA_PHY_P0_PARAM4); 115 reg = reg | SATA_PHY_RESET; 116 writel_relaxed(reg, phy->mmio + SATA_PHY_P0_PARAM4); 117 118 return 0; 119 } 120 121 static const struct phy_ops qcom_ipq806x_sata_phy_ops = { 122 .init = qcom_ipq806x_sata_phy_init, 123 .exit = qcom_ipq806x_sata_phy_exit, 124 .owner = THIS_MODULE, 125 }; 126 127 static int qcom_ipq806x_sata_phy_probe(struct platform_device *pdev) 128 { 129 struct qcom_ipq806x_sata_phy *phy; 130 struct device *dev = &pdev->dev; 131 struct resource *res; 132 struct phy_provider *phy_provider; 133 struct phy *generic_phy; 134 int ret; 135 136 phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); 137 if (!phy) 138 return -ENOMEM; 139 140 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 141 phy->mmio = devm_ioremap_resource(dev, res); 142 if (IS_ERR(phy->mmio)) 143 return PTR_ERR(phy->mmio); 144 145 generic_phy = devm_phy_create(dev, NULL, &qcom_ipq806x_sata_phy_ops); 146 if (IS_ERR(generic_phy)) { 147 dev_err(dev, "%s: failed to create phy\n", __func__); 148 return PTR_ERR(generic_phy); 149 } 150 151 phy->dev = dev; 152 phy_set_drvdata(generic_phy, phy); 153 platform_set_drvdata(pdev, phy); 154 155 phy->cfg_clk = devm_clk_get(dev, "cfg"); 156 if (IS_ERR(phy->cfg_clk)) { 157 dev_err(dev, "Failed to get sata cfg clock\n"); 158 return PTR_ERR(phy->cfg_clk); 159 } 160 161 ret = clk_prepare_enable(phy->cfg_clk); 162 if (ret) 163 return ret; 164 165 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 166 if (IS_ERR(phy_provider)) { 167 clk_disable_unprepare(phy->cfg_clk); 168 dev_err(dev, "%s: failed to register phy\n", __func__); 169 return PTR_ERR(phy_provider); 170 } 171 172 return 0; 173 } 174 175 static int qcom_ipq806x_sata_phy_remove(struct platform_device *pdev) 176 { 177 struct qcom_ipq806x_sata_phy *phy = platform_get_drvdata(pdev); 178 179 clk_disable_unprepare(phy->cfg_clk); 180 181 return 0; 182 } 183 184 static const struct of_device_id qcom_ipq806x_sata_phy_of_match[] = { 185 { .compatible = "qcom,ipq806x-sata-phy" }, 186 { }, 187 }; 188 MODULE_DEVICE_TABLE(of, qcom_ipq806x_sata_phy_of_match); 189 190 static struct platform_driver qcom_ipq806x_sata_phy_driver = { 191 .probe = qcom_ipq806x_sata_phy_probe, 192 .remove = qcom_ipq806x_sata_phy_remove, 193 .driver = { 194 .name = "qcom-ipq806x-sata-phy", 195 .of_match_table = qcom_ipq806x_sata_phy_of_match, 196 } 197 }; 198 module_platform_driver(qcom_ipq806x_sata_phy_driver); 199 200 MODULE_DESCRIPTION("QCOM IPQ806x SATA PHY driver"); 201 MODULE_LICENSE("GPL v2"); 202