phy-qcom-ipq806x-sata.c (6125B)
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 18struct 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 53static 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 108static 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 121static 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 127static 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 173static int 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 return 0; 180} 181 182static const struct of_device_id qcom_ipq806x_sata_phy_of_match[] = { 183 { .compatible = "qcom,ipq806x-sata-phy" }, 184 { }, 185}; 186MODULE_DEVICE_TABLE(of, qcom_ipq806x_sata_phy_of_match); 187 188static struct platform_driver qcom_ipq806x_sata_phy_driver = { 189 .probe = qcom_ipq806x_sata_phy_probe, 190 .remove = qcom_ipq806x_sata_phy_remove, 191 .driver = { 192 .name = "qcom-ipq806x-sata-phy", 193 .of_match_table = qcom_ipq806x_sata_phy_of_match, 194 } 195}; 196module_platform_driver(qcom_ipq806x_sata_phy_driver); 197 198MODULE_DESCRIPTION("QCOM IPQ806x SATA PHY driver"); 199MODULE_LICENSE("GPL v2");