Skip to contentSkip to conversation

Synopsys DW DPHY Driver

PATCH In review Karthik Poduval 5 participants 18 messages Jul 10, 2025 – Jul 11, 2025

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

v2 cover Synopsys DW DPHY Driver

v2: fix dt_binding_check errors

Karthik Poduval (2):
phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX
phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI D-PHY RX

 .../bindings/phy/snps,dw-dphy-rx.yaml         |  44 ++
 MAINTAINERS                                   |   7 +
 drivers/phy/Kconfig                           |  11 +
 drivers/phy/Makefile                          |   1 +
 drivers/phy/phy-dw-dphy.c                     | 575 ++++++++++++++++++
 5 files changed, 638 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml
 create mode 100644 drivers/phy/phy-dw-dphy.c
Signature · 1 line
2.43.0
#1 lore raw

PATCH v2 1/2 phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX

Add support for Synopsys DesignWare MIPI D-PHY RX v1.2. The driver supports data rates from 80Mbps to 2500Mbps.

---
 drivers/phy/Kconfig       |  11 +
 drivers/phy/Makefile      |   1 +
 drivers/phy/phy-dw-dphy.c | 575 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 587 insertions(+)
 create mode 100644 drivers/phy/phy-dw-dphy.c
drivers/phy/Kconfig +11 -0
index 58c911e1b2d2..34c245ca5d12 100644
@@ -101,6 +101,17 @@ config PHY_NXP_PTN3222
 	  schemes. It supports all three USB 2.0 data rates: Low Speed, Full
 	  Speed and High Speed.
 
+config PHY_SYNOPSYS_DW_DPHY_RX
+	tristate "Synopsys DesignWare D-PHY Rx Support"
+	depends on HAS_IOMEM && REGMAP_MMIO
+	select GENERIC_PHY
+	select GENERIC_PHY_MIPI_DPHY
+	help
+	  This option enables support for Synopsys DW MIPI D-PHY RX IP. This driver
+	  provides D-PHY functionality using Generic PHY framework and is meant to
+	  be used by MIPI CSI2 receivers over the PPI hardware interface. MIPI CSI2
+	  receivers may find this driver and use it via Generic PHY Framework API.
+
 source "drivers/phy/allwinner/Kconfig"
 source "drivers/phy/amlogic/Kconfig"
 source "drivers/phy/broadcom/Kconfig"
drivers/phy/Makefile +1 -0
index c670a8dac468..ed0836adb835 100644
@@ -13,6 +13,7 @@ obj-$(CONFIG_PHY_SNPS_EUSB2)		+= phy-snps-eusb2.o
 obj-$(CONFIG_USB_LGM_PHY)		+= phy-lgm-usb.o
 obj-$(CONFIG_PHY_AIROHA_PCIE)		+= phy-airoha-pcie.o
 obj-$(CONFIG_PHY_NXP_PTN3222)		+= phy-nxp-ptn3222.o
+obj-$(CONFIG_PHY_SYNOPSYS_DW_DPHY_RX)	+= phy-dw-dphy.o
 obj-y					+= allwinner/	\
 					   amlogic/	\
 					   broadcom/	\
drivers/phy/phy-dw-dphy.c new file +575 -0

575 lines not on this page · raw message

Signature · 1 line
2.43.0
maintainer
#2 lore raw

Re: [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX

Quoted 534 lines · Karthik Poduval

Add support for Synopsys DesignWare MIPI D-PHY RX v1.2. The driver supports data rates from 80Mbps to 2500Mbps.

---
 drivers/phy/Kconfig       |  11 +
 drivers/phy/Makefile      |   1 +
 drivers/phy/phy-dw-dphy.c | 575 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 587 insertions(+)
 create mode 100644 drivers/phy/phy-dw-dphy.c
drivers/phy/Kconfig +11 -0
index 58c911e1b2d2..34c245ca5d12 100644
@@ -101,6 +101,17 @@ config PHY_NXP_PTN3222
 	  schemes. It supports all three USB 2.0 data rates: Low Speed, Full
 	  Speed and High Speed.
 
+config PHY_SYNOPSYS_DW_DPHY_RX
+	tristate "Synopsys DesignWare D-PHY Rx Support"
+	depends on HAS_IOMEM && REGMAP_MMIO
+	select GENERIC_PHY
+	select GENERIC_PHY_MIPI_DPHY
+	help
+	  This option enables support for Synopsys DW MIPI D-PHY RX IP. This driver
+	  provides D-PHY functionality using Generic PHY framework and is meant to
+	  be used by MIPI CSI2 receivers over the PPI hardware interface. MIPI CSI2
+	  receivers may find this driver and use it via Generic PHY Framework API.
+
 source "drivers/phy/allwinner/Kconfig"
 source "drivers/phy/amlogic/Kconfig"
 source "drivers/phy/broadcom/Kconfig"
drivers/phy/Makefile +1 -0
index c670a8dac468..ed0836adb835 100644
@@ -13,6 +13,7 @@ obj-$(CONFIG_PHY_SNPS_EUSB2)		+= phy-snps-eusb2.o
 obj-$(CONFIG_USB_LGM_PHY)		+= phy-lgm-usb.o
 obj-$(CONFIG_PHY_AIROHA_PCIE)		+= phy-airoha-pcie.o
 obj-$(CONFIG_PHY_NXP_PTN3222)		+= phy-nxp-ptn3222.o
+obj-$(CONFIG_PHY_SYNOPSYS_DW_DPHY_RX)	+= phy-dw-dphy.o
 obj-y					+= allwinner/	\
 					   amlogic/	\
 					   broadcom/	\
drivers/phy/phy-dw-dphy.c new file +483 -0
new file mode 100644
index 000000000000..2248f690b861
@@ -0,0 +1,575 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright © 2025 Amazon.com, Inc. or its affiliates.
+ * Copyright © 2025 Synopsys, Inc. (www.synopsys.com)
+ */
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/regmap.h>
+
+#include <linux/phy/phy.h>
+#include <linux/phy/phy-mipi-dphy.h>
+
+#define KHZ (1000)
+#define MHZ (KHZ * KHZ)
+
+enum dw_dphy_reg_fields_cfg1 {
+	PHY_SHUTDOWNZ,
+	DPHY_RSTZ,
+	TEST_CLR,
+	TEST_CLK,
+	TEST_IN,
+	TEST_OUT,
+	TEST_EN,
+	DW_DPHY_RF_CFG1_MAX
+};
+
+enum dw_dphy_reg_fields_cfg2 {
+	EN_CONT_REG_UPDATE,
+	TURN_REQUEST_0,
+	TURN_DISABLE_0,
+	ENABLE_CLK,
+	FORCE_TX_STOP_MODE_0,
+	FORCE_RX_MODE,
+	BASE_DIR_0,
+	CFG_CLK_FREQ_RANGE,
+	HS_FREQ_RANGE,
+	CONT_EN,
+	DW_DPHY_RF_CFG2_MAX
+};
+
+static const struct reg_field dw_dphy_v1_2_cfg1[DW_DPHY_RF_CFG1_MAX] = {
+	[PHY_SHUTDOWNZ] = REG_FIELD(0x0, 0, 0),
+	[DPHY_RSTZ] = REG_FIELD(0x4, 0, 0),
+	[TEST_CLR] = REG_FIELD(0x10, 0, 0),
+	[TEST_CLK] = REG_FIELD(0x10, 1, 1),
+	[TEST_IN] = REG_FIELD(0x14, 0, 7),
+	[TEST_OUT] = REG_FIELD(0x14, 8, 15),
+	[TEST_EN] = REG_FIELD(0x14, 16, 16),
+};
+
+static const struct reg_field dw_dphy_v1_2_cfg2[DW_DPHY_RF_CFG2_MAX] = {
+	[EN_CONT_REG_UPDATE] = REG_FIELD(0x0, 23, 23),
+	[TURN_REQUEST_0] = REG_FIELD(0x0, 22, 22),
+	[TURN_DISABLE_0] = REG_FIELD(0x0, 21, 21),
+	[ENABLE_CLK] = REG_FIELD(0x0, 20, 20),
+	[FORCE_TX_STOP_MODE_0] = REG_FIELD(0x0, 19, 19),
+	[FORCE_RX_MODE] = REG_FIELD(0x0, 15, 18),
+	[BASE_DIR_0] = REG_FIELD(0x0, 14, 14),
+	[CFG_CLK_FREQ_RANGE] = REG_FIELD(0x0, 8, 13),
+	[HS_FREQ_RANGE] = REG_FIELD(0x0, 1, 7),
+	[CONT_EN] = REG_FIELD(0x0, 0, 0),
+};
+
+enum dphy_12bit_interface_addr {
+	RX_SYS_0 = 0x01,
+	RX_SYS_1 = 0x02,
+	RX_SYS_7 = 0x08,
+	RX_RX_STARTUP_OVR_0 = 0xe0,
+	RX_RX_STARTUP_OVR_1 = 0xe1,
+	RX_RX_STARTUP_OVR_2 = 0xe2,
+	RX_RX_STARTUP_OVR_3 = 0xe3,
+	RX_RX_STARTUP_OVR_4 = 0xe4,
+};
+
+/**
+ * struct range_dphy_gen3 - frequency range calibration structure
+ *
+ * @freq: input freqency to calibration table
+ * @hsfregrange: corresponding clock to configure DW D-PHY IP
+ * @osc_freq_target: corresponding clock to configure DW D-PHY IP
+ *
+ **/
+struct range_dphy_gen3 {
+	u32 freq;
+	u8 hsfregrange;
+	u32 osc_freq_target;
+};
+
+/**
+ * struct dt_data_dw_dphy - DPHY configuration data structure
+ * @table: Pointer to array of DPHY Gen3 timing range configurations
+ * @table_size: Number of entries in the timing range table
+ * @phy_ops: Pointer to PHY operations structure containing callback functions
+ *
+ **/
+struct dt_data_dw_dphy {
+	struct range_dphy_gen3 *table;
+	int table_size;
+	const struct phy_ops *phy_ops;
+};
+
+/*
+ * DW DPHY Gen3 calibration table
+ *
+ */
+struct range_dphy_gen3 range_gen3[] = {
+	{ 80, 0b0000000, 460 },	  { 90, 0b0010000, 460 },
+	{ 100, 0b0100000, 460 },  { 110, 0b0110000, 460 },
+	{ 120, 0b0000001, 460 },  { 130, 0b0010001, 460 },
+	{ 140, 0b0100001, 460 },  { 150, 0b0110001, 460 },
+	{ 160, 0b0000010, 460 },  { 170, 0b0010010, 460 },
+	{ 180, 0b0100010, 460 },  { 190, 0b0110010, 460 },
+	{ 205, 0b0000011, 460 },  { 220, 0b0010011, 460 },
+	{ 235, 0b0100011, 460 },  { 250, 0b0110011, 460 },
+	{ 275, 0b0000100, 460 },  { 300, 0b0010100, 460 },
+	{ 325, 0b0100101, 460 },  { 350, 0b0110101, 460 },
+	{ 400, 0b0000101, 460 },  { 450, 0b0010110, 460 },
+	{ 500, 0b0100110, 460 },  { 550, 0b0110111, 460 },
+	{ 600, 0b0000111, 460 },  { 650, 0b0011000, 460 },
+	{ 700, 0b0101000, 460 },  { 750, 0b0111001, 460 },
+	{ 800, 0b0001001, 460 },  { 850, 0b0011001, 460 },
+	{ 900, 0b0101001, 460 },  { 950, 0b0111010, 460 },
+	{ 1000, 0b0001010, 460 }, { 1050, 0b0011010, 460 },
+	{ 1110, 0b0101010, 460 }, { 1150, 0b0111011, 460 },
+	{ 1200, 0b0001011, 460 }, { 1250, 0b0011011, 460 },
+	{ 1300, 0b0101011, 460 }, { 1350, 0b0111100, 460 },
+	{ 1400, 0b0001100, 460 }, { 1450, 0b0011100, 460 },
+	{ 1500, 0b0101100, 460 }, { 1550, 0b0111101, 285 },
+	{ 1600, 0b0001101, 295 }, { 1650, 0b0011101, 304 },
+	{ 1700, 0b0101110, 313 }, { 1750, 0b0111110, 322 },
+	{ 1800, 0b0001110, 331 }, { 1850, 0b0011110, 341 },
+	{ 1900, 0b0101111, 350 }, { 1950, 0b0111111, 359 },
+	{ 2000, 0b0001111, 368 }, { 2050, 0b1000000, 377 },
+	{ 2100, 0b1000001, 387 }, { 2150, 0b1000010, 396 },
+	{ 2200, 0b1000011, 405 }, { 2250, 0b1000100, 414 },
+	{ 2300, 0b1000101, 423 }, { 2350, 0b1000110, 432 },
+	{ 2400, 0b1000111, 442 }, { 2450, 0b1001000, 451 },
+	{ 2500, 0b1001001, 460 }
+};
+
+/**
+ * struct dw_dphy - DW D-PHY driver private structure
+ *
+ * @regmap: pointer to regmap
+ * @regmap_cfg1: pointer to config1 regmap
+ * @regmap_cfg2: pointer to config2 regmap
+ * @rf_cfg1: array of regfields for config1
+ * @rf_cfg2: array of regfields for config2
+ * @iomem_cfg1: MMIO address for cfg1 section
+ * @iomem_cfg2: MMIO address for cfg2 section
+ * @phy: pointer to the phy data structure
+ * @hs_clk_rate: high speed clock rate as per image sensor configuration
+ * @dt_data_dw_dphy: device tree specific data
+ *
+ **/
+struct dw_dphy {
+	struct regmap *regmap_cfg1;
+	struct regmap *regmap_cfg2;
+	struct regmap_field *rf_cfg1[DW_DPHY_RF_CFG1_MAX];
+	struct regmap_field *rf_cfg2[DW_DPHY_RF_CFG2_MAX];
+	void __iomem *iomem_cfg1;
+	void __iomem *iomem_cfg2;
+	struct phy *phy;
+	struct device *dev;
+	unsigned long hs_clk_rate;
+	struct dt_data_dw_dphy *dt_data;
+};
+
+/**
+ * dw_dphy_te_write - write register into test enable interface
+ *
+ * @dphy: pointer to the dw_dphy private data structure
+ * @addr: 12 bit TE address register (16 bit container)
+ * @data: 8 bit data to be written to TE register
+ *
+ **/
+static void dw_dphy_te_write(struct dw_dphy *dphy, u16 addr, u8 data)
+{
+	/* For writing the 4-bit testcode MSBs */
+
+	/* Ensure that testclk and testen is set to low */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
+	regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
+
+	/* Set testen to high */
+	regmap_field_write(dphy->rf_cfg1[TEST_EN], 1);
+
+	/* Set testclk to high */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
+
+	/* Place 0x00 in testdin */
+	regmap_field_write(dphy->rf_cfg1[TEST_IN], 0);
+
+	/*
+	 * Set testclk to low (with the falling edge on testclk, the testdin signal
+	 * content is latched internally)
+	 */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
+
+	/* Set testen to low */
+	regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
+
+	/* Place the 8-bit word corresponding to the testcode MSBs in testdin */
+	regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr >> 8));
+
+	/* Set testclk to high */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
+
+	/* For writing the 8-bit testcode LSBs */
+
+	/* Set testclk to low */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
+
+	/* Set testen to high */
+	regmap_field_write(dphy->rf_cfg1[TEST_EN], 1);
+
+	/* Set testclk to high */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
+
+	/* Place the 8-bit word test data in testdin */
+	regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr & 0xff));
+
+	/*
+	 * Set testclk to low (with the falling edge on testclk, the testdin signal
+	 * content is latched internally)
+	 */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
+
+	/* Set testen to low */
+	regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
+
+	/* For writing the data */
+
+	/* Place the 8-bit word corresponding to the page offset in testdin */
+	regmap_field_write(dphy->rf_cfg1[TEST_IN], data);
+
+	/* Set testclk to high (test data is programmed internally) */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
+}
+
+/**
+ * dw_dphy_te_read - read register from test enable interface
+ *
+ * @dphy: pointer to the dw_dphy private data structure
+ * @addr: 12 bit TE address register (16 bit container)
+ * @returns: 8 bit data from TE register
+ **/
+static u8 dw_dphy_te_read(struct dw_dphy *dphy, u16 addr)
+{
+	u32 data;
+
+	/* For writing the 4-bit testcode MSBs */
+
+	/* Ensure that testclk and testen is set to low */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
+	regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
+
+	/* Set testen to high */
+	regmap_field_write(dphy->rf_cfg1[TEST_EN], 1);
+
+	/* Set testclk to high */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
+
+	/* Place 0x00 in testdin */
+	regmap_field_write(dphy->rf_cfg1[TEST_IN], 0);
+
+	/*
+	 * Set testclk to low (with the falling edge on testclk, the testdin signal
+	 * content is latched internally)
+	 */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
+
+	/* Set testen to low */
+	regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
+
+	/* Place the 8-bit word corresponding to the testcode MSBs in testdin */
+	regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr >> 8));
+
+	/* Set testclk to high */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
+
+	/* For writing the 8-bit testcode LSBs */
+
+	/* Set testclk to low */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
+
+	/* Set testen to high */
+	regmap_field_write(dphy->rf_cfg1[TEST_EN], 1);
+
+	/* Set testclk to high */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
+
+	/* Place the 8-bit word test data in testdin */
+	regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr & 0xff));
+
+	/*
+	 * Set testclk to low (with the falling edge on testclk, the testdin signal
+	 * content is latched internally)
+	 */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
+
+	/* Set testen to low */
+	regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
+
+	regmap_field_read(dphy->rf_cfg1[TEST_OUT], &data);
+
+	return (u8)data;
+}
+
+/**
+ * dw_dphy_configure - configure the D-PHY
+ *
+ * @phy: pointer to the phy data structure
+ * @opts: pointer to the phy configuration options
+ * @returns 0 if success else appropriate error code
+ *
+ **/
+static int dw_dphy_configure(struct phy *phy, union phy_configure_opts *opts)
+{
+	struct dw_dphy *dphy = phy_get_drvdata(phy);
+
+	dphy->hs_clk_rate = opts->mipi_dphy.hs_clk_rate;
+	dev_dbg(dphy->dev, "hs_clk_rate=%ld\n", dphy->hs_clk_rate);
+
+	return 0;
+}
+
+/**
+ * dw_dphy_power_on_1p2 - power on the DPHY version 1.2
+ *
+ * @phy: pointer to the phy data structure
+ * @returns 0 if success else appropriate error code
+ *
+ **/
+static int dw_dphy_power_on_1p2(struct phy *phy)
+{
+	struct dw_dphy *dphy = phy_get_drvdata(phy);
+
+	uint8_t counter_for_des_en_config_if_rw = 0x1;
+	u8 range = 0;
+
+	for (range = 0;
+	     (range < dphy->dt_data->table_size - 1) &&
+	     ((dphy->hs_clk_rate) > dphy->dt_data->table[range].freq);
+	     range++)
+		;
+
+	/* in case requested hs_clk_rate is out of range, return -EINVAL */
+	if (range >= dphy->dt_data->table_size)
+		return -EINVAL;
+
+	dev_dbg(dphy->dev, "12bit: PHY GEN 3: Freq: %ld %x\n", dphy->hs_clk_rate,
+		 range_gen3[range].hsfregrange);
+
+	regmap_field_write(dphy->rf_cfg1[DPHY_RSTZ], 0);
+	regmap_field_write(dphy->rf_cfg1[PHY_SHUTDOWNZ], 0);
+	regmap_field_write(dphy->rf_cfg1[TEST_CLR], 0);
+	regmap_field_write(dphy->rf_cfg1[TEST_CLR], 1);
+	regmap_field_write(dphy->rf_cfg1[TEST_CLR], 0);
+	regmap_field_write(dphy->rf_cfg2[CFG_CLK_FREQ_RANGE], 0x28);
+	dw_dphy_te_write(dphy, RX_SYS_1,
+			 dphy->dt_data->table[range].hsfregrange);
+	dw_dphy_te_write(dphy, RX_SYS_0, 0x20);
+	dw_dphy_te_write(dphy, RX_RX_STARTUP_OVR_2,
+			 (u8)dphy->dt_data->table[range].osc_freq_target);
+	dw_dphy_te_write(dphy, RX_RX_STARTUP_OVR_3,
+			 (u8)(dphy->dt_data->table[range].osc_freq_target >>
+			      8));
+	dw_dphy_te_write(dphy, 0xe4,
+			 (counter_for_des_en_config_if_rw << 4) | 0b1);
+
+	dw_dphy_te_write(dphy, RX_RX_STARTUP_OVR_1, 0x01);
+	dw_dphy_te_write(dphy, RX_RX_STARTUP_OVR_0, 0x80);
+
+	regmap_field_write(dphy->rf_cfg2[BASE_DIR_0], 1);
+	regmap_field_write(dphy->rf_cfg2[ENABLE_CLK], 1);
+	regmap_field_write(dphy->rf_cfg2[FORCE_RX_MODE], 0x0);
+
+	regmap_field_write(dphy->rf_cfg1[PHY_SHUTDOWNZ], 1);
+	regmap_field_write(dphy->rf_cfg1[DPHY_RSTZ], 1);
+
+	return 0;
+}
+
+/**
+ * dw_dphy_power_off - power off the DPHY
+ *
+ * @phy: pointer to the phy data structure
+ * @returns 0 if success else appropriate error code
+ *
+ **/
+static int dw_dphy_power_off(struct phy *phy)
+{
+	struct dw_dphy *dphy = phy_get_drvdata(phy);
+
+	regmap_field_write(dphy->rf_cfg1[DPHY_RSTZ], 0);
+	regmap_field_write(dphy->rf_cfg1[PHY_SHUTDOWNZ], 0);
+	return 0;
+}
+
+/**
+ * dw_dphy_ops_1p2 - PHY operations for DWC DPHY v1.2
+ * @configure: Configures DPHY timing and operation parameters
+ * @power_on: Powers on the DPHY using v1.2 specific sequence
+ * @power_off: Powers off the DPHY
+ *
+ **/
+static const struct phy_ops dw_dphy_ops_1p2 = {
+	.configure = dw_dphy_configure,
+	.power_on = dw_dphy_power_on_1p2,
+	.power_off = dw_dphy_power_off,
+};
+
+/**
+ * dw_dphy_1p2 - DWC DPHY v1.2 configuration instance
+ * @table: Points to range_gen3 timing parameters table
+ * @table_size: Size of range_gen3 table calculated at compile time
+ * @phy_ops: Points to v1.2 specific PHY operations structure
+ *
+ **/
+struct dt_data_dw_dphy dw_dphy_1p2 = {
+	.table = range_gen3,
+	.table_size = ARRAY_SIZE(range_gen3),
+	.phy_ops = &dw_dphy_ops_1p2,
+};
+
+/**
+ * dw_dphy_regmap_cfg1 - Register map configuration for DW DPHY
+ * @reg_bits: Width of register address in bits (32)
+ * @val_bits: Width of register value in bits (32)
+ * @reg_stride: Number of bytes between registers (4)
+ * @name: Name identifier for this register map
+ * @fast_io: Flag to indicate fast I/O operations are supported
+ *
+ **/
+static const struct regmap_config dw_dphy_regmap_cfg1 = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
+	.name = "dw-dhpy-cfg1",
+	.fast_io = true,
+};
+
+/**
+ * dw_dphy_regmap_cfg2 - Register map configuration for DW DPHY
+ * @reg_bits: Width of register address in bits (32)
+ * @val_bits: Width of register value in bits (32)
+ * @reg_stride: Number of bytes between registers (4)
+ * @name: Name identifier for this register map
+ * @fast_io: Flag to indicate fast I/O operations are supported
+ *
+ **/
+static const struct regmap_config dw_dphy_regmap_cfg2 = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
+	.name = "dw-dhpy-cfg2",
+	.fast_io = true,
+};
+
+/**
+ * dw_dphy_probe - Probe and initialize DW DPHY device
+ * @pdev: Platform device pointer
+ * Return: 0 on success, negative error code on failure
+ *
+ **/
+static int dw_dphy_probe(struct platform_device *pdev)
+{
+	struct dw_dphy *dphy;
+	struct resource *res;
+	struct device *dev = &pdev->dev;
+	struct phy_provider *phy_provider;
+	int ret;
+
+	dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL);
+	if (!dphy)
+		return -ENOMEM;

drivers/phy/phy-dw-dphy.c line 493

Quoted 10 lines
drivers/phy/phy-dw-dphy.c new file +10 -0
+
+	dphy->dt_data =
+		(struct dt_data_dw_dphy *)of_device_get_match_data(&pdev->dev);
+	dev_set_drvdata(&pdev->dev, dphy);
+	dphy->dev = &pdev->dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	dphy->iomem_cfg1 = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(dphy->iomem_cfg1))
+		return PTR_ERR(dphy->iomem_cfg1);

cfg1 is part of DW MIPI-CSI2 MMIO space. how to cooperate with dw MIPI-CSI2 controller.

Please CC me for next version. I am working on DW MIPI-CSI2 work.

https://lore.kernel.org/imx/[email protected]/

Frank

Quoted 85 lines
drivers/phy/phy-dw-dphy.c new file +82 -1
+
+	dphy->regmap_cfg1 =
+		devm_regmap_init_mmio(dev, dphy->iomem_cfg1, &dw_dphy_regmap_cfg1);
+	if (IS_ERR(dphy->regmap_cfg1))
+		return PTR_ERR(dphy->regmap_cfg1);
+
+	ret = devm_regmap_field_bulk_alloc(dev, dphy->regmap_cfg1, dphy->rf_cfg1,
+					   dw_dphy_v1_2_cfg1, DW_DPHY_RF_CFG1_MAX);
+	if (ret < 0) {
+		dev_err(dev, "Could not alloc RF\n");
+		return ret;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	dphy->iomem_cfg2 = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(dphy->iomem_cfg2))
+		return PTR_ERR(dphy->iomem_cfg2);
+
+	dphy->regmap_cfg2 = devm_regmap_init_mmio(dev, dphy->iomem_cfg2,
+						 &dw_dphy_regmap_cfg2);
+	if (IS_ERR(dphy->regmap_cfg2))
+		return PTR_ERR(dphy->regmap_cfg2);
+
+	ret = devm_regmap_field_bulk_alloc(dev, dphy->regmap_cfg2, dphy->rf_cfg2,
+					   dw_dphy_v1_2_cfg2, DW_DPHY_RF_CFG2_MAX);
+	if (ret < 0) {
+		dev_err(dev, "Could not alloc RF\n");
+		return ret;
+	}
+
+	dphy->phy = devm_phy_create(&pdev->dev, NULL, dphy->dt_data->phy_ops);
+	if (IS_ERR(dphy->phy)) {
+		dev_err(dev, "failed to create PHY\n");
+		return PTR_ERR(dphy->phy);
+	}
+
+	phy_set_drvdata(dphy->phy, dphy);
+	phy_provider =
+		devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
+
+	return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+/**
+ * dw_dphy_of_match - Device tree match table for DW DPHY
+ * @compatible: Compatible string to match device tree node
+ * @data: Pointer to configuration data for matched device
+ *
+ * Table of compatible strings and associated configuration data
+ * for supported DW DPHY variants.
+ * Currently supports:
+ * - DW DPHY v1.2 ("snps,dw-dphy-1p2")
+ *
+ **/
+static const struct of_device_id dw_dphy_of_match[] = {
+	{ .compatible = "snps,dw-dphy-1p2", .data = &dw_dphy_1p2 },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, dw_dphy_of_match);
+
+/**
+ * dw_dphy_platform_driver - Platform driver structure for DW DPHY
+ * @probe: Pointer to probe function called on device discovery
+ * @driver: Core driver structure containing:
+ *         - name: Driver name used for matching and debugging
+ *         - of_match_table: Table of compatible device tree matches
+ *
+ **/
+static struct platform_driver dw_dphy_platform_driver = {
+	.probe		= dw_dphy_probe,
+	.driver		= {
+		.name		= "dw-dphy",
+		.of_match_table	= dw_dphy_of_match,
+	},
+};
+module_platform_driver(dw_dphy_platform_driver);
+
+MODULE_AUTHOR("Karthik Poduval <[email protected]>");
+MODULE_AUTHOR("Jason Xiong <[email protected]>");
+MODULE_AUTHOR("Miguel Lopes <[email protected]>");
+MODULE_DESCRIPTION("DW D-PHY RX Driver");
+MODULE_LICENSE("GPL");
--

2.43.0

#3 lore raw

Re: [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX

Quoted 577 lines · Frank Li

CAUTION: This email originated from outside of the organization. Do not click links or open attachments unless you can confirm the sender and know the content is safe.

Quoted 570 lines · Karthik Poduval

Add support for Synopsys DesignWare MIPI D-PHY RX v1.2. The driver supports data rates from 80Mbps to 2500Mbps.

---
 drivers/phy/Kconfig       |  11 +
 drivers/phy/Makefile      |   1 +
 drivers/phy/phy-dw-dphy.c | 575
++++++++++++++++++++++++++++++++++++++

 3 files changed, 587 insertions(+)

 create mode 100644 drivers/phy/phy-dw-dphy.c

drivers/phy/Kconfig +0 -0
index 58c911e1b2d2..34c245ca5d12 100644
@@ -101,6 +101,17 @@ config PHY_NXP_PTN3222

        schemes. It supports all three USB 2.0 data rates: Low Speed, Full
        Speed and High Speed.

+config PHY_SYNOPSYS_DW_DPHY_RX
+     tristate "Synopsys DesignWare D-PHY Rx Support"
+     depends on HAS_IOMEM && REGMAP_MMIO
+     select GENERIC_PHY
+     select GENERIC_PHY_MIPI_DPHY
+     help
+       This option enables support for Synopsys DW MIPI D-PHY RX IP. This driver
+       provides D-PHY functionality using Generic PHY framework and is meant to
+       be used by MIPI CSI2 receivers over the PPI hardware interface. MIPI CSI2
+       receivers may find this driver and use it via Generic PHY Framework API.
+
 source "drivers/phy/allwinner/Kconfig"
 source "drivers/phy/amlogic/Kconfig"
 source "drivers/phy/broadcom/Kconfig"

drivers/phy/Makefile +0 -0
index c670a8dac468..ed0836adb835 100644
@@ -13,6 +13,7 @@ obj-$(CONFIG_PHY_SNPS_EUSB2)                +=

phy-snps-eusb2.o
 obj-$(CONFIG_USB_LGM_PHY)            += phy-lgm-usb.o obj-$(CONFIG_PHY_AIROHA_PCIE)                += phy-airoha-pcie.o obj-$(CONFIG_PHY_NXP_PTN3222)                += phy-nxp-ptn3222.o +obj-$(CONFIG_PHY_SYNOPSYS_DW_DPHY_RX)        += phy-dw-dphy.o obj-y                                        += allwinner/   \
                                         amlogic/     \
                                         broadcom/    \

drivers/phy/phy-dw-dphy.c new file +47 -0
new file mode 100644
index 000000000000..2248f690b861
@@ -0,0 +1,575 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright © 2025 Amazon.com, Inc. or its affiliates.
+ * Copyright © 2025 Synopsys, Inc. (www.synopsys.com)
+ */
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/regmap.h>
+
+#include <linux/phy/phy.h>
+#include <linux/phy/phy-mipi-dphy.h>
+
+#define KHZ (1000)
+#define MHZ (KHZ * KHZ)
+
+enum dw_dphy_reg_fields_cfg1 {
+     PHY_SHUTDOWNZ,
+     DPHY_RSTZ,
+     TEST_CLR,
+     TEST_CLK,
+     TEST_IN,
+     TEST_OUT,
+     TEST_EN,
+     DW_DPHY_RF_CFG1_MAX
+};
+
+enum dw_dphy_reg_fields_cfg2 {
+     EN_CONT_REG_UPDATE,
+     TURN_REQUEST_0,
+     TURN_DISABLE_0,
+     ENABLE_CLK,
+     FORCE_TX_STOP_MODE_0,
+     FORCE_RX_MODE,
+     BASE_DIR_0,
+     CFG_CLK_FREQ_RANGE,
+     HS_FREQ_RANGE,
+     CONT_EN,
+     DW_DPHY_RF_CFG2_MAX
+};
+
+static const struct reg_field

dw_dphy_v1_2_cfg1[DW_DPHY_RF_CFG1_MAX] = {
+     [PHY_SHUTDOWNZ] = REG_FIELD(0x0, 0, 0),
+     [DPHY_RSTZ] = REG_FIELD(0x4, 0, 0),
+     [TEST_CLR] = REG_FIELD(0x10, 0, 0),
+     [TEST_CLK] = REG_FIELD(0x10, 1, 1),
+     [TEST_IN] = REG_FIELD(0x14, 0, 7),
+     [TEST_OUT] = REG_FIELD(0x14, 8, 15),
+     [TEST_EN] = REG_FIELD(0x14, 16, 16),

drivers/phy/phy-dw-dphy.c new file +3 -0
+};
+
+static const struct reg_field

dw_dphy_v1_2_cfg2[DW_DPHY_RF_CFG2_MAX] = {
+     [EN_CONT_REG_UPDATE] = REG_FIELD(0x0, 23, 23), +     [TURN_REQUEST_0] = REG_FIELD(0x0, 22, 22), +     [TURN_DISABLE_0] = REG_FIELD(0x0, 21, 21), +     [ENABLE_CLK] = REG_FIELD(0x0, 20, 20), +     [FORCE_TX_STOP_MODE_0] = REG_FIELD(0x0, 19, 19), +     [FORCE_RX_MODE] = REG_FIELD(0x0, 15, 18), +     [BASE_DIR_0] = REG_FIELD(0x0, 14, 14), +     [CFG_CLK_FREQ_RANGE] = REG_FIELD(0x0, 8, 13), +     [HS_FREQ_RANGE] = REG_FIELD(0x0, 1, 7), +     [CONT_EN] = REG_FIELD(0x0, 0, 0),

drivers/phy/phy-dw-dphy.c new file +30 -0
+};
+
+enum dphy_12bit_interface_addr {
+     RX_SYS_0 = 0x01,
+     RX_SYS_1 = 0x02,
+     RX_SYS_7 = 0x08,
+     RX_RX_STARTUP_OVR_0 = 0xe0,
+     RX_RX_STARTUP_OVR_1 = 0xe1,
+     RX_RX_STARTUP_OVR_2 = 0xe2,
+     RX_RX_STARTUP_OVR_3 = 0xe3,
+     RX_RX_STARTUP_OVR_4 = 0xe4,
+};
+
+/**
+ * struct range_dphy_gen3 - frequency range calibration structure
+ *
+ * @freq: input freqency to calibration table
+ * @hsfregrange: corresponding clock to configure DW D-PHY IP
+ * @osc_freq_target: corresponding clock to configure DW D-PHY IP
+ *
+ **/
+struct range_dphy_gen3 {
+     u32 freq;
+     u8 hsfregrange;
+     u32 osc_freq_target;
+};
+
+/**
+ * struct dt_data_dw_dphy - DPHY configuration data structure
+ * @table: Pointer to array of DPHY Gen3 timing range

configurations
+ * @table_size: Number of entries in the timing range table
+ * @phy_ops: Pointer to PHY operations structure containing callback functions
+ *
+ **/

drivers/phy/phy-dw-dphy.c new file +57 -0
+struct dt_data_dw_dphy {
+     struct range_dphy_gen3 *table;
+     int table_size;
+     const struct phy_ops *phy_ops;
+};
+
+/*
+ * DW DPHY Gen3 calibration table
+ *
+ */
+struct range_dphy_gen3 range_gen3[] = {
+     { 80, 0b0000000, 460 },   { 90, 0b0010000, 460 },
+     { 100, 0b0100000, 460 },  { 110, 0b0110000, 460 },
+     { 120, 0b0000001, 460 },  { 130, 0b0010001, 460 },
+     { 140, 0b0100001, 460 },  { 150, 0b0110001, 460 },
+     { 160, 0b0000010, 460 },  { 170, 0b0010010, 460 },
+     { 180, 0b0100010, 460 },  { 190, 0b0110010, 460 },
+     { 205, 0b0000011, 460 },  { 220, 0b0010011, 460 },
+     { 235, 0b0100011, 460 },  { 250, 0b0110011, 460 },
+     { 275, 0b0000100, 460 },  { 300, 0b0010100, 460 },
+     { 325, 0b0100101, 460 },  { 350, 0b0110101, 460 },
+     { 400, 0b0000101, 460 },  { 450, 0b0010110, 460 },
+     { 500, 0b0100110, 460 },  { 550, 0b0110111, 460 },
+     { 600, 0b0000111, 460 },  { 650, 0b0011000, 460 },
+     { 700, 0b0101000, 460 },  { 750, 0b0111001, 460 },
+     { 800, 0b0001001, 460 },  { 850, 0b0011001, 460 },
+     { 900, 0b0101001, 460 },  { 950, 0b0111010, 460 },
+     { 1000, 0b0001010, 460 }, { 1050, 0b0011010, 460 },
+     { 1110, 0b0101010, 460 }, { 1150, 0b0111011, 460 },
+     { 1200, 0b0001011, 460 }, { 1250, 0b0011011, 460 },
+     { 1300, 0b0101011, 460 }, { 1350, 0b0111100, 460 },
+     { 1400, 0b0001100, 460 }, { 1450, 0b0011100, 460 },
+     { 1500, 0b0101100, 460 }, { 1550, 0b0111101, 285 },
+     { 1600, 0b0001101, 295 }, { 1650, 0b0011101, 304 },
+     { 1700, 0b0101110, 313 }, { 1750, 0b0111110, 322 },
+     { 1800, 0b0001110, 331 }, { 1850, 0b0011110, 341 },
+     { 1900, 0b0101111, 350 }, { 1950, 0b0111111, 359 },
+     { 2000, 0b0001111, 368 }, { 2050, 0b1000000, 377 },
+     { 2100, 0b1000001, 387 }, { 2150, 0b1000010, 396 },
+     { 2200, 0b1000011, 405 }, { 2250, 0b1000100, 414 },
+     { 2300, 0b1000101, 423 }, { 2350, 0b1000110, 432 },
+     { 2400, 0b1000111, 442 }, { 2450, 0b1001000, 451 },
+     { 2500, 0b1001001, 460 }
+};
+
+/**
+ * struct dw_dphy - DW D-PHY driver private structure
+ *
+ * @regmap: pointer to regmap
+ * @regmap_cfg1: pointer to config1 regmap
+ * @regmap_cfg2: pointer to config2 regmap
+ * @rf_cfg1: array of regfields for config1
+ * @rf_cfg2: array of regfields for config2
+ * @iomem_cfg1: MMIO address for cfg1 section
+ * @iomem_cfg2: MMIO address for cfg2 section
+ * @phy: pointer to the phy data structure
+ * @hs_clk_rate: high speed clock rate as per image sensor

configuration
+ * @dt_data_dw_dphy: device tree specific data
+ *
+ **/

drivers/phy/phy-dw-dphy.c new file +22 -0
+struct dw_dphy {
+     struct regmap *regmap_cfg1;
+     struct regmap *regmap_cfg2;
+     struct regmap_field *rf_cfg1[DW_DPHY_RF_CFG1_MAX];
+     struct regmap_field *rf_cfg2[DW_DPHY_RF_CFG2_MAX];
+     void __iomem *iomem_cfg1;
+     void __iomem *iomem_cfg2;
+     struct phy *phy;
+     struct device *dev;
+     unsigned long hs_clk_rate;
+     struct dt_data_dw_dphy *dt_data;
+};
+
+/**
+ * dw_dphy_te_write - write register into test enable interface
+ *
+ * @dphy: pointer to the dw_dphy private data structure
+ * @addr: 12 bit TE address register (16 bit container)
+ * @data: 8 bit data to be written to TE register
+ *
+ **/
+static void dw_dphy_te_write(struct dw_dphy *dphy, u16 addr, u8

data)

drivers/phy/phy-dw-dphy.c new file +18 -0
+{
+     /* For writing the 4-bit testcode MSBs */
+
+     /* Ensure that testclk and testen is set to low */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
+     regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
+
+     /* Set testen to high */
+     regmap_field_write(dphy->rf_cfg1[TEST_EN], 1);
+
+     /* Set testclk to high */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
+
+     /* Place 0x00 in testdin */
+     regmap_field_write(dphy->rf_cfg1[TEST_IN], 0);
+
+     /*
+      * Set testclk to low (with the falling edge on testclk, the

testdin signal
+      * content is latched internally)
+      */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);

drivers/phy/phy-dw-dphy.c new file +5 -0
+
+     /* Set testen to low */
+     regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
+
+     /* Place the 8-bit word corresponding to the testcode MSBs in

testdin */
+     regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr >> 8));

drivers/phy/phy-dw-dphy.c new file +20 -0
+
+     /* Set testclk to high */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
+
+     /* For writing the 8-bit testcode LSBs */
+
+     /* Set testclk to low */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
+
+     /* Set testen to high */
+     regmap_field_write(dphy->rf_cfg1[TEST_EN], 1);
+
+     /* Set testclk to high */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
+
+     /* Place the 8-bit word test data in testdin */
+     regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr & 0xff));
+
+     /*
+      * Set testclk to low (with the falling edge on testclk, the

testdin signal
+      * content is latched internally)
+      */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);

drivers/phy/phy-dw-dphy.c new file +7 -0
+
+     /* Set testen to low */
+     regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
+
+     /* For writing the data */
+
+     /* Place the 8-bit word corresponding to the page offset in

testdin */
+     regmap_field_write(dphy->rf_cfg1[TEST_IN], data); +
+     /* Set testclk to high (test data is programmed internally) */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);

drivers/phy/phy-dw-dphy.c new file +30 -0
+}
+
+/**
+ * dw_dphy_te_read - read register from test enable interface
+ *
+ * @dphy: pointer to the dw_dphy private data structure
+ * @addr: 12 bit TE address register (16 bit container)
+ * @returns: 8 bit data from TE register
+ **/
+static u8 dw_dphy_te_read(struct dw_dphy *dphy, u16 addr)
+{
+     u32 data;
+
+     /* For writing the 4-bit testcode MSBs */
+
+     /* Ensure that testclk and testen is set to low */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
+     regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
+
+     /* Set testen to high */
+     regmap_field_write(dphy->rf_cfg1[TEST_EN], 1);
+
+     /* Set testclk to high */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
+
+     /* Place 0x00 in testdin */
+     regmap_field_write(dphy->rf_cfg1[TEST_IN], 0);
+
+     /*
+      * Set testclk to low (with the falling edge on testclk, the

testdin signal
+      * content is latched internally)
+      */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);

drivers/phy/phy-dw-dphy.c new file +5 -0
+
+     /* Set testen to low */
+     regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
+
+     /* Place the 8-bit word corresponding to the testcode MSBs in

testdin */
+     regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr >> 8));

drivers/phy/phy-dw-dphy.c new file +20 -0
+
+     /* Set testclk to high */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
+
+     /* For writing the 8-bit testcode LSBs */
+
+     /* Set testclk to low */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
+
+     /* Set testen to high */
+     regmap_field_write(dphy->rf_cfg1[TEST_EN], 1);
+
+     /* Set testclk to high */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
+
+     /* Place the 8-bit word test data in testdin */
+     regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr & 0xff));
+
+     /*
+      * Set testclk to low (with the falling edge on testclk, the

testdin signal
+      * content is latched internally)
+      */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);

drivers/phy/phy-dw-dphy.c new file +18 -0
+
+     /* Set testen to low */
+     regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
+
+     regmap_field_read(dphy->rf_cfg1[TEST_OUT], &data);
+
+     return (u8)data;
+}
+
+/**
+ * dw_dphy_configure - configure the D-PHY
+ *
+ * @phy: pointer to the phy data structure
+ * @opts: pointer to the phy configuration options
+ * @returns 0 if success else appropriate error code
+ *
+ **/
+static int dw_dphy_configure(struct phy *phy, union

phy_configure_opts *opts)

drivers/phy/phy-dw-dphy.c new file +26 -0
+{
+     struct dw_dphy *dphy = phy_get_drvdata(phy);
+
+     dphy->hs_clk_rate = opts->mipi_dphy.hs_clk_rate;
+     dev_dbg(dphy->dev, "hs_clk_rate=%ld\n", dphy->hs_clk_rate);
+
+     return 0;
+}
+
+/**
+ * dw_dphy_power_on_1p2 - power on the DPHY version 1.2
+ *
+ * @phy: pointer to the phy data structure
+ * @returns 0 if success else appropriate error code
+ *
+ **/
+static int dw_dphy_power_on_1p2(struct phy *phy)
+{
+     struct dw_dphy *dphy = phy_get_drvdata(phy);
+
+     uint8_t counter_for_des_en_config_if_rw = 0x1;
+     u8 range = 0;
+
+     for (range = 0;
+          (range < dphy->dt_data->table_size - 1) &&
+          ((dphy->hs_clk_rate) > dphy->dt_data-
Quoted 1 line

table[range].freq);

+          range++)
+             ;
+
+     /* in case requested hs_clk_rate is out of range, return - EINVAL */
+     if (range >= dphy->dt_data->table_size)
+             return -EINVAL;
+
+     dev_dbg(dphy->dev, "12bit: PHY GEN 3: Freq: %ld %x\n", dphy-

Quoted 1 line

hs_clk_rate,

+              range_gen3[range].hsfregrange);
+
+     regmap_field_write(dphy->rf_cfg1[DPHY_RSTZ], 0); +     regmap_field_write(dphy->rf_cfg1[PHY_SHUTDOWNZ], 0); +     regmap_field_write(dphy->rf_cfg1[TEST_CLR], 0);
+     regmap_field_write(dphy->rf_cfg1[TEST_CLR], 1);
+     regmap_field_write(dphy->rf_cfg1[TEST_CLR], 0);
+     regmap_field_write(dphy->rf_cfg2[CFG_CLK_FREQ_RANGE], 0x28); +     dw_dphy_te_write(dphy, RX_SYS_1,
+                      dphy->dt_data->table[range].hsfregrange); +     dw_dphy_te_write(dphy, RX_SYS_0, 0x20);
+     dw_dphy_te_write(dphy, RX_RX_STARTUP_OVR_2,
+                      (u8)dphy->dt_data-

Quoted 1 line

table[range].osc_freq_target);

+     dw_dphy_te_write(dphy, RX_RX_STARTUP_OVR_3,
+                      (u8)(dphy->dt_data-

Quoted 1 line

table[range].osc_freq_target >>

+                           8));
+     dw_dphy_te_write(dphy, 0xe4,
+                      (counter_for_des_en_config_if_rw << 4) | 0b1);

drivers/phy/phy-dw-dphy.c new file +47 -0
+
+     dw_dphy_te_write(dphy, RX_RX_STARTUP_OVR_1, 0x01);
+     dw_dphy_te_write(dphy, RX_RX_STARTUP_OVR_0, 0x80);
+
+     regmap_field_write(dphy->rf_cfg2[BASE_DIR_0], 1);
+     regmap_field_write(dphy->rf_cfg2[ENABLE_CLK], 1);
+     regmap_field_write(dphy->rf_cfg2[FORCE_RX_MODE], 0x0);
+
+     regmap_field_write(dphy->rf_cfg1[PHY_SHUTDOWNZ], 1);
+     regmap_field_write(dphy->rf_cfg1[DPHY_RSTZ], 1);
+
+     return 0;
+}
+
+/**
+ * dw_dphy_power_off - power off the DPHY
+ *
+ * @phy: pointer to the phy data structure
+ * @returns 0 if success else appropriate error code
+ *
+ **/
+static int dw_dphy_power_off(struct phy *phy)
+{
+     struct dw_dphy *dphy = phy_get_drvdata(phy);
+
+     regmap_field_write(dphy->rf_cfg1[DPHY_RSTZ], 0);
+     regmap_field_write(dphy->rf_cfg1[PHY_SHUTDOWNZ], 0);
+     return 0;
+}
+
+/**
+ * dw_dphy_ops_1p2 - PHY operations for DWC DPHY v1.2
+ * @configure: Configures DPHY timing and operation parameters
+ * @power_on: Powers on the DPHY using v1.2 specific sequence
+ * @power_off: Powers off the DPHY
+ *
+ **/
+static const struct phy_ops dw_dphy_ops_1p2 = {
+     .configure = dw_dphy_configure,
+     .power_on = dw_dphy_power_on_1p2,
+     .power_off = dw_dphy_power_off,
+};
+
+/**
+ * dw_dphy_1p2 - DWC DPHY v1.2 configuration instance
+ * @table: Points to range_gen3 timing parameters table
+ * @table_size: Size of range_gen3 table calculated at compile

time
+ * @phy_ops: Points to v1.2 specific PHY operations structure
+ *
+ **/

drivers/phy/phy-dw-dphy.c new file +60 -0
+struct dt_data_dw_dphy dw_dphy_1p2 = {
+     .table = range_gen3,
+     .table_size = ARRAY_SIZE(range_gen3),
+     .phy_ops = &dw_dphy_ops_1p2,
+};
+
+/**
+ * dw_dphy_regmap_cfg1 - Register map configuration for DW DPHY
+ * @reg_bits: Width of register address in bits (32)
+ * @val_bits: Width of register value in bits (32)
+ * @reg_stride: Number of bytes between registers (4)
+ * @name: Name identifier for this register map
+ * @fast_io: Flag to indicate fast I/O operations are supported
+ *
+ **/
+static const struct regmap_config dw_dphy_regmap_cfg1 = {
+     .reg_bits = 32,
+     .val_bits = 32,
+     .reg_stride = 4,
+     .name = "dw-dhpy-cfg1",
+     .fast_io = true,
+};
+
+/**
+ * dw_dphy_regmap_cfg2 - Register map configuration for DW DPHY
+ * @reg_bits: Width of register address in bits (32)
+ * @val_bits: Width of register value in bits (32)
+ * @reg_stride: Number of bytes between registers (4)
+ * @name: Name identifier for this register map
+ * @fast_io: Flag to indicate fast I/O operations are supported
+ *
+ **/
+static const struct regmap_config dw_dphy_regmap_cfg2 = {
+     .reg_bits = 32,
+     .val_bits = 32,
+     .reg_stride = 4,
+     .name = "dw-dhpy-cfg2",
+     .fast_io = true,
+};
+
+/**
+ * dw_dphy_probe - Probe and initialize DW DPHY device
+ * @pdev: Platform device pointer
+ * Return: 0 on success, negative error code on failure
+ *
+ **/
+static int dw_dphy_probe(struct platform_device *pdev)
+{
+     struct dw_dphy *dphy;
+     struct resource *res;
+     struct device *dev = &pdev->dev;
+     struct phy_provider *phy_provider;
+     int ret;
+
+     dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL);
+     if (!dphy)
+             return -ENOMEM;
+
+     dphy->dt_data =
+             (struct dt_data_dw_dphy

*)of_device_get_match_data(&pdev->dev);
+     dev_set_drvdata(&pdev->dev, dphy);
+     dphy->dev = &pdev->dev;
+

Quoted 8 lines
Quoted 4 lines

+     res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +     dphy->iomem_cfg1 = devm_ioremap_resource(&pdev->dev, res); +     if (IS_ERR(dphy->iomem_cfg1))
+             return PTR_ERR(dphy->iomem_cfg1);

cfg1 is part of DW MIPI-CSI2 MMIO space. how to cooperate with dw MIPI-CSI2
controller.

This is essentially why we created two MMIO spaces as CSI2 and D-PHY are intermixed in the MMIO space and regmap driver detects the conflict.

Quoted 6 lines

Please CC me for next version. I am working on DW MIPI-CSI2 work.

https://lore.kernel.org/imx/[email protected]/

Frank

Sure, Frank, perhaps loop in Miguel as he might be able to know about all the variants out there for this IP.

Quoted 95 lines
Quoted 95 lines

+
+     dphy->regmap_cfg1 =
+             devm_regmap_init_mmio(dev, dphy->iomem_cfg1, &dw_dphy_regmap_cfg1);
+     if (IS_ERR(dphy->regmap_cfg1))
+             return PTR_ERR(dphy->regmap_cfg1);
+
+     ret = devm_regmap_field_bulk_alloc(dev, dphy->regmap_cfg1, dphy->rf_cfg1,
+                                        dw_dphy_v1_2_cfg1, DW_DPHY_RF_CFG1_MAX);
+     if (ret < 0) {
+             dev_err(dev, "Could not alloc RF\n");
+             return ret;
+     }

drivers/phy/phy-dw-dphy.c new file +7 -0
+
+     res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+     dphy->iomem_cfg2 = devm_ioremap_resource(&pdev->dev, res);
+     if (IS_ERR(dphy->iomem_cfg2))
+             return PTR_ERR(dphy->iomem_cfg2);
+
+     dphy->regmap_cfg2 = devm_regmap_init_mmio(dev, dphy-
Quoted 1 line

iomem_cfg2,

+
&dw_dphy_regmap_cfg2);
+     if (IS_ERR(dphy->regmap_cfg2))
+             return PTR_ERR(dphy->regmap_cfg2);
+
+     ret = devm_regmap_field_bulk_alloc(dev, dphy->regmap_cfg2, dphy->rf_cfg2,
+                                        dw_dphy_v1_2_cfg2, DW_DPHY_RF_CFG2_MAX);
+     if (ret < 0) {
+             dev_err(dev, "Could not alloc RF\n");
+             return ret;
+     }
+
+     dphy->phy = devm_phy_create(&pdev->dev, NULL, dphy->dt_data-

Quoted 1 line

phy_ops);

+     if (IS_ERR(dphy->phy)) {
+             dev_err(dev, "failed to create PHY\n"); +             return PTR_ERR(dphy->phy);
+     }
+
+     phy_set_drvdata(dphy->phy, dphy);
+     phy_provider =
+             devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);

drivers/phy/phy-dw-dphy.c new file +27 -0
+
+     return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+/**
+ * dw_dphy_of_match - Device tree match table for DW DPHY
+ * @compatible: Compatible string to match device tree node
+ * @data: Pointer to configuration data for matched device
+ *
+ * Table of compatible strings and associated configuration data
+ * for supported DW DPHY variants.
+ * Currently supports:
+ * - DW DPHY v1.2 ("snps,dw-dphy-1p2")
+ *
+ **/
+static const struct of_device_id dw_dphy_of_match[] = {
+     { .compatible = "snps,dw-dphy-1p2", .data = &dw_dphy_1p2 },
+     { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, dw_dphy_of_match);
+
+/**
+ * dw_dphy_platform_driver - Platform driver structure for DW DPHY
+ * @probe: Pointer to probe function called on device discovery
+ * @driver: Core driver structure containing:
+ *         - name: Driver name used for matching and debugging
+ *         - of_match_table: Table of compatible device tree

matches
+ *
+ **/

drivers/phy/phy-dw-dphy.c new file +14 -1
+static struct platform_driver dw_dphy_platform_driver = {
+     .probe          = dw_dphy_probe,
+     .driver         = {
+             .name           = "dw-dphy",
+             .of_match_table = dw_dphy_of_match,
+     },
+};
+module_platform_driver(dw_dphy_platform_driver);
+
+MODULE_AUTHOR("Karthik Poduval <[email protected]>");
+MODULE_AUTHOR("Jason Xiong <[email protected]>");
+MODULE_AUTHOR("Miguel Lopes <[email protected]>");
+MODULE_DESCRIPTION("DW D-PHY RX Driver");
+MODULE_LICENSE("GPL");
--

2.43.0

maintainer
#4 lore raw

Re: [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX

Quoted 7 lines · Karthik
Quoted 6 lines · Frank Li

CAUTION: This email originated from outside of the organization. Do not click links or open attachments unless you can confirm the sender and know the content is safe.

...

Quoted 15 lines
Quoted 7 lines
Quoted 7 lines

+
+     dphy->dt_data =
+             (struct dt_data_dw_dphy
*)of_device_get_match_data(&pdev->dev);
+     dev_set_drvdata(&pdev->dev, dphy);
+     dphy->dev = &pdev->dev;
+

Quoted 8 lines
Quoted 4 lines

+     res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +     dphy->iomem_cfg1 = devm_ioremap_resource(&pdev->dev, res); +     if (IS_ERR(dphy->iomem_cfg1))
+             return PTR_ERR(dphy->iomem_cfg1);

cfg1 is part of DW MIPI-CSI2 MMIO space. how to cooperate with dw MIPI-CSI2
controller.

Quoted 3 lines

This is essentially why we created two MMIO spaces as CSI2 and D-PHY are intermixed in the MMIO space and regmap driver detects the conflict.

Because there are not CSI2 part code, It is not clear how to avoid this problem by use cfg1 and cfg2.

CSI2 register look like
version
n_lan
...
phy_tst_ctrl1
phy_tst_ctrl2
...
other register like irqs

Frank

Quoted 8 lines
Quoted 6 lines

Please CC me for next version. I am working on DW MIPI-CSI2 work.

https://lore.kernel.org/imx/[email protected]/

Frank

Sure, Frank, perhaps loop in Miguel as he might be able to know about all the variants out there for this IP.

...

Quoted 5 lines
Quoted 4 lines
Quoted 4 lines

+MODULE_LICENSE("GPL");
--
2.43.0

maintainer
#5 lore raw

Re: [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX

In reply to Karthik Poduval
Quoted 3 lines · Karthik Poduval

Add support for Synopsys DesignWare MIPI D-PHY RX v1.2. The driver supports data rates from 80Mbps to 2500Mbps.

where download spec?

And I think you should cc: [email protected]

In https://lore.kernel.org/imx/[email protected]/

drivers/media/platform/raspberrypi/rp1-cfe/dphy.c do similar work.

Frank

Quoted 626 lines
---
 drivers/phy/Kconfig       |  11 +
 drivers/phy/Makefile      |   1 +
 drivers/phy/phy-dw-dphy.c | 575 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 587 insertions(+)
 create mode 100644 drivers/phy/phy-dw-dphy.c
drivers/phy/Kconfig +11 -0
index 58c911e1b2d2..34c245ca5d12 100644
@@ -101,6 +101,17 @@ config PHY_NXP_PTN3222
 	  schemes. It supports all three USB 2.0 data rates: Low Speed, Full
 	  Speed and High Speed.
 
+config PHY_SYNOPSYS_DW_DPHY_RX
+	tristate "Synopsys DesignWare D-PHY Rx Support"
+	depends on HAS_IOMEM && REGMAP_MMIO
+	select GENERIC_PHY
+	select GENERIC_PHY_MIPI_DPHY
+	help
+	  This option enables support for Synopsys DW MIPI D-PHY RX IP. This driver
+	  provides D-PHY functionality using Generic PHY framework and is meant to
+	  be used by MIPI CSI2 receivers over the PPI hardware interface. MIPI CSI2
+	  receivers may find this driver and use it via Generic PHY Framework API.
+
 source "drivers/phy/allwinner/Kconfig"
 source "drivers/phy/amlogic/Kconfig"
 source "drivers/phy/broadcom/Kconfig"
drivers/phy/Makefile +1 -0
index c670a8dac468..ed0836adb835 100644
@@ -13,6 +13,7 @@ obj-$(CONFIG_PHY_SNPS_EUSB2)		+= phy-snps-eusb2.o
 obj-$(CONFIG_USB_LGM_PHY)		+= phy-lgm-usb.o
 obj-$(CONFIG_PHY_AIROHA_PCIE)		+= phy-airoha-pcie.o
 obj-$(CONFIG_PHY_NXP_PTN3222)		+= phy-nxp-ptn3222.o
+obj-$(CONFIG_PHY_SYNOPSYS_DW_DPHY_RX)	+= phy-dw-dphy.o
 obj-y					+= allwinner/	\
 					   amlogic/	\
 					   broadcom/	\
drivers/phy/phy-dw-dphy.c new file +575 -1
new file mode 100644
index 000000000000..2248f690b861
@@ -0,0 +1,575 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright © 2025 Amazon.com, Inc. or its affiliates.
+ * Copyright © 2025 Synopsys, Inc. (www.synopsys.com)
+ */
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/regmap.h>
+
+#include <linux/phy/phy.h>
+#include <linux/phy/phy-mipi-dphy.h>
+
+#define KHZ (1000)
+#define MHZ (KHZ * KHZ)
+
+enum dw_dphy_reg_fields_cfg1 {
+	PHY_SHUTDOWNZ,
+	DPHY_RSTZ,
+	TEST_CLR,
+	TEST_CLK,
+	TEST_IN,
+	TEST_OUT,
+	TEST_EN,
+	DW_DPHY_RF_CFG1_MAX
+};
+
+enum dw_dphy_reg_fields_cfg2 {
+	EN_CONT_REG_UPDATE,
+	TURN_REQUEST_0,
+	TURN_DISABLE_0,
+	ENABLE_CLK,
+	FORCE_TX_STOP_MODE_0,
+	FORCE_RX_MODE,
+	BASE_DIR_0,
+	CFG_CLK_FREQ_RANGE,
+	HS_FREQ_RANGE,
+	CONT_EN,
+	DW_DPHY_RF_CFG2_MAX
+};
+
+static const struct reg_field dw_dphy_v1_2_cfg1[DW_DPHY_RF_CFG1_MAX] = {
+	[PHY_SHUTDOWNZ] = REG_FIELD(0x0, 0, 0),
+	[DPHY_RSTZ] = REG_FIELD(0x4, 0, 0),
+	[TEST_CLR] = REG_FIELD(0x10, 0, 0),
+	[TEST_CLK] = REG_FIELD(0x10, 1, 1),
+	[TEST_IN] = REG_FIELD(0x14, 0, 7),
+	[TEST_OUT] = REG_FIELD(0x14, 8, 15),
+	[TEST_EN] = REG_FIELD(0x14, 16, 16),
+};
+
+static const struct reg_field dw_dphy_v1_2_cfg2[DW_DPHY_RF_CFG2_MAX] = {
+	[EN_CONT_REG_UPDATE] = REG_FIELD(0x0, 23, 23),
+	[TURN_REQUEST_0] = REG_FIELD(0x0, 22, 22),
+	[TURN_DISABLE_0] = REG_FIELD(0x0, 21, 21),
+	[ENABLE_CLK] = REG_FIELD(0x0, 20, 20),
+	[FORCE_TX_STOP_MODE_0] = REG_FIELD(0x0, 19, 19),
+	[FORCE_RX_MODE] = REG_FIELD(0x0, 15, 18),
+	[BASE_DIR_0] = REG_FIELD(0x0, 14, 14),
+	[CFG_CLK_FREQ_RANGE] = REG_FIELD(0x0, 8, 13),
+	[HS_FREQ_RANGE] = REG_FIELD(0x0, 1, 7),
+	[CONT_EN] = REG_FIELD(0x0, 0, 0),
+};
+
+enum dphy_12bit_interface_addr {
+	RX_SYS_0 = 0x01,
+	RX_SYS_1 = 0x02,
+	RX_SYS_7 = 0x08,
+	RX_RX_STARTUP_OVR_0 = 0xe0,
+	RX_RX_STARTUP_OVR_1 = 0xe1,
+	RX_RX_STARTUP_OVR_2 = 0xe2,
+	RX_RX_STARTUP_OVR_3 = 0xe3,
+	RX_RX_STARTUP_OVR_4 = 0xe4,
+};
+
+/**
+ * struct range_dphy_gen3 - frequency range calibration structure
+ *
+ * @freq: input freqency to calibration table
+ * @hsfregrange: corresponding clock to configure DW D-PHY IP
+ * @osc_freq_target: corresponding clock to configure DW D-PHY IP
+ *
+ **/
+struct range_dphy_gen3 {
+	u32 freq;
+	u8 hsfregrange;
+	u32 osc_freq_target;
+};
+
+/**
+ * struct dt_data_dw_dphy - DPHY configuration data structure
+ * @table: Pointer to array of DPHY Gen3 timing range configurations
+ * @table_size: Number of entries in the timing range table
+ * @phy_ops: Pointer to PHY operations structure containing callback functions
+ *
+ **/
+struct dt_data_dw_dphy {
+	struct range_dphy_gen3 *table;
+	int table_size;
+	const struct phy_ops *phy_ops;
+};
+
+/*
+ * DW DPHY Gen3 calibration table
+ *
+ */
+struct range_dphy_gen3 range_gen3[] = {
+	{ 80, 0b0000000, 460 },	  { 90, 0b0010000, 460 },
+	{ 100, 0b0100000, 460 },  { 110, 0b0110000, 460 },
+	{ 120, 0b0000001, 460 },  { 130, 0b0010001, 460 },
+	{ 140, 0b0100001, 460 },  { 150, 0b0110001, 460 },
+	{ 160, 0b0000010, 460 },  { 170, 0b0010010, 460 },
+	{ 180, 0b0100010, 460 },  { 190, 0b0110010, 460 },
+	{ 205, 0b0000011, 460 },  { 220, 0b0010011, 460 },
+	{ 235, 0b0100011, 460 },  { 250, 0b0110011, 460 },
+	{ 275, 0b0000100, 460 },  { 300, 0b0010100, 460 },
+	{ 325, 0b0100101, 460 },  { 350, 0b0110101, 460 },
+	{ 400, 0b0000101, 460 },  { 450, 0b0010110, 460 },
+	{ 500, 0b0100110, 460 },  { 550, 0b0110111, 460 },
+	{ 600, 0b0000111, 460 },  { 650, 0b0011000, 460 },
+	{ 700, 0b0101000, 460 },  { 750, 0b0111001, 460 },
+	{ 800, 0b0001001, 460 },  { 850, 0b0011001, 460 },
+	{ 900, 0b0101001, 460 },  { 950, 0b0111010, 460 },
+	{ 1000, 0b0001010, 460 }, { 1050, 0b0011010, 460 },
+	{ 1110, 0b0101010, 460 }, { 1150, 0b0111011, 460 },
+	{ 1200, 0b0001011, 460 }, { 1250, 0b0011011, 460 },
+	{ 1300, 0b0101011, 460 }, { 1350, 0b0111100, 460 },
+	{ 1400, 0b0001100, 460 }, { 1450, 0b0011100, 460 },
+	{ 1500, 0b0101100, 460 }, { 1550, 0b0111101, 285 },
+	{ 1600, 0b0001101, 295 }, { 1650, 0b0011101, 304 },
+	{ 1700, 0b0101110, 313 }, { 1750, 0b0111110, 322 },
+	{ 1800, 0b0001110, 331 }, { 1850, 0b0011110, 341 },
+	{ 1900, 0b0101111, 350 }, { 1950, 0b0111111, 359 },
+	{ 2000, 0b0001111, 368 }, { 2050, 0b1000000, 377 },
+	{ 2100, 0b1000001, 387 }, { 2150, 0b1000010, 396 },
+	{ 2200, 0b1000011, 405 }, { 2250, 0b1000100, 414 },
+	{ 2300, 0b1000101, 423 }, { 2350, 0b1000110, 432 },
+	{ 2400, 0b1000111, 442 }, { 2450, 0b1001000, 451 },
+	{ 2500, 0b1001001, 460 }
+};
+
+/**
+ * struct dw_dphy - DW D-PHY driver private structure
+ *
+ * @regmap: pointer to regmap
+ * @regmap_cfg1: pointer to config1 regmap
+ * @regmap_cfg2: pointer to config2 regmap
+ * @rf_cfg1: array of regfields for config1
+ * @rf_cfg2: array of regfields for config2
+ * @iomem_cfg1: MMIO address for cfg1 section
+ * @iomem_cfg2: MMIO address for cfg2 section
+ * @phy: pointer to the phy data structure
+ * @hs_clk_rate: high speed clock rate as per image sensor configuration
+ * @dt_data_dw_dphy: device tree specific data
+ *
+ **/
+struct dw_dphy {
+	struct regmap *regmap_cfg1;
+	struct regmap *regmap_cfg2;
+	struct regmap_field *rf_cfg1[DW_DPHY_RF_CFG1_MAX];
+	struct regmap_field *rf_cfg2[DW_DPHY_RF_CFG2_MAX];
+	void __iomem *iomem_cfg1;
+	void __iomem *iomem_cfg2;
+	struct phy *phy;
+	struct device *dev;
+	unsigned long hs_clk_rate;
+	struct dt_data_dw_dphy *dt_data;
+};
+
+/**
+ * dw_dphy_te_write - write register into test enable interface
+ *
+ * @dphy: pointer to the dw_dphy private data structure
+ * @addr: 12 bit TE address register (16 bit container)
+ * @data: 8 bit data to be written to TE register
+ *
+ **/
+static void dw_dphy_te_write(struct dw_dphy *dphy, u16 addr, u8 data)
+{
+	/* For writing the 4-bit testcode MSBs */
+
+	/* Ensure that testclk and testen is set to low */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
+	regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
+
+	/* Set testen to high */
+	regmap_field_write(dphy->rf_cfg1[TEST_EN], 1);
+
+	/* Set testclk to high */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
+
+	/* Place 0x00 in testdin */
+	regmap_field_write(dphy->rf_cfg1[TEST_IN], 0);
+
+	/*
+	 * Set testclk to low (with the falling edge on testclk, the testdin signal
+	 * content is latched internally)
+	 */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
+
+	/* Set testen to low */
+	regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
+
+	/* Place the 8-bit word corresponding to the testcode MSBs in testdin */
+	regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr >> 8));
+
+	/* Set testclk to high */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
+
+	/* For writing the 8-bit testcode LSBs */
+
+	/* Set testclk to low */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
+
+	/* Set testen to high */
+	regmap_field_write(dphy->rf_cfg1[TEST_EN], 1);
+
+	/* Set testclk to high */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
+
+	/* Place the 8-bit word test data in testdin */
+	regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr & 0xff));
+
+	/*
+	 * Set testclk to low (with the falling edge on testclk, the testdin signal
+	 * content is latched internally)
+	 */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
+
+	/* Set testen to low */
+	regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
+
+	/* For writing the data */
+
+	/* Place the 8-bit word corresponding to the page offset in testdin */
+	regmap_field_write(dphy->rf_cfg1[TEST_IN], data);
+
+	/* Set testclk to high (test data is programmed internally) */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
+}
+
+/**
+ * dw_dphy_te_read - read register from test enable interface
+ *
+ * @dphy: pointer to the dw_dphy private data structure
+ * @addr: 12 bit TE address register (16 bit container)
+ * @returns: 8 bit data from TE register
+ **/
+static u8 dw_dphy_te_read(struct dw_dphy *dphy, u16 addr)
+{
+	u32 data;
+
+	/* For writing the 4-bit testcode MSBs */
+
+	/* Ensure that testclk and testen is set to low */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
+	regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
+
+	/* Set testen to high */
+	regmap_field_write(dphy->rf_cfg1[TEST_EN], 1);
+
+	/* Set testclk to high */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
+
+	/* Place 0x00 in testdin */
+	regmap_field_write(dphy->rf_cfg1[TEST_IN], 0);
+
+	/*
+	 * Set testclk to low (with the falling edge on testclk, the testdin signal
+	 * content is latched internally)
+	 */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
+
+	/* Set testen to low */
+	regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
+
+	/* Place the 8-bit word corresponding to the testcode MSBs in testdin */
+	regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr >> 8));
+
+	/* Set testclk to high */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
+
+	/* For writing the 8-bit testcode LSBs */
+
+	/* Set testclk to low */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
+
+	/* Set testen to high */
+	regmap_field_write(dphy->rf_cfg1[TEST_EN], 1);
+
+	/* Set testclk to high */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
+
+	/* Place the 8-bit word test data in testdin */
+	regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr & 0xff));
+
+	/*
+	 * Set testclk to low (with the falling edge on testclk, the testdin signal
+	 * content is latched internally)
+	 */
+	regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
+
+	/* Set testen to low */
+	regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
+
+	regmap_field_read(dphy->rf_cfg1[TEST_OUT], &data);
+
+	return (u8)data;
+}
+
+/**
+ * dw_dphy_configure - configure the D-PHY
+ *
+ * @phy: pointer to the phy data structure
+ * @opts: pointer to the phy configuration options
+ * @returns 0 if success else appropriate error code
+ *
+ **/
+static int dw_dphy_configure(struct phy *phy, union phy_configure_opts *opts)
+{
+	struct dw_dphy *dphy = phy_get_drvdata(phy);
+
+	dphy->hs_clk_rate = opts->mipi_dphy.hs_clk_rate;
+	dev_dbg(dphy->dev, "hs_clk_rate=%ld\n", dphy->hs_clk_rate);
+
+	return 0;
+}
+
+/**
+ * dw_dphy_power_on_1p2 - power on the DPHY version 1.2
+ *
+ * @phy: pointer to the phy data structure
+ * @returns 0 if success else appropriate error code
+ *
+ **/
+static int dw_dphy_power_on_1p2(struct phy *phy)
+{
+	struct dw_dphy *dphy = phy_get_drvdata(phy);
+
+	uint8_t counter_for_des_en_config_if_rw = 0x1;
+	u8 range = 0;
+
+	for (range = 0;
+	     (range < dphy->dt_data->table_size - 1) &&
+	     ((dphy->hs_clk_rate) > dphy->dt_data->table[range].freq);
+	     range++)
+		;
+
+	/* in case requested hs_clk_rate is out of range, return -EINVAL */
+	if (range >= dphy->dt_data->table_size)
+		return -EINVAL;
+
+	dev_dbg(dphy->dev, "12bit: PHY GEN 3: Freq: %ld %x\n", dphy->hs_clk_rate,
+		 range_gen3[range].hsfregrange);
+
+	regmap_field_write(dphy->rf_cfg1[DPHY_RSTZ], 0);
+	regmap_field_write(dphy->rf_cfg1[PHY_SHUTDOWNZ], 0);
+	regmap_field_write(dphy->rf_cfg1[TEST_CLR], 0);
+	regmap_field_write(dphy->rf_cfg1[TEST_CLR], 1);
+	regmap_field_write(dphy->rf_cfg1[TEST_CLR], 0);
+	regmap_field_write(dphy->rf_cfg2[CFG_CLK_FREQ_RANGE], 0x28);
+	dw_dphy_te_write(dphy, RX_SYS_1,
+			 dphy->dt_data->table[range].hsfregrange);
+	dw_dphy_te_write(dphy, RX_SYS_0, 0x20);
+	dw_dphy_te_write(dphy, RX_RX_STARTUP_OVR_2,
+			 (u8)dphy->dt_data->table[range].osc_freq_target);
+	dw_dphy_te_write(dphy, RX_RX_STARTUP_OVR_3,
+			 (u8)(dphy->dt_data->table[range].osc_freq_target >>
+			      8));
+	dw_dphy_te_write(dphy, 0xe4,
+			 (counter_for_des_en_config_if_rw << 4) | 0b1);
+
+	dw_dphy_te_write(dphy, RX_RX_STARTUP_OVR_1, 0x01);
+	dw_dphy_te_write(dphy, RX_RX_STARTUP_OVR_0, 0x80);
+
+	regmap_field_write(dphy->rf_cfg2[BASE_DIR_0], 1);
+	regmap_field_write(dphy->rf_cfg2[ENABLE_CLK], 1);
+	regmap_field_write(dphy->rf_cfg2[FORCE_RX_MODE], 0x0);
+
+	regmap_field_write(dphy->rf_cfg1[PHY_SHUTDOWNZ], 1);
+	regmap_field_write(dphy->rf_cfg1[DPHY_RSTZ], 1);
+
+	return 0;
+}
+
+/**
+ * dw_dphy_power_off - power off the DPHY
+ *
+ * @phy: pointer to the phy data structure
+ * @returns 0 if success else appropriate error code
+ *
+ **/
+static int dw_dphy_power_off(struct phy *phy)
+{
+	struct dw_dphy *dphy = phy_get_drvdata(phy);
+
+	regmap_field_write(dphy->rf_cfg1[DPHY_RSTZ], 0);
+	regmap_field_write(dphy->rf_cfg1[PHY_SHUTDOWNZ], 0);
+	return 0;
+}
+
+/**
+ * dw_dphy_ops_1p2 - PHY operations for DWC DPHY v1.2
+ * @configure: Configures DPHY timing and operation parameters
+ * @power_on: Powers on the DPHY using v1.2 specific sequence
+ * @power_off: Powers off the DPHY
+ *
+ **/
+static const struct phy_ops dw_dphy_ops_1p2 = {
+	.configure = dw_dphy_configure,
+	.power_on = dw_dphy_power_on_1p2,
+	.power_off = dw_dphy_power_off,
+};
+
+/**
+ * dw_dphy_1p2 - DWC DPHY v1.2 configuration instance
+ * @table: Points to range_gen3 timing parameters table
+ * @table_size: Size of range_gen3 table calculated at compile time
+ * @phy_ops: Points to v1.2 specific PHY operations structure
+ *
+ **/
+struct dt_data_dw_dphy dw_dphy_1p2 = {
+	.table = range_gen3,
+	.table_size = ARRAY_SIZE(range_gen3),
+	.phy_ops = &dw_dphy_ops_1p2,
+};
+
+/**
+ * dw_dphy_regmap_cfg1 - Register map configuration for DW DPHY
+ * @reg_bits: Width of register address in bits (32)
+ * @val_bits: Width of register value in bits (32)
+ * @reg_stride: Number of bytes between registers (4)
+ * @name: Name identifier for this register map
+ * @fast_io: Flag to indicate fast I/O operations are supported
+ *
+ **/
+static const struct regmap_config dw_dphy_regmap_cfg1 = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
+	.name = "dw-dhpy-cfg1",
+	.fast_io = true,
+};
+
+/**
+ * dw_dphy_regmap_cfg2 - Register map configuration for DW DPHY
+ * @reg_bits: Width of register address in bits (32)
+ * @val_bits: Width of register value in bits (32)
+ * @reg_stride: Number of bytes between registers (4)
+ * @name: Name identifier for this register map
+ * @fast_io: Flag to indicate fast I/O operations are supported
+ *
+ **/
+static const struct regmap_config dw_dphy_regmap_cfg2 = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
+	.name = "dw-dhpy-cfg2",
+	.fast_io = true,
+};
+
+/**
+ * dw_dphy_probe - Probe and initialize DW DPHY device
+ * @pdev: Platform device pointer
+ * Return: 0 on success, negative error code on failure
+ *
+ **/
+static int dw_dphy_probe(struct platform_device *pdev)
+{
+	struct dw_dphy *dphy;
+	struct resource *res;
+	struct device *dev = &pdev->dev;
+	struct phy_provider *phy_provider;
+	int ret;
+
+	dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL);
+	if (!dphy)
+		return -ENOMEM;
+
+	dphy->dt_data =
+		(struct dt_data_dw_dphy *)of_device_get_match_data(&pdev->dev);
+	dev_set_drvdata(&pdev->dev, dphy);
+	dphy->dev = &pdev->dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	dphy->iomem_cfg1 = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(dphy->iomem_cfg1))
+		return PTR_ERR(dphy->iomem_cfg1);
+
+	dphy->regmap_cfg1 =
+		devm_regmap_init_mmio(dev, dphy->iomem_cfg1, &dw_dphy_regmap_cfg1);
+	if (IS_ERR(dphy->regmap_cfg1))
+		return PTR_ERR(dphy->regmap_cfg1);
+
+	ret = devm_regmap_field_bulk_alloc(dev, dphy->regmap_cfg1, dphy->rf_cfg1,
+					   dw_dphy_v1_2_cfg1, DW_DPHY_RF_CFG1_MAX);
+	if (ret < 0) {
+		dev_err(dev, "Could not alloc RF\n");
+		return ret;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	dphy->iomem_cfg2 = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(dphy->iomem_cfg2))
+		return PTR_ERR(dphy->iomem_cfg2);
+
+	dphy->regmap_cfg2 = devm_regmap_init_mmio(dev, dphy->iomem_cfg2,
+						 &dw_dphy_regmap_cfg2);
+	if (IS_ERR(dphy->regmap_cfg2))
+		return PTR_ERR(dphy->regmap_cfg2);
+
+	ret = devm_regmap_field_bulk_alloc(dev, dphy->regmap_cfg2, dphy->rf_cfg2,
+					   dw_dphy_v1_2_cfg2, DW_DPHY_RF_CFG2_MAX);
+	if (ret < 0) {
+		dev_err(dev, "Could not alloc RF\n");
+		return ret;
+	}
+
+	dphy->phy = devm_phy_create(&pdev->dev, NULL, dphy->dt_data->phy_ops);
+	if (IS_ERR(dphy->phy)) {
+		dev_err(dev, "failed to create PHY\n");
+		return PTR_ERR(dphy->phy);
+	}
+
+	phy_set_drvdata(dphy->phy, dphy);
+	phy_provider =
+		devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
+
+	return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+/**
+ * dw_dphy_of_match - Device tree match table for DW DPHY
+ * @compatible: Compatible string to match device tree node
+ * @data: Pointer to configuration data for matched device
+ *
+ * Table of compatible strings and associated configuration data
+ * for supported DW DPHY variants.
+ * Currently supports:
+ * - DW DPHY v1.2 ("snps,dw-dphy-1p2")
+ *
+ **/
+static const struct of_device_id dw_dphy_of_match[] = {
+	{ .compatible = "snps,dw-dphy-1p2", .data = &dw_dphy_1p2 },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, dw_dphy_of_match);
+
+/**
+ * dw_dphy_platform_driver - Platform driver structure for DW DPHY
+ * @probe: Pointer to probe function called on device discovery
+ * @driver: Core driver structure containing:
+ *         - name: Driver name used for matching and debugging
+ *         - of_match_table: Table of compatible device tree matches
+ *
+ **/
+static struct platform_driver dw_dphy_platform_driver = {
+	.probe		= dw_dphy_probe,
+	.driver		= {
+		.name		= "dw-dphy",
+		.of_match_table	= dw_dphy_of_match,
+	},
+};
+module_platform_driver(dw_dphy_platform_driver);
+
+MODULE_AUTHOR("Karthik Poduval <[email protected]>");
+MODULE_AUTHOR("Jason Xiong <[email protected]>");
+MODULE_AUTHOR("Miguel Lopes <[email protected]>");
+MODULE_DESCRIPTION("DW D-PHY RX Driver");
+MODULE_LICENSE("GPL");
--

2.43.0

#6 lore raw

Re: [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX

Quoted 6 lines · Frank Li

CAUTION: This email originated from outside of the organization. Do not click links or open attachments unless you can confirm the sender and know the content is safe.

Quoted 8 lines
Quoted 3 lines · Karthik Poduval

Add support for Synopsys DesignWare MIPI D-PHY RX v1.2. The driver supports data rates from 80Mbps to 2500Mbps.

where download spec?

And I think you should cc: [email protected]

Sure.

Quoted 674 lines

In
https://lore.kernel.org/imx/[email protected]/

drivers/media/platform/raspberrypi/rp1-cfe/dphy.c do similar work.

Frank

Quoted 666 lines

---
 drivers/phy/Kconfig       |  11 +
 drivers/phy/Makefile      |   1 +
 drivers/phy/phy-dw-dphy.c | 575
++++++++++++++++++++++++++++++++++++++

 3 files changed, 587 insertions(+)

 create mode 100644 drivers/phy/phy-dw-dphy.c

drivers/phy/Kconfig +0 -0
index 58c911e1b2d2..34c245ca5d12 100644
@@ -101,6 +101,17 @@ config PHY_NXP_PTN3222

        schemes. It supports all three USB 2.0 data rates: Low Speed, Full
        Speed and High Speed.

+config PHY_SYNOPSYS_DW_DPHY_RX
+     tristate "Synopsys DesignWare D-PHY Rx Support"
+     depends on HAS_IOMEM && REGMAP_MMIO
+     select GENERIC_PHY
+     select GENERIC_PHY_MIPI_DPHY
+     help
+       This option enables support for Synopsys DW MIPI D-PHY RX IP. This driver
+       provides D-PHY functionality using Generic PHY framework and is meant to
+       be used by MIPI CSI2 receivers over the PPI hardware interface. MIPI CSI2
+       receivers may find this driver and use it via Generic PHY Framework API.
+
 source "drivers/phy/allwinner/Kconfig"
 source "drivers/phy/amlogic/Kconfig"
 source "drivers/phy/broadcom/Kconfig"

drivers/phy/Makefile +0 -0
index c670a8dac468..ed0836adb835 100644
@@ -13,6 +13,7 @@ obj-$(CONFIG_PHY_SNPS_EUSB2)                +=

phy-snps-eusb2.o
 obj-$(CONFIG_USB_LGM_PHY)            += phy-lgm-usb.o obj-$(CONFIG_PHY_AIROHA_PCIE)                += phy-airoha-pcie.o obj-$(CONFIG_PHY_NXP_PTN3222)                += phy-nxp-ptn3222.o +obj-$(CONFIG_PHY_SYNOPSYS_DW_DPHY_RX)        += phy-dw-dphy.o obj-y                                        += allwinner/   \
                                         amlogic/     \
                                         broadcom/    \

drivers/phy/phy-dw-dphy.c new file +47 -0
new file mode 100644
index 000000000000..2248f690b861
@@ -0,0 +1,575 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright © 2025 Amazon.com, Inc. or its affiliates.
+ * Copyright © 2025 Synopsys, Inc. (www.synopsys.com)
+ */
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/regmap.h>
+
+#include <linux/phy/phy.h>
+#include <linux/phy/phy-mipi-dphy.h>
+
+#define KHZ (1000)
+#define MHZ (KHZ * KHZ)
+
+enum dw_dphy_reg_fields_cfg1 {
+     PHY_SHUTDOWNZ,
+     DPHY_RSTZ,
+     TEST_CLR,
+     TEST_CLK,
+     TEST_IN,
+     TEST_OUT,
+     TEST_EN,
+     DW_DPHY_RF_CFG1_MAX
+};
+
+enum dw_dphy_reg_fields_cfg2 {
+     EN_CONT_REG_UPDATE,
+     TURN_REQUEST_0,
+     TURN_DISABLE_0,
+     ENABLE_CLK,
+     FORCE_TX_STOP_MODE_0,
+     FORCE_RX_MODE,
+     BASE_DIR_0,
+     CFG_CLK_FREQ_RANGE,
+     HS_FREQ_RANGE,
+     CONT_EN,
+     DW_DPHY_RF_CFG2_MAX
+};
+
+static const struct reg_field

dw_dphy_v1_2_cfg1[DW_DPHY_RF_CFG1_MAX] = {
+     [PHY_SHUTDOWNZ] = REG_FIELD(0x0, 0, 0),
+     [DPHY_RSTZ] = REG_FIELD(0x4, 0, 0),
+     [TEST_CLR] = REG_FIELD(0x10, 0, 0),
+     [TEST_CLK] = REG_FIELD(0x10, 1, 1),
+     [TEST_IN] = REG_FIELD(0x14, 0, 7),
+     [TEST_OUT] = REG_FIELD(0x14, 8, 15),
+     [TEST_EN] = REG_FIELD(0x14, 16, 16),

drivers/phy/phy-dw-dphy.c new file +3 -0
+};
+
+static const struct reg_field

dw_dphy_v1_2_cfg2[DW_DPHY_RF_CFG2_MAX] = {
+     [EN_CONT_REG_UPDATE] = REG_FIELD(0x0, 23, 23), +     [TURN_REQUEST_0] = REG_FIELD(0x0, 22, 22), +     [TURN_DISABLE_0] = REG_FIELD(0x0, 21, 21), +     [ENABLE_CLK] = REG_FIELD(0x0, 20, 20), +     [FORCE_TX_STOP_MODE_0] = REG_FIELD(0x0, 19, 19), +     [FORCE_RX_MODE] = REG_FIELD(0x0, 15, 18), +     [BASE_DIR_0] = REG_FIELD(0x0, 14, 14), +     [CFG_CLK_FREQ_RANGE] = REG_FIELD(0x0, 8, 13), +     [HS_FREQ_RANGE] = REG_FIELD(0x0, 1, 7), +     [CONT_EN] = REG_FIELD(0x0, 0, 0),

drivers/phy/phy-dw-dphy.c new file +30 -0
+};
+
+enum dphy_12bit_interface_addr {
+     RX_SYS_0 = 0x01,
+     RX_SYS_1 = 0x02,
+     RX_SYS_7 = 0x08,
+     RX_RX_STARTUP_OVR_0 = 0xe0,
+     RX_RX_STARTUP_OVR_1 = 0xe1,
+     RX_RX_STARTUP_OVR_2 = 0xe2,
+     RX_RX_STARTUP_OVR_3 = 0xe3,
+     RX_RX_STARTUP_OVR_4 = 0xe4,
+};
+
+/**
+ * struct range_dphy_gen3 - frequency range calibration structure
+ *
+ * @freq: input freqency to calibration table
+ * @hsfregrange: corresponding clock to configure DW D-PHY IP
+ * @osc_freq_target: corresponding clock to configure DW D-PHY IP
+ *
+ **/
+struct range_dphy_gen3 {
+     u32 freq;
+     u8 hsfregrange;
+     u32 osc_freq_target;
+};
+
+/**
+ * struct dt_data_dw_dphy - DPHY configuration data structure
+ * @table: Pointer to array of DPHY Gen3 timing range

configurations
+ * @table_size: Number of entries in the timing range table
+ * @phy_ops: Pointer to PHY operations structure containing callback functions
+ *
+ **/

drivers/phy/phy-dw-dphy.c new file +57 -0
+struct dt_data_dw_dphy {
+     struct range_dphy_gen3 *table;
+     int table_size;
+     const struct phy_ops *phy_ops;
+};
+
+/*
+ * DW DPHY Gen3 calibration table
+ *
+ */
+struct range_dphy_gen3 range_gen3[] = {
+     { 80, 0b0000000, 460 },   { 90, 0b0010000, 460 },
+     { 100, 0b0100000, 460 },  { 110, 0b0110000, 460 },
+     { 120, 0b0000001, 460 },  { 130, 0b0010001, 460 },
+     { 140, 0b0100001, 460 },  { 150, 0b0110001, 460 },
+     { 160, 0b0000010, 460 },  { 170, 0b0010010, 460 },
+     { 180, 0b0100010, 460 },  { 190, 0b0110010, 460 },
+     { 205, 0b0000011, 460 },  { 220, 0b0010011, 460 },
+     { 235, 0b0100011, 460 },  { 250, 0b0110011, 460 },
+     { 275, 0b0000100, 460 },  { 300, 0b0010100, 460 },
+     { 325, 0b0100101, 460 },  { 350, 0b0110101, 460 },
+     { 400, 0b0000101, 460 },  { 450, 0b0010110, 460 },
+     { 500, 0b0100110, 460 },  { 550, 0b0110111, 460 },
+     { 600, 0b0000111, 460 },  { 650, 0b0011000, 460 },
+     { 700, 0b0101000, 460 },  { 750, 0b0111001, 460 },
+     { 800, 0b0001001, 460 },  { 850, 0b0011001, 460 },
+     { 900, 0b0101001, 460 },  { 950, 0b0111010, 460 },
+     { 1000, 0b0001010, 460 }, { 1050, 0b0011010, 460 },
+     { 1110, 0b0101010, 460 }, { 1150, 0b0111011, 460 },
+     { 1200, 0b0001011, 460 }, { 1250, 0b0011011, 460 },
+     { 1300, 0b0101011, 460 }, { 1350, 0b0111100, 460 },
+     { 1400, 0b0001100, 460 }, { 1450, 0b0011100, 460 },
+     { 1500, 0b0101100, 460 }, { 1550, 0b0111101, 285 },
+     { 1600, 0b0001101, 295 }, { 1650, 0b0011101, 304 },
+     { 1700, 0b0101110, 313 }, { 1750, 0b0111110, 322 },
+     { 1800, 0b0001110, 331 }, { 1850, 0b0011110, 341 },
+     { 1900, 0b0101111, 350 }, { 1950, 0b0111111, 359 },
+     { 2000, 0b0001111, 368 }, { 2050, 0b1000000, 377 },
+     { 2100, 0b1000001, 387 }, { 2150, 0b1000010, 396 },
+     { 2200, 0b1000011, 405 }, { 2250, 0b1000100, 414 },
+     { 2300, 0b1000101, 423 }, { 2350, 0b1000110, 432 },
+     { 2400, 0b1000111, 442 }, { 2450, 0b1001000, 451 },
+     { 2500, 0b1001001, 460 }
+};
+
+/**
+ * struct dw_dphy - DW D-PHY driver private structure
+ *
+ * @regmap: pointer to regmap
+ * @regmap_cfg1: pointer to config1 regmap
+ * @regmap_cfg2: pointer to config2 regmap
+ * @rf_cfg1: array of regfields for config1
+ * @rf_cfg2: array of regfields for config2
+ * @iomem_cfg1: MMIO address for cfg1 section
+ * @iomem_cfg2: MMIO address for cfg2 section
+ * @phy: pointer to the phy data structure
+ * @hs_clk_rate: high speed clock rate as per image sensor

configuration
+ * @dt_data_dw_dphy: device tree specific data
+ *
+ **/

drivers/phy/phy-dw-dphy.c new file +22 -0
+struct dw_dphy {
+     struct regmap *regmap_cfg1;
+     struct regmap *regmap_cfg2;
+     struct regmap_field *rf_cfg1[DW_DPHY_RF_CFG1_MAX];
+     struct regmap_field *rf_cfg2[DW_DPHY_RF_CFG2_MAX];
+     void __iomem *iomem_cfg1;
+     void __iomem *iomem_cfg2;
+     struct phy *phy;
+     struct device *dev;
+     unsigned long hs_clk_rate;
+     struct dt_data_dw_dphy *dt_data;
+};
+
+/**
+ * dw_dphy_te_write - write register into test enable interface
+ *
+ * @dphy: pointer to the dw_dphy private data structure
+ * @addr: 12 bit TE address register (16 bit container)
+ * @data: 8 bit data to be written to TE register
+ *
+ **/
+static void dw_dphy_te_write(struct dw_dphy *dphy, u16 addr, u8

data)

drivers/phy/phy-dw-dphy.c new file +18 -0
+{
+     /* For writing the 4-bit testcode MSBs */
+
+     /* Ensure that testclk and testen is set to low */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
+     regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
+
+     /* Set testen to high */
+     regmap_field_write(dphy->rf_cfg1[TEST_EN], 1);
+
+     /* Set testclk to high */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
+
+     /* Place 0x00 in testdin */
+     regmap_field_write(dphy->rf_cfg1[TEST_IN], 0);
+
+     /*
+      * Set testclk to low (with the falling edge on testclk, the

testdin signal
+      * content is latched internally)
+      */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);

drivers/phy/phy-dw-dphy.c new file +5 -0
+
+     /* Set testen to low */
+     regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
+
+     /* Place the 8-bit word corresponding to the testcode MSBs in

testdin */
+     regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr >> 8));

drivers/phy/phy-dw-dphy.c new file +20 -0
+
+     /* Set testclk to high */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
+
+     /* For writing the 8-bit testcode LSBs */
+
+     /* Set testclk to low */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
+
+     /* Set testen to high */
+     regmap_field_write(dphy->rf_cfg1[TEST_EN], 1);
+
+     /* Set testclk to high */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
+
+     /* Place the 8-bit word test data in testdin */
+     regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr & 0xff));
+
+     /*
+      * Set testclk to low (with the falling edge on testclk, the

testdin signal
+      * content is latched internally)
+      */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);

drivers/phy/phy-dw-dphy.c new file +7 -0
+
+     /* Set testen to low */
+     regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
+
+     /* For writing the data */
+
+     /* Place the 8-bit word corresponding to the page offset in

testdin */
+     regmap_field_write(dphy->rf_cfg1[TEST_IN], data); +
+     /* Set testclk to high (test data is programmed internally) */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);

drivers/phy/phy-dw-dphy.c new file +30 -0
+}
+
+/**
+ * dw_dphy_te_read - read register from test enable interface
+ *
+ * @dphy: pointer to the dw_dphy private data structure
+ * @addr: 12 bit TE address register (16 bit container)
+ * @returns: 8 bit data from TE register
+ **/
+static u8 dw_dphy_te_read(struct dw_dphy *dphy, u16 addr)
+{
+     u32 data;
+
+     /* For writing the 4-bit testcode MSBs */
+
+     /* Ensure that testclk and testen is set to low */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
+     regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
+
+     /* Set testen to high */
+     regmap_field_write(dphy->rf_cfg1[TEST_EN], 1);
+
+     /* Set testclk to high */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
+
+     /* Place 0x00 in testdin */
+     regmap_field_write(dphy->rf_cfg1[TEST_IN], 0);
+
+     /*
+      * Set testclk to low (with the falling edge on testclk, the

testdin signal
+      * content is latched internally)
+      */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);

drivers/phy/phy-dw-dphy.c new file +5 -0
+
+     /* Set testen to low */
+     regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
+
+     /* Place the 8-bit word corresponding to the testcode MSBs in

testdin */
+     regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr >> 8));

drivers/phy/phy-dw-dphy.c new file +20 -0
+
+     /* Set testclk to high */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
+
+     /* For writing the 8-bit testcode LSBs */
+
+     /* Set testclk to low */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
+
+     /* Set testen to high */
+     regmap_field_write(dphy->rf_cfg1[TEST_EN], 1);
+
+     /* Set testclk to high */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
+
+     /* Place the 8-bit word test data in testdin */
+     regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr & 0xff));
+
+     /*
+      * Set testclk to low (with the falling edge on testclk, the

testdin signal
+      * content is latched internally)
+      */
+     regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);

drivers/phy/phy-dw-dphy.c new file +18 -0
+
+     /* Set testen to low */
+     regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
+
+     regmap_field_read(dphy->rf_cfg1[TEST_OUT], &data);
+
+     return (u8)data;
+}
+
+/**
+ * dw_dphy_configure - configure the D-PHY
+ *
+ * @phy: pointer to the phy data structure
+ * @opts: pointer to the phy configuration options
+ * @returns 0 if success else appropriate error code
+ *
+ **/
+static int dw_dphy_configure(struct phy *phy, union

phy_configure_opts *opts)

drivers/phy/phy-dw-dphy.c new file +26 -0
+{
+     struct dw_dphy *dphy = phy_get_drvdata(phy);
+
+     dphy->hs_clk_rate = opts->mipi_dphy.hs_clk_rate;
+     dev_dbg(dphy->dev, "hs_clk_rate=%ld\n", dphy->hs_clk_rate);
+
+     return 0;
+}
+
+/**
+ * dw_dphy_power_on_1p2 - power on the DPHY version 1.2
+ *
+ * @phy: pointer to the phy data structure
+ * @returns 0 if success else appropriate error code
+ *
+ **/
+static int dw_dphy_power_on_1p2(struct phy *phy)
+{
+     struct dw_dphy *dphy = phy_get_drvdata(phy);
+
+     uint8_t counter_for_des_en_config_if_rw = 0x1;
+     u8 range = 0;
+
+     for (range = 0;
+          (range < dphy->dt_data->table_size - 1) &&
+          ((dphy->hs_clk_rate) > dphy->dt_data-
Quoted 1 line

table[range].freq);

+          range++)
+             ;
+
+     /* in case requested hs_clk_rate is out of range, return - EINVAL */
+     if (range >= dphy->dt_data->table_size)
+             return -EINVAL;
+
+     dev_dbg(dphy->dev, "12bit: PHY GEN 3: Freq: %ld %x\n", dphy-

Quoted 1 line

hs_clk_rate,

+              range_gen3[range].hsfregrange);
+
+     regmap_field_write(dphy->rf_cfg1[DPHY_RSTZ], 0); +     regmap_field_write(dphy->rf_cfg1[PHY_SHUTDOWNZ], 0); +     regmap_field_write(dphy->rf_cfg1[TEST_CLR], 0);
+     regmap_field_write(dphy->rf_cfg1[TEST_CLR], 1);
+     regmap_field_write(dphy->rf_cfg1[TEST_CLR], 0);
+     regmap_field_write(dphy->rf_cfg2[CFG_CLK_FREQ_RANGE], 0x28); +     dw_dphy_te_write(dphy, RX_SYS_1,
+                      dphy->dt_data->table[range].hsfregrange); +     dw_dphy_te_write(dphy, RX_SYS_0, 0x20);
+     dw_dphy_te_write(dphy, RX_RX_STARTUP_OVR_2,
+                      (u8)dphy->dt_data-

Quoted 1 line

table[range].osc_freq_target);

+     dw_dphy_te_write(dphy, RX_RX_STARTUP_OVR_3,
+                      (u8)(dphy->dt_data-

Quoted 1 line

table[range].osc_freq_target >>

+                           8));
+     dw_dphy_te_write(dphy, 0xe4,
+                      (counter_for_des_en_config_if_rw << 4) | 0b1);

drivers/phy/phy-dw-dphy.c new file +47 -0
+
+     dw_dphy_te_write(dphy, RX_RX_STARTUP_OVR_1, 0x01);
+     dw_dphy_te_write(dphy, RX_RX_STARTUP_OVR_0, 0x80);
+
+     regmap_field_write(dphy->rf_cfg2[BASE_DIR_0], 1);
+     regmap_field_write(dphy->rf_cfg2[ENABLE_CLK], 1);
+     regmap_field_write(dphy->rf_cfg2[FORCE_RX_MODE], 0x0);
+
+     regmap_field_write(dphy->rf_cfg1[PHY_SHUTDOWNZ], 1);
+     regmap_field_write(dphy->rf_cfg1[DPHY_RSTZ], 1);
+
+     return 0;
+}
+
+/**
+ * dw_dphy_power_off - power off the DPHY
+ *
+ * @phy: pointer to the phy data structure
+ * @returns 0 if success else appropriate error code
+ *
+ **/
+static int dw_dphy_power_off(struct phy *phy)
+{
+     struct dw_dphy *dphy = phy_get_drvdata(phy);
+
+     regmap_field_write(dphy->rf_cfg1[DPHY_RSTZ], 0);
+     regmap_field_write(dphy->rf_cfg1[PHY_SHUTDOWNZ], 0);
+     return 0;
+}
+
+/**
+ * dw_dphy_ops_1p2 - PHY operations for DWC DPHY v1.2
+ * @configure: Configures DPHY timing and operation parameters
+ * @power_on: Powers on the DPHY using v1.2 specific sequence
+ * @power_off: Powers off the DPHY
+ *
+ **/
+static const struct phy_ops dw_dphy_ops_1p2 = {
+     .configure = dw_dphy_configure,
+     .power_on = dw_dphy_power_on_1p2,
+     .power_off = dw_dphy_power_off,
+};
+
+/**
+ * dw_dphy_1p2 - DWC DPHY v1.2 configuration instance
+ * @table: Points to range_gen3 timing parameters table
+ * @table_size: Size of range_gen3 table calculated at compile

time
+ * @phy_ops: Points to v1.2 specific PHY operations structure
+ *
+ **/

drivers/phy/phy-dw-dphy.c new file +60 -0
+struct dt_data_dw_dphy dw_dphy_1p2 = {
+     .table = range_gen3,
+     .table_size = ARRAY_SIZE(range_gen3),
+     .phy_ops = &dw_dphy_ops_1p2,
+};
+
+/**
+ * dw_dphy_regmap_cfg1 - Register map configuration for DW DPHY
+ * @reg_bits: Width of register address in bits (32)
+ * @val_bits: Width of register value in bits (32)
+ * @reg_stride: Number of bytes between registers (4)
+ * @name: Name identifier for this register map
+ * @fast_io: Flag to indicate fast I/O operations are supported
+ *
+ **/
+static const struct regmap_config dw_dphy_regmap_cfg1 = {
+     .reg_bits = 32,
+     .val_bits = 32,
+     .reg_stride = 4,
+     .name = "dw-dhpy-cfg1",
+     .fast_io = true,
+};
+
+/**
+ * dw_dphy_regmap_cfg2 - Register map configuration for DW DPHY
+ * @reg_bits: Width of register address in bits (32)
+ * @val_bits: Width of register value in bits (32)
+ * @reg_stride: Number of bytes between registers (4)
+ * @name: Name identifier for this register map
+ * @fast_io: Flag to indicate fast I/O operations are supported
+ *
+ **/
+static const struct regmap_config dw_dphy_regmap_cfg2 = {
+     .reg_bits = 32,
+     .val_bits = 32,
+     .reg_stride = 4,
+     .name = "dw-dhpy-cfg2",
+     .fast_io = true,
+};
+
+/**
+ * dw_dphy_probe - Probe and initialize DW DPHY device
+ * @pdev: Platform device pointer
+ * Return: 0 on success, negative error code on failure
+ *
+ **/
+static int dw_dphy_probe(struct platform_device *pdev)
+{
+     struct dw_dphy *dphy;
+     struct resource *res;
+     struct device *dev = &pdev->dev;
+     struct phy_provider *phy_provider;
+     int ret;
+
+     dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL);
+     if (!dphy)
+             return -ENOMEM;
+
+     dphy->dt_data =
+             (struct dt_data_dw_dphy

*)of_device_get_match_data(&pdev->dev);
+     dev_set_drvdata(&pdev->dev, dphy);
+     dphy->dev = &pdev->dev;

drivers/phy/phy-dw-dphy.c new file +8 -0
+
+     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+     dphy->iomem_cfg1 = devm_ioremap_resource(&pdev->dev, res);
+     if (IS_ERR(dphy->iomem_cfg1))
+             return PTR_ERR(dphy->iomem_cfg1);
+
+     dphy->regmap_cfg1 =
+             devm_regmap_init_mmio(dev, dphy->iomem_cfg1,

&dw_dphy_regmap_cfg1);
+     if (IS_ERR(dphy->regmap_cfg1))
+             return PTR_ERR(dphy->regmap_cfg1);
+
+     ret = devm_regmap_field_bulk_alloc(dev, dphy->regmap_cfg1, dphy->rf_cfg1,
+                                        dw_dphy_v1_2_cfg1, DW_DPHY_RF_CFG1_MAX);
+     if (ret < 0) {
+             dev_err(dev, "Could not alloc RF\n");
+             return ret;
+     }

drivers/phy/phy-dw-dphy.c new file +7 -0
+
+     res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+     dphy->iomem_cfg2 = devm_ioremap_resource(&pdev->dev, res);
+     if (IS_ERR(dphy->iomem_cfg2))
+             return PTR_ERR(dphy->iomem_cfg2);
+
+     dphy->regmap_cfg2 = devm_regmap_init_mmio(dev, dphy-
Quoted 1 line

iomem_cfg2,

+
&dw_dphy_regmap_cfg2);
+     if (IS_ERR(dphy->regmap_cfg2))
+             return PTR_ERR(dphy->regmap_cfg2);
+
+     ret = devm_regmap_field_bulk_alloc(dev, dphy->regmap_cfg2, dphy->rf_cfg2,
+                                        dw_dphy_v1_2_cfg2, DW_DPHY_RF_CFG2_MAX);
+     if (ret < 0) {
+             dev_err(dev, "Could not alloc RF\n");
+             return ret;
+     }
+
+     dphy->phy = devm_phy_create(&pdev->dev, NULL, dphy->dt_data-

Quoted 1 line

phy_ops);

+     if (IS_ERR(dphy->phy)) {
+             dev_err(dev, "failed to create PHY\n"); +             return PTR_ERR(dphy->phy);
+     }
+
+     phy_set_drvdata(dphy->phy, dphy);
+     phy_provider =
+             devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);

drivers/phy/phy-dw-dphy.c new file +27 -0
+
+     return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+/**
+ * dw_dphy_of_match - Device tree match table for DW DPHY
+ * @compatible: Compatible string to match device tree node
+ * @data: Pointer to configuration data for matched device
+ *
+ * Table of compatible strings and associated configuration data
+ * for supported DW DPHY variants.
+ * Currently supports:
+ * - DW DPHY v1.2 ("snps,dw-dphy-1p2")
+ *
+ **/
+static const struct of_device_id dw_dphy_of_match[] = {
+     { .compatible = "snps,dw-dphy-1p2", .data = &dw_dphy_1p2 },
+     { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, dw_dphy_of_match);
+
+/**
+ * dw_dphy_platform_driver - Platform driver structure for DW DPHY
+ * @probe: Pointer to probe function called on device discovery
+ * @driver: Core driver structure containing:
+ *         - name: Driver name used for matching and debugging
+ *         - of_match_table: Table of compatible device tree

matches
+ *
+ **/

drivers/phy/phy-dw-dphy.c new file +14 -1
+static struct platform_driver dw_dphy_platform_driver = {
+     .probe          = dw_dphy_probe,
+     .driver         = {
+             .name           = "dw-dphy",
+             .of_match_table = dw_dphy_of_match,
+     },
+};
+module_platform_driver(dw_dphy_platform_driver);
+
+MODULE_AUTHOR("Karthik Poduval <[email protected]>");
+MODULE_AUTHOR("Jason Xiong <[email protected]>");
+MODULE_AUTHOR("Miguel Lopes <[email protected]>");
+MODULE_DESCRIPTION("DW D-PHY RX Driver");
+MODULE_LICENSE("GPL");
--

2.43.0

#7 lore raw

Re: [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX

In reply to Karthik Poduval
Quoted 7 lines · Karthik Poduval
drivers/phy/phy-dw-dphy.c new file +7 -0
+static const struct regmap_config dw_dphy_regmap_cfg1 = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
+	.name = "dw-dhpy-cfg1",
+	.fast_io = true,
+};

drivers/phy/phy-dw-dphy.c line 458

Quoted 10 lines
drivers/phy/phy-dw-dphy.c new file +10 -0
+
+/**
+ * dw_dphy_regmap_cfg2 - Register map configuration for DW DPHY
+ * @reg_bits: Width of register address in bits (32)
+ * @val_bits: Width of register value in bits (32)
+ * @reg_stride: Number of bytes between registers (4)
+ * @name: Name identifier for this register map
+ * @fast_io: Flag to indicate fast I/O operations are supported
+ *
+ **/

Drop

Quoted 4 lines
drivers/phy/phy-dw-dphy.c new file +4 -0
+static const struct regmap_config dw_dphy_regmap_cfg2 = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,

drivers/phy/phy-dw-dphy.c line 472

Quoted 10 lines
drivers/phy/phy-dw-dphy.c new file +10 -0
+	.name = "dw-dhpy-cfg2",
+	.fast_io = true,
+};
+
+/**
+ * dw_dphy_probe - Probe and initialize DW DPHY device
+ * @pdev: Platform device pointer
+ * Return: 0 on success, negative error code on failure
+ *
+ **/

Drop

Quoted 65 lines
drivers/phy/phy-dw-dphy.c new file +65 -0
+static int dw_dphy_probe(struct platform_device *pdev)
+{
+	struct dw_dphy *dphy;
+	struct resource *res;
+	struct device *dev = &pdev->dev;
+	struct phy_provider *phy_provider;
+	int ret;
+
+	dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL);
+	if (!dphy)
+		return -ENOMEM;
+
+	dphy->dt_data =
+		(struct dt_data_dw_dphy *)of_device_get_match_data(&pdev->dev);
+	dev_set_drvdata(&pdev->dev, dphy);
+	dphy->dev = &pdev->dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	dphy->iomem_cfg1 = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(dphy->iomem_cfg1))
+		return PTR_ERR(dphy->iomem_cfg1);
+
+	dphy->regmap_cfg1 =
+		devm_regmap_init_mmio(dev, dphy->iomem_cfg1, &dw_dphy_regmap_cfg1);
+	if (IS_ERR(dphy->regmap_cfg1))
+		return PTR_ERR(dphy->regmap_cfg1);
+
+	ret = devm_regmap_field_bulk_alloc(dev, dphy->regmap_cfg1, dphy->rf_cfg1,
+					   dw_dphy_v1_2_cfg1, DW_DPHY_RF_CFG1_MAX);
+	if (ret < 0) {
+		dev_err(dev, "Could not alloc RF\n");
+		return ret;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	dphy->iomem_cfg2 = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(dphy->iomem_cfg2))
+		return PTR_ERR(dphy->iomem_cfg2);
+
+	dphy->regmap_cfg2 = devm_regmap_init_mmio(dev, dphy->iomem_cfg2,
+						 &dw_dphy_regmap_cfg2);
+	if (IS_ERR(dphy->regmap_cfg2))
+		return PTR_ERR(dphy->regmap_cfg2);
+
+	ret = devm_regmap_field_bulk_alloc(dev, dphy->regmap_cfg2, dphy->rf_cfg2,
+					   dw_dphy_v1_2_cfg2, DW_DPHY_RF_CFG2_MAX);
+	if (ret < 0) {
+		dev_err(dev, "Could not alloc RF\n");
+		return ret;
+	}
+
+	dphy->phy = devm_phy_create(&pdev->dev, NULL, dphy->dt_data->phy_ops);
+	if (IS_ERR(dphy->phy)) {
+		dev_err(dev, "failed to create PHY\n");
+		return PTR_ERR(dphy->phy);
+	}
+
+	phy_set_drvdata(dphy->phy, dphy);
+	phy_provider =
+		devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
+
+	return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+/**

drivers/phy/phy-dw-dphy.c line 547

Quoted 10 lines
drivers/phy/phy-dw-dphy.c new file +10 -0
+ * dw_dphy_of_match - Device tree match table for DW DPHY
+ * @compatible: Compatible string to match device tree node
+ * @data: Pointer to configuration data for matched device
+ *
+ * Table of compatible strings and associated configuration data
+ * for supported DW DPHY variants.
+ * Currently supports:
+ * - DW DPHY v1.2 ("snps,dw-dphy-1p2")
+ *
+ **/

Drop

Quoted 4 lines
drivers/phy/phy-dw-dphy.c new file +4 -0
+static const struct of_device_id dw_dphy_of_match[] = {
+	{ .compatible = "snps,dw-dphy-1p2", .data = &dw_dphy_1p2 },
+	{ /* sentinel */ },
+};

drivers/phy/phy-dw-dphy.c line 561

Quoted 10 lines
drivers/phy/phy-dw-dphy.c new file +10 -0
+MODULE_DEVICE_TABLE(of, dw_dphy_of_match);
+
+/**
+ * dw_dphy_platform_driver - Platform driver structure for DW DPHY
+ * @probe: Pointer to probe function called on device discovery
+ * @driver: Core driver structure containing:
+ *         - name: Driver name used for matching and debugging
+ *         - of_match_table: Table of compatible device tree matches
+ *
+ **/

Drop all such useless generic kerneldocs. Not helpful. Keep useful ones, so ones not saying obvious parts of core

drivers/phy/phy-dw-dphy.c line 563

Quoted 2 lines
drivers/phy/phy-dw-dphy.c new file +2 -0
+static struct platform_driver dw_dphy_platform_driver = {
+	.probe		= dw_dphy_probe,

Best regards,
Krzysztof

#8 lore raw

Re: [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX

In reply to Karthik Poduval
kernel test robot noticed the following build warnings:

Hi Karthik,

kernel test robot noticed the following build warnings:

[auto build test WARNING on robh/for-next]
[also build test WARNING on linus/master v6.16-rc5 next-20250710] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Karthik-Poduval/phy-dw-dphy-rx-Add-Synopsys-DesignWare-D-PHY-RX/20250710-104505
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
patch link:    https://lore.kernel.org/r/2383f8cf2a8f5e1b914d4cf9bd11674ed55876d2.1752106239.git.kpoduval%40lab126.com
patch subject: [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX
config: x86_64-randconfig-002-20250711 (https://download.01.org/0day-ci/archive/20250711/[email protected]/config)
compiler: gcc-12 (Debian 12.2.0-14+deb12u1) 12.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250711/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All warnings (new ones prefixed by >>):

>> drivers/phy/phy-dw-dphy.c:254:11: warning: 'dw_dphy_te_read' defined but not used [-Wunused-function]
     254 | static u8 dw_dphy_te_read(struct dw_dphy *dphy, u16 addr)
         |           ^~~~~~~~~~~~~~~
--
>> Warning: drivers/phy/phy-dw-dphy.c:172 struct member 'dev' not described in 'dw_dphy'
>> Warning: drivers/phy/phy-dw-dphy.c:172 struct member 'dt_data' not described in 'dw_dphy'
>> Warning: drivers/phy/phy-dw-dphy.c:172 Excess struct member 'regmap' description in 'dw_dphy'
>> Warning: drivers/phy/phy-dw-dphy.c:172 Excess struct member 'dt_data_dw_dphy' description in 'dw_dphy'

vim +/dw_dphy_te_read +254 drivers/phy/phy-dw-dphy.c

146
147 /**
148 * struct dw_dphy - DW D-PHY driver private structure
149 *
150 * @regmap: pointer to regmap
151 * @regmap_cfg1: pointer to config1 regmap
152 * @regmap_cfg2: pointer to config2 regmap
153 * @rf_cfg1: array of regfields for config1
154 * @rf_cfg2: array of regfields for config2
155 * @iomem_cfg1: MMIO address for cfg1 section
156 * @iomem_cfg2: MMIO address for cfg2 section
157 * @phy: pointer to the phy data structure
158 * @hs_clk_rate: high speed clock rate as per image sensor configuration
159 * @dt_data_dw_dphy: device tree specific data
160 *
161 **/
162 struct dw_dphy {
163 struct regmap *regmap_cfg1;
164 struct regmap *regmap_cfg2;
165 struct regmap_field *rf_cfg1[DW_DPHY_RF_CFG1_MAX];
166 struct regmap_field *rf_cfg2[DW_DPHY_RF_CFG2_MAX];
167 void __iomem *iomem_cfg1;
168 void __iomem *iomem_cfg2;
169 struct phy *phy;
170 struct device *dev;
171 unsigned long hs_clk_rate;

 > 172		struct dt_data_dw_dphy *dt_data;
   173	};
   174	
   175	/**
   176	 * dw_dphy_te_write - write register into test enable interface
   177	 *
   178	 * @dphy: pointer to the dw_dphy private data structure
   179	 * @addr: 12 bit TE address register (16 bit container)
   180	 * @data: 8 bit data to be written to TE register
   181	 *
   182	 **/
   183	static void dw_dphy_te_write(struct dw_dphy *dphy, u16 addr, u8 data)
   184	{
   185		/* For writing the 4-bit testcode MSBs */
   186	
   187		/* Ensure that testclk and testen is set to low */
   188		regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
   189		regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
   190	
   191		/* Set testen to high */
   192		regmap_field_write(dphy->rf_cfg1[TEST_EN], 1);
   193	
   194		/* Set testclk to high */
   195		regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
   196	
   197		/* Place 0x00 in testdin */
   198		regmap_field_write(dphy->rf_cfg1[TEST_IN], 0);
   199	
   200		/*
   201		 * Set testclk to low (with the falling edge on testclk, the testdin signal
   202		 * content is latched internally)
   203		 */
   204		regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
   205	
   206		/* Set testen to low */
   207		regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
   208	
   209		/* Place the 8-bit word corresponding to the testcode MSBs in testdin */
   210		regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr >> 8));
   211	
   212		/* Set testclk to high */
   213		regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
   214	
   215		/* For writing the 8-bit testcode LSBs */
   216	
   217		/* Set testclk to low */
   218		regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
   219	
   220		/* Set testen to high */
   221		regmap_field_write(dphy->rf_cfg1[TEST_EN], 1);
   222	
   223		/* Set testclk to high */
   224		regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
   225	
   226		/* Place the 8-bit word test data in testdin */
   227		regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr & 0xff));
   228	
   229		/*
   230		 * Set testclk to low (with the falling edge on testclk, the testdin signal
   231		 * content is latched internally)
   232		 */
   233		regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
   234	
   235		/* Set testen to low */
   236		regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
   237	
   238		/* For writing the data */
   239	
   240		/* Place the 8-bit word corresponding to the page offset in testdin */
   241		regmap_field_write(dphy->rf_cfg1[TEST_IN], data);
   242	
   243		/* Set testclk to high (test data is programmed internally) */
   244		regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
   245	}
   246	
   247	/**
   248	 * dw_dphy_te_read - read register from test enable interface
   249	 *
   250	 * @dphy: pointer to the dw_dphy private data structure
   251	 * @addr: 12 bit TE address register (16 bit container)
   252	 * @returns: 8 bit data from TE register
   253	 **/
 > 254	static u8 dw_dphy_te_read(struct dw_dphy *dphy, u16 addr)

255 {
256 u32 data;
257
258 /* For writing the 4-bit testcode MSBs */
259
260 /* Ensure that testclk and testen is set to low */
261 regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
262 regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
263
264 /* Set testen to high */
265 regmap_field_write(dphy->rf_cfg1[TEST_EN], 1);
266
267 /* Set testclk to high */
268 regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
269
270 /* Place 0x00 in testdin */
271 regmap_field_write(dphy->rf_cfg1[TEST_IN], 0);
272
273 /*
274 * Set testclk to low (with the falling edge on testclk, the testdin signal
275 * content is latched internally)
276 */
277 regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
278
279 /* Set testen to low */
280 regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
281
282 /* Place the 8-bit word corresponding to the testcode MSBs in testdin */
283 regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr >> 8));
284
285 /* Set testclk to high */
286 regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
287
288 /* For writing the 8-bit testcode LSBs */
289
290 /* Set testclk to low */
291 regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
292
293 /* Set testen to high */
294 regmap_field_write(dphy->rf_cfg1[TEST_EN], 1);
295
296 /* Set testclk to high */
297 regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
298
299 /* Place the 8-bit word test data in testdin */
300 regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr & 0xff));
301
302 /*
303 * Set testclk to low (with the falling edge on testclk, the testdin signal
304 * content is latched internally)
305 */
306 regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
307
308 /* Set testen to low */
309 regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
310
311 regmap_field_read(dphy->rf_cfg1[TEST_OUT], &data);
312
313 return (u8)data;
314 }
315

Signature · 2 lines
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
#9 lore raw

Re: [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX

In reply to Karthik Poduval
kernel test robot noticed the following build warnings:

Hi Karthik,

kernel test robot noticed the following build warnings:

[auto build test WARNING on robh/for-next]
[also build test WARNING on linus/master v6.16-rc5 next-20250710] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Karthik-Poduval/phy-dw-dphy-rx-Add-Synopsys-DesignWare-D-PHY-RX/20250710-104505
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
patch link:    https://lore.kernel.org/r/2383f8cf2a8f5e1b914d4cf9bd11674ed55876d2.1752106239.git.kpoduval%40lab126.com
patch subject: [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX
config: sparc-randconfig-r123-20250711 (https://download.01.org/0day-ci/archive/20250711/[email protected]/config)
compiler: sparc-linux-gcc (GCC) 12.4.0
reproduce: (https://download.01.org/0day-ci/archive/20250711/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

sparse warnings: (new ones prefixed by >>)

>> drivers/phy/phy-dw-dphy.c:112:24: sparse: sparse: symbol 'range_gen3' was not declared. Should it be static?
>> drivers/phy/phy-dw-dphy.c:427:24: sparse: sparse: symbol 'dw_dphy_1p2' was not declared. Should it be static?

vim +/range_gen3 +112 drivers/phy/phy-dw-dphy.c

107
108 /*
109 * DW DPHY Gen3 calibration table
110 *
111 */

 > 112	struct range_dphy_gen3 range_gen3[] = {
   113		{ 80, 0b0000000, 460 },	  { 90, 0b0010000, 460 },
   114		{ 100, 0b0100000, 460 },  { 110, 0b0110000, 460 },
   115		{ 120, 0b0000001, 460 },  { 130, 0b0010001, 460 },
   116		{ 140, 0b0100001, 460 },  { 150, 0b0110001, 460 },
   117		{ 160, 0b0000010, 460 },  { 170, 0b0010010, 460 },
   118		{ 180, 0b0100010, 460 },  { 190, 0b0110010, 460 },
   119		{ 205, 0b0000011, 460 },  { 220, 0b0010011, 460 },
   120		{ 235, 0b0100011, 460 },  { 250, 0b0110011, 460 },
   121		{ 275, 0b0000100, 460 },  { 300, 0b0010100, 460 },
   122		{ 325, 0b0100101, 460 },  { 350, 0b0110101, 460 },
   123		{ 400, 0b0000101, 460 },  { 450, 0b0010110, 460 },
   124		{ 500, 0b0100110, 460 },  { 550, 0b0110111, 460 },
   125		{ 600, 0b0000111, 460 },  { 650, 0b0011000, 460 },
   126		{ 700, 0b0101000, 460 },  { 750, 0b0111001, 460 },
   127		{ 800, 0b0001001, 460 },  { 850, 0b0011001, 460 },
   128		{ 900, 0b0101001, 460 },  { 950, 0b0111010, 460 },

129 { 1000, 0b0001010, 460 }, { 1050, 0b0011010, 460 },
130 { 1110, 0b0101010, 460 }, { 1150, 0b0111011, 460 },
131 { 1200, 0b0001011, 460 }, { 1250, 0b0011011, 460 },
132 { 1300, 0b0101011, 460 }, { 1350, 0b0111100, 460 },
133 { 1400, 0b0001100, 460 }, { 1450, 0b0011100, 460 },
134 { 1500, 0b0101100, 460 }, { 1550, 0b0111101, 285 },
135 { 1600, 0b0001101, 295 }, { 1650, 0b0011101, 304 },
136 { 1700, 0b0101110, 313 }, { 1750, 0b0111110, 322 },
137 { 1800, 0b0001110, 331 }, { 1850, 0b0011110, 341 },
138 { 1900, 0b0101111, 350 }, { 1950, 0b0111111, 359 },
139 { 2000, 0b0001111, 368 }, { 2050, 0b1000000, 377 },
140 { 2100, 0b1000001, 387 }, { 2150, 0b1000010, 396 },
141 { 2200, 0b1000011, 405 }, { 2250, 0b1000100, 414 },
142 { 2300, 0b1000101, 423 }, { 2350, 0b1000110, 432 },
143 { 2400, 0b1000111, 442 }, { 2450, 0b1001000, 451 },
144 { 2500, 0b1001001, 460 }
145 };
146

Signature · 2 lines
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
#10 lore raw

PATCH v2 2/2 phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI D-PHY RX

In reply to Karthik Poduval

Add DT Bindings for Synopsys D-PHY RX, presently tested on version 1.2

---
 .../bindings/phy/snps,dw-dphy-rx.yaml         | 44 +++++++++++++++++++
 MAINTAINERS                                   |  7 +++
 2 files changed, 51 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +44 -0
new file mode 100644
index 000000000000..c3c657b1e77d
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/snps,dw-dphy-rx.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Synopsys Designware MIPI D-PHY RX
+
+maintainers:
+  - Karthik Poduval <[email protected]>
+  - Jason Xiong <[email protected]>
+  - Miguel Lopes <[email protected]
+
+description: |
+  These are the bindings for Synopsys Designware MIPI DPHY RX phy driver.
+  Currently only supported phy version is v1.2.
+
+properties:
+  compatible:
+    const: snps,dw-dphy-1p2
+
+  '#phy-cells':
+    const: 0
+
+  reg:
+    minItems: 2
+    maxItems: 2
+
+required:
+  - compatible
+  - '#phy-cells'
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    dw_dphy_rx: dw-dphy@900000040 {
+        compatible = "snps,dw-dphy-1p2";
+        #phy-cells = <0>;
+        reg = <0x0 0x90000040 0x0 0x20>, <0x0 0x90001000 0x0 0x8>;
+        status = "disabled";
+    };
+
MAINTAINERS +7 -0
index b5a472a544cf..5fd5a92431bd 100644
@@ -24217,6 +24217,13 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml
 F:	drivers/dma/dw-axi-dmac/
 
+SYNOPSYS DESIGNWARE MIPI D-PHY RX DRIVER
+M:	Karthik Poduval <[email protected]>
+M:	Jason Xiong <[email protected]>
+M:	Miguel Lopes <[email protected]>
+S:	Supported
+F:	Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml
+
 SYNOPSYS DESIGNWARE DMAC DRIVER
 M:	Viresh Kumar <[email protected]>
 R:	Andy Shevchenko <[email protected]>
Signature · 1 line
2.43.0
#11 lore raw

Re: [PATCH v2 2/2] phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI D-PHY RX

Quoted 9 lines · Karthik Poduval

Add DT Bindings for Synopsys D-PHY RX, presently tested on version 1.2

---
 .../bindings/phy/snps,dw-dphy-rx.yaml         | 44 +++++++++++++++++++
 MAINTAINERS                                   |  7 +++
 2 files changed, 51 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.example.dtb: dw-dphy@900000040 (snps,dw-dphy-1p2): reg: [[0, 2415919168], [0, 32], [0, 2415923200], [0, 8]] is too long
from schema $id: http://devicetree.org/schemas/phy/snps,dw-dphy-rx.yaml#

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/7f4b676678b27ea91314c834a297c1e057959b09.1752106239.git.kpoduval@lab126.com

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.

maintainer
#12 lore raw

Re: [PATCH v2 2/2] phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI D-PHY RX

In reply to Karthik Poduval
Quoted 19 lines · Karthik Poduval

Add DT Bindings for Synopsys D-PHY RX, presently tested on version 1.2

---
 .../bindings/phy/snps,dw-dphy-rx.yaml         | 44 +++++++++++++++++++
 MAINTAINERS                                   |  7 +++
 2 files changed, 51 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +4 -0
new file mode 100644
index 000000000000..c3c657b1e77d
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/snps,dw-dphy-rx.yaml#

Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml line 14

Quoted 10 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +10 -0
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Synopsys Designware MIPI D-PHY RX
+
+maintainers:
+  - Karthik Poduval <[email protected]>
+  - Jason Xiong <[email protected]>
+  - Miguel Lopes <[email protected]
+
+description: |

Needn't |

Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml line 27

Quoted 13 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +13 -0
+  These are the bindings for Synopsys Designware MIPI DPHY RX phy driver.
+  Currently only supported phy version is v1.2.
+
+properties:
+  compatible:
+    const: snps,dw-dphy-1p2
+
+  '#phy-cells':
+    const: 0
+
+  reg:
+    minItems: 2
+    maxItems: 2

items:
- description: ....
- description: ....

Not all dphy have second register.

Quoted 4 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +4 -0
+
+required:
+  - compatible
+  - '#phy-cells'

Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml line 41

Quoted 10 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +10 -0
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    dw_dphy_rx: dw-dphy@900000040 {
+        compatible = "snps,dw-dphy-1p2";
+        #phy-cells = <0>;
+        reg = <0x0 0x90000040 0x0 0x20>, <0x0 0x90001000 0x0 0x8>;

Some DW MIPI CSI2 test1/test2 register is not tail part of whole MMIO space

such as imx93.

Frank

Quoted 24 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +3 -0
+        status = "disabled";
+    };
+
MAINTAINERS +7 -1
index b5a472a544cf..5fd5a92431bd 100644
@@ -24217,6 +24217,13 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml
 F:	drivers/dma/dw-axi-dmac/
 
+SYNOPSYS DESIGNWARE MIPI D-PHY RX DRIVER
+M:	Karthik Poduval <[email protected]>
+M:	Jason Xiong <[email protected]>
+M:	Miguel Lopes <[email protected]>
+S:	Supported
+F:	Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml
+
 SYNOPSYS DESIGNWARE DMAC DRIVER
 M:	Viresh Kumar <[email protected]>
 R:	Andy Shevchenko <[email protected]>
--

2.43.0

#13 lore raw

Re: [PATCH v2 2/2] phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI D-PHY RX

In reply to Karthik Poduval
Quoted 2 lines · Karthik Poduval

+---
+$id: http://devicetree.org/schemas/phy/snps,dw-dphy-rx.yaml#

Filename and id should match compatible.

Quoted 6 lines

+$schema: http://devicetree.org/meta-schemas/core.yaml#

Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +5 -0
+
+title: Synopsys Designware MIPI D-PHY RX
+
+maintainers:
+  - Karthik Poduval <[email protected]>

Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml line 20

Quoted 10 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +10 -0
+  - Jason Xiong <[email protected]>
+  - Miguel Lopes <[email protected]
+
+description: |
+  These are the bindings for Synopsys Designware MIPI DPHY RX phy driver.
+  Currently only supported phy version is v1.2.
+
+properties:
+  compatible:
+    const: snps,dw-dphy-1p2

You should rather use SoC compatibles.

Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml line 27

Quoted 7 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +7 -0
+
+  '#phy-cells':
+    const: 0
+
+  reg:
+    minItems: 2
+    maxItems: 2

List the items instead

And fix the order, reg goes second.

Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml line 32

Quoted 5 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +5 -0
+
+required:
+  - compatible
+  - '#phy-cells'
+  - reg

Here as well

Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml line 38

Quoted 6 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +6 -0
+
+additionalProperties: false
+
+examples:
+  - |
+    dw_dphy_rx: dw-dphy@900000040 {

phy@

Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml line 42

Quoted 4 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +4 -0
+        compatible = "snps,dw-dphy-1p2";
+        #phy-cells = <0>;
+        reg = <0x0 0x90000040 0x0 0x20>, <0x0 0x90001000 0x0 0x8>;
+        status = "disabled";

No, drop. And fix the order of properties, see DTS coding style.

Quoted 1 line

+ };

Best regards,
Krzysztof

#14 lore raw

Re: [PATCH v2 2/2] phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI D-PHY RX

Hi Krzysztof,

Thanks for your comments.

Quoted 23 lines · Krzysztof Kozlowski

CAUTION: This email originated from outside of the organization. Do not click links or open attachments unless you can confirm the sender and know the content is safe.

Quoted 2 lines · Karthik Poduval

+---
+$id: http://devicetree.org/schemas/phy/snps,dw-dphy-rx.yaml#

Filename and id should match compatible.

Quoted 11 lines

+$schema: http://devicetree.org/meta-schemas/core.yaml#

Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +10 -0
+
+title: Synopsys Designware MIPI D-PHY RX
+
+maintainers:
+  - Karthik Poduval <[email protected]>
+  - Jason Xiong <[email protected]>
+  - Miguel Lopes <[email protected]
+
+description: |
+  These are the bindings for Synopsys Designware MIPI DPHY RX phy
Quoted 8 lines

Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml line 20

Quoted 6 lines

driver.
+  Currently only supported phy version is v1.2.

Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +4 -0
+
+properties:
+  compatible:
+    const: snps,dw-dphy-1p2

You should rather use SoC compatibles.

If similar Synopsys D-PHY is used in multiple SoCs with slight variations, should each SoC have its own D-PHY driver or is it better to have a common one that works for all SoCs like arm,smmu-v3 or like the EEPROM driver below ?
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/misc/eeprom/eeprom_93xx46.c?h=v6.16-rc5#n391
where driver specific driver_data could support multiple versions or SoC variations.
Our team thought of the common driver approach however looking for general guidance from PHY subsystem maintainers and contributors.

Quoted 11 lines

Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml line 27

Quoted 8 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +7 -0
+
+  '#phy-cells':
+    const: 0
+
+  reg:
+    minItems: 2
+    maxItems: 2

List the items instead

Quoted 1 line

And fix the order, reg goes second.

ack

Quoted 8 lines

Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml line 32

Quoted 6 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +5 -0
+
+required:
+  - compatible
+  - '#phy-cells'
+  - reg

Here as well

ack

Quoted 22 lines

Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml line 38

Quoted 7 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +6 -0
+
+additionalProperties: false
+
+examples:
+  - |
+    dw_dphy_rx: dw-dphy@900000040 {

phy@

Quoted 4 lines

+        compatible = "snps,dw-dphy-1p2";
+        #phy-cells = <0>;
+        reg = <0x0 0x90000040 0x0 0x20>, <0x0 0x90001000 0x0 0x8>; +        status = "disabled";

No, drop. And fix the order of properties, see DTS coding style.

Quoted 1 line

+    };

Best regards,
Krzysztof

#15 lore raw

Re: [PATCH v2 2/2] phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI D-PHY RX

Quoted 15 lines · Karthik
Quoted 7 lines
Quoted 7 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +7 -0
+maintainers:
+  - Karthik Poduval <[email protected]>
+  - Jason Xiong <[email protected]>
+  - Miguel Lopes <[email protected]
+
+description: |
+  These are the bindings for Synopsys Designware MIPI DPHY RX phy
Quoted 8 lines

Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml line 20

Quoted 6 lines

driver.
+  Currently only supported phy version is v1.2.

Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +4 -0
+
+properties:
+  compatible:
+    const: snps,dw-dphy-1p2

You should rather use SoC compatibles.

Quoted 2 lines

If similar Synopsys D-PHY is used in multiple SoCs with slight variations, should each SoC have its own D-PHY driver or is it better

Your incorrect subject probably mislead you, but this is not a driver patch. These are DT bindings.

SoC specific compatibles are almost always preferred.

Quoted 7 lines

to have a common one that works for all SoCs like arm,smmu-v3 or like the EEPROM driver below ?
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/misc/eeprom/eeprom_93xx46.c?h=v6.16-rc5#n391
where driver specific driver_data could support multiple versions or SoC variations.
Our team thought of the common driver approach however looking for general guidance from PHY subsystem maintainers and contributors.

We don't discuss here driver.

Best regards,
Krzysztof

#16 lore raw

Re: [PATCH v2 2/2] phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI D-PHY RX

In reply to Karthik Poduval
Quoted 7 lines · Karthik Poduval

Add DT Bindings for Synopsys D-PHY RX, presently tested on version 1.2

---
 .../bindings/phy/snps,dw-dphy-rx.yaml         | 44 +++++++++++++++++++
 MAINTAINERS                                   |  7 +++
 2 files changed, 51 insertions(+)

Please use subject prefixes matching the subsystem. You can get them for example with git log --oneline -- DIRECTORY_OR_FILE on the directory your patch is touching. For bindings, the preferred subjects are explained here:
https://www.kernel.org/doc/html/latest/devicetree/bindings/submitting-patches.html#i-for-patch-submitters

Best regards,
Krzysztof

maintainer
#17 lore raw
In reply to Karthik Poduval
Quoted 5 lines · Karthik Poduval

v2: fix dt_binding_check errors

Karthik Poduval (2):
phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX
phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI D-PHY RX

Can you post patches or link, which use this phy?

There were many attempt to try to support this PHY.

Frank

Quoted 13 lines
 .../bindings/phy/snps,dw-dphy-rx.yaml         |  44 ++
 MAINTAINERS                                   |   7 +
 drivers/phy/Kconfig                           |  11 +
 drivers/phy/Makefile                          |   1 +
 drivers/phy/phy-dw-dphy.c                     | 575 ++++++++++++++++++
 5 files changed, 638 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml
 create mode 100644 drivers/phy/phy-dw-dphy.c

--
2.43.0