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