Hi, Julien: Julien Stephan <jstephan@xxxxxxxxxxxx> 於 2023年4月3日 週一 下午3:20寫道: > > From: Phi-bang Nguyen <pnguyen@xxxxxxxxxxxx> > > This is a new driver that supports the MIPI CSI CD-PHY for mediatek > mt8365 soc > > Signed-off-by: Louis Kuo <louis.kuo@xxxxxxxxxxxx> > Signed-off-by: Phi-bang Nguyen <pnguyen@xxxxxxxxxxxx> > [Julien Stephan: use regmap] > [Julien Stephan: use GENMASK] > Co-developed-by: Julien Stephan <jstephan@xxxxxxxxxxxx> > Signed-off-by: Julien Stephan <jstephan@xxxxxxxxxxxx> > --- > .../bindings/phy/mediatek,csi-phy.yaml | 9 +- > MAINTAINERS | 1 + > drivers/phy/mediatek/Kconfig | 8 + > drivers/phy/mediatek/Makefile | 2 + > .../phy/mediatek/phy-mtk-mipi-csi-rx-reg.h | 435 ++++++++++++++++++ > drivers/phy/mediatek/phy-mtk-mipi-csi.c | 392 ++++++++++++++++ > 6 files changed, 845 insertions(+), 2 deletions(-) > create mode 100644 drivers/phy/mediatek/phy-mtk-mipi-csi-rx-reg.h > create mode 100644 drivers/phy/mediatek/phy-mtk-mipi-csi.c > [snip] > +static int mtk_mipi_phy_power_on(struct phy *phy) > +{ > + struct mtk_mipi_dphy_port *port = phy_get_drvdata(phy); > + struct mtk_mipi_dphy *priv = port->dev; > + struct regmap *regmap_base = port->regmap_base; > + struct regmap *regmap_4d1c = port->regmap_4d1c; > + int ret = 0; > + > + mutex_lock(&priv->lock); > + > + switch (port->id) { > + case MTK_MIPI_PHY_PORT_0: > + if (priv->ports[MTK_MIPI_PHY_PORT_0A].active || > + priv->ports[MTK_MIPI_PHY_PORT_0B].active) > + ret = -EBUSY; > + break; > + > + case MTK_MIPI_PHY_PORT_0A: > + case MTK_MIPI_PHY_PORT_0B: > + if (priv->ports[MTK_MIPI_PHY_PORT_0].active) > + ret = -EBUSY; > + break; > + } > + > + if (!ret) > + port->active = true; > + > + mutex_unlock(&priv->lock); > + > + if (ret < 0) > + return ret; > + > + /* Set analog phy mode to DPHY */ > + if (port->is_cdphy) > + REGMAP_BIT(regmap_base, MIPI_RX_ANA00_CSIxA, > + RG_CSI0A_CPHY_EN, 0); > + > + if (port->is_4d1c) { > + REGMAP_BIT(regmap_base, MIPI_RX_ANA00_CSIxA, > + RG_CSIxA_DPHY_L0_CKMODE_EN, 0); > + REGMAP_BIT(regmap_base, MIPI_RX_ANA00_CSIxA, > + RG_CSIxA_DPHY_L0_CKSEL, 1); > + REGMAP_BIT(regmap_base, MIPI_RX_ANA00_CSIxA, > + RG_CSIxA_DPHY_L1_CKMODE_EN, 0); > + REGMAP_BIT(regmap_base, MIPI_RX_ANA00_CSIxA, > + RG_CSIxA_DPHY_L1_CKSEL, 1); > + REGMAP_BIT(regmap_base, MIPI_RX_ANA00_CSIxA, > + RG_CSIxA_DPHY_L2_CKMODE_EN, 1); > + REGMAP_BIT(regmap_base, MIPI_RX_ANA00_CSIxA, > + RG_CSIxA_DPHY_L2_CKSEL, 1); > + } else { > + REGMAP_BIT(regmap_base, MIPI_RX_ANA00_CSIxA, > + RG_CSIxA_DPHY_L0_CKMODE_EN, 0); > + REGMAP_BIT(regmap_base, MIPI_RX_ANA00_CSIxA, > + RG_CSIxA_DPHY_L0_CKSEL, 0); > + REGMAP_BIT(regmap_base, MIPI_RX_ANA00_CSIxA, > + RG_CSIxA_DPHY_L1_CKMODE_EN, 1); > + REGMAP_BIT(regmap_base, MIPI_RX_ANA00_CSIxA, > + RG_CSIxA_DPHY_L1_CKSEL, 0); > + REGMAP_BIT(regmap_base, MIPI_RX_ANA00_CSIxA, > + RG_CSIxA_DPHY_L2_CKMODE_EN, 0); > + REGMAP_BIT(regmap_base, MIPI_RX_ANA00_CSIxA, > + RG_CSIxA_DPHY_L2_CKSEL, 0); > + } > + > + if (port->is_4d1c) { > + if (port->is_cdphy) > + REGMAP_BIT(regmap_4d1c, MIPI_RX_ANA00_CSIxA, > + RG_CSI0A_CPHY_EN, 0); > + > + REGMAP_BIT(regmap_4d1c, MIPI_RX_ANA00_CSIxA, > + RG_CSIxA_DPHY_L0_CKMODE_EN, 0); > + REGMAP_BIT(regmap_4d1c, MIPI_RX_ANA00_CSIxA, > + RG_CSIxA_DPHY_L0_CKSEL, 1); > + REGMAP_BIT(regmap_4d1c, MIPI_RX_ANA00_CSIxA, > + RG_CSIxA_DPHY_L1_CKMODE_EN, 0); > + REGMAP_BIT(regmap_4d1c, MIPI_RX_ANA00_CSIxA, > + RG_CSIxA_DPHY_L1_CKSEL, 1); > + REGMAP_BIT(regmap_4d1c, MIPI_RX_ANA00_CSIxA, > + RG_CSIxA_DPHY_L2_CKMODE_EN, 0); > + REGMAP_BIT(regmap_4d1c, MIPI_RX_ANA00_CSIxA, > + RG_CSIxA_DPHY_L2_CKSEL, 1); > + } > + > + /* Byte clock invert */ > + REGMAP_BIT(regmap_base, MIPI_RX_ANAA8_CSIxA, > + RG_CSIxA_CDPHY_L0_T0_BYTECK_INVERT, 1); > + REGMAP_BIT(regmap_base, MIPI_RX_ANAA8_CSIxA, > + RG_CSIxA_DPHY_L1_BYTECK_INVERT, 1); > + REGMAP_BIT(regmap_base, MIPI_RX_ANAA8_CSIxA, > + RG_CSIxA_CDPHY_L2_T1_BYTECK_INVERT, 1); > + > + if (port->is_4d1c) { > + REGMAP_BIT(regmap_4d1c, MIPI_RX_ANAA8_CSIxA, > + RG_CSIxA_CDPHY_L0_T0_BYTECK_INVERT, 1); > + REGMAP_BIT(regmap_4d1c, MIPI_RX_ANAA8_CSIxA, > + RG_CSIxA_DPHY_L1_BYTECK_INVERT, 1); > + REGMAP_BIT(regmap_4d1c, MIPI_RX_ANAA8_CSIxA, > + RG_CSIxA_CDPHY_L2_T1_BYTECK_INVERT, 1); > + } > + > + /* Start ANA EQ tuning */ > + if (port->is_cdphy) { > + REGMAP_BIT(regmap_base, MIPI_RX_ANA18_CSIxA, > + RG_CSI0A_L0_T0AB_EQ_IS, 1); > + REGMAP_BIT(regmap_base, MIPI_RX_ANA18_CSIxA, > + RG_CSI0A_L0_T0AB_EQ_BW, 1); > + REGMAP_BIT(regmap_base, MIPI_RX_ANA1C_CSIxA, > + RG_CSI0A_L1_T1AB_EQ_IS, 1); > + REGMAP_BIT(regmap_base, MIPI_RX_ANA1C_CSIxA, > + RG_CSI0A_L1_T1AB_EQ_BW, 1); > + REGMAP_BIT(regmap_base, MIPI_RX_ANA20_CSI0A, > + RG_CSI0A_L2_T1BC_EQ_IS, 1); > + REGMAP_BIT(regmap_base, MIPI_RX_ANA20_CSI0A, > + RG_CSI0A_L2_T1BC_EQ_BW, 1); > + > + if (port->is_4d1c) { > + REGMAP_BIT(regmap_4d1c, MIPI_RX_ANA18_CSIxA, > + RG_CSI0A_L0_T0AB_EQ_IS, 1); > + REGMAP_BIT(regmap_4d1c, MIPI_RX_ANA18_CSIxA, > + RG_CSI0A_L0_T0AB_EQ_BW, 1); > + REGMAP_BIT(regmap_4d1c, MIPI_RX_ANA1C_CSIxA, > + RG_CSI0A_L1_T1AB_EQ_IS, 1); > + REGMAP_BIT(regmap_4d1c, MIPI_RX_ANA1C_CSIxA, > + RG_CSI0A_L1_T1AB_EQ_BW, 1); > + REGMAP_BIT(regmap_4d1c, MIPI_RX_ANA20_CSI0A, > + RG_CSI0A_L2_T1BC_EQ_IS, 1); > + REGMAP_BIT(regmap_4d1c, MIPI_RX_ANA20_CSI0A, > + RG_CSI0A_L2_T1BC_EQ_BW, 1); > + } > + } else { > + REGMAP_BIT(regmap_base, MIPI_RX_ANA18_CSIxA, > + RG_CSI1A_L0_EQ_IS, 1); > + REGMAP_BIT(regmap_base, MIPI_RX_ANA18_CSIxA, > + RG_CSI1A_L0_EQ_BW, 1); > + REGMAP_BIT(regmap_base, MIPI_RX_ANA18_CSIxA, > + RG_CSI1A_L1_EQ_IS, 1); > + REGMAP_BIT(regmap_base, MIPI_RX_ANA18_CSIxA, > + RG_CSI1A_L1_EQ_BW, 1); > + REGMAP_BIT(regmap_base, MIPI_RX_ANA1C_CSIxA, > + RG_CSI1A_L2_EQ_IS, 1); > + REGMAP_BIT(regmap_base, MIPI_RX_ANA1C_CSIxA, > + RG_CSI1A_L2_EQ_BW, 1); > + > + if (port->is_4d1c) { > + REGMAP_BIT(regmap_4d1c, MIPI_RX_ANA18_CSIxA, > + RG_CSI1A_L0_EQ_IS, 1); RG_CSI1A_L0_EQ_IS is identical to RG_CSI0A_L0_T0AB_EQ_IS, and ditto for below register. I think the function of each bitwise register is the same. Define only one copy of the these register, don't duplicate the same thing. Regards, Chun-Kuang. > + REGMAP_BIT(regmap_4d1c, MIPI_RX_ANA18_CSIxA, > + RG_CSI1A_L0_EQ_BW, 1); > + REGMAP_BIT(regmap_4d1c, MIPI_RX_ANA18_CSIxA, > + RG_CSI1A_L1_EQ_IS, 1); > + REGMAP_BIT(regmap_4d1c, MIPI_RX_ANA18_CSIxA, > + RG_CSI1A_L1_EQ_BW, 1); > + REGMAP_BIT(regmap_4d1c, MIPI_RX_ANA1C_CSIxA, > + RG_CSI1A_L2_EQ_IS, 1); > + REGMAP_BIT(regmap_4d1c, MIPI_RX_ANA1C_CSIxA, > + RG_CSI1A_L2_EQ_BW, 1); > + } > + } > + > + /* End ANA EQ tuning */ > + regmap_write(regmap_base, MIPI_RX_ANA40_CSIxA, 0x90); > + > + REGMAP_BIT(regmap_base, MIPI_RX_ANA24_CSIxA, > + RG_CSIxA_RESERVE, 0x40); > + if (port->is_4d1c) > + REGMAP_BIT(regmap_4d1c, MIPI_RX_ANA24_CSIxA, > + RG_CSIxA_RESERVE, 0x40); > + REGMAP_BIT(regmap_base, MIPI_RX_WRAPPER80_CSIxA, > + CSR_CSI_RST_MODE, 0); > + if (port->is_4d1c) > + REGMAP_BIT(regmap_4d1c, MIPI_RX_WRAPPER80_CSIxA, > + CSR_CSI_RST_MODE, 0); > + /* ANA power on */ > + REGMAP_BIT(regmap_base, MIPI_RX_ANA00_CSIxA, > + RG_CSIxA_BG_CORE_EN, 1); > + if (port->is_4d1c) > + REGMAP_BIT(regmap_4d1c, MIPI_RX_ANA00_CSIxA, > + RG_CSIxA_BG_CORE_EN, 1); > + usleep_range(20, 40); > + REGMAP_BIT(regmap_base, MIPI_RX_ANA00_CSIxA, > + RG_CSIxA_BG_LPF_EN, 1); > + if (port->is_4d1c) > + REGMAP_BIT(regmap_4d1c, MIPI_RX_ANA00_CSIxA, > + RG_CSIxA_BG_LPF_EN, 1); > + > + return 0; > +} > +