1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * MediaTek MIPI CSI v0.5 driver 4 * 5 * Copyright (c) 2023, MediaTek Inc. 6 * Copyright (c) 2023, BayLibre Inc. 7 */ 8 9 #include <dt-bindings/phy/phy.h> 10 #include <linux/bitfield.h> 11 #include <linux/delay.h> 12 #include <linux/io.h> 13 #include <linux/module.h> 14 #include <linux/mutex.h> 15 #include <linux/phy/phy.h> 16 #include <linux/platform_device.h> 17 #include <linux/slab.h> 18 19 #include "phy-mtk-io.h" 20 #include "phy-mtk-mipi-csi-0-5-rx-reg.h" 21 22 #define CSIXB_OFFSET 0x1000 23 24 struct mtk_mipi_cdphy_port { 25 struct device *dev; 26 void __iomem *base; 27 struct phy *phy; 28 u32 type; 29 u32 mode; 30 u32 num_lanes; 31 }; 32 33 enum PHY_TYPE { 34 DPHY = 0, 35 CPHY, 36 CDPHY, 37 }; 38 39 static void mtk_phy_csi_cdphy_ana_eq_tune(void __iomem *base) 40 { 41 mtk_phy_update_field(base + MIPI_RX_ANA18_CSIXA, RG_CSI0A_L0_T0AB_EQ_IS, 1); 42 mtk_phy_update_field(base + MIPI_RX_ANA18_CSIXA, RG_CSI0A_L0_T0AB_EQ_BW, 1); 43 mtk_phy_update_field(base + MIPI_RX_ANA1C_CSIXA, RG_CSI0A_L1_T1AB_EQ_IS, 1); 44 mtk_phy_update_field(base + MIPI_RX_ANA1C_CSIXA, RG_CSI0A_L1_T1AB_EQ_BW, 1); 45 mtk_phy_update_field(base + MIPI_RX_ANA20_CSI0A, RG_CSI0A_L2_T1BC_EQ_IS, 1); 46 mtk_phy_update_field(base + MIPI_RX_ANA20_CSI0A, RG_CSI0A_L2_T1BC_EQ_BW, 1); 47 48 mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA18_CSIXA, RG_CSI0A_L0_T0AB_EQ_IS, 1); 49 mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA18_CSIXA, RG_CSI0A_L0_T0AB_EQ_BW, 1); 50 mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA1C_CSIXA, RG_CSI0A_L1_T1AB_EQ_IS, 1); 51 mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA1C_CSIXA, RG_CSI0A_L1_T1AB_EQ_BW, 1); 52 mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA20_CSI0A, RG_CSI0A_L2_T1BC_EQ_IS, 1); 53 mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA20_CSI0A, RG_CSI0A_L2_T1BC_EQ_BW, 1); 54 } 55 56 static void mtk_phy_csi_dphy_ana_eq_tune(void __iomem *base) 57 { 58 mtk_phy_update_field(base + MIPI_RX_ANA18_CSIXA, RG_CSI1A_L0_EQ_IS, 1); 59 mtk_phy_update_field(base + MIPI_RX_ANA18_CSIXA, RG_CSI1A_L0_EQ_BW, 1); 60 mtk_phy_update_field(base + MIPI_RX_ANA18_CSIXA, RG_CSI1A_L1_EQ_IS, 1); 61 mtk_phy_update_field(base + MIPI_RX_ANA18_CSIXA, RG_CSI1A_L1_EQ_BW, 1); 62 mtk_phy_update_field(base + MIPI_RX_ANA1C_CSIXA, RG_CSI1A_L2_EQ_IS, 1); 63 mtk_phy_update_field(base + MIPI_RX_ANA1C_CSIXA, RG_CSI1A_L2_EQ_BW, 1); 64 65 mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA18_CSIXA, RG_CSI1A_L0_EQ_IS, 1); 66 mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA18_CSIXA, RG_CSI1A_L0_EQ_BW, 1); 67 mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA18_CSIXA, RG_CSI1A_L1_EQ_IS, 1); 68 mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA18_CSIXA, RG_CSI1A_L1_EQ_BW, 1); 69 mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA1C_CSIXA, RG_CSI1A_L2_EQ_IS, 1); 70 mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA1C_CSIXA, RG_CSI1A_L2_EQ_BW, 1); 71 } 72 73 static int mtk_mipi_phy_power_on(struct phy *phy) 74 { 75 struct mtk_mipi_cdphy_port *port = phy_get_drvdata(phy); 76 void __iomem *base = port->base; 77 78 /* 79 * The driver currently supports DPHY and CD-PHY phys, 80 * but the only mode supported is DPHY, 81 * so CD-PHY capable phys must be configured in DPHY mode 82 */ 83 if (port->type == CDPHY) { 84 mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSI0A_CPHY_EN, 0); 85 mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, 86 RG_CSI0A_CPHY_EN, 0); 87 } 88 89 /* 90 * Lane configuration: 91 * 92 * Only 4 data + 1 clock is supported for now with the following mapping: 93 * 94 * CSIXA_LNR0 --> D2 95 * CSIXA_LNR1 --> D0 96 * CSIXA_LNR2 --> C 97 * CSIXB_LNR0 --> D1 98 * CSIXB_LNR1 --> D3 99 */ 100 mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_DPHY_L0_CKMODE_EN, 0); 101 mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_DPHY_L0_CKSEL, 1); 102 mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_DPHY_L1_CKMODE_EN, 0); 103 mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_DPHY_L1_CKSEL, 1); 104 mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_DPHY_L2_CKMODE_EN, 1); 105 mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_DPHY_L2_CKSEL, 1); 106 107 mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, 108 RG_CSIXA_DPHY_L0_CKMODE_EN, 0); 109 mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, RG_CSIXA_DPHY_L0_CKSEL, 1); 110 mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, 111 RG_CSIXA_DPHY_L1_CKMODE_EN, 0); 112 mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, RG_CSIXA_DPHY_L1_CKSEL, 1); 113 mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, 114 RG_CSIXA_DPHY_L2_CKMODE_EN, 0); 115 mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, RG_CSIXA_DPHY_L2_CKSEL, 1); 116 117 /* Byte clock invert */ 118 mtk_phy_update_field(base + MIPI_RX_ANAA8_CSIXA, RG_CSIXA_CDPHY_L0_T0_BYTECK_INVERT, 1); 119 mtk_phy_update_field(base + MIPI_RX_ANAA8_CSIXA, RG_CSIXA_DPHY_L1_BYTECK_INVERT, 1); 120 mtk_phy_update_field(base + MIPI_RX_ANAA8_CSIXA, RG_CSIXA_CDPHY_L2_T1_BYTECK_INVERT, 1); 121 122 mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANAA8_CSIXA, 123 RG_CSIXA_CDPHY_L0_T0_BYTECK_INVERT, 1); 124 mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANAA8_CSIXA, 125 RG_CSIXA_DPHY_L1_BYTECK_INVERT, 1); 126 mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANAA8_CSIXA, 127 RG_CSIXA_CDPHY_L2_T1_BYTECK_INVERT, 1); 128 129 /* Start ANA EQ tuning */ 130 if (port->type == CDPHY) 131 mtk_phy_csi_cdphy_ana_eq_tune(base); 132 else 133 mtk_phy_csi_dphy_ana_eq_tune(base); 134 135 /* End ANA EQ tuning */ 136 mtk_phy_set_bits(base + MIPI_RX_ANA40_CSIXA, 0x90); 137 138 mtk_phy_update_field(base + MIPI_RX_ANA24_CSIXA, RG_CSIXA_RESERVE, 0x40); 139 mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA24_CSIXA, RG_CSIXA_RESERVE, 0x40); 140 mtk_phy_update_field(base + MIPI_RX_WRAPPER80_CSIXA, CSR_CSI_RST_MODE, 0); 141 mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_WRAPPER80_CSIXA, CSR_CSI_RST_MODE, 0); 142 /* ANA power on */ 143 mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_BG_CORE_EN, 1); 144 mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, RG_CSIXA_BG_CORE_EN, 1); 145 usleep_range(20, 40); 146 mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_BG_LPF_EN, 1); 147 mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, RG_CSIXA_BG_LPF_EN, 1); 148 149 return 0; 150 } 151 152 static int mtk_mipi_phy_power_off(struct phy *phy) 153 { 154 struct mtk_mipi_cdphy_port *port = phy_get_drvdata(phy); 155 void __iomem *base = port->base; 156 157 /* Disable MIPI BG. */ 158 mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_BG_CORE_EN, 0); 159 mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_BG_LPF_EN, 0); 160 161 mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, RG_CSIXA_BG_CORE_EN, 0); 162 mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, RG_CSIXA_BG_LPF_EN, 0); 163 164 return 0; 165 } 166 167 static struct phy *mtk_mipi_cdphy_xlate(struct device *dev, 168 const struct of_phandle_args *args) 169 { 170 struct mtk_mipi_cdphy_port *priv = dev_get_drvdata(dev); 171 172 /* 173 * If PHY is CD-PHY then we need to get the operating mode 174 * For now only D-PHY mode is supported 175 */ 176 if (priv->type == CDPHY) { 177 if (args->args_count != 1) { 178 dev_err(dev, "invalid number of arguments\n"); 179 return ERR_PTR(-EINVAL); 180 } 181 switch (args->args[0]) { 182 case PHY_TYPE_DPHY: 183 priv->mode = DPHY; 184 if (priv->num_lanes != 4) { 185 dev_err(dev, "Only 4D1C mode is supported for now!\n"); 186 return ERR_PTR(-EINVAL); 187 } 188 break; 189 default: 190 dev_err(dev, "Unsupported PHY type: %i\n", args->args[0]); 191 return ERR_PTR(-EINVAL); 192 } 193 } else { 194 if (args->args_count) { 195 dev_err(dev, "invalid number of arguments\n"); 196 return ERR_PTR(-EINVAL); 197 } 198 priv->mode = DPHY; 199 } 200 201 return priv->phy; 202 } 203 204 static const struct phy_ops mtk_cdphy_ops = { 205 .power_on = mtk_mipi_phy_power_on, 206 .power_off = mtk_mipi_phy_power_off, 207 .owner = THIS_MODULE, 208 }; 209 210 static int mtk_mipi_cdphy_probe(struct platform_device *pdev) 211 { 212 struct device *dev = &pdev->dev; 213 struct phy_provider *phy_provider; 214 struct mtk_mipi_cdphy_port *port; 215 struct phy *phy; 216 int ret; 217 u32 phy_type; 218 219 port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); 220 if (!port) 221 return -ENOMEM; 222 223 dev_set_drvdata(dev, port); 224 225 port->dev = dev; 226 227 port->base = devm_platform_ioremap_resource(pdev, 0); 228 if (IS_ERR(port->base)) 229 return PTR_ERR(port->base); 230 231 ret = of_property_read_u32(dev->of_node, "num-lanes", &port->num_lanes); 232 if (ret) { 233 dev_err(dev, "Failed to read num-lanes property: %i\n", ret); 234 return ret; 235 } 236 237 /* 238 * phy-type is optional, if not present, PHY is considered to be CD-PHY 239 */ 240 if (device_property_present(dev, "phy-type")) { 241 ret = of_property_read_u32(dev->of_node, "phy-type", &phy_type); 242 if (ret) { 243 dev_err(dev, "Failed to read phy-type property: %i\n", ret); 244 return ret; 245 } 246 switch (phy_type) { 247 case PHY_TYPE_DPHY: 248 port->type = DPHY; 249 break; 250 default: 251 dev_err(dev, "Unsupported PHY type: %i\n", phy_type); 252 return -EINVAL; 253 } 254 } else { 255 port->type = CDPHY; 256 } 257 258 phy = devm_phy_create(dev, NULL, &mtk_cdphy_ops); 259 if (IS_ERR(phy)) { 260 dev_err(dev, "Failed to create PHY: %ld\n", PTR_ERR(phy)); 261 return PTR_ERR(phy); 262 } 263 264 port->phy = phy; 265 phy_set_drvdata(phy, port); 266 267 phy_provider = devm_of_phy_provider_register(dev, mtk_mipi_cdphy_xlate); 268 if (IS_ERR(phy_provider)) { 269 dev_err(dev, "Failed to register PHY provider: %ld\n", 270 PTR_ERR(phy_provider)); 271 return PTR_ERR(phy_provider); 272 } 273 274 return 0; 275 } 276 277 static const struct of_device_id mtk_mipi_cdphy_of_match[] = { 278 { .compatible = "mediatek,mt8365-csi-rx" }, 279 { /* sentinel */}, 280 }; 281 MODULE_DEVICE_TABLE(of, mtk_mipi_cdphy_of_match); 282 283 static struct platform_driver mipi_cdphy_pdrv = { 284 .probe = mtk_mipi_cdphy_probe, 285 .driver = { 286 .name = "mtk-mipi-csi-0-5", 287 .of_match_table = mtk_mipi_cdphy_of_match, 288 }, 289 }; 290 module_platform_driver(mipi_cdphy_pdrv); 291 292 MODULE_DESCRIPTION("MediaTek MIPI CSI CD-PHY v0.5 Driver"); 293 MODULE_AUTHOR("Louis Kuo <louis.kuo@mediatek.com>"); 294 MODULE_LICENSE("GPL"); 295