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 154 dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL); 155 if (!dphy) 156 return -ENOMEM; 157 158 dphy->info = of_device_get_match_data(&pdev->dev); 159 160 dev_set_drvdata(&pdev->dev, dphy); 161 dphy->dev = &pdev->dev; 162 163 dphy->regs = devm_platform_ioremap_resource(pdev, 0); 164 if (IS_ERR(dphy->regs)) 165 return PTR_ERR(dphy->regs); 166 167 dphy->cfg_clk = devm_clk_get(&pdev->dev, "cfg"); 168 if (IS_ERR(dphy->cfg_clk)) 169 return PTR_ERR(dphy->cfg_clk); 170 171 dphy->ref_clk = devm_clk_get(&pdev->dev, "ref"); 172 if (IS_ERR(dphy->ref_clk)) 173 return PTR_ERR(dphy->ref_clk); 174 175 dphy->tx_clk = devm_clk_get(&pdev->dev, "tx"); 176 if (IS_ERR(dphy->tx_clk)) 177 return PTR_ERR(dphy->tx_clk); 178 179 dphy->rstc = devm_reset_control_array_get_exclusive(&pdev->dev); 180 if (IS_ERR(dphy->rstc)) 181 return PTR_ERR(dphy->rstc); 182 183 dphy->mipi_0p9 = devm_regulator_get(&pdev->dev, "mipi_0p9"); 184 if (IS_ERR(dphy->mipi_0p9)) 185 return PTR_ERR(dphy->mipi_0p9); 186 187 dphy->phy = devm_phy_create(&pdev->dev, NULL, &stf_dphy_ops); 188 if (IS_ERR(dphy->phy)) { 189 dev_err(&pdev->dev, "Failed to create PHY\n"); 190 return PTR_ERR(dphy->phy); 191 } 192 193 pm_runtime_enable(&pdev->dev); 194 195 phy_set_drvdata(dphy->phy, dphy); 196 phy_provider = devm_of_phy_provider_register(&pdev->dev, 197 of_phy_simple_xlate); 198 199 return PTR_ERR_OR_ZERO(phy_provider); 200 } 201 202 static const struct stf_dphy_info starfive_dphy_info = { 203 .maps = {4, 0, 1, 2, 3, 5}, 204 }; 205 206 static const struct of_device_id stf_dphy_dt_ids[] = { 207 { 208 .compatible = "starfive,jh7110-dphy-rx", 209 .data = &starfive_dphy_info, 210 }, 211 { /* sentinel */ }, 212 }; 213 MODULE_DEVICE_TABLE(of, stf_dphy_dt_ids); 214 215 static struct platform_driver stf_dphy_driver = { 216 .probe = stf_dphy_probe, 217 .driver = { 218 .name = "starfive-dphy-rx", 219 .of_match_table = stf_dphy_dt_ids, 220 }, 221 }; 222 module_platform_driver(stf_dphy_driver); 223 224 MODULE_AUTHOR("Jack Zhu <jack.zhu@starfivetech.com>"); 225 MODULE_AUTHOR("Changhuang Liang <changhuang.liang@starfivetech.com>"); 226 MODULE_DESCRIPTION("StarFive JH7110 DPHY RX driver"); 227 MODULE_LICENSE("GPL"); 228