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 phy_provider *phy_provider; 132 struct phy *generic_phy; 133 int ret; 134 135 phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); 136 if (!phy) 137 return -ENOMEM; 138 139 phy->mmio = devm_platform_ioremap_resource(pdev, 0); 140 if (IS_ERR(phy->mmio)) 141 return PTR_ERR(phy->mmio); 142 143 generic_phy = devm_phy_create(dev, NULL, &qcom_ipq806x_sata_phy_ops); 144 if (IS_ERR(generic_phy)) { 145 dev_err(dev, "%s: failed to create phy\n", __func__); 146 return PTR_ERR(generic_phy); 147 } 148 149 phy->dev = dev; 150 phy_set_drvdata(generic_phy, phy); 151 platform_set_drvdata(pdev, phy); 152 153 phy->cfg_clk = devm_clk_get(dev, "cfg"); 154 if (IS_ERR(phy->cfg_clk)) { 155 dev_err(dev, "Failed to get sata cfg clock\n"); 156 return PTR_ERR(phy->cfg_clk); 157 } 158 159 ret = clk_prepare_enable(phy->cfg_clk); 160 if (ret) 161 return ret; 162 163 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 164 if (IS_ERR(phy_provider)) { 165 clk_disable_unprepare(phy->cfg_clk); 166 dev_err(dev, "%s: failed to register phy\n", __func__); 167 return PTR_ERR(phy_provider); 168 } 169 170 return 0; 171 } 172 173 static void qcom_ipq806x_sata_phy_remove(struct platform_device *pdev) 174 { 175 struct qcom_ipq806x_sata_phy *phy = platform_get_drvdata(pdev); 176 177 clk_disable_unprepare(phy->cfg_clk); 178 } 179 180 static const struct of_device_id qcom_ipq806x_sata_phy_of_match[] = { 181 { .compatible = "qcom,ipq806x-sata-phy" }, 182 { }, 183 }; 184 MODULE_DEVICE_TABLE(of, qcom_ipq806x_sata_phy_of_match); 185 186 static struct platform_driver qcom_ipq806x_sata_phy_driver = { 187 .probe = qcom_ipq806x_sata_phy_probe, 188 .remove = qcom_ipq806x_sata_phy_remove, 189 .driver = { 190 .name = "qcom-ipq806x-sata-phy", 191 .of_match_table = qcom_ipq806x_sata_phy_of_match, 192 } 193 }; 194 module_platform_driver(qcom_ipq806x_sata_phy_driver); 195 196 MODULE_DESCRIPTION("QCOM IPQ806x SATA PHY driver"); 197 MODULE_LICENSE("GPL v2"); 198