2023-04-03 07:30:50

by Julien Stephan

[permalink] [raw]
Subject: [PATCH 0/2] phy: mtk-mipi-csi: add driver for CSI phy

Adding a new driver for the MIPI CSI CD-PHY for mediatek mt8365 soc

This driver was adapted from https://patchwork.kernel.org/project/linux-mediatek/cover/[email protected]/

Florian Sylvestre (1):
dt-bindings: phy: add mtk-mipi-csi driver

Phi-bang Nguyen (1):
phy: mtk-mipi-csi: add driver for CSI phy

.../bindings/phy/mediatek,csi-phy.yaml | 46 ++
MAINTAINERS | 7 +
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, 890 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml
create mode 100644 drivers/phy/mediatek/phy-mtk-mipi-csi-rx-reg.h
create mode 100644 drivers/phy/mediatek/phy-mtk-mipi-csi.c

--
2.40.0


2023-04-03 07:31:07

by Julien Stephan

[permalink] [raw]
Subject: [PATCH 1/2] dt-bindings: phy: add mtk-mipi-csi driver

From: Florian Sylvestre <[email protected]>

Signed-off-by: Florian Sylvestre <[email protected]>
Signed-off-by: Julien Stephan <[email protected]>
---
.../bindings/phy/mediatek,csi-phy.yaml | 41 +++++++++++++++++++
MAINTAINERS | 6 +++
2 files changed, 47 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml

diff --git a/Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml b/Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml
new file mode 100644
index 000000000000..c026e43f35fd
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml
@@ -0,0 +1,41 @@
+# SPDX-License-Identifier: (GPL-2.0-Only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/mediatek,csi-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Mediatek Sensor Interface MIPI CSI CD-PHY
+
+maintainers:
+ - Julien Stephan <[email protected]>
+ - Andy Hsieh <[email protected]>
+
+description: |
+ The SENINF CD-PHY is a set of CD-PHY connected to the SENINF CSI-2
+ receivers. The number of PHYs depends on the SoC model.
+
+properties:
+ compatible:
+ const: mediatek,mt8365-mipi-csi
+
+ reg:
+ minItems: 1
+
+ '#phy-cells':
+ const: 1
+
+required:
+ - compatible
+ - reg
+ - '#phy-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ phy@10011800 {
+ compatible = "mediatek,mt8365-mipi-csi";
+ reg = <0 0x10011800 0 0x60>;
+ #phy-cells = <1>;
+ };
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index 6d54f3193075..9308b4bb88bf 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13098,6 +13098,12 @@ F: Documentation/devicetree/bindings/media/mediatek-vpu.txt
F: drivers/media/platform/mediatek/vcodec/
F: drivers/media/platform/mediatek/vpu/

+MEDIATEK MIPI-CSI CDPHY DRIVER
+M: Julien Stephan <[email protected]>
+M: Andy Hsieh <[email protected]>
+S: Supported
+F: Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml
+
MEDIATEK MMC/SD/SDIO DRIVER
M: Chaotian Jing <[email protected]>
S: Maintained
--
2.40.0

2023-04-03 07:31:19

by Julien Stephan

[permalink] [raw]
Subject: [PATCH 2/2] phy: mtk-mipi-csi: add driver for CSI phy

From: Phi-bang Nguyen <[email protected]>

This is a new driver that supports the MIPI CSI CD-PHY for mediatek
mt8365 soc

Signed-off-by: Louis Kuo <[email protected]>
Signed-off-by: Phi-bang Nguyen <[email protected]>
[Julien Stephan: use regmap]
[Julien Stephan: use GENMASK]
Co-developed-by: Julien Stephan <[email protected]>
Signed-off-by: Julien Stephan <[email protected]>
---
.../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

diff --git a/Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml b/Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml
index c026e43f35fd..ad4ba1d93a68 100644
--- a/Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml
@@ -33,9 +33,14 @@ additionalProperties: false

examples:
- |
- phy@10011800 {
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ phy@11c10000 {
compatible = "mediatek,mt8365-mipi-csi";
- reg = <0 0x10011800 0 0x60>;
+ reg = <0 0x11c10000 0 0x4000>;
#phy-cells = <1>;
+ };
};
...
diff --git a/MAINTAINERS b/MAINTAINERS
index 9308b4bb88bf..b3077eddd0bf 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13103,6 +13103,7 @@ M: Julien Stephan <[email protected]>
M: Andy Hsieh <[email protected]>
S: Supported
F: Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml
+F: drivers/phy/mediatek/phy-mtk-mipi-csi*

MEDIATEK MMC/SD/SDIO DRIVER
M: Chaotian Jing <[email protected]>
diff --git a/drivers/phy/mediatek/Kconfig b/drivers/phy/mediatek/Kconfig
index 3125ecb5d119..63fb0fa77573 100644
--- a/drivers/phy/mediatek/Kconfig
+++ b/drivers/phy/mediatek/Kconfig
@@ -74,3 +74,11 @@ config PHY_MTK_DP
select GENERIC_PHY
help
Support DisplayPort PHY for MediaTek SoCs.
+
+config PHY_MTK_MIPI_CSI
+ tristate "MediaTek CSI CD-PHY Driver"
+ depends on ARCH_MEDIATEK && OF
+ select GENERIC_PHY
+ help
+ Enable this to support the MIPI CSI CD-PHY receiver.
+ The driver supports multiple CSI cdphy ports simultaneously.
diff --git a/drivers/phy/mediatek/Makefile b/drivers/phy/mediatek/Makefile
index fb1f8edaffa7..9a178c1c2628 100644
--- a/drivers/phy/mediatek/Makefile
+++ b/drivers/phy/mediatek/Makefile
@@ -18,3 +18,5 @@ phy-mtk-mipi-dsi-drv-y := phy-mtk-mipi-dsi.o
phy-mtk-mipi-dsi-drv-y += phy-mtk-mipi-dsi-mt8173.o
phy-mtk-mipi-dsi-drv-y += phy-mtk-mipi-dsi-mt8183.o
obj-$(CONFIG_PHY_MTK_MIPI_DSI) += phy-mtk-mipi-dsi-drv.o
+
+obj-$(CONFIG_PHY_MTK_MIPI_CSI) += phy-mtk-mipi-csi.o
diff --git a/drivers/phy/mediatek/phy-mtk-mipi-csi-rx-reg.h b/drivers/phy/mediatek/phy-mtk-mipi-csi-rx-reg.h
new file mode 100644
index 000000000000..f360e807e3d1
--- /dev/null
+++ b/drivers/phy/mediatek/phy-mtk-mipi-csi-rx-reg.h
@@ -0,0 +1,435 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __MIPI_CDPHY_RX_REG_H__
+#define __MIPI_CDPHY_RX_REG_H__
+
+/*
+ * CSI1 and CSI2 are identical, and similar to CSI0. All CSIx macros are
+ * applicable to the three PHYs. Where differences exist, they are denoted by
+ * macro names using CSI0 and CSI1, the latter being applicable to CSI1 and
+ * CSI2 alike.
+ */
+
+/*
+ * Due to lanes supporting C-PHY mode on CSI0, register fields that control the
+ * behaviour of lanes are named differently between CSI0 and CSI1/CSI2, even
+ * when they control parameters that are agnostic to the PHY mode. In those
+ * cases, the macros below use the CSI0 field names (e.g.
+ * MIPI_RX_ANA08_CSIxA_RG_CSIxA_L0P_T0A_HSRT_CODE_SHIFT).
+ */
+
+#define MIPI_RX_ANA00_CSIxA 0x0000
+#define MIPI_RX_ANA00_CSIxA_RG_CSI0A_CPHY_EN_SHIFT 0
+#define MIPI_RX_ANA00_CSIxA_RG_CSI0A_CPHY_EN_MASK BIT(0)
+#define MIPI_RX_ANA00_CSIxA_RG_CSIxA_EQ_PROTECT_EN_SHIFT 1
+#define MIPI_RX_ANA00_CSIxA_RG_CSIxA_EQ_PROTECT_EN_MASK BIT(1)
+#define MIPI_RX_ANA00_CSIxA_RG_CSIxA_BG_LPF_EN_SHIFT 2
+#define MIPI_RX_ANA00_CSIxA_RG_CSIxA_BG_LPF_EN_MASK BIT(2)
+#define MIPI_RX_ANA00_CSIxA_RG_CSIxA_BG_CORE_EN_SHIFT 3
+#define MIPI_RX_ANA00_CSIxA_RG_CSIxA_BG_CORE_EN_MASK BIT(3)
+#define MIPI_RX_ANA00_CSIxA_RG_CSIxA_DPHY_L0_CKMODE_EN_SHIFT 5
+#define MIPI_RX_ANA00_CSIxA_RG_CSIxA_DPHY_L0_CKMODE_EN_MASK BIT(5)
+#define MIPI_RX_ANA00_CSIxA_RG_CSIxA_DPHY_L0_CKSEL_SHIFT 6
+#define MIPI_RX_ANA00_CSIxA_RG_CSIxA_DPHY_L0_CKSEL_MASK BIT(6)
+#define MIPI_RX_ANA00_CSIxA_RG_CSIxA_DPHY_L1_CKMODE_EN_SHIFT 8
+#define MIPI_RX_ANA00_CSIxA_RG_CSIxA_DPHY_L1_CKMODE_EN_MASK BIT(8)
+#define MIPI_RX_ANA00_CSIxA_RG_CSIxA_DPHY_L1_CKSEL_SHIFT 9
+#define MIPI_RX_ANA00_CSIxA_RG_CSIxA_DPHY_L1_CKSEL_MASK BIT(9)
+#define MIPI_RX_ANA00_CSIxA_RG_CSIxA_DPHY_L2_CKMODE_EN_SHIFT 11
+#define MIPI_RX_ANA00_CSIxA_RG_CSIxA_DPHY_L2_CKMODE_EN_MASK BIT(11)
+#define MIPI_RX_ANA00_CSIxA_RG_CSIxA_DPHY_L2_CKSEL_SHIFT 12
+#define MIPI_RX_ANA00_CSIxA_RG_CSIxA_DPHY_L2_CKSEL_MASK BIT(12)
+
+#define MIPI_RX_ANA04_CSIxA 0x0004
+#define MIPI_RX_ANA04_CSIxA_RG_CSIxA_BG_LPRX_VTH_SEL_SHIFT 0
+#define MIPI_RX_ANA04_CSIxA_RG_CSIxA_BG_LPRX_VTH_SEL_MASK GENMASK(2, 0)
+#define MIPI_RX_ANA04_CSIxA_RG_CSIxA_BG_LPRX_VTL_SEL_SHIFT 4
+#define MIPI_RX_ANA04_CSIxA_RG_CSIxA_BG_LPRX_VTL_SEL_MASK GENMASK(6, 4)
+#define MIPI_RX_ANA04_CSIxA_RG_CSIxA_BG_HSDET_VTH_SEL_SHIFT 8
+#define MIPI_RX_ANA04_CSIxA_RG_CSIxA_BG_HSDET_VTH_SEL_MASK GENMASK(10, 8)
+#define MIPI_RX_ANA04_CSIxA_RG_CSIxA_BG_HSDET_VTL_SEL_SHIFT 12
+#define MIPI_RX_ANA04_CSIxA_RG_CSIxA_BG_HSDET_VTL_SEL_MASK GENMASK(14, 12)
+#define MIPI_RX_ANA04_CSIxA_RG_CSIxA_BG_VREF_SEL_SHIFT 16
+#define MIPI_RX_ANA04_CSIxA_RG_CSIxA_BG_VREF_SEL_MASK GENMASK(19, 16)
+#define MIPI_RX_ANA04_CSIxA_RG_CSIxA_BG_MON_VREF_SEL_SHIFT 24
+#define MIPI_RX_ANA04_CSIxA_RG_CSIxA_BG_MON_VREF_SEL_MASK GENMASK(27, 24)
+#define MIPI_RX_ANA04_CSIxA_RG_CSIxA_FORCE_HSRT_EN_SHIFT 28
+#define MIPI_RX_ANA04_CSIxA_RG_CSIxA_FORCE_HSRT_EN_MASK BIT(28)
+
+#define MIPI_RX_ANA08_CSIxA 0x0008
+#define MIPI_RX_ANA08_CSIxA_RG_CSIxA_L0P_T0A_HSRT_CODE_SHIFT 0
+#define MIPI_RX_ANA08_CSIxA_RG_CSIxA_L0P_T0A_HSRT_CODE_MASK GENMASK(4, 0)
+#define MIPI_RX_ANA08_CSIxA_RG_CSIxA_L0N_T0B_HSRT_CODE_SHIFT 8
+#define MIPI_RX_ANA08_CSIxA_RG_CSIxA_L0N_T0B_HSRT_CODE_MASK GENMASK(12, 8)
+#define MIPI_RX_ANA08_CSIxA_RG_CSIxA_L1P_T0C_HSRT_CODE_SHIFT 16
+#define MIPI_RX_ANA08_CSIxA_RG_CSIxA_L1P_T0C_HSRT_CODE_MASK GENMASK(20, 16)
+#define MIPI_RX_ANA08_CSIxA_RG_CSIxA_L1N_T1A_HSRT_CODE_SHIFT 24
+#define MIPI_RX_ANA08_CSIxA_RG_CSIxA_L1N_T1A_HSRT_CODE_MASK GENMASK(28, 24)
+
+#define MIPI_RX_ANA0C_CSIxA 0x000c
+#define MIPI_RX_ANA0C_CSIxA_RG_CSIxA_L2P_T1B_HSRT_CODE_SHIFT 0
+#define MIPI_RX_ANA0C_CSIxA_RG_CSIxA_L2P_T1B_HSRT_CODE_MASK GENMASK(4, 0)
+#define MIPI_RX_ANA0C_CSIxA_RG_CSIxA_L2N_T1C_HSRT_CODE_SHIFT 8
+#define MIPI_RX_ANA0C_CSIxA_RG_CSIxA_L2N_T1C_HSRT_CODE_MASK GENMASK(12, 8)
+
+#define MIPI_RX_ANA10_CSIxA 0x0010
+#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L0_DELAYCAL_EN_SHIFT 0
+#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L0_DELAYCAL_EN_MASK BIT(0)
+#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L0_DELAYCAL_RSTB_SHIFT 1
+#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L0_DELAYCAL_RSTB_MASK BIT(1)
+#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L0_VREF_SEL_SHIFT 2
+#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L0_VREF_SEL_MASK GENMASK(7, 2)
+#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L1_DELAYCAL_EN_SHIFT 8
+#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L1_DELAYCAL_EN_MASK BIT(8)
+#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L1_DELAYCAL_RSTB_SHIFT 9
+#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L1_DELAYCAL_RSTB_MASK BIT(9)
+#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L1_VREF_SEL_SHIFT 10
+#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L1_VREF_SEL_MASK GENMASK(15, 10)
+#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L2_DELAYCAL_EN_SHIFT 16
+#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L2_DELAYCAL_EN_MASK BIT(16)
+#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L2_DELAYCAL_RSTB_SHIFT 17
+#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L2_DELAYCAL_RSTB_MASK BIT(17)
+#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L2_VREF_SEL_SHIFT 18
+#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L2_VREF_SEL_MASK GENMASK(23, 18)
+/* C-PHY fields are only available in CSIx. */
+#define MIPI_RX_ANA10_CSIxA_RG_CSI0A_CPHY_T0_CDR_DELAYCAL_EN_SHIFT 24
+#define MIPI_RX_ANA10_CSIxA_RG_CSI0A_CPHY_T0_CDR_DELAYCAL_EN_MASK BIT(24)
+#define MIPI_RX_ANA10_CSIxA_RG_CSI0A_CPHY_T0_CDR_DELAYCAL_RSTB_SHIFT 25
+#define MIPI_RX_ANA10_CSIxA_RG_CSI0A_CPHY_T0_CDR_DELAYCAL_RSTB_MASK BIT(25)
+#define MIPI_RX_ANA10_CSIxA_RG_CSI0A_CPHY_T0_VREF_SEL_SHIFT 26
+#define MIPI_RX_ANA10_CSIxA_RG_CSI0A_CPHY_T0_VREF_SEL_MASK GENMASK(31, 26)
+
+#define MIPI_RX_ANA14_CSIxA 0x0014
+/* C-PHY fields are only available in CSIx. */
+#define MIPI_RX_ANA14_CSIxA_RG_CSI0A_CPHY_T1_CDR_DELAYCAL_EN_SHIFT 0
+#define MIPI_RX_ANA14_CSIxA_RG_CSI0A_CPHY_T1_CDR_DELAYCAL_EN_MASK BIT(0)
+#define MIPI_RX_ANA14_CSIxA_RG_CSI0A_CPHY_T1_CDR_DELAYCAL_RSTB_SHIFT 1
+#define MIPI_RX_ANA14_CSIxA_RG_CSI0A_CPHY_T1_CDR_DELAYCAL_RSTB_MASK BIT(1)
+#define MIPI_RX_ANA14_CSIxA_RG_CSI0A_CPHY_T1_VREF_SEL_SHIFT 2
+#define MIPI_RX_ANA14_CSIxA_RG_CSI0A_CPHY_T1_VREF_SEL_MASK GENMASK(7, 2)
+
+#define MIPI_RX_ANA18_CSIxA 0x0018
+/* CSIx-specific fields. */
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_L0_T0AB_EQ_OS_CAL_EN_SHIFT 0
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_L0_T0AB_EQ_OS_CAL_EN_MASK BIT(0)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_L0_T0AB_EQ_MON_EN_SHIFT 1
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_L0_T0AB_EQ_MON_EN_MASK BIT(1)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_L0_T0AB_EQ_SCA_SHIFT 2
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_L0_T0AB_EQ_SCA_MASK BIT(2)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_L0_T0AB_EQ_SCB_SHIFT 3
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_L0_T0AB_EQ_SCB_MASK BIT(3)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_L0_T0AB_EQ_IS_SHIFT 4
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_L0_T0AB_EQ_IS_MASK GENMASK(5, 4)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_L0_T0AB_EQ_BW_SHIFT 6
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_L0_T0AB_EQ_BW_MASK GENMASK(7, 6)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_L0_T0AB_EQ_SRA_SHIFT 8
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_L0_T0AB_EQ_SRA_MASK GENMASK(11, 8)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_L0_T0AB_EQ_SRB_SHIFT 12
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_L0_T0AB_EQ_SRB_MASK GENMASK(15, 12)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_XX_T0CA_EQ_OS_CAL_EN_SHIFT 16
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_XX_T0CA_EQ_OS_CAL_EN_MASK BIT(16)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_XX_T0CA_EQ_MON_EN_SHIFT 17
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_XX_T0CA_EQ_MON_EN_MASK BIT(17)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_XX_T0CA_EQ_SCA_SHIFT 18
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_XX_T0CA_EQ_SCA_MASK BIT(18)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_XX_T0CA_EQ_SCB_SHIFT 19
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_XX_T0CA_EQ_SCB_MASK BIT(19)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_XX_T0CA_EQ_IS_SHIFT 20
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_XX_T0CA_EQ_IS_MASK GENMASK(21, 20)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_XX_T0CA_EQ_BW_SHIFT 22
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_XX_T0CA_EQ_BW_MASK GENMASK(23, 22)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_XX_T0CA_EQ_SRA_SHIFT 24
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_XX_T0CA_EQ_SRA_MASK GENMASK(27, 24)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_XX_T0CA_EQ_SRB_SHIFT 28
+#define MIPI_RX_ANA18_CSIxA_RG_CSI0A_XX_T0CA_EQ_SRB_MASK GENMASK(31, 28)
+/* CSI1- and CSI2-specific fields. */
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L0_EQ_OS_CAL_EN_SHIFT 0
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L0_EQ_OS_CAL_EN_MASK BIT(0)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L0_EQ_MON_EN_SHIFT 1
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L0_EQ_MON_EN_MASK BIT(1)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L0_EQ_SCA_SHIFT 2
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L0_EQ_SCA_MASK BIT(2)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L0_EQ_SCB_SHIFT 3
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L0_EQ_SCB_MASK BIT(3)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L0_EQ_IS_SHIFT 4
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L0_EQ_IS_MASK GENMASK(5, 4)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L0_EQ_BW_SHIFT 6
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L0_EQ_BW_MASK GENMASK(7, 6)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L0_EQ_SRA_SHIFT 8
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L0_EQ_SRA_MASK GENMASK(11, 8)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L0_EQ_SRB_SHIFT 12
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L0_EQ_SRB_MASK GENMASK(15, 12)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L1_EQ_OS_CAL_EN_SHIFT 16
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L1_EQ_OS_CAL_EN_MASK BIT(16)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L1_EQ_MON_EN_SHIFT 17
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L1_EQ_MON_EN_MASK BIT(17)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L1_EQ_SCA_SHIFT 18
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L1_EQ_SCA_MASK BIT(18)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L1_EQ_SCB_SHIFT 19
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L1_EQ_SCB_MASK BIT(19)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L1_EQ_IS_SHIFT 20
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L1_EQ_IS_MASK GENMASK(21, 20)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L1_EQ_BW_SHIFT 22
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L1_EQ_BW_MASK GENMASK(23, 22)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L1_EQ_SRA_SHIFT 24
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L1_EQ_SRA_MASK GENMASK(27, 24)
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L1_EQ_SRB_SHIFT 28
+#define MIPI_RX_ANA18_CSIxA_RG_CSI1A_L1_EQ_SRB_MASK GENMASK(31, 28)
+
+#define MIPI_RX_ANA1C_CSIxA 0x001c
+/* CSIx-specific fields. */
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_XX_T0BC_EQ_OS_CAL_EN_SHIFT 0
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_XX_T0BC_EQ_OS_CAL_EN_MASK BIT(0)
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_XX_T0BC_EQ_MON_EN_SHIFT 1
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_XX_T0BC_EQ_MON_EN_MASK BIT(1)
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_XX_T0BC_EQ_SCA_SHIFT 2
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_XX_T0BC_EQ_SCA_MASK BIT(2)
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_XX_T0BC_EQ_SCB_SHIFT 3
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_XX_T0BC_EQ_SCB_MASK BIT(3)
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_XX_T0BC_EQ_IS_SHIFT 4
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_XX_T0BC_EQ_IS_MASK GENMASK(5, 4)
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_XX_T0BC_EQ_BW_SHIFT 6
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_XX_T0BC_EQ_BW_MASK GENMASK(7, 6)
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_XX_T0BC_EQ_SRA_SHIFT 8
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_XX_T0BC_EQ_SRA_MASK GENMASK(11, 8)
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_XX_T0BC_EQ_SRB_SHIFT 12
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_XX_T0BC_EQ_SRB_MASK GENMASK(15, 12)
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_L1_T1AB_EQ_OS_CAL_EN_SHIFT 16
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_L1_T1AB_EQ_OS_CAL_EN_MASK BIT(16)
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_L1_T1AB_EQ_MON_EN_SHIFT 17
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_L1_T1AB_EQ_MON_EN_MASK BIT(17)
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_L1_T1AB_EQ_SCA_SHIFT 18
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_L1_T1AB_EQ_SCA_MASK BIT(18)
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_L1_T1AB_EQ_SCB_SHIFT 19
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_L1_T1AB_EQ_SCB_MASK BIT(19)
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_L1_T1AB_EQ_IS_SHIFT 20
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_L1_T1AB_EQ_IS_MASK GENMASK(21, 20)
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_L1_T1AB_EQ_BW_SHIFT 22
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_L1_T1AB_EQ_BW_MASK GENMASK(23, 22)
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_L1_T1AB_EQ_SRA_SHIFT 24
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_L1_T1AB_EQ_SRA_MASK GENMASK(27, 24)
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_L1_T1AB_EQ_SRB_SHIFT 28
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI0A_L1_T1AB_EQ_SRB_MASK GENMASK(31, 28)
+/* CSI1- and CSI2-specific fields. */
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI1A_L2_EQ_OS_CAL_EN_SHIFT 0
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI1A_L2_EQ_OS_CAL_EN_MASK BIT(0)
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI1A_L2_EQ_MON_EN_SHIFT 1
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI1A_L2_EQ_MON_EN_MASK BIT(1)
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI1A_L2_EQ_SCA_SHIFT 2
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI1A_L2_EQ_SCA_MASK BIT(2)
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI1A_L2_EQ_SCB_SHIFT 3
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI1A_L2_EQ_SCB_MASK BIT(3)
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI1A_L2_EQ_IS_SHIFT 4
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI1A_L2_EQ_IS_MASK GENMASK(5, 4)
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI1A_L2_EQ_BW_SHIFT 6
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI1A_L2_EQ_BW_MASK GENMASK(7, 6)
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI1A_L2_EQ_SRA_SHIFT 8
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI1A_L2_EQ_SRA_MASK GENMASK(11, 8)
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI1A_L2_EQ_SRB_SHIFT 12
+#define MIPI_RX_ANA1C_CSIxA_RG_CSI1A_L2_EQ_SRB_MASK GENMASK(15, 12)
+
+/* CSI0-specific register. */
+#define MIPI_RX_ANA20_CSI0A 0x0020
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_XX_T1CA_EQ_OS_CAL_EN_SHIFT 0
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_XX_T1CA_EQ_OS_CAL_EN_MASK BIT(0)
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_XX_T1CA_EQ_MON_EN_SHIFT 1
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_XX_T1CA_EQ_MON_EN_MASK BIT(1)
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_XX_T1CA_EQ_SCA_SHIFT 2
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_XX_T1CA_EQ_SCA_MASK BIT(2)
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_XX_T1CA_EQ_SCB_SHIFT 3
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_XX_T1CA_EQ_SCB_MASK BIT(3)
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_XX_T1CA_EQ_IS_SHIFT 4
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_XX_T1CA_EQ_IS_MASK GENMASK(5, 4)
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_XX_T1CA_EQ_BW_SHIFT 6
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_XX_T1CA_EQ_BW_MASK GENMASK(7, 6)
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_XX_T1CA_EQ_SRA_SHIFT 8
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_XX_T1CA_EQ_SRA_MASK GENMASK(11, 8)
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_XX_T1CA_EQ_SRB_SHIFT 12
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_XX_T1CA_EQ_SRB_MASK GENMASK(15, 12)
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_L2_T1BC_EQ_OS_CAL_EN_SHIFT 16
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_L2_T1BC_EQ_OS_CAL_EN_MASK BIT(16)
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_L2_T1BC_EQ_MON_EN_SHIFT 17
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_L2_T1BC_EQ_MON_EN_MASK BIT(17)
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_L2_T1BC_EQ_SCA_SHIFT 18
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_L2_T1BC_EQ_SCA_MASK BIT(18)
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_L2_T1BC_EQ_SCB_SHIFT 19
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_L2_T1BC_EQ_SCB_MASK BIT(19)
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_L2_T1BC_EQ_IS_SHIFT 20
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_L2_T1BC_EQ_IS_MASK GENMASK(21, 20)
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_L2_T1BC_EQ_BW_SHIFT 22
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_L2_T1BC_EQ_BW_MASK GENMASK(23, 22)
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_L2_T1BC_EQ_SRA_SHIFT 24
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_L2_T1BC_EQ_SRA_MASK GENMASK(27, 24)
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_L2_T1BC_EQ_SRB_SHIFT 28
+#define MIPI_RX_ANA20_CSI0A_RG_CSI0A_L2_T1BC_EQ_SRB_MASK GENMASK(31, 28)
+
+#define MIPI_RX_ANA24_CSIxA 0x0024
+#define MIPI_RX_ANA24_CSIxA_RG_CSIxA_RESERVE_SHIFT 24
+#define MIPI_RX_ANA24_CSIxA_RG_CSIxA_RESERVE_MASK (0xff << 24)
+
+/* CSI0-specific register. */
+#define MIPI_RX_ANA28_CSI0A 0x0028
+#define MIPI_RX_ANA28_CSI0A_RG_CSI0A_CPHY_T0_CDR_DIRECT_EN_SHIFT 0
+#define MIPI_RX_ANA28_CSI0A_RG_CSI0A_CPHY_T0_CDR_DIRECT_EN_MASK BIT(0)
+#define MIPI_RX_ANA28_CSI0A_RG_CSI0A_CPHY_T0_CDR_AUTOLOAD_EN_SHIFT 1
+#define MIPI_RX_ANA28_CSI0A_RG_CSI0A_CPHY_T0_CDR_AUTOLOAD_EN_MASK BIT(1)
+#define MIPI_RX_ANA28_CSI0A_RG_CSI0A_CPHY_T0_CDR_LPF_CTRL_SHIFT 2
+#define MIPI_RX_ANA28_CSI0A_RG_CSI0A_CPHY_T0_CDR_LPF_CTRL_MASK GENMASK(3, 2)
+#define MIPI_RX_ANA28_CSI0A_RG_CSI0A_CPHY_T0_CDR_AB_WIDTH_SHIFT 4
+#define MIPI_RX_ANA28_CSI0A_RG_CSI0A_CPHY_T0_CDR_AB_WIDTH_MASK GENMASK(7, 4)
+#define MIPI_RX_ANA28_CSI0A_RG_CSI0A_CPHY_T0_CDR_BC_WIDTH_SHIFT 8
+#define MIPI_RX_ANA28_CSI0A_RG_CSI0A_CPHY_T0_CDR_BC_WIDTH_MASK GENMASK(11, 8)
+#define MIPI_RX_ANA28_CSI0A_RG_CSI0A_CPHY_T0_CDR_CA_WIDTH_SHIFT 12
+#define MIPI_RX_ANA28_CSI0A_RG_CSI0A_CPHY_T0_CDR_CA_WIDTH_MASK GENMASK(15, 12)
+#define MIPI_RX_ANA28_CSI0A_RG_CSI0A_CPHY_T0_CDR_CK_DELAY_SHIFT 16
+#define MIPI_RX_ANA28_CSI0A_RG_CSI0A_CPHY_T0_CDR_CK_DELAY_MASK GENMASK(19, 16)
+#define MIPI_RX_ANA28_CSI0A_RG_CSI0A_CPHY_T0_HSDET_SEL_SHIFT 20
+#define MIPI_RX_ANA28_CSI0A_RG_CSI0A_CPHY_T0_HSDET_SEL_MASK GENMASK(21, 20)
+#define MIPI_RX_ANA28_CSI0A_RG_CSI0A_CPHY_T0_CDR_MANUAL_EN_SHIFT 24
+#define MIPI_RX_ANA28_CSI0A_RG_CSI0A_CPHY_T0_CDR_MANUAL_EN_MASK BIT(24)
+
+/* CSI0-specific register. */
+#define MIPI_RX_ANA2C_CSI0A 0x002c
+#define MIPI_RX_ANA2C_CSI0A_RG_CSI0A_CPHY_T0_CDR_INIT_CODE_SHIFT 0
+#define MIPI_RX_ANA2C_CSI0A_RG_CSI0A_CPHY_T0_CDR_INIT_CODE_MASK GENMASK(4, 0)
+#define MIPI_RX_ANA2C_CSI0A_RG_CSI0A_CPHY_T0_CDR_EARLY_CODE_SHIFT 8
+#define MIPI_RX_ANA2C_CSI0A_RG_CSI0A_CPHY_T0_CDR_EARLY_CODE_MASK GENMASK(12, 8)
+#define MIPI_RX_ANA2C_CSI0A_RG_CSI0A_CPHY_T0_CDR_LATE_CODE_SHIFT 16
+#define MIPI_RX_ANA2C_CSI0A_RG_CSI0A_CPHY_T0_CDR_LATE_CODE_MASK GENMASK(20, 16)
+
+/* CSI0-specific register. */
+#define MIPI_RX_ANA34_CSI0A 0x0034
+#define MIPI_RX_ANA34_CSI0A_RG_CSI0A_CPHY_T1_CDR_DIRECT_EN_SHIFT 0
+#define MIPI_RX_ANA34_CSI0A_RG_CSI0A_CPHY_T1_CDR_DIRECT_EN_MASK BIT(0)
+#define MIPI_RX_ANA34_CSI0A_RG_CSI0A_CPHY_T1_CDR_AUTOLOAD_EN_SHIFT 1
+#define MIPI_RX_ANA34_CSI0A_RG_CSI0A_CPHY_T1_CDR_AUTOLOAD_EN_MASK BIT(1)
+#define MIPI_RX_ANA34_CSI0A_RG_CSI0A_CPHY_T1_CDR_LPF_CTRL_SHIFT 2
+#define MIPI_RX_ANA34_CSI0A_RG_CSI0A_CPHY_T1_CDR_LPF_CTRL_MASK GENMASK(3, 2)
+#define MIPI_RX_ANA34_CSI0A_RG_CSI0A_CPHY_T1_CDR_AB_WIDTH_SHIFT 4
+#define MIPI_RX_ANA34_CSI0A_RG_CSI0A_CPHY_T1_CDR_AB_WIDTH_MASK GENMASK(7, 4)
+#define MIPI_RX_ANA34_CSI0A_RG_CSI0A_CPHY_T1_CDR_BC_WIDTH_SHIFT 8
+#define MIPI_RX_ANA34_CSI0A_RG_CSI0A_CPHY_T1_CDR_BC_WIDTH_MASK GENMASK(11, 8)
+#define MIPI_RX_ANA34_CSI0A_RG_CSI0A_CPHY_T1_CDR_CA_WIDTH_SHIFT 12
+#define MIPI_RX_ANA34_CSI0A_RG_CSI0A_CPHY_T1_CDR_CA_WIDTH_MASK GENMASK(15, 12)
+#define MIPI_RX_ANA34_CSI0A_RG_CSI0A_CPHY_T1_CDR_CK_DELAY_SHIFT 16
+#define MIPI_RX_ANA34_CSI0A_RG_CSI0A_CPHY_T1_CDR_CK_DELAY_MASK GENMASK(19, 16)
+#define MIPI_RX_ANA34_CSI0A_RG_CSI0A_CPHY_T1_HSDET_SEL_SHIFT 20
+#define MIPI_RX_ANA34_CSI0A_RG_CSI0A_CPHY_T1_HSDET_SEL_MASK GENMASK(21, 20)
+#define MIPI_RX_ANA34_CSI0A_RG_CSI0A_CPHY_T1_CDR_MANUAL_EN_SHIFT 24
+#define MIPI_RX_ANA34_CSI0A_RG_CSI0A_CPHY_T1_CDR_MANUAL_EN_MASK BIT(24)
+
+/* CSI0-specific register. */
+#define MIPI_RX_ANA38_CSI0A 0x0038
+#define MIPI_RX_ANA38_CSI0A_RG_CSI0A_CPHY_T1_CDR_INIT_CODE_SHIFT 0
+#define MIPI_RX_ANA38_CSI0A_RG_CSI0A_CPHY_T1_CDR_INIT_CODE_MASK GENMASK(4, 0)
+#define MIPI_RX_ANA38_CSI0A_RG_CSI0A_CPHY_T1_CDR_EARLY_CODE_SHIFT 8
+#define MIPI_RX_ANA38_CSI0A_RG_CSI0A_CPHY_T1_CDR_EARLY_CODE_MASK GENMASK(12, 8)
+#define MIPI_RX_ANA38_CSI0A_RG_CSI0A_CPHY_T1_CDR_LATE_CODE_SHIFT 16
+#define MIPI_RX_ANA38_CSI0A_RG_CSI0A_CPHY_T1_CDR_LATE_CODE_MASK GENMASK(20, 16)
+
+#define MIPI_RX_ANA40_CSIxA 0x0040
+#define MIPI_RX_ANA40_CSIxA_RG_CSIxA_CPHY_FMCK_SEL_SHIFT 0
+#define MIPI_RX_ANA40_CSIxA_RG_CSIxA_CPHY_FMCK_SEL_MASK GENMASK(1, 0)
+#define MIPI_RX_ANA40_CSIxA_RG_CSIxA_ASYNC_OPTION_SHIFT 4
+#define MIPI_RX_ANA40_CSIxA_RG_CSIxA_ASYNC_OPTION_MASK GENMASK(7, 4)
+#define MIPI_RX_ANA40_CSIxA_RG_CSIxA_CPHY_SPARE_SHIFT 16
+#define MIPI_RX_ANA40_CSIxA_RG_CSIxA_CPHY_SPARE_MASK GENMASK(31, 16)
+
+#define MIPI_RX_ANA48_CSIxA 0x0048
+/* CSI0-specific fields. */
+#define MIPI_RX_ANA48_CSIxA_RGS_CSI0A_CDPHY_L0_T0AB_OS_CAL_CPLT_SHIFT 0
+#define MIPI_RX_ANA48_CSIxA_RGS_CSI0A_CDPHY_L0_T0AB_OS_CAL_CPLT_MASK BIT(0)
+#define MIPI_RX_ANA48_CSIxA_RGS_CSI0A_CPHY_T0CA_OS_CAL_CPLT_SHIFT 1
+#define MIPI_RX_ANA48_CSIxA_RGS_CSI0A_CPHY_T0CA_OS_CAL_CPLT_MASK BIT(1)
+#define MIPI_RX_ANA48_CSIxA_RGS_CSI0A_CPHY_T0BC_OS_CAL_CPLT_SHIFT 2
+#define MIPI_RX_ANA48_CSIxA_RGS_CSI0A_CPHY_T0BC_OS_CAL_CPLT_MASK BIT(2)
+#define MIPI_RX_ANA48_CSIxA_RGS_CSI0A_CDPHY_L1_T1AB_OS_CAL_CPLT_SHIFT 3
+#define MIPI_RX_ANA48_CSIxA_RGS_CSI0A_CDPHY_L1_T1AB_OS_CAL_CPLT_MASK BIT(3)
+#define MIPI_RX_ANA48_CSIxA_RGS_CSI0A_CPHY_T1CA_OS_CAL_CPLT_SHIFT 4
+#define MIPI_RX_ANA48_CSIxA_RGS_CSI0A_CPHY_T1CA_OS_CAL_CPLT_MASK BIT(4)
+#define MIPI_RX_ANA48_CSIxA_RGS_CSI0A_CDPHY_L2_T1BC_OS_CAL_CPLT_SHIFT 5
+#define MIPI_RX_ANA48_CSIxA_RGS_CSI0A_CDPHY_L2_T1BC_OS_CAL_CPLT_MASK BIT(5)
+/* CSI1- and CSI2-specific fields. */
+#define MIPI_RX_ANA48_CSIxA_RGS_CSI1A_DPHY_L0_OS_CAL_CPLT_SHIFT 3
+#define MIPI_RX_ANA48_CSIxA_RGS_CSI1A_DPHY_L0_OS_CAL_CPLT_MASK BIT(3)
+#define MIPI_RX_ANA48_CSIxA_RGS_CSI1A_DPHY_L1_OS_CAL_CPLT_SHIFT 4
+#define MIPI_RX_ANA48_CSIxA_RGS_CSI1A_DPHY_L1_OS_CAL_CPLT_MASK BIT(4)
+#define MIPI_RX_ANA48_CSIxA_RGS_CSI1A_DPHY_L2_OS_CAL_CPLT_SHIFT 5
+#define MIPI_RX_ANA48_CSIxA_RGS_CSI1A_DPHY_L2_OS_CAL_CPLT_MASK BIT(5)
+/* Common fields. */
+#define MIPI_RX_ANA48_CSIxA_RGS_CSIxA_OS_CAL_CODE_SHIFT 8
+#define MIPI_RX_ANA48_CSIxA_RGS_CSIxA_OS_CAL_CODE_MASK GENMASK(15, 8)
+
+#define MIPI_RX_WRAPPER80_CSIxA 0x0080
+#define MIPI_RX_WRAPPER80_CSIxA_CSR_CSI_CLK_MON_SHIFT 0
+#define MIPI_RX_WRAPPER80_CSIxA_CSR_CSI_CLK_MON_MASK BIT(0)
+#define MIPI_RX_WRAPPER80_CSIxA_CSR_CSI_CLK_EN_SHIFT 1
+#define MIPI_RX_WRAPPER80_CSIxA_CSR_CSI_CLK_EN_MASK BIT(1)
+#define MIPI_RX_WRAPPER80_CSIxA_CSR_CSI_MON_MUX_SHIFT 8
+#define MIPI_RX_WRAPPER80_CSIxA_CSR_CSI_MON_MUX_MASK GENMASK(15, 8)
+#define MIPI_RX_WRAPPER80_CSIxA_CSR_CSI_RST_MODE_SHIFT 16
+#define MIPI_RX_WRAPPER80_CSIxA_CSR_CSI_RST_MODE_MASK GENMASK(17, 16)
+#define MIPI_RX_WRAPPER80_CSIxA_CSR_SW_RST_SHIFT 24
+#define MIPI_RX_WRAPPER80_CSIxA_CSR_SW_RST_MASK GENMASK(27, 24)
+
+#define MIPI_RX_WRAPPER84_CSIxA 0x0084
+#define MIPI_RX_WRAPPER84_CSIxA_CSI_DEBUG_OUT_SHIFT 0
+#define MIPI_RX_WRAPPER84_CSIxA_CSI_DEBUG_OUT_MASK GENMASK(31, 0)
+
+#define MIPI_RX_WRAPPER88_CSIxA 0x0088
+#define MIPI_RX_WRAPPER88_CSIxA_CSR_SW_MODE_0_SHIFT 0
+#define MIPI_RX_WRAPPER88_CSIxA_CSR_SW_MODE_0_MASK GENMASK(31, 0)
+
+#define MIPI_RX_WRAPPER8C_CSIxA 0x008c
+#define MIPI_RX_WRAPPER8C_CSIxA_CSR_SW_MODE_1_SHIFT 0
+#define MIPI_RX_WRAPPER8C_CSIxA_CSR_SW_MODE_1_MASK GENMASK(31, 0)
+
+#define MIPI_RX_WRAPPER90_CSIxA 0x0090
+#define MIPI_RX_WRAPPER90_CSIxA_CSR_SW_MODE_2_SHIFT 0
+#define MIPI_RX_WRAPPER90_CSIxA_CSR_SW_MODE_2_MASK GENMASK(31, 0)
+
+#define MIPI_RX_WRAPPER94_CSIxA 0x0094
+#define MIPI_RX_WRAPPER94_CSIxA_CSR_SW_VALUE_0_SHIFT 0
+#define MIPI_RX_WRAPPER94_CSIxA_CSR_SW_VALUE_0_MASK GENMASK(31, 0)
+
+#define MIPI_RX_WRAPPER98_CSIxA 0x0098
+#define MIPI_RX_WRAPPER98_CSIxA_CSR_SW_VALUE_1_SHIFT 0
+#define MIPI_RX_WRAPPER98_CSIxA_CSR_SW_VALUE_1_MASK GENMASK(31, 0)
+
+#define MIPI_RX_WRAPPER9C_CSIxA 0x009c
+#define MIPI_RX_WRAPPER9C_CSIxA_CSR_SW_VALUE_2_SHIFT 0
+#define MIPI_RX_WRAPPER9C_CSIxA_CSR_SW_VALUE_2_MASK GENMASK(31, 0)
+
+#define MIPI_RX_ANAA4_CSIxA 0x00a4
+#define MIPI_RX_ANAA4_CSIxA_RG_CSIxA_CDPHY_L0_T0_SYNC_INIT_SEL_SHIFT 0
+#define MIPI_RX_ANAA4_CSIxA_RG_CSIxA_CDPHY_L0_T0_SYNC_INIT_SEL_MASK BIT(0)
+#define MIPI_RX_ANAA4_CSIxA_RG_CSIxA_CDPHY_L0_T0_FORCE_INIT_SHIFT 1
+#define MIPI_RX_ANAA4_CSIxA_RG_CSIxA_CDPHY_L0_T0_FORCE_INIT_MASK BIT(1)
+#define MIPI_RX_ANAA4_CSIxA_RG_CSIxA_DPHY_L1_SYNC_INIT_SEL_SHIFT 2
+#define MIPI_RX_ANAA4_CSIxA_RG_CSIxA_DPHY_L1_SYNC_INIT_SEL_MASK BIT(2)
+#define MIPI_RX_ANAA4_CSIxA_RG_CSIxA_DPHY_L1_FORCE_INIT_SHIFT 3
+#define MIPI_RX_ANAA4_CSIxA_RG_CSIxA_DPHY_L1_FORCE_INIT_MASK BIT(3)
+#define MIPI_RX_ANAA4_CSIxA_RG_CSIxA_CDPHY_L2_T2_SYNC_INIT_SEL_SHIFT 4
+#define MIPI_RX_ANAA4_CSIxA_RG_CSIxA_CDPHY_L2_T2_SYNC_INIT_SEL_MASK BIT(4)
+#define MIPI_RX_ANAA4_CSIxA_RG_CSIxA_CDPHY_L2_T2_FORCE_INIT_SHIFT 5
+#define MIPI_RX_ANAA4_CSIxA_RG_CSIxA_CDPHY_L2_T2_FORCE_INIT_MASK BIT(5)
+
+#define MIPI_RX_ANAA8_CSIxA 0x00a8
+#define MIPI_RX_ANAA8_CSIxA_RG_CSIxA_CDPHY_L0_T0_BYTECK_INVERT_SHIFT 0
+#define MIPI_RX_ANAA8_CSIxA_RG_CSIxA_CDPHY_L0_T0_BYTECK_INVERT_MASK BIT(0)
+#define MIPI_RX_ANAA8_CSIxA_RG_CSIxA_DPHY_L1_BYTECK_INVERT_SHIFT 1
+#define MIPI_RX_ANAA8_CSIxA_RG_CSIxA_DPHY_L1_BYTECK_INVERT_MASK BIT(1)
+#define MIPI_RX_ANAA8_CSIxA_RG_CSIxA_CDPHY_L2_T1_BYTECK_INVERT_SHIFT 2
+#define MIPI_RX_ANAA8_CSIxA_RG_CSIxA_CDPHY_L2_T1_BYTECK_INVERT_MASK BIT(2)
+#define MIPI_RX_ANAA8_CSIxA_RG_CSIxA_DPHY_HSDET_LEVEL_MODE_EN_SHIFT 3
+#define MIPI_RX_ANAA8_CSIxA_RG_CSIxA_DPHY_HSDET_LEVEL_MODE_EN_MASK BIT(3)
+#define MIPI_RX_ANAA8_CSIxA_RG_CSIxA_OS_CAL_SEL_SHIFT 4
+#define MIPI_RX_ANAA8_CSIxA_RG_CSIxA_OS_CAL_SEL_MASK GENMASK(6, 4)
+#define MIPI_RX_ANAA8_CSIxA_RG_CSIxA_DPHY_HSDET_DIG_BACK_EN_SHIFT 7
+#define MIPI_RX_ANAA8_CSIxA_RG_CSIxA_DPHY_HSDET_DIG_BACK_EN_MASK BIT(7)
+#define MIPI_RX_ANAA8_CSIxA_RG_CSIxA_CDPHY_DELAYCAL_CK_SEL_SHIFT 8
+#define MIPI_RX_ANAA8_CSIxA_RG_CSIxA_CDPHY_DELAYCAL_CK_SEL_MASK GENMASK(10, 8)
+#define MIPI_RX_ANAA8_CSIxA_RG_CSIxA_OS_CAL_DIV_SHIFT 11
+#define MIPI_RX_ANAA8_CSIxA_RG_CSIxA_OS_CAL_DIV_MASK GENMASK(12, 11)
+
+#endif
diff --git a/drivers/phy/mediatek/phy-mtk-mipi-csi.c b/drivers/phy/mediatek/phy-mtk-mipi-csi.c
new file mode 100644
index 000000000000..6ce3f95f57bd
--- /dev/null
+++ b/drivers/phy/mediatek/phy-mtk-mipi-csi.c
@@ -0,0 +1,392 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+
+#include "phy-mtk-mipi-csi-rx-reg.h"
+
+#define CSIxB_OFFSET 0x1000
+
+struct mtk_mipi_dphy;
+
+enum mtk_mipi_dphy_port_id {
+ MTK_MIPI_PHY_PORT_0 = 0x0, /* 4D1C - CDPHY */
+ MTK_MIPI_PHY_PORT_1, /* 4D1C - DPHY */
+ MTK_MIPI_PHY_PORT_2, /* 4D1C - DPHY */
+ MTK_MIPI_PHY_PORT_0A, /* 2D1C - CDPHY */
+ MTK_MIPI_PHY_PORT_0B, /* 2D1C - CDPHY */
+ MTK_MIPI_PHY_PORT_MAX_NUM
+};
+
+struct mtk_mipi_dphy_port {
+ struct mtk_mipi_dphy *dev;
+ enum mtk_mipi_dphy_port_id id;
+ struct regmap *regmap_base;
+ struct regmap *regmap_4d1c;
+ struct phy *phy;
+ bool active;
+ bool is_cdphy;
+ bool is_4d1c;
+};
+
+struct mtk_mipi_dphy {
+ struct device *dev;
+ void __iomem *rx;
+ struct mtk_mipi_dphy_port ports[MTK_MIPI_PHY_PORT_MAX_NUM];
+ struct mutex lock; /* Ports CSI0 and CSI0A/B are mutually exclusive */
+};
+
+#define REGMAP_BIT(map, reg, field, val) \
+ regmap_update_bits((map), reg, reg##_##field##_MASK, \
+ (val) << reg##_##field##_SHIFT)
+
+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);
+ 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;
+}
+
+static int mtk_mipi_phy_power_off(struct phy *phy)
+{
+ struct mtk_mipi_dphy_port *port = phy_get_drvdata(phy);
+ struct regmap *regmap_base = port->regmap_base;
+ struct regmap *regmap_4d1c = port->regmap_4d1c;
+
+ /* Disable MIPI BG. */
+ REGMAP_BIT(regmap_base, MIPI_RX_ANA00_CSIxA,
+ RG_CSIxA_BG_CORE_EN, 0);
+ REGMAP_BIT(regmap_base, MIPI_RX_ANA00_CSIxA,
+ RG_CSIxA_BG_LPF_EN, 0);
+
+ if (port->is_4d1c) {
+ REGMAP_BIT(regmap_4d1c, MIPI_RX_ANA00_CSIxA,
+ RG_CSIxA_BG_CORE_EN, 0);
+ REGMAP_BIT(regmap_4d1c, MIPI_RX_ANA00_CSIxA,
+ RG_CSIxA_BG_LPF_EN, 0);
+ }
+
+ mutex_lock(&port->dev->lock);
+ port->active = false;
+ mutex_unlock(&port->dev->lock);
+
+ return 0;
+}
+
+static const struct phy_ops mtk_dphy_ops = {
+ .power_on = mtk_mipi_phy_power_on,
+ .power_off = mtk_mipi_phy_power_off,
+ .owner = THIS_MODULE,
+};
+
+static struct phy *mtk_mipi_dphy_xlate(struct device *dev,
+ struct of_phandle_args *args)
+{
+ struct mtk_mipi_dphy *priv = dev_get_drvdata(dev);
+
+ if (args->args_count != 1)
+ return ERR_PTR(-EINVAL);
+
+ if (args->args[0] >= ARRAY_SIZE(priv->ports))
+ return ERR_PTR(-ENODEV);
+
+ return priv->ports[args->args[0]].phy;
+}
+
+static const struct regmap_config mt8365_phy_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = 0x700,
+};
+
+static int mtk_mipi_dphy_probe(struct platform_device *pdev)
+{
+ static const unsigned int ports_offsets[] = {
+ [MTK_MIPI_PHY_PORT_0] = 0,
+ [MTK_MIPI_PHY_PORT_0A] = 0,
+ [MTK_MIPI_PHY_PORT_0B] = 0x1000,
+ [MTK_MIPI_PHY_PORT_1] = 0x2000,
+ [MTK_MIPI_PHY_PORT_2] = 0x4000,
+ };
+
+ struct device *dev = &pdev->dev;
+ struct phy_provider *phy_provider;
+ struct mtk_mipi_dphy *priv;
+ struct resource *res;
+ unsigned int i;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, priv);
+ priv->dev = dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->rx = devm_ioremap_resource(dev, res);
+ if (IS_ERR(priv->rx))
+ return PTR_ERR(priv->rx);
+
+ for (i = 0; i < ARRAY_SIZE(priv->ports); ++i) {
+ struct mtk_mipi_dphy_port *port = &priv->ports[i];
+ struct phy *phy;
+ void __iomem *base;
+
+ port->dev = priv;
+ port->id = i;
+ base = priv->rx + ports_offsets[i];
+
+ port->regmap_base = devm_regmap_init_mmio(port->dev->dev,
+ base,
+ &mt8365_phy_regmap_config);
+
+ port->is_cdphy = i == MTK_MIPI_PHY_PORT_0A ||
+ i == MTK_MIPI_PHY_PORT_0B ||
+ i == MTK_MIPI_PHY_PORT_0;
+ port->is_4d1c = i < MTK_MIPI_PHY_PORT_0A;
+
+ if (port->is_4d1c)
+ port->regmap_4d1c = devm_regmap_init_mmio(port->dev->dev,
+ base + CSIxB_OFFSET,
+ &mt8365_phy_regmap_config);
+
+ phy = devm_phy_create(dev, NULL, &mtk_dphy_ops);
+ if (IS_ERR(phy)) {
+ dev_err(dev, "Failed to create PHY: %ld\n", PTR_ERR(phy));
+ return PTR_ERR(phy);
+ }
+
+ port->phy = phy;
+ phy_set_drvdata(phy, port);
+ }
+
+ phy_provider = devm_of_phy_provider_register(dev, mtk_mipi_dphy_xlate);
+ if (IS_ERR(phy_provider)) {
+ dev_err(dev, "Failed to register PHY provider: %ld\n",
+ PTR_ERR(phy_provider));
+ return PTR_ERR(phy_provider);
+ }
+
+ mutex_init(&priv->lock);
+
+ return 0;
+}
+
+static int mtk_mipi_dphy_remove(struct platform_device *pdev)
+{
+ struct mtk_mipi_dphy *priv = platform_get_drvdata(pdev);
+
+ mutex_destroy(&priv->lock);
+
+ return 0;
+}
+
+static const struct of_device_id mtk_mipi_dphy_of_match[] = {
+ {.compatible = "mediatek,mt8365-mipi-csi"},
+ {},
+};
+MODULE_DEVICE_TABLE(of, mtk_mipi_dphy_of_match);
+
+static struct platform_driver mipi_dphy_pdrv = {
+ .probe = mtk_mipi_dphy_probe,
+ .remove = mtk_mipi_dphy_remove,
+ .driver = {
+ .name = "mtk-mipi-csi",
+ .of_match_table = of_match_ptr(mtk_mipi_dphy_of_match),
+ },
+};
+
+module_platform_driver(mipi_dphy_pdrv);
+
+MODULE_DESCRIPTION("MTK mipi csi cdphy driver");
+MODULE_AUTHOR("Louis Kuo <[email protected]>");
+MODULE_LICENSE("GPL");
--
2.40.0

2023-04-03 09:55:20

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH 2/2] phy: mtk-mipi-csi: add driver for CSI phy

On 03/04/2023 09:19, Julien Stephan wrote:
> From: Phi-bang Nguyen <[email protected]>
>
> This is a new driver that supports the MIPI CSI CD-PHY for mediatek
> mt8365 soc
>
> Signed-off-by: Louis Kuo <[email protected]>
> Signed-off-by: Phi-bang Nguyen <[email protected]>
> [Julien Stephan: use regmap]
> [Julien Stephan: use GENMASK]
> Co-developed-by: Julien Stephan <[email protected]>
> Signed-off-by: Julien Stephan <[email protected]>
> ---
> .../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
>
> diff --git a/Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml b/Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml
> index c026e43f35fd..ad4ba1d93a68 100644
> --- a/Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml
> +++ b/Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml

NAK, bindings are always separate patches. It also does not make any
sense - you just added it.

> @@ -33,9 +33,14 @@ additionalProperties: false
>
> examples:
> - |
> - phy@10011800 {
> + soc {
> + #address-cells = <2>;
> + #size-cells = <2>;
> +
> + phy@11c10000 {
> compatible = "mediatek,mt8365-mipi-csi";
> - reg = <0 0x10011800 0 0x60>;
> + reg = <0 0x11c10000 0 0x4000>;
> #phy-cells = <1>;
> + };
> };



k_mipi_dphy_of_match[] = {
> + {.compatible = "mediatek,mt8365-mipi-csi"},
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, mtk_mipi_dphy_of_match);
> +
> +static struct platform_driver mipi_dphy_pdrv = {
> + .probe = mtk_mipi_dphy_probe,
> + .remove = mtk_mipi_dphy_remove,
> + .driver = {
> + .name = "mtk-mipi-csi",
> + .of_match_table = of_match_ptr(mtk_mipi_dphy_of_match),

Drop of_match_ptr(). You should see W=1 warnings when compile testing.


Best regards,
Krzysztof

2023-04-03 09:56:13

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH 1/2] dt-bindings: phy: add mtk-mipi-csi driver

On 03/04/2023 09:19, Julien Stephan wrote:
> From: Florian Sylvestre <[email protected]>
>

There is no commit msg.

> Signed-off-by: Florian Sylvestre <[email protected]>
> Signed-off-by: Julien Stephan <[email protected]>
> ---
> .../bindings/phy/mediatek,csi-phy.yaml | 41 +++++++++++++++++++
> MAINTAINERS | 6 +++
> 2 files changed, 47 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml
>
> diff --git a/Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml b/Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml
> new file mode 100644
> index 000000000000..c026e43f35fd
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml

Filename like compatible.

> @@ -0,0 +1,41 @@
> +# SPDX-License-Identifier: (GPL-2.0-Only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/phy/mediatek,csi-phy.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Mediatek Sensor Interface MIPI CSI CD-PHY
> +
> +maintainers:
> + - Julien Stephan <[email protected]>
> + - Andy Hsieh <[email protected]>
> +
> +description: |

Do not need '|'.

> + The SENINF CD-PHY is a set of CD-PHY connected to the SENINF CSI-2
> + receivers. The number of PHYs depends on the SoC model.
> +
> +properties:
> + compatible:
> + const: mediatek,mt8365-mipi-csi
> +
> + reg:
> + minItems: 1

maxItems instead
(from where did you get such example?)

> +
> + '#phy-cells':
> + const: 1
> +


Best regards,
Krzysztof

2023-04-03 10:21:15

by Chun-Kuang Hu

[permalink] [raw]
Subject: Re: [PATCH 2/2] phy: mtk-mipi-csi: add driver for CSI phy

Hi, Julien:

Julien Stephan <[email protected]> 於 2023年4月3日 週一 下午3:20寫道:
>
> From: Phi-bang Nguyen <[email protected]>
>
> This is a new driver that supports the MIPI CSI CD-PHY for mediatek
> mt8365 soc
>
> Signed-off-by: Louis Kuo <[email protected]>
> Signed-off-by: Phi-bang Nguyen <[email protected]>
> [Julien Stephan: use regmap]
> [Julien Stephan: use GENMASK]
> Co-developed-by: Julien Stephan <[email protected]>
> Signed-off-by: Julien Stephan <[email protected]>
> ---
> .../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;
> +}
> +

2023-04-03 13:14:55

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH 1/2] dt-bindings: phy: add mtk-mipi-csi driver


On Mon, 03 Apr 2023 09:19:28 +0200, Julien Stephan wrote:
> From: Florian Sylvestre <[email protected]>
>
> Signed-off-by: Florian Sylvestre <[email protected]>
> Signed-off-by: Julien Stephan <[email protected]>
> ---
> .../bindings/phy/mediatek,csi-phy.yaml | 41 +++++++++++++++++++
> MAINTAINERS | 6 +++
> 2 files changed, 47 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml
>

My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):

yamllint warnings/errors:

dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/phy/mediatek,csi-phy.example.dtb: phy@10011800: reg: [[0, 268507136], [0, 96]] is too long
From schema: /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/[email protected]

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.

2023-04-03 15:25:07

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH 1/2] dt-bindings: phy: add mtk-mipi-csi driver

On 03/04/2023 16:40, Julien Stephan wrote:
> Hi Krzysztof,
>
> Le lun. 3 avr. 2023 à 11:49, Krzysztof Kozlowski <
> [email protected]> a écrit :
>
>> On 03/04/2023 09:19, Julien Stephan wrote:
>>> From: Florian Sylvestre <[email protected]>
>>>
>>
>> There is no commit msg.
>>
>>> Signed-off-by: Florian Sylvestre <[email protected]>
>>> Signed-off-by: Julien Stephan <[email protected]>
>>> ---
>>> .../bindings/phy/mediatek,csi-phy.yaml | 41 +++++++++++++++++++
>>> MAINTAINERS | 6 +++
>>> 2 files changed, 47 insertions(+)
>>> create mode 100644
>> Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml
>>>
>>> diff --git a/Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml
>> b/Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml
>>> new file mode 100644
>>> index 000000000000..c026e43f35fd
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml
>>
>> Filename like compatible.
>>
> Should I rename the binding file
> Documentation/devicetree/bindings/phy/mediatek,mt8365-mipi-csi.yaml or

This.

> should I rename the compatible string mediatek,csi-phy?
> The csi PHY module is a module of the mt8365 soc and can possibly be used
> on other mediatek soc. I think this binding is generic enough to have a
> generic name, what do you think?

You did not allow adding new variants, as you made it const, not enum.
If there are other devices with this phy, they could be even added now.
Bindings should be rather complete.


Best regards,
Krzysztof

2023-04-03 15:30:58

by Chun-Kuang Hu

[permalink] [raw]
Subject: Re: [PATCH 2/2] phy: mtk-mipi-csi: add driver for CSI phy

Hi, Julien:

Julien Stephan <[email protected]> 於 2023年4月3日 週一 下午3:20寫道:
>
> From: Phi-bang Nguyen <[email protected]>
>
> This is a new driver that supports the MIPI CSI CD-PHY for mediatek
> mt8365 soc
>
> Signed-off-by: Louis Kuo <[email protected]>
> Signed-off-by: Phi-bang Nguyen <[email protected]>
> [Julien Stephan: use regmap]
> [Julien Stephan: use GENMASK]
> Co-developed-by: Julien Stephan <[email protected]>
> Signed-off-by: Julien Stephan <[email protected]>
> ---
> .../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]

> +
> +#define MIPI_RX_ANA04_CSIxA 0x0004

Useless, so drop this.

> +#define MIPI_RX_ANA04_CSIxA_RG_CSIxA_BG_LPRX_VTH_SEL_SHIFT 0
> +#define MIPI_RX_ANA04_CSIxA_RG_CSIxA_BG_LPRX_VTH_SEL_MASK GENMASK(2, 0)
> +#define MIPI_RX_ANA04_CSIxA_RG_CSIxA_BG_LPRX_VTL_SEL_SHIFT 4
> +#define MIPI_RX_ANA04_CSIxA_RG_CSIxA_BG_LPRX_VTL_SEL_MASK GENMASK(6, 4)
> +#define MIPI_RX_ANA04_CSIxA_RG_CSIxA_BG_HSDET_VTH_SEL_SHIFT 8
> +#define MIPI_RX_ANA04_CSIxA_RG_CSIxA_BG_HSDET_VTH_SEL_MASK GENMASK(10, 8)
> +#define MIPI_RX_ANA04_CSIxA_RG_CSIxA_BG_HSDET_VTL_SEL_SHIFT 12
> +#define MIPI_RX_ANA04_CSIxA_RG_CSIxA_BG_HSDET_VTL_SEL_MASK GENMASK(14, 12)
> +#define MIPI_RX_ANA04_CSIxA_RG_CSIxA_BG_VREF_SEL_SHIFT 16
> +#define MIPI_RX_ANA04_CSIxA_RG_CSIxA_BG_VREF_SEL_MASK GENMASK(19, 16)
> +#define MIPI_RX_ANA04_CSIxA_RG_CSIxA_BG_MON_VREF_SEL_SHIFT 24
> +#define MIPI_RX_ANA04_CSIxA_RG_CSIxA_BG_MON_VREF_SEL_MASK GENMASK(27, 24)
> +#define MIPI_RX_ANA04_CSIxA_RG_CSIxA_FORCE_HSRT_EN_SHIFT 28
> +#define MIPI_RX_ANA04_CSIxA_RG_CSIxA_FORCE_HSRT_EN_MASK BIT(28)
> +
> +#define MIPI_RX_ANA08_CSIxA 0x0008

Ditto.

> +#define MIPI_RX_ANA08_CSIxA_RG_CSIxA_L0P_T0A_HSRT_CODE_SHIFT 0
> +#define MIPI_RX_ANA08_CSIxA_RG_CSIxA_L0P_T0A_HSRT_CODE_MASK GENMASK(4, 0)
> +#define MIPI_RX_ANA08_CSIxA_RG_CSIxA_L0N_T0B_HSRT_CODE_SHIFT 8
> +#define MIPI_RX_ANA08_CSIxA_RG_CSIxA_L0N_T0B_HSRT_CODE_MASK GENMASK(12, 8)
> +#define MIPI_RX_ANA08_CSIxA_RG_CSIxA_L1P_T0C_HSRT_CODE_SHIFT 16
> +#define MIPI_RX_ANA08_CSIxA_RG_CSIxA_L1P_T0C_HSRT_CODE_MASK GENMASK(20, 16)
> +#define MIPI_RX_ANA08_CSIxA_RG_CSIxA_L1N_T1A_HSRT_CODE_SHIFT 24
> +#define MIPI_RX_ANA08_CSIxA_RG_CSIxA_L1N_T1A_HSRT_CODE_MASK GENMASK(28, 24)
> +
> +#define MIPI_RX_ANA0C_CSIxA 0x000c

Ditto.

> +#define MIPI_RX_ANA0C_CSIxA_RG_CSIxA_L2P_T1B_HSRT_CODE_SHIFT 0
> +#define MIPI_RX_ANA0C_CSIxA_RG_CSIxA_L2P_T1B_HSRT_CODE_MASK GENMASK(4, 0)
> +#define MIPI_RX_ANA0C_CSIxA_RG_CSIxA_L2N_T1C_HSRT_CODE_SHIFT 8
> +#define MIPI_RX_ANA0C_CSIxA_RG_CSIxA_L2N_T1C_HSRT_CODE_MASK GENMASK(12, 8)
> +
> +#define MIPI_RX_ANA10_CSIxA 0x0010

Ditto.

> +#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L0_DELAYCAL_EN_SHIFT 0
> +#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L0_DELAYCAL_EN_MASK BIT(0)
> +#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L0_DELAYCAL_RSTB_SHIFT 1
> +#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L0_DELAYCAL_RSTB_MASK BIT(1)
> +#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L0_VREF_SEL_SHIFT 2
> +#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L0_VREF_SEL_MASK GENMASK(7, 2)
> +#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L1_DELAYCAL_EN_SHIFT 8
> +#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L1_DELAYCAL_EN_MASK BIT(8)
> +#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L1_DELAYCAL_RSTB_SHIFT 9
> +#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L1_DELAYCAL_RSTB_MASK BIT(9)
> +#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L1_VREF_SEL_SHIFT 10
> +#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L1_VREF_SEL_MASK GENMASK(15, 10)
> +#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L2_DELAYCAL_EN_SHIFT 16
> +#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L2_DELAYCAL_EN_MASK BIT(16)
> +#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L2_DELAYCAL_RSTB_SHIFT 17
> +#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L2_DELAYCAL_RSTB_MASK BIT(17)
> +#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L2_VREF_SEL_SHIFT 18
> +#define MIPI_RX_ANA10_CSIxA_RG_CSIxA_DPHY_L2_VREF_SEL_MASK GENMASK(23, 18)
> +/* C-PHY fields are only available in CSIx. */
> +#define MIPI_RX_ANA10_CSIxA_RG_CSI0A_CPHY_T0_CDR_DELAYCAL_EN_SHIFT 24
> +#define MIPI_RX_ANA10_CSIxA_RG_CSI0A_CPHY_T0_CDR_DELAYCAL_EN_MASK BIT(24)
> +#define MIPI_RX_ANA10_CSIxA_RG_CSI0A_CPHY_T0_CDR_DELAYCAL_RSTB_SHIFT 25
> +#define MIPI_RX_ANA10_CSIxA_RG_CSI0A_CPHY_T0_CDR_DELAYCAL_RSTB_MASK BIT(25)
> +#define MIPI_RX_ANA10_CSIxA_RG_CSI0A_CPHY_T0_VREF_SEL_SHIFT 26
> +#define MIPI_RX_ANA10_CSIxA_RG_CSI0A_CPHY_T0_VREF_SEL_MASK GENMASK(31, 26)
> +
> +#define MIPI_RX_ANA14_CSIxA 0x0014

Ditto.

Regards,
Chun-Kuang.


> +/* C-PHY fields are only available in CSIx. */
> +#define MIPI_RX_ANA14_CSIxA_RG_CSI0A_CPHY_T1_CDR_DELAYCAL_EN_SHIFT 0
> +#define MIPI_RX_ANA14_CSIxA_RG_CSI0A_CPHY_T1_CDR_DELAYCAL_EN_MASK BIT(0)
> +#define MIPI_RX_ANA14_CSIxA_RG_CSI0A_CPHY_T1_CDR_DELAYCAL_RSTB_SHIFT 1
> +#define MIPI_RX_ANA14_CSIxA_RG_CSI0A_CPHY_T1_CDR_DELAYCAL_RSTB_MASK BIT(1)
> +#define MIPI_RX_ANA14_CSIxA_RG_CSI0A_CPHY_T1_VREF_SEL_SHIFT 2
> +#define MIPI_RX_ANA14_CSIxA_RG_CSI0A_CPHY_T1_VREF_SEL_MASK GENMASK(7, 2)
> +

2023-04-03 16:53:41

by Chun-Kuang Hu

[permalink] [raw]
Subject: Re: [PATCH 2/2] phy: mtk-mipi-csi: add driver for CSI phy

Hi, Julien:

Julien Stephan <[email protected]> 於 2023年4月3日 週一 下午3:20寫道:
>
> From: Phi-bang Nguyen <[email protected]>
>
> This is a new driver that supports the MIPI CSI CD-PHY for mediatek
> mt8365 soc
>
> Signed-off-by: Louis Kuo <[email protected]>
> Signed-off-by: Phi-bang Nguyen <[email protected]>
> [Julien Stephan: use regmap]
> [Julien Stephan: use GENMASK]
> Co-developed-by: Julien Stephan <[email protected]>
> Signed-off-by: Julien Stephan <[email protected]>
> ---
> .../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]

> +
> +#define REGMAP_BIT(map, reg, field, val) \
> + regmap_update_bits((map), reg, reg##_##field##_MASK, \
> + (val) << reg##_##field##_SHIFT)
> +

Use FIELD_PREP() macro so you can drop the definition of SHIFT symbol.

Regards,
Chun-Kuang.

2023-04-05 09:28:59

by Julien Stephan

[permalink] [raw]
Subject: Re: [PATCH 2/2] phy: mtk-mipi-csi: add driver for CSI phy

On Mon, Apr 03, 2023 at 11:51:50AM +0200, Krzysztof Kozlowski wrote:
> On 03/04/2023 09:19, Julien Stephan wrote:
> > From: Phi-bang Nguyen <[email protected]>
> >
> > This is a new driver that supports the MIPI CSI CD-PHY for mediatek
> > mt8365 soc
> >
> > Signed-off-by: Louis Kuo <[email protected]>
> > Signed-off-by: Phi-bang Nguyen <[email protected]>
> > [Julien Stephan: use regmap]
> > [Julien Stephan: use GENMASK]
> > Co-developed-by: Julien Stephan <[email protected]>
> > Signed-off-by: Julien Stephan <[email protected]>
> > ---
> > .../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
> >
> > diff --git a/Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml b/Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml
> > index c026e43f35fd..ad4ba1d93a68 100644
> > --- a/Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml
> > +++ b/Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml
>
> NAK, bindings are always separate patches. It also does not make any
> sense - you just added it.
>
:( I messed up my rebase -i. This need to be moved and squashed with the
previous patch. I will fix it in v2. Thank you for reporting it

> > @@ -33,9 +33,14 @@ additionalProperties: false
> >
> > examples:
> > - |
> > - phy@10011800 {
> > + soc {
> > + #address-cells = <2>;
> > + #size-cells = <2>;
> > +
> > + phy@11c10000 {
> > compatible = "mediatek,mt8365-mipi-csi";
> > - reg = <0 0x10011800 0 0x60>;
> > + reg = <0 0x11c10000 0 0x4000>;
> > #phy-cells = <1>;
> > + };
> > };
>
>
>
> k_mipi_dphy_of_match[] = {
> > + {.compatible = "mediatek,mt8365-mipi-csi"},
> > + {},
> > +};
> > +MODULE_DEVICE_TABLE(of, mtk_mipi_dphy_of_match);
> > +
> > +static struct platform_driver mipi_dphy_pdrv = {
> > + .probe = mtk_mipi_dphy_probe,
> > + .remove = mtk_mipi_dphy_remove,
> > + .driver = {
> > + .name = "mtk-mipi-csi",
> > + .of_match_table = of_match_ptr(mtk_mipi_dphy_of_match),
>
> Drop of_match_ptr(). You should see W=1 warnings when compile testing.
>
I do not not see any warnings when trying to compile with W=1. Am I
missing something? I will drop it in v2 anyway

Best
Julien
>
> Best regards,
> Krzysztof
>

2023-04-07 03:00:02

by Chunfeng Yun

[permalink] [raw]
Subject: Re: [PATCH 1/2] dt-bindings: phy: add mtk-mipi-csi driver

On Mon, 2023-04-03 at 09:19 +0200, Julien Stephan wrote:
> External email : Please do not click links or open attachments until
> you have verified the sender or the content.
>
>
> From: Florian Sylvestre <[email protected]>
>
> Signed-off-by: Florian Sylvestre <[email protected]>
> Signed-off-by: Julien Stephan <[email protected]>
> ---
> .../bindings/phy/mediatek,csi-phy.yaml | 41
> +++++++++++++++++++
> MAINTAINERS | 6 +++
> 2 files changed, 47 insertions(+)
> create mode 100644
> Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml
>
> diff --git a/Documentation/devicetree/bindings/phy/mediatek,csi-
> phy.yaml b/Documentation/devicetree/bindings/phy/mediatek,csi-
> phy.yaml
> new file mode 100644
> index 000000000000..c026e43f35fd
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml
> @@ -0,0 +1,41 @@
> +# SPDX-License-Identifier: (GPL-2.0-Only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id:
> https://urldefense.com/v3/__http://devicetree.org/schemas/phy/mediatek,csi-phy.yaml*__;Iw!!CTRNKA9wMg0ARbw!mTbIWKpb_vVGXYBKekejuVYU2klIR9-8QPOgiz10q0x3Z6HJDPsRfDQSCeu16k_wvfoHyXxRY0rTScjIpDTpsqc$
> +$schema:
> https://urldefense.com/v3/__http://devicetree.org/meta-schemas/core.yaml*__;Iw!!CTRNKA9wMg0ARbw!mTbIWKpb_vVGXYBKekejuVYU2klIR9-8QPOgiz10q0x3Z6HJDPsRfDQSCeu16k_wvfoHyXxRY0rTScjIaHVQBOI$
> +
> +title: Mediatek Sensor Interface MIPI CSI CD-PHY
> +
> +maintainers:
> + - Julien Stephan <[email protected]>
> + - Andy Hsieh <[email protected]>
> +
> +description: |
> + The SENINF CD-PHY is a set of CD-PHY connected to the SENINF CSI-2
> + receivers. The number of PHYs depends on the SoC model.
> +
> +properties:
> + compatible:
> + const: mediatek,mt8365-mipi-csi
> +
> + reg:
> + minItems: 1
> +
> + '#phy-cells':
> + const: 1
Please describe what means for each value

> +
> +required:
> + - compatible
> + - reg
> + - '#phy-cells'
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + phy@10011800 {
> + compatible = "mediatek,mt8365-mipi-csi";
> + reg = <0 0x10011800 0 0x60>;
> + #phy-cells = <1>;
> + };
> +...
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 6d54f3193075..9308b4bb88bf 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -13098,6 +13098,12 @@
> F: Documentation/devicetree/bindings/media/mediatek-vpu.txt
> F: drivers/media/platform/mediatek/vcodec/
> F: drivers/media/platform/mediatek/vpu/
>
> +MEDIATEK MIPI-CSI CDPHY DRIVER
> +M: Julien Stephan <[email protected]>
> +M: Andy Hsieh <[email protected]>
> +S: Supported
> +F: Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml
> +
> MEDIATEK MMC/SD/SDIO DRIVER
> M: Chaotian Jing <[email protected]>
> S: Maintained
> --
> 2.40.0
>

2023-04-07 03:48:58

by Chunfeng Yun

[permalink] [raw]
Subject: Re: [PATCH 2/2] phy: mtk-mipi-csi: add driver for CSI phy

On Mon, 2023-04-03 at 09:19 +0200, Julien Stephan wrote:
> External email : Please do not click links or open attachments until
> you have verified the sender or the content.
>
>
> From: Phi-bang Nguyen <[email protected]>
>
> This is a new driver that supports the MIPI CSI CD-PHY for mediatek
> mt8365 soc
>
> Signed-off-by: Louis Kuo <[email protected]>
> Signed-off-by: Phi-bang Nguyen <[email protected]>
> [Julien Stephan: use regmap]
> [Julien Stephan: use GENMASK]
> Co-developed-by: Julien Stephan <[email protected]>
> Signed-off-by: Julien Stephan <[email protected]>
> ---
> .../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

Please cc [email protected]

>
> ...
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 9308b4bb88bf..b3077eddd0bf 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -13103,6 +13103,7 @@ M: Julien Stephan <[email protected]
> >
>
> M: Andy Hsieh <[email protected]>
> S: Supported
> F: Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml
> +F: drivers/phy/mediatek/phy-mtk-mipi-csi*
>
> MEDIATEK MMC/SD/SDIO DRIVER
> M: Chaotian Jing <[email protected]>

separate a new patch for MAINTAINERS change?


> diff --git a/drivers/phy/mediatek/Kconfig
> b/drivers/phy/mediatek/Kconfig
> index 3125ecb5d119..63fb0fa77573 100644
> --- a/drivers/phy/mediatek/Kconfig
> +++ b/drivers/phy/mediatek/Kconfig
> @@ -74,3 +74,11 @@ config PHY_MTK_DP
> select GENERIC_PHY
> help
> Support DisplayPort PHY for MediaTek SoCs.
> +
> +config PHY_MTK_MIPI_CSI
> + tristate "MediaTek CSI CD-PHY Driver"
> + depends on ARCH_MEDIATEK && OF
> + select GENERIC_PHY
> + help
> + Enable this to support the MIPI CSI CD-PHY receiver.
> + The driver supports multiple CSI cdphy ports
> simultaneously.
> diff --git a/drivers/phy/mediatek/Makefile
> b/drivers/phy/mediatek/Makefile
> index fb1f8edaffa7..9a178c1c2628 100644
> --- a/drivers/phy/mediatek/Makefile
> +++ b/drivers/phy/mediatek/Makefile
> @@ -18,3 +18,5 @@ phy-mtk-mipi-dsi-drv-y :=
> phy-mtk-mipi-dsi.o
> phy-mtk-mipi-dsi-drv-y += phy-mtk-mipi-dsi-mt8173.o
> phy-mtk-mipi-dsi-drv-y += phy-mtk-mipi-dsi-mt8183.o
> obj-$(CONFIG_PHY_MTK_MIPI_DSI) += phy-mtk-mipi-dsi-drv.o
> +
> +obj-$(CONFIG_PHY_MTK_MIPI_CSI) += phy-mtk-mipi-csi.o
> diff --git a/drivers/phy/mediatek/phy-mtk-mipi-csi-rx-reg.h
> b/drivers/phy/mediatek/phy-mtk-mipi-csi-rx-reg.h
> new file mode 100644
> index 000000000000..f360e807e3d1
> --- /dev/null
> +++ b/drivers/phy/mediatek/phy-mtk-mipi-csi-rx-reg.h
> @@ -0,0 +1,435 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +#ifndef __MIPI_CDPHY_RX_REG_H__
> +#define __MIPI_CDPHY_RX_REG_H__
> +
> +/*
> + * CSI1 and CSI2 are identical, and similar to CSI0. All CSIx macros
> are
> + * applicable to the three PHYs. Where differences exist, they are
> denoted by
> + * macro names using CSI0 and CSI1, the latter being applicable to
> CSI1 and
> + * CSI2 alike.
> + */
> +
> +/*
> + * Due to lanes supporting C-PHY mode on CSI0, register fields that
> control the
> + * behaviour of lanes are named differently between CSI0 and
> CSI1/CSI2, even
> + * when they control parameters that are agnostic to the PHY mode.
> In those
> + * cases, the macros below use the CSI0 field names (e.g.
> + * MIPI_RX_ANA08_CSIxA_RG_CSIxA_L0P_T0A_HSRT_CODE_SHIFT).
> + */
> +
> <skip>
>
> +#define
> MIPI_RX_ANA24_CSIxA_RG_CSIxA_RESERVE_SHIFT
> 24
> +#define
> MIPI_RX_ANA24_CSIxA_RG_CSIxA_RESERVE_MASK
> (0xff << 24)

Use GENMASK()


> +
> +/* CSI0-specific register. */
> +#define
> MIPI_RX_ANA28_CSI0A
> 0x0028
> +#define
> MIPI_RX_ANA28_CSI0A_RG_CSI0A_CPHY_T0_CDR_DIRECT_EN_SHIFT
> 0
>
>
> +#define
> MIPI_RX_ANA48_CSIxA_RGS_CSI1A_DPHY_L2_OS_CAL_CPLT_SHIFT
> 5
> +#define
> MIPI_RX_ANA48_CSIxA_RGS_CSI1A_DPHY_L2_OS_CAL_CPLT_MASK
> BIT(5)
> +/* Common fields. */
> +#define
> MIPI_RX_ANA48_CSIxA_RGS_CSIxA_OS_CAL_CODE_SHIFT
> 8
> +#define
> MIPI_RX_ANA48_CSIxA_RGS_CSIxA_OS_CAL_CODE_MASK
> GENMASK(15, 8)
> +
> +#define
> MIPI_RX_WRAPPER80_CSIxA
> 0x0080
> +#define
> MIPI_RX_WRAPPER80_CSIxA_CSR_CSI_CLK_MON_SHIFT
> 0
> +#define
> MIPI_RX_WRAPPER80_CSIxA_CSR_CSI_CLK_MON_MASK
> BIT(0)
> +#define
> MIPI_RX_WRAPPER80_CSIxA_CSR_CSI_CLK_EN_SHIFT
> 1
> +#define
> MIPI_RX_WRAPPER80_CSIxA_CSR_CSI_CLK_EN_MASK
> BIT(1)
> +#define
> MIPI_RX_WRAPPER80_CSIxA_CSR_CSI_MON_MUX_SHIFT
> 8
> +#define
> MIPI_RX_WRAPPER80_CSIxA_CSR_CSI_MON_MUX_MASK
> GENMASK(15, 8)
> +#define
> MIPI_RX_WRAPPER80_CSIxA_CSR_CSI_RST_MODE_SHIFT
> 16
> +#define
> MIPI_RX_WRAPPER80_CSIxA_CSR_CSI_RST_MODE_MASK
> GENMASK(17, 16)
> +#define
> MIPI_RX_WRAPPER80_CSIxA_CSR_SW_RST_SHIFT
> 24
> +#define
> MIPI_RX_WRAPPER80_CSIxA_CSR_SW_RST_MASK
> GENMASK(27, 24)
> +
> +#define
> MIPI_RX_WRAPPER84_CSIxA
> 0x0084
> +#define
> MIPI_RX_WRAPPER84_CSIxA_CSI_DEBUG_OUT_SHIFT
> 0
> +#define
> MIPI_RX_WRAPPER84_CSIxA_CSI_DEBUG_OUT_MASK
> GENMASK(31, 0)
> +
> +#define
> MIPI_RX_WRAPPER88_CSIxA
> 0x0088
> +#define
> MIPI_RX_WRAPPER88_CSIxA_CSR_SW_MODE_0_SHIFT
> 0
> +#define
> MIPI_RX_WRAPPER88_CSIxA_CSR_SW_MODE_0_MASK
> GENMASK(31, 0)
> +
> +#define
> MIPI_RX_WRAPPER8C_CSIxA
> 0x008c
> +#define
> MIPI_RX_WRAPPER8C_CSIxA_CSR_SW_MODE_1_SHIFT
> 0
> +#define
> MIPI_RX_WRAPPER8C_CSIxA_CSR_SW_MODE_1_MASK
> GENMASK(31, 0)
> +
> +#define
> MIPI_RX_WRAPPER90_CSIxA
> 0x0090
> +#define
> MIPI_RX_WRAPPER90_CSIxA_CSR_SW_MODE_2_SHIFT
> 0
> +#define
> MIPI_RX_WRAPPER90_CSIxA_CSR_SW_MODE_2_MASK
> GENMASK(31, 0)
> +
> +#define
> MIPI_RX_WRAPPER94_CSIxA
> 0x0094
> +#define
> MIPI_RX_WRAPPER94_CSIxA_CSR_SW_VALUE_0_SHIFT
> 0
> +#define
> MIPI_RX_WRAPPER94_CSIxA_CSR_SW_VALUE_0_MASK
> GENMASK(31, 0)
> +
> +#define
> MIPI_RX_WRAPPER98_CSIxA
> 0x0098
> +#define
> MIPI_RX_WRAPPER98_CSIxA_CSR_SW_VALUE_1_SHIFT
> 0
> +#define
> MIPI_RX_WRAPPER98_CSIxA_CSR_SW_VALUE_1_MASK
> GENMASK(31, 0)
> +
> +#define
> MIPI_RX_WRAPPER9C_CSIxA
> 0x009c
> +#define
> MIPI_RX_WRAPPER9C_CSIxA_CSR_SW_VALUE_2_SHIFT
> 0
> +#define
> MIPI_RX_WRAPPER9C_CSIxA_CSR_SW_VALUE_2_MASK
> GENMASK(31, 0)
> +
> +#define
> MIPI_RX_ANAA4_CSIxA
> 0x00a4
> +#define
> MIPI_RX_ANAA4_CSIxA_RG_CSIxA_CDPHY_L0_T0_SYNC_INIT_SEL_SHIFT
> 0
> +#define
> MIPI_RX_ANAA4_CSIxA_RG_CSIxA_CDPHY_L0_T0_SYNC_INIT_SEL_MASK
> BIT(0)
> +#define
> MIPI_RX_ANAA4_CSIxA_RG_CSIxA_CDPHY_L0_T0_FORCE_INIT_SHIFT
> 1
> +#define
> MIPI_RX_ANAA4_CSIxA_RG_CSIxA_CDPHY_L0_T0_FORCE_INIT_MASK
> BIT(1)
> +#define
> MIPI_RX_ANAA4_CSIxA_RG_CSIxA_DPHY_L1_SYNC_INIT_SEL_SHIFT
> 2
> +#define
> MIPI_RX_ANAA4_CSIxA_RG_CSIxA_DPHY_L1_SYNC_INIT_SEL_MASK
> BIT(2)
> +#define
> MIPI_RX_ANAA4_CSIxA_RG_CSIxA_DPHY_L1_FORCE_INIT_SHIFT
> 3
> +#define
> MIPI_RX_ANAA4_CSIxA_RG_CSIxA_DPHY_L1_FORCE_INIT_MASK
> BIT(3)
> +#define
> MIPI_RX_ANAA4_CSIxA_RG_CSIxA_CDPHY_L2_T2_SYNC_INIT_SEL_SHIFT
> 4
> +#define
> MIPI_RX_ANAA4_CSIxA_RG_CSIxA_CDPHY_L2_T2_SYNC_INIT_SEL_MASK
> BIT(4)
> +#define
> MIPI_RX_ANAA4_CSIxA_RG_CSIxA_CDPHY_L2_T2_FORCE_INIT_SHIFT
> 5
> +#define
> MIPI_RX_ANAA4_CSIxA_RG_CSIxA_CDPHY_L2_T2_FORCE_INIT_MASK
> BIT(5)
> +
> +#define
> MIPI_RX_ANAA8_CSIxA
> 0x00a8
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_CDPHY_L0_T0_BYTECK_INVERT_SHIFT
> 0
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_CDPHY_L0_T0_BYTECK_INVERT_MASK
> BIT(0)
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_DPHY_L1_BYTECK_INVERT_SHIFT
> 1
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_DPHY_L1_BYTECK_INVERT_MASK
> BIT(1)
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_CDPHY_L2_T1_BYTECK_INVERT_SHIFT
> 2
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_CDPHY_L2_T1_BYTECK_INVERT_MASK
> BIT(2)
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_DPHY_HSDET_LEVEL_MODE_EN_SHIFT
> 3
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_DPHY_HSDET_LEVEL_MODE_EN_MASK
> BIT(3)
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_OS_CAL_SEL_SHIFT
> 4
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_OS_CAL_SEL_MASK
> GENMASK(6, 4)
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_DPHY_HSDET_DIG_BACK_EN_SHIFT
> 7
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_DPHY_HSDET_DIG_BACK_EN_MASK
> BIT(7)
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_CDPHY_DELAYCAL_CK_SEL_SHIFT
> 8
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_CDPHY_DELAYCAL_CK_SEL_MASK
> GENMASK(10, 8)
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_OS_CAL_DIV_SHIFT
> 11
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_OS_CAL_DIV_MASK
> GENMASK(12, 11)
> +
> +#endif
> diff --git a/drivers/phy/mediatek/phy-mtk-mipi-csi.c
> b/drivers/phy/mediatek/phy-mtk-mipi-csi.c
> new file mode 100644
> index 000000000000..6ce3f95f57bd
> --- /dev/null
> +++ b/drivers/phy/mediatek/phy-mtk-mipi-csi.c
> @@ -0,0 +1,392 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/regmap.h>
> +
> +#include "phy-mtk-mipi-csi-rx-reg.h"
> +
> +#define CSIxB_OFFSET 0x1000
> +
> +struct mtk_mipi_dphy;
> +
> +enum mtk_mipi_dphy_port_id {
> + MTK_MIPI_PHY_PORT_0 = 0x0, /* 4D1C - CDPHY */
> + MTK_MIPI_PHY_PORT_1, /* 4D1C - DPHY */
> + MTK_MIPI_PHY_PORT_2, /* 4D1C - DPHY */
> + MTK_MIPI_PHY_PORT_0A, /* 2D1C - CDPHY */
> + MTK_MIPI_PHY_PORT_0B, /* 2D1C - CDPHY */
> + MTK_MIPI_PHY_PORT_MAX_NUM
> +};
> +
> +struct mtk_mipi_dphy_port {
> + struct mtk_mipi_dphy *dev;
> + enum mtk_mipi_dphy_port_id id;
> + struct regmap *regmap_base;
> + struct regmap *regmap_4d1c;

Could you avoid using regmap if the registers are only used by this
driver, use phy-mtk-io.h api instead.

> + struct phy *phy;
> + bool active;
> + bool is_cdphy;
> + bool is_4d1c;
> +};
> +
> +struct mtk_mipi_dphy {
> + struct device *dev;
> + void __iomem *rx;
> + struct mtk_mipi_dphy_port ports[MTK_MIPI_PHY_PORT_MAX_NUM];
> + struct mutex lock; /* Ports CSI0 and CSI0A/B are mutually
> exclusive */

phy core already provides a mutex, no need provide another one.

Do you switch them at runtime for port 0?

From binding, I guess we use mtk_mipi_dphy_port_id in DTS to determine
which mode is used.

> +};
> +
> +#define REGMAP_BIT(map, reg, field, val) \
> + regmap_update_bits((map), reg, reg##_##field##_MASK, \
> + (val) << reg##_##field##_SHIFT)
> +
> +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);
> + 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;
> +}
> +
> +static int mtk_mipi_phy_power_off(struct phy *phy)
> +{
> + struct mtk_mipi_dphy_port *port = phy_get_drvdata(phy);
> + struct regmap *regmap_base = port->regmap_base;
> + struct regmap *regmap_4d1c = port->regmap_4d1c;
> +
> + /* Disable MIPI BG. */
> + REGMAP_BIT(regmap_base, MIPI_RX_ANA00_CSIxA,
> + RG_CSIxA_BG_CORE_EN, 0);
> + REGMAP_BIT(regmap_base, MIPI_RX_ANA00_CSIxA,
> + RG_CSIxA_BG_LPF_EN, 0);
> +
> + if (port->is_4d1c) {
> + REGMAP_BIT(regmap_4d1c, MIPI_RX_ANA00_CSIxA,
> + RG_CSIxA_BG_CORE_EN, 0);
> + REGMAP_BIT(regmap_4d1c, MIPI_RX_ANA00_CSIxA,
> + RG_CSIxA_BG_LPF_EN, 0);
> + }
> +
> + mutex_lock(&port->dev->lock);
> + port->active = false;
> + mutex_unlock(&port->dev->lock);
> +
> + return 0;
> +}
> +
> +static const struct phy_ops mtk_dphy_ops = {
> + .power_on = mtk_mipi_phy_power_on,
> + .power_off = mtk_mipi_phy_power_off,
> + .owner = THIS_MODULE,
> +};
> +
> +static struct phy *mtk_mipi_dphy_xlate(struct device *dev,
> + struct of_phandle_args *args)
> +{
> + struct mtk_mipi_dphy *priv = dev_get_drvdata(dev);
> +
> + if (args->args_count != 1)
> + return ERR_PTR(-EINVAL);
> +
> + if (args->args[0] >= ARRAY_SIZE(priv->ports))
> + return ERR_PTR(-ENODEV);
> +
> + return priv->ports[args->args[0]].phy;
> +}
> +
> +static const struct regmap_config mt8365_phy_regmap_config = {
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = 4,
> + .max_register = 0x700,
> +};
> +
> +static int mtk_mipi_dphy_probe(struct platform_device *pdev)
> +{
> + static const unsigned int ports_offsets[] = {
> + [MTK_MIPI_PHY_PORT_0] = 0,
> + [MTK_MIPI_PHY_PORT_0A] = 0,
> + [MTK_MIPI_PHY_PORT_0B] = 0x1000,
> + [MTK_MIPI_PHY_PORT_1] = 0x2000,
> + [MTK_MIPI_PHY_PORT_2] = 0x4000,
> + };

How about provide three subnode (p0/p1/p2)in dts like as tphy driver?

for the port 0, it works as three mode (*_0/0A/0B, or 4d1c/2d1c), we
can distinguish it from phy arguments, also the same for port 1/2

> +
> + struct device *dev = &pdev->dev;
> + struct phy_provider *phy_provider;
> + struct mtk_mipi_dphy *priv;
> + struct resource *res;
> + unsigned int i;
> +
> + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> +
> + dev_set_drvdata(dev, priv);
> + priv->dev = dev;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + priv->rx = devm_ioremap_resource(dev, res);

use devm_platform_ioremap_resource()

> + if (IS_ERR(priv->rx))
> + return PTR_ERR(priv->rx);
> +
> + for (i = 0; i < ARRAY_SIZE(priv->ports); ++i) {
> + struct mtk_mipi_dphy_port *port = &priv->ports[i];
> + struct phy *phy;
> + void __iomem *base;
> +
> + port->dev = priv;
> + port->id = i;
> + base = priv->rx + ports_offsets[i];
> +
> + port->regmap_base = devm_regmap_init_mmio(port->dev-
> > dev,
>
> + base,
> + &mt8365_phy
> _regmap_config);
> +
> + port->is_cdphy = i == MTK_MIPI_PHY_PORT_0A ||
> + i == MTK_MIPI_PHY_PORT_0B ||
> + i == MTK_MIPI_PHY_PORT_0;
> + port->is_4d1c = i < MTK_MIPI_PHY_PORT_0A;
> +
> + if (port->is_4d1c)
> + port->regmap_4d1c =
> devm_regmap_init_mmio(port->dev->dev,
> + bas
> e + CSIxB_OFFSET,
> + &mt
> 8365_phy_regmap_config);
> +
> + phy = devm_phy_create(dev, NULL, &mtk_dphy_ops);
> + if (IS_ERR(phy)) {
> + dev_err(dev, "Failed to create PHY: %ld\n",
> PTR_ERR(phy));
> + return PTR_ERR(phy);
> + }
> +
> + port->phy = phy;
> + phy_set_drvdata(phy, port);
> + }
> +
> + phy_provider = devm_of_phy_provider_register(dev,
> mtk_mipi_dphy_xlate);
> + if (IS_ERR(phy_provider)) {
> + dev_err(dev, "Failed to register PHY provider:
> %ld\n",
> + PTR_ERR(phy_provider));
> + return PTR_ERR(phy_provider);
> + }
> +
> + mutex_init(&priv->lock);
> +
> + return 0;
> +}
> +
> +static int mtk_mipi_dphy_remove(struct platform_device *pdev)
> +{
> + struct mtk_mipi_dphy *priv = platform_get_drvdata(pdev);
> +
> + mutex_destroy(&priv->lock);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id mtk_mipi_dphy_of_match[] = {
> + {.compatible = "mediatek,mt8365-mipi-csi"},

prefer to provide a generic compatible if not a specific controller
only for mt8365.

Thanks a lot
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, mtk_mipi_dphy_of_match);


> +
> +static struct platform_driver mipi_dphy_pdrv = {
> + .probe = mtk_mipi_dphy_probe,
> + .remove = mtk_mipi_dphy_remove,
> + .driver = {
> + .name = "mtk-mipi-csi",
> + .of_match_table =
> of_match_ptr(mtk_mipi_dphy_of_match),
> + },
> +};
> +
> +module_platform_driver(mipi_dphy_pdrv);
> +
> +MODULE_DESCRIPTION("MTK mipi csi cdphy driver");
> +MODULE_AUTHOR("Louis Kuo <[email protected]>");
> +MODULE_LICENSE("GPL");
> --
> 2.40.0
>

2023-04-07 05:33:50

by Chunfeng Yun

[permalink] [raw]
Subject: Re: [PATCH 2/2] phy: mtk-mipi-csi: add driver for CSI phy

On Mon, 2023-04-03 at 09:19 +0200, Julien Stephan wrote:
> External email : Please do not click links or open attachments until
> you have verified the sender or the content.
>
>
> From: Phi-bang Nguyen <[email protected]>
>
> This is a new driver that supports the MIPI CSI CD-PHY for mediatek
> mt8365 soc
>
> Signed-off-by: Louis Kuo <[email protected]>
> Signed-off-by: Phi-bang Nguyen <[email protected]>
> [Julien Stephan: use regmap]
> [Julien Stephan: use GENMASK]
> Co-developed-by: Julien Stephan <[email protected]>
> Signed-off-by: Julien Stephan <[email protected]>
> ---
> .../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

Please cc [email protected]

>
> ...
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 9308b4bb88bf..b3077eddd0bf 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -13103,6 +13103,7 @@ M: Julien Stephan <[email protected]
> >
> M: Andy Hsieh <[email protected]>
> S: Supported
> F: Documentation/devicetree/bindings/phy/mediatek,csi-phy.yaml
> +F: drivers/phy/mediatek/phy-mtk-mipi-csi*
>
> MEDIATEK MMC/SD/SDIO DRIVER
> M: Chaotian Jing <[email protected]>

separate a new patch for MAINTAINERS change?


> diff --git a/drivers/phy/mediatek/Kconfig
> b/drivers/phy/mediatek/Kconfig
> index 3125ecb5d119..63fb0fa77573 100644
> --- a/drivers/phy/mediatek/Kconfig
> +++ b/drivers/phy/mediatek/Kconfig
> @@ -74,3 +74,11 @@ config PHY_MTK_DP
> select GENERIC_PHY
> help
> Support DisplayPort PHY for MediaTek SoCs.
> +
> +config PHY_MTK_MIPI_CSI
> + tristate "MediaTek CSI CD-PHY Driver"
> + depends on ARCH_MEDIATEK && OF
> + select GENERIC_PHY
> + help
> + Enable this to support the MIPI CSI CD-PHY receiver.
> + The driver supports multiple CSI cdphy ports
> simultaneously.
> diff --git a/drivers/phy/mediatek/Makefile
> b/drivers/phy/mediatek/Makefile
> index fb1f8edaffa7..9a178c1c2628 100644
> --- a/drivers/phy/mediatek/Makefile
> +++ b/drivers/phy/mediatek/Makefile
> @@ -18,3 +18,5 @@ phy-mtk-mipi-dsi-drv-y :=
> phy-mtk-mipi-dsi.o
> phy-mtk-mipi-dsi-drv-y += phy-mtk-mipi-dsi-mt8173.o
> phy-mtk-mipi-dsi-drv-y += phy-mtk-mipi-dsi-mt8183.o
> obj-$(CONFIG_PHY_MTK_MIPI_DSI) += phy-mtk-mipi-dsi-drv.o
> +
> +obj-$(CONFIG_PHY_MTK_MIPI_CSI) += phy-mtk-mipi-csi.o
> diff --git a/drivers/phy/mediatek/phy-mtk-mipi-csi-rx-reg.h
> b/drivers/phy/mediatek/phy-mtk-mipi-csi-rx-reg.h
> new file mode 100644
> index 000000000000..f360e807e3d1
> --- /dev/null
> +++ b/drivers/phy/mediatek/phy-mtk-mipi-csi-rx-reg.h
> @@ -0,0 +1,435 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +#ifndef __MIPI_CDPHY_RX_REG_H__
> +#define __MIPI_CDPHY_RX_REG_H__
> +
> +/*
> + * CSI1 and CSI2 are identical, and similar to CSI0. All CSIx macros
> are
> + * applicable to the three PHYs. Where differences exist, they are
> denoted by
> + * macro names using CSI0 and CSI1, the latter being applicable to
> CSI1 and
> + * CSI2 alike.
> + */
> +
> +/*
> + * Due to lanes supporting C-PHY mode on CSI0, register fields that
> control the
> + * behaviour of lanes are named differently between CSI0 and
> CSI1/CSI2, even
> + * when they control parameters that are agnostic to the PHY mode.
> In those
> + * cases, the macros below use the CSI0 field names (e.g.
> + * MIPI_RX_ANA08_CSIxA_RG_CSIxA_L0P_T0A_HSRT_CODE_SHIFT).
> + */
> +
> <skip>
>
> +#define
> MIPI_RX_ANA24_CSIxA_RG_CSIxA_RESERVE_SHIFT
> 24
> +#define
> MIPI_RX_ANA24_CSIxA_RG_CSIxA_RESERVE_MASK
> (0xff << 24)

Use GENMASK()


> +
> +/* CSI0-specific register. */
> +#define
> MIPI_RX_ANA28_CSI0A
> 0x0028
> +#define
> MIPI_RX_ANA28_CSI0A_RG_CSI0A_CPHY_T0_CDR_DIRECT_EN_SHIFT
> 0
>
>
> +#define
> MIPI_RX_ANA48_CSIxA_RGS_CSI1A_DPHY_L2_OS_CAL_CPLT_SHIFT
> 5
> +#define
> MIPI_RX_ANA48_CSIxA_RGS_CSI1A_DPHY_L2_OS_CAL_CPLT_MASK
> BIT(5)
> +/* Common fields. */
> +#define
> MIPI_RX_ANA48_CSIxA_RGS_CSIxA_OS_CAL_CODE_SHIFT
> 8
> +#define
> MIPI_RX_ANA48_CSIxA_RGS_CSIxA_OS_CAL_CODE_MASK
> GENMASK(15, 8)
> +
> +#define
> MIPI_RX_WRAPPER80_CSIxA
> 0x0080
> +#define
> MIPI_RX_WRAPPER80_CSIxA_CSR_CSI_CLK_MON_SHIFT
> 0
> +#define
> MIPI_RX_WRAPPER80_CSIxA_CSR_CSI_CLK_MON_MASK
> BIT(0)
> +#define
> MIPI_RX_WRAPPER80_CSIxA_CSR_CSI_CLK_EN_SHIFT
> 1
> +#define
> MIPI_RX_WRAPPER80_CSIxA_CSR_CSI_CLK_EN_MASK
> BIT(1)
> +#define
> MIPI_RX_WRAPPER80_CSIxA_CSR_CSI_MON_MUX_SHIFT
> 8
> +#define
> MIPI_RX_WRAPPER80_CSIxA_CSR_CSI_MON_MUX_MASK
> GENMASK(15, 8)
> +#define
> MIPI_RX_WRAPPER80_CSIxA_CSR_CSI_RST_MODE_SHIFT
> 16
> +#define
> MIPI_RX_WRAPPER80_CSIxA_CSR_CSI_RST_MODE_MASK
> GENMASK(17, 16)
> +#define
> MIPI_RX_WRAPPER80_CSIxA_CSR_SW_RST_SHIFT
> 24
> +#define
> MIPI_RX_WRAPPER80_CSIxA_CSR_SW_RST_MASK
> GENMASK(27, 24)
> +
> +#define
> MIPI_RX_WRAPPER84_CSIxA
> 0x0084
> +#define
> MIPI_RX_WRAPPER84_CSIxA_CSI_DEBUG_OUT_SHIFT
> 0
> +#define
> MIPI_RX_WRAPPER84_CSIxA_CSI_DEBUG_OUT_MASK
> GENMASK(31, 0)
> +
> +#define
> MIPI_RX_WRAPPER88_CSIxA
> 0x0088
> +#define
> MIPI_RX_WRAPPER88_CSIxA_CSR_SW_MODE_0_SHIFT
> 0
> +#define
> MIPI_RX_WRAPPER88_CSIxA_CSR_SW_MODE_0_MASK
> GENMASK(31, 0)
> +
> +#define
> MIPI_RX_WRAPPER8C_CSIxA
> 0x008c
> +#define
> MIPI_RX_WRAPPER8C_CSIxA_CSR_SW_MODE_1_SHIFT
> 0
> +#define
> MIPI_RX_WRAPPER8C_CSIxA_CSR_SW_MODE_1_MASK
> GENMASK(31, 0)
> +
> +#define
> MIPI_RX_WRAPPER90_CSIxA
> 0x0090
> +#define
> MIPI_RX_WRAPPER90_CSIxA_CSR_SW_MODE_2_SHIFT
> 0
> +#define
> MIPI_RX_WRAPPER90_CSIxA_CSR_SW_MODE_2_MASK
> GENMASK(31, 0)
> +
> +#define
> MIPI_RX_WRAPPER94_CSIxA
> 0x0094
> +#define
> MIPI_RX_WRAPPER94_CSIxA_CSR_SW_VALUE_0_SHIFT
> 0
> +#define
> MIPI_RX_WRAPPER94_CSIxA_CSR_SW_VALUE_0_MASK
> GENMASK(31, 0)
> +
> +#define
> MIPI_RX_WRAPPER98_CSIxA
> 0x0098
> +#define
> MIPI_RX_WRAPPER98_CSIxA_CSR_SW_VALUE_1_SHIFT
> 0
> +#define
> MIPI_RX_WRAPPER98_CSIxA_CSR_SW_VALUE_1_MASK
> GENMASK(31, 0)
> +
> +#define
> MIPI_RX_WRAPPER9C_CSIxA
> 0x009c
> +#define
> MIPI_RX_WRAPPER9C_CSIxA_CSR_SW_VALUE_2_SHIFT
> 0
> +#define
> MIPI_RX_WRAPPER9C_CSIxA_CSR_SW_VALUE_2_MASK
> GENMASK(31, 0)
> +
> +#define
> MIPI_RX_ANAA4_CSIxA
> 0x00a4
> +#define
> MIPI_RX_ANAA4_CSIxA_RG_CSIxA_CDPHY_L0_T0_SYNC_INIT_SEL_SHIFT
> 0
> +#define
> MIPI_RX_ANAA4_CSIxA_RG_CSIxA_CDPHY_L0_T0_SYNC_INIT_SEL_MASK
> BIT(0)
> +#define
> MIPI_RX_ANAA4_CSIxA_RG_CSIxA_CDPHY_L0_T0_FORCE_INIT_SHIFT
> 1
> +#define
> MIPI_RX_ANAA4_CSIxA_RG_CSIxA_CDPHY_L0_T0_FORCE_INIT_MASK
> BIT(1)
> +#define
> MIPI_RX_ANAA4_CSIxA_RG_CSIxA_DPHY_L1_SYNC_INIT_SEL_SHIFT
> 2
> +#define
> MIPI_RX_ANAA4_CSIxA_RG_CSIxA_DPHY_L1_SYNC_INIT_SEL_MASK
> BIT(2)
> +#define
> MIPI_RX_ANAA4_CSIxA_RG_CSIxA_DPHY_L1_FORCE_INIT_SHIFT
> 3
> +#define
> MIPI_RX_ANAA4_CSIxA_RG_CSIxA_DPHY_L1_FORCE_INIT_MASK
> BIT(3)
> +#define
> MIPI_RX_ANAA4_CSIxA_RG_CSIxA_CDPHY_L2_T2_SYNC_INIT_SEL_SHIFT
> 4
> +#define
> MIPI_RX_ANAA4_CSIxA_RG_CSIxA_CDPHY_L2_T2_SYNC_INIT_SEL_MASK
> BIT(4)
> +#define
> MIPI_RX_ANAA4_CSIxA_RG_CSIxA_CDPHY_L2_T2_FORCE_INIT_SHIFT
> 5
> +#define
> MIPI_RX_ANAA4_CSIxA_RG_CSIxA_CDPHY_L2_T2_FORCE_INIT_MASK
> BIT(5)
> +
> +#define
> MIPI_RX_ANAA8_CSIxA
> 0x00a8
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_CDPHY_L0_T0_BYTECK_INVERT_SHIFT
> 0
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_CDPHY_L0_T0_BYTECK_INVERT_MASK
> BIT(0)
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_DPHY_L1_BYTECK_INVERT_SHIFT
> 1
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_DPHY_L1_BYTECK_INVERT_MASK
> BIT(1)
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_CDPHY_L2_T1_BYTECK_INVERT_SHIFT
> 2
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_CDPHY_L2_T1_BYTECK_INVERT_MASK
> BIT(2)
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_DPHY_HSDET_LEVEL_MODE_EN_SHIFT
> 3
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_DPHY_HSDET_LEVEL_MODE_EN_MASK
> BIT(3)
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_OS_CAL_SEL_SHIFT
> 4
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_OS_CAL_SEL_MASK
> GENMASK(6, 4)
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_DPHY_HSDET_DIG_BACK_EN_SHIFT
> 7
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_DPHY_HSDET_DIG_BACK_EN_MASK
> BIT(7)
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_CDPHY_DELAYCAL_CK_SEL_SHIFT
> 8
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_CDPHY_DELAYCAL_CK_SEL_MASK
> GENMASK(10, 8)
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_OS_CAL_DIV_SHIFT
> 11
> +#define
> MIPI_RX_ANAA8_CSIxA_RG_CSIxA_OS_CAL_DIV_MASK
> GENMASK(12, 11)
> +
> +#endif
> diff --git a/drivers/phy/mediatek/phy-mtk-mipi-csi.c
> b/drivers/phy/mediatek/phy-mtk-mipi-csi.c
> new file mode 100644
> index 000000000000..6ce3f95f57bd
> --- /dev/null
> +++ b/drivers/phy/mediatek/phy-mtk-mipi-csi.c
> @@ -0,0 +1,392 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/regmap.h>
> +
> +#include "phy-mtk-mipi-csi-rx-reg.h"
> +
> +#define CSIxB_OFFSET 0x1000
> +
> +struct mtk_mipi_dphy;
> +
> +enum mtk_mipi_dphy_port_id {
> + MTK_MIPI_PHY_PORT_0 = 0x0, /* 4D1C - CDPHY */
> + MTK_MIPI_PHY_PORT_1, /* 4D1C - DPHY */
> + MTK_MIPI_PHY_PORT_2, /* 4D1C - DPHY */
> + MTK_MIPI_PHY_PORT_0A, /* 2D1C - CDPHY */
> + MTK_MIPI_PHY_PORT_0B, /* 2D1C - CDPHY */
> + MTK_MIPI_PHY_PORT_MAX_NUM
> +};
> +
> +struct mtk_mipi_dphy_port {
> + struct mtk_mipi_dphy *dev;
> + enum mtk_mipi_dphy_port_id id;
> + struct regmap *regmap_base;
> + struct regmap *regmap_4d1c;
Could you avoid using regmap if the registers are only used by this
driver, use phy-mtk-io.h api instead.

> + struct phy *phy;
> + bool active;
> + bool is_cdphy;
> + bool is_4d1c;
> +};
> +
> +struct mtk_mipi_dphy {
> + struct device *dev;
> + void __iomem *rx;
> + struct mtk_mipi_dphy_port ports[MTK_MIPI_PHY_PORT_MAX_NUM];
> + struct mutex lock; /* Ports CSI0 and CSI0A/B are mutually
> exclusive */
phy core already provides a mutex, no need provide another one.

Do you switch them at runtime for port 0?

From binding, I guess we use mtk_mipi_dphy_port_id in DTS to determine
which mode is used.

> +};
> +
> +#define REGMAP_BIT(map, reg, field, val) \
> + regmap_update_bits((map), reg, reg##_##field##_MASK, \
> + (val) << reg##_##field##_SHIFT)
> +
> +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);
> + 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;
> +}
> +
> +static int mtk_mipi_phy_power_off(struct phy *phy)
> +{
> + struct mtk_mipi_dphy_port *port = phy_get_drvdata(phy);
> + struct regmap *regmap_base = port->regmap_base;
> + struct regmap *regmap_4d1c = port->regmap_4d1c;
> +
> + /* Disable MIPI BG. */
> + REGMAP_BIT(regmap_base, MIPI_RX_ANA00_CSIxA,
> + RG_CSIxA_BG_CORE_EN, 0);
> + REGMAP_BIT(regmap_base, MIPI_RX_ANA00_CSIxA,
> + RG_CSIxA_BG_LPF_EN, 0);
> +
> + if (port->is_4d1c) {
> + REGMAP_BIT(regmap_4d1c, MIPI_RX_ANA00_CSIxA,
> + RG_CSIxA_BG_CORE_EN, 0);
> + REGMAP_BIT(regmap_4d1c, MIPI_RX_ANA00_CSIxA,
> + RG_CSIxA_BG_LPF_EN, 0);
> + }
> +
> + mutex_lock(&port->dev->lock);
> + port->active = false;
> + mutex_unlock(&port->dev->lock);
> +
> + return 0;
> +}
> +
> +static const struct phy_ops mtk_dphy_ops = {
> + .power_on = mtk_mipi_phy_power_on,
> + .power_off = mtk_mipi_phy_power_off,
> + .owner = THIS_MODULE,
> +};
> +
> +static struct phy *mtk_mipi_dphy_xlate(struct device *dev,
> + struct of_phandle_args *args)
> +{
> + struct mtk_mipi_dphy *priv = dev_get_drvdata(dev);
> +
> + if (args->args_count != 1)
> + return ERR_PTR(-EINVAL);
> +
> + if (args->args[0] >= ARRAY_SIZE(priv->ports))
> + return ERR_PTR(-ENODEV);
> +
> + return priv->ports[args->args[0]].phy;
> +}
> +
> +static const struct regmap_config mt8365_phy_regmap_config = {
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = 4,
> + .max_register = 0x700,
> +};
> +
> +static int mtk_mipi_dphy_probe(struct platform_device *pdev)
> +{
> + static const unsigned int ports_offsets[] = {
> + [MTK_MIPI_PHY_PORT_0] = 0,
> + [MTK_MIPI_PHY_PORT_0A] = 0,
> + [MTK_MIPI_PHY_PORT_0B] = 0x1000,
> + [MTK_MIPI_PHY_PORT_1] = 0x2000,
> + [MTK_MIPI_PHY_PORT_2] = 0x4000,
> + };
How about provide three subnode (p0/p1/p2)in dts like as tphy driver?

for the port 0, it works as three mode (*_0/0A/0B, or 4d1c/2d1c), we
can distinguish it from phy arguments, also the same for port 1/2

> +
> + struct device *dev = &pdev->dev;
> + struct phy_provider *phy_provider;
> + struct mtk_mipi_dphy *priv;
> + struct resource *res;
> + unsigned int i;
> +
> + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> +
> + dev_set_drvdata(dev, priv);
> + priv->dev = dev;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + priv->rx = devm_ioremap_resource(dev, res);
use devm_platform_ioremap_resource()

> + if (IS_ERR(priv->rx))
> + return PTR_ERR(priv->rx);
> +
> + for (i = 0; i < ARRAY_SIZE(priv->ports); ++i) {
> + struct mtk_mipi_dphy_port *port = &priv->ports[i];
> + struct phy *phy;
> + void __iomem *base;
> +
> + port->dev = priv;
> + port->id = i;
> + base = priv->rx + ports_offsets[i];
> +
> + port->regmap_base = devm_regmap_init_mmio(port->dev-
> >dev,
> + base,
> + &mt8365_phy
> _regmap_config);
> +
> + port->is_cdphy = i == MTK_MIPI_PHY_PORT_0A ||
> + i == MTK_MIPI_PHY_PORT_0B ||
> + i == MTK_MIPI_PHY_PORT_0;
> + port->is_4d1c = i < MTK_MIPI_PHY_PORT_0A;
> +
> + if (port->is_4d1c)
> + port->regmap_4d1c =
> devm_regmap_init_mmio(port->dev->dev,
> + bas
> e + CSIxB_OFFSET,
> + &mt
> 8365_phy_regmap_config);
> +
> + phy = devm_phy_create(dev, NULL, &mtk_dphy_ops);
> + if (IS_ERR(phy)) {
> + dev_err(dev, "Failed to create PHY: %ld\n",
> PTR_ERR(phy));
> + return PTR_ERR(phy);
> + }
> +
> + port->phy = phy;
> + phy_set_drvdata(phy, port);
> + }
> +
> + phy_provider = devm_of_phy_provider_register(dev,
> mtk_mipi_dphy_xlate);
> + if (IS_ERR(phy_provider)) {
> + dev_err(dev, "Failed to register PHY provider:
> %ld\n",
> + PTR_ERR(phy_provider));
> + return PTR_ERR(phy_provider);
> + }
> +
> + mutex_init(&priv->lock);
> +
> + return 0;
> +}
> +
> +static int mtk_mipi_dphy_remove(struct platform_device *pdev)
> +{
> + struct mtk_mipi_dphy *priv = platform_get_drvdata(pdev);
> +
> + mutex_destroy(&priv->lock);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id mtk_mipi_dphy_of_match[] = {
> + {.compatible = "mediatek,mt8365-mipi-csi"},
prefer to provide a generic compatible if not a specific controller
only for mt8365.

Thanks a lot
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, mtk_mipi_dphy_of_match);


> +
> +static struct platform_driver mipi_dphy_pdrv = {
> + .probe = mtk_mipi_dphy_probe,
> + .remove = mtk_mipi_dphy_remove,
> + .driver = {
> + .name = "mtk-mipi-csi",
> + .of_match_table =
> of_match_ptr(mtk_mipi_dphy_of_match),
> + },
> +};
> +
> +module_platform_driver(mipi_dphy_pdrv);
> +
> +MODULE_DESCRIPTION("MTK mipi csi cdphy driver");
> +MODULE_AUTHOR("Louis Kuo <[email protected]>");
> +MODULE_LICENSE("GPL");
> --
> 2.40.0
>