Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

phy: starfive: Add mipi dphy rx support

Add mipi dphy rx support for the StarFive JH7110 SoC. It is used to
transfer CSI camera data.

Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
Reviewed-by: Minda Chen <minda.chen@starfivetech.com>
Link: https://lore.kernel.org/r/20230718070803.16660-3-changhuang.liang@starfivetech.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Changhuang Liang and committed by
Vinod Koul
f8aa6608 ae07a9a8

+251 -2
+7
MAINTAINERS
··· 20265 20265 F: Documentation/devicetree/bindings/net/starfive,jh7110-dwmac.yaml 20266 20266 F: drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c 20267 20267 20268 + STARFIVE JH7110 DPHY RX DRIVER 20269 + M: Jack Zhu <jack.zhu@starfivetech.com> 20270 + M: Changhuang Liang <changhuang.liang@starfivetech.com> 20271 + S: Supported 20272 + F: Documentation/devicetree/bindings/phy/starfive,jh7110-dphy-rx.yaml 20273 + F: drivers/phy/starfive/phy-starfive-dphy-rx.c 20274 + 20268 20275 STARFIVE JH7110 MMC/SD/SDIO DRIVER 20269 20276 M: William Qiu <william.qiu@starfivetech.com> 20270 20277 S: Supported
+9
drivers/phy/starfive/Kconfig
··· 3 3 # Phy drivers for StarFive platforms 4 4 # 5 5 6 + config PHY_STARFIVE_JH7110_DPHY_RX 7 + tristate "StarFive JH7110 D-PHY RX support" 8 + select GENERIC_PHY 9 + select GENERIC_PHY_MIPI_DPHY 10 + help 11 + Choose this option if you have a StarFive D-PHY in your 12 + system. If M is selected, the module will be called 13 + phy-jh7110-dphy-rx.ko. 14 + 6 15 config PHY_STARFIVE_JH7110_PCIE 7 16 tristate "Starfive JH7110 PCIE 2.0/USB 3.0 PHY support" 8 17 depends on HAS_IOMEM
+3 -2
drivers/phy/starfive/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 - obj-$(CONFIG_PHY_STARFIVE_JH7110_PCIE) += phy-jh7110-pcie.o 3 - obj-$(CONFIG_PHY_STARFIVE_JH7110_USB) += phy-jh7110-usb.o 2 + obj-$(CONFIG_PHY_STARFIVE_JH7110_DPHY_RX) += phy-jh7110-dphy-rx.o 3 + obj-$(CONFIG_PHY_STARFIVE_JH7110_PCIE) += phy-jh7110-pcie.o 4 + obj-$(CONFIG_PHY_STARFIVE_JH7110_USB) += phy-jh7110-usb.o
+232
drivers/phy/starfive/phy-jh7110-dphy-rx.c
··· 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");