1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * StarFive JH7110 DPHY RX driver 4 * 5 * Copyright (C) 2023 StarFive Technology Co., Ltd. 6 * Author: Jack Zhu <jack.zhu@starfivetech.com> 7 * Author: Changhuang Liang <changhuang.liang@starfivetech.com> 8 */ 9 10 #include <linux/bitfield.h> 11 #include <linux/bitops.h> 12 #include <linux/clk.h> 13 #include <linux/io.h> 14 #include <linux/module.h> 15 #include <linux/of.h> 16 #include <linux/phy/phy.h> 17 #include <linux/platform_device.h> 18 #include <linux/pm_runtime.h> 19 #include <linux/reset.h> 20 21 #define STF_DPHY_APBCFGSAIF_SYSCFG(x) (x) 22 23 #define STF_DPHY_ENABLE_CLK BIT(6) 24 #define STF_DPHY_ENABLE_CLK1 BIT(7) 25 #define STF_DPHY_ENABLE_LAN0 BIT(8) 26 #define STF_DPHY_ENABLE_LAN1 BIT(9) 27 #define STF_DPHY_ENABLE_LAN2 BIT(10) 28 #define STF_DPHY_ENABLE_LAN3 BIT(11) 29 #define STF_DPHY_LANE_SWAP_CLK GENMASK(22, 20) 30 #define STF_DPHY_LANE_SWAP_CLK1 GENMASK(25, 23) 31 #define STF_DPHY_LANE_SWAP_LAN0 GENMASK(28, 26) 32 #define STF_DPHY_LANE_SWAP_LAN1 GENMASK(31, 29) 33 34 #define STF_DPHY_LANE_SWAP_LAN2 GENMASK(2, 0) 35 #define STF_DPHY_LANE_SWAP_LAN3 GENMASK(5, 3) 36 #define STF_DPHY_PLL_CLK_SEL GENMASK(21, 12) 37 #define STF_DPHY_PRECOUNTER_IN_CLK GENMASK(29, 22) 38 39 #define STF_DPHY_PRECOUNTER_IN_CLK1 GENMASK(7, 0) 40 #define STF_DPHY_PRECOUNTER_IN_LAN0 GENMASK(15, 8) 41 #define STF_DPHY_PRECOUNTER_IN_LAN1 GENMASK(23, 16) 42 #define STF_DPHY_PRECOUNTER_IN_LAN2 GENMASK(31, 24) 43 44 #define STF_DPHY_PRECOUNTER_IN_LAN3 GENMASK(7, 0) 45 #define STF_DPHY_RX_1C2C_SEL BIT(8) 46 47 #define STF_MAP_LANES_NUM 6 48 49 struct stf_dphy_info { 50 /** 51 * @maps: 52 * 53 * Physical lanes and logic lanes mapping table. 54 * 55 * The default order is: 56 * [clk lane0, data lane 0, data lane 1, data lane 2, date lane 3, clk lane 1] 57 */ 58 u8 maps[STF_MAP_LANES_NUM]; 59 }; 60 61 struct stf_dphy { 62 struct device *dev; 63 void __iomem *regs; 64 struct clk *cfg_clk; 65 struct clk *ref_clk; 66 struct clk *tx_clk; 67 struct reset_control *rstc; 68 struct regulator *mipi_0p9; 69 struct phy *phy; 70 const struct stf_dphy_info *info; 71 }; 72 73 static int stf_dphy_configure(struct phy *phy, union phy_configure_opts *opts) 74 { 75 struct stf_dphy *dphy = phy_get_drvdata(phy); 76 const struct stf_dphy_info *info = dphy->info; 77 78 writel(FIELD_PREP(STF_DPHY_ENABLE_CLK, 1) | 79 FIELD_PREP(STF_DPHY_ENABLE_CLK1, 1) | 80 FIELD_PREP(STF_DPHY_ENABLE_LAN0, 1) | 81 FIELD_PREP(STF_DPHY_ENABLE_LAN1, 1) | 82 FIELD_PREP(STF_DPHY_ENABLE_LAN2, 1) | 83 FIELD_PREP(STF_DPHY_ENABLE_LAN3, 1) | 84 FIELD_PREP(STF_DPHY_LANE_SWAP_CLK, info->maps[0]) | 85 FIELD_PREP(STF_DPHY_LANE_SWAP_CLK1, info->maps[5]) | 86 FIELD_PREP(STF_DPHY_LANE_SWAP_LAN0, info->maps[1]) | 87 FIELD_PREP(STF_DPHY_LANE_SWAP_LAN1, info->maps[2]), 88 dphy->regs + STF_DPHY_APBCFGSAIF_SYSCFG(188)); 89 90 writel(FIELD_PREP(STF_DPHY_LANE_SWAP_LAN2, info->maps[3]) | 91 FIELD_PREP(STF_DPHY_LANE_SWAP_LAN3, info->maps[4]) | 92 FIELD_PREP(STF_DPHY_PRECOUNTER_IN_CLK, 8), 93 dphy->regs + STF_DPHY_APBCFGSAIF_SYSCFG(192)); 94 95 writel(FIELD_PREP(STF_DPHY_PRECOUNTER_IN_CLK1, 8) | 96 FIELD_PREP(STF_DPHY_PRECOUNTER_IN_LAN0, 7) | 97 FIELD_PREP(STF_DPHY_PRECOUNTER_IN_LAN1, 7) | 98 FIELD_PREP(STF_DPHY_PRECOUNTER_IN_LAN2, 7), 99 dphy->regs + STF_DPHY_APBCFGSAIF_SYSCFG(196)); 100 101 writel(FIELD_PREP(STF_DPHY_PRECOUNTER_IN_LAN3, 7), 102 dphy->regs + STF_DPHY_APBCFGSAIF_SYSCFG(200)); 103 104 return 0; 105 } 106 107 static int stf_dphy_power_on(struct phy *phy) 108 { 109 struct stf_dphy *dphy = phy_get_drvdata(phy); 110 int ret; 111 112 ret = pm_runtime_resume_and_get(dphy->dev); 113 if (ret < 0) 114 return ret; 115 116 ret = regulator_enable(dphy->mipi_0p9); 117 if (ret) { 118 pm_runtime_put(dphy->dev); 119 return ret; 120 } 121 122 clk_set_rate(dphy->cfg_clk, 99000000); 123 clk_set_rate(dphy->ref_clk, 49500000); 124 clk_set_rate(dphy->tx_clk, 19800000); 125 reset_control_deassert(dphy->rstc); 126 127 return 0; 128 } 129 130 static int stf_dphy_power_off(struct phy *phy) 131 { 132 struct stf_dphy *dphy = phy_get_drvdata(phy); 133 134 reset_control_assert(dphy->rstc); 135 136 regulator_disable(dphy->mipi_0p9); 137 138 pm_runtime_put_sync(dphy->dev); 139 140 return 0; 141 } 142 143 static const struct phy_ops stf_dphy_ops = { 144 .configure = stf_dphy_configure, 145 .power_on = stf_dphy_power_on, 146 .power_off = stf_dphy_power_off, 147 }; 148 149 static int stf_dphy_probe(struct platform_device *pdev) 150 { 151 struct phy_provider *phy_provider; 152 struct stf_dphy *dphy; 153 int ret; 154 155 dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL); 156 if (!dphy) 157 return -ENOMEM; 158 159 dphy->info = of_device_get_match_data(&pdev->dev); 160 161 dev_set_drvdata(&pdev->dev, dphy); 162 dphy->dev = &pdev->dev; 163 164 dphy->regs = devm_platform_ioremap_resource(pdev, 0); 165 if (IS_ERR(dphy->regs)) 166 return PTR_ERR(dphy->regs); 167 168 dphy->cfg_clk = devm_clk_get(&pdev->dev, "cfg"); 169 if (IS_ERR(dphy->cfg_clk)) 170 return PTR_ERR(dphy->cfg_clk); 171 172 dphy->ref_clk = devm_clk_get(&pdev->dev, "ref"); 173 if (IS_ERR(dphy->ref_clk)) 174 return PTR_ERR(dphy->ref_clk); 175 176 dphy->tx_clk = devm_clk_get(&pdev->dev, "tx"); 177 if (IS_ERR(dphy->tx_clk)) 178 return PTR_ERR(dphy->tx_clk); 179 180 dphy->rstc = devm_reset_control_array_get_exclusive(&pdev->dev); 181 if (IS_ERR(dphy->rstc)) 182 return PTR_ERR(dphy->rstc); 183 184 dphy->mipi_0p9 = devm_regulator_get(&pdev->dev, "mipi_0p9"); 185 if (IS_ERR(dphy->mipi_0p9)) 186 return PTR_ERR(dphy->mipi_0p9); 187 188 dphy->phy = devm_phy_create(&pdev->dev, NULL, &stf_dphy_ops); 189 if (IS_ERR(dphy->phy)) { 190 dev_err(&pdev->dev, "Failed to create PHY\n"); 191 return PTR_ERR(dphy->phy); 192 } 193 194 ret = devm_pm_runtime_enable(&pdev->dev); 195 if (ret) 196 return ret; 197 198 phy_set_drvdata(dphy->phy, dphy); 199 phy_provider = devm_of_phy_provider_register(&pdev->dev, 200 of_phy_simple_xlate); 201 202 return PTR_ERR_OR_ZERO(phy_provider); 203 } 204 205 static const struct stf_dphy_info starfive_dphy_info = { 206 .maps = {4, 0, 1, 2, 3, 5}, 207 }; 208 209 static const struct of_device_id stf_dphy_dt_ids[] = { 210 { 211 .compatible = "starfive,jh7110-dphy-rx", 212 .data = &starfive_dphy_info, 213 }, 214 { /* sentinel */ }, 215 }; 216 MODULE_DEVICE_TABLE(of, stf_dphy_dt_ids); 217 218 static struct platform_driver stf_dphy_driver = { 219 .probe = stf_dphy_probe, 220 .driver = { 221 .name = "starfive-dphy-rx", 222 .of_match_table = stf_dphy_dt_ids, 223 }, 224 }; 225 module_platform_driver(stf_dphy_driver); 226 227 MODULE_AUTHOR("Jack Zhu <jack.zhu@starfivetech.com>"); 228 MODULE_AUTHOR("Changhuang Liang <changhuang.liang@starfivetech.com>"); 229 MODULE_DESCRIPTION("StarFive JH7110 DPHY RX driver"); 230 MODULE_LICENSE("GPL"); 231