* [PATCH v2 0/2] Synopsys DW DPHY Driver
@ 2025-07-10 2:42 Karthik Poduval
2025-07-10 2:42 ` [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX Karthik Poduval
` (2 more replies)
0 siblings, 3 replies; 18+ messages in thread
From: Karthik Poduval @ 2025-07-10 2:42 UTC (permalink / raw)
To: jyxiong, miguel.lopes, anishkmr, vkoul, kishon, linux-kernel,
linux-phy, robh, krzk+dt, conor+dt, devicetree
Cc: 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
.../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
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX
2025-07-10 2:42 [PATCH v2 0/2] Synopsys DW DPHY Driver Karthik Poduval
@ 2025-07-10 2:42 ` Karthik Poduval
2025-07-10 4:08 ` Frank Li
` (4 more replies)
2025-07-10 2:42 ` [PATCH v2 2/2] phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI " Karthik Poduval
2025-07-10 3:56 ` [PATCH v2 0/2] Synopsys DW DPHY Driver Frank Li
2 siblings, 5 replies; 18+ messages in thread
From: Karthik Poduval @ 2025-07-10 2:42 UTC (permalink / raw)
To: jyxiong, miguel.lopes, anishkmr, vkoul, kishon, linux-kernel,
linux-phy, robh, krzk+dt, conor+dt, devicetree
Cc: Karthik Poduval
Add support for Synopsys DesignWare MIPI D-PHY RX v1.2. The driver
supports data rates from 80Mbps to 2500Mbps.
Signed-off-by: Karthik Poduval <kpoduval@lab126.com>
---
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
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 58c911e1b2d2..34c245ca5d12 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -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"
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index c670a8dac468..ed0836adb835 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -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/ \
diff --git a/drivers/phy/phy-dw-dphy.c b/drivers/phy/phy-dw-dphy.c
new file mode 100644
index 000000000000..2248f690b861
--- /dev/null
+++ b/drivers/phy/phy-dw-dphy.c
@@ -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 <kpoduval@lab126.com>");
+MODULE_AUTHOR("Jason Xiong <jyxiong@amazon.com>");
+MODULE_AUTHOR("Miguel Lopes <miguel.lopes@synopsys.com>");
+MODULE_DESCRIPTION("DW D-PHY RX Driver");
+MODULE_LICENSE("GPL");
--
2.43.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v2 2/2] phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI D-PHY RX
2025-07-10 2:42 [PATCH v2 0/2] Synopsys DW DPHY Driver Karthik Poduval
2025-07-10 2:42 ` [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX Karthik Poduval
@ 2025-07-10 2:42 ` Karthik Poduval
2025-07-10 3:32 ` Rob Herring (Arm)
` (3 more replies)
2025-07-10 3:56 ` [PATCH v2 0/2] Synopsys DW DPHY Driver Frank Li
2 siblings, 4 replies; 18+ messages in thread
From: Karthik Poduval @ 2025-07-10 2:42 UTC (permalink / raw)
To: jyxiong, miguel.lopes, anishkmr, vkoul, kishon, linux-kernel,
linux-phy, robh, krzk+dt, conor+dt, devicetree
Cc: Karthik Poduval
Add DT Bindings for Synopsys D-PHY RX, presently tested on version 1.2
Signed-off-by: Karthik Poduval <kpoduval@lab126.com>
---
.../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
diff --git a/Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml b/Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml
new file mode 100644
index 000000000000..c3c657b1e77d
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml
@@ -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 <kpoduval@lab126.com>
+ - Jason Xiong <jyxiong@amazon.com>
+ - Miguel Lopes <miguel.lopes@synopsys.com
+
+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";
+ };
+
diff --git a/MAINTAINERS b/MAINTAINERS
index b5a472a544cf..5fd5a92431bd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -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 <kpoduval@lab126.com>
+M: Jason Xiong <jyxiong@amazon.com>
+M: Miguel Lopes <miguel.lopes@synopsys.com>
+S: Supported
+F: Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml
+
SYNOPSYS DESIGNWARE DMAC DRIVER
M: Viresh Kumar <vireshk@kernel.org>
R: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
--
2.43.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH v2 2/2] phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI D-PHY RX
2025-07-10 2:42 ` [PATCH v2 2/2] phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI " Karthik Poduval
@ 2025-07-10 3:32 ` Rob Herring (Arm)
2025-07-10 4:02 ` Frank Li
` (2 subsequent siblings)
3 siblings, 0 replies; 18+ messages in thread
From: Rob Herring (Arm) @ 2025-07-10 3:32 UTC (permalink / raw)
To: Karthik Poduval
Cc: linux-kernel, vkoul, anishkmr, krzk+dt, conor+dt, devicetree,
jyxiong, miguel.lopes, kishon, linux-phy
On Wed, 09 Jul 2025 19:42:21 -0700, Karthik Poduval wrote:
> Add DT Bindings for Synopsys D-PHY RX, presently tested on version 1.2
>
> Signed-off-by: Karthik Poduval <kpoduval@lab126.com>
> ---
> .../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.
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 0/2] Synopsys DW DPHY Driver
2025-07-10 2:42 [PATCH v2 0/2] Synopsys DW DPHY Driver Karthik Poduval
2025-07-10 2:42 ` [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX Karthik Poduval
2025-07-10 2:42 ` [PATCH v2 2/2] phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI " Karthik Poduval
@ 2025-07-10 3:56 ` Frank Li
2 siblings, 0 replies; 18+ messages in thread
From: Frank Li @ 2025-07-10 3:56 UTC (permalink / raw)
To: Karthik Poduval
Cc: jyxiong, miguel.lopes, anishkmr, vkoul, kishon, linux-kernel,
linux-phy, robh, krzk+dt, conor+dt, devicetree
On Wed, Jul 09, 2025 at 07:42:19PM -0700, Karthik Poduval wrote:
> 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
>
> .../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
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 2/2] phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI D-PHY RX
2025-07-10 2:42 ` [PATCH v2 2/2] phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI " Karthik Poduval
2025-07-10 3:32 ` Rob Herring (Arm)
@ 2025-07-10 4:02 ` Frank Li
2025-07-10 7:24 ` Krzysztof Kozlowski
2025-07-10 7:27 ` Krzysztof Kozlowski
3 siblings, 0 replies; 18+ messages in thread
From: Frank Li @ 2025-07-10 4:02 UTC (permalink / raw)
To: Karthik Poduval
Cc: jyxiong, miguel.lopes, anishkmr, vkoul, kishon, linux-kernel,
linux-phy, robh, krzk+dt, conor+dt, devicetree
On Wed, Jul 09, 2025 at 07:42:21PM -0700, Karthik Poduval wrote:
> Add DT Bindings for Synopsys D-PHY RX, presently tested on version 1.2
>
> Signed-off-by: Karthik Poduval <kpoduval@lab126.com>
> ---
> .../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
>
> diff --git a/Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml b/Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml
> new file mode 100644
> index 000000000000..c3c657b1e77d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml
> @@ -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 <kpoduval@lab126.com>
> + - Jason Xiong <jyxiong@amazon.com>
> + - Miguel Lopes <miguel.lopes@synopsys.com
> +
> +description: |
Needn't |
> + 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.
> +
> +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>;
Some DW MIPI CSI2 test1/test2 register is not tail part of whole MMIO space
such as imx93.
Frank
> + status = "disabled";
> + };
> +
> diff --git a/MAINTAINERS b/MAINTAINERS
> index b5a472a544cf..5fd5a92431bd 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -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 <kpoduval@lab126.com>
> +M: Jason Xiong <jyxiong@amazon.com>
> +M: Miguel Lopes <miguel.lopes@synopsys.com>
> +S: Supported
> +F: Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml
> +
> SYNOPSYS DESIGNWARE DMAC DRIVER
> M: Viresh Kumar <vireshk@kernel.org>
> R: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX
2025-07-10 2:42 ` [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX Karthik Poduval
@ 2025-07-10 4:08 ` Frank Li
2025-07-10 5:12 ` Poduval, Karthik
2025-07-10 4:14 ` Frank Li
` (3 subsequent siblings)
4 siblings, 1 reply; 18+ messages in thread
From: Frank Li @ 2025-07-10 4:08 UTC (permalink / raw)
To: Karthik Poduval
Cc: jyxiong, miguel.lopes, anishkmr, vkoul, kishon, linux-kernel,
linux-phy, robh, krzk+dt, conor+dt, devicetree
On Wed, Jul 09, 2025 at 07:42:20PM -0700, Karthik Poduval wrote:
> Add support for Synopsys DesignWare MIPI D-PHY RX v1.2. The driver
> supports data rates from 80Mbps to 2500Mbps.
>
> Signed-off-by: Karthik Poduval <kpoduval@lab126.com>
> ---
> 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
>
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index 58c911e1b2d2..34c245ca5d12 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -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"
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index c670a8dac468..ed0836adb835 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -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/ \
> diff --git a/drivers/phy/phy-dw-dphy.c b/drivers/phy/phy-dw-dphy.c
> new file mode 100644
> index 000000000000..2248f690b861
> --- /dev/null
> +++ b/drivers/phy/phy-dw-dphy.c
> @@ -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);
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/20250701-95_cam-v1-5-c5172bab387b@nxp.com/
Frank
> +
> + 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 <kpoduval@lab126.com>");
> +MODULE_AUTHOR("Jason Xiong <jyxiong@amazon.com>");
> +MODULE_AUTHOR("Miguel Lopes <miguel.lopes@synopsys.com>");
> +MODULE_DESCRIPTION("DW D-PHY RX Driver");
> +MODULE_LICENSE("GPL");
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX
2025-07-10 2:42 ` [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX Karthik Poduval
2025-07-10 4:08 ` Frank Li
@ 2025-07-10 4:14 ` Frank Li
2025-07-10 5:15 ` Poduval, Karthik
2025-07-10 7:26 ` Krzysztof Kozlowski
` (2 subsequent siblings)
4 siblings, 1 reply; 18+ messages in thread
From: Frank Li @ 2025-07-10 4:14 UTC (permalink / raw)
To: Karthik Poduval
Cc: jyxiong, miguel.lopes, anishkmr, vkoul, kishon, linux-kernel,
linux-phy, robh, krzk+dt, conor+dt, devicetree
On Wed, Jul 09, 2025 at 07:42:20PM -0700, Karthik Poduval wrote:
> 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: linux-media@vger.kernel.org
In https://lore.kernel.org/imx/20250702093806.GF16835@pendragon.ideasonboard.com/
drivers/media/platform/raspberrypi/rp1-cfe/dphy.c do similar work.
Frank
> Signed-off-by: Karthik Poduval <kpoduval@lab126.com>
> ---
> 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
>
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index 58c911e1b2d2..34c245ca5d12 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -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"
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index c670a8dac468..ed0836adb835 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -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/ \
> diff --git a/drivers/phy/phy-dw-dphy.c b/drivers/phy/phy-dw-dphy.c
> new file mode 100644
> index 000000000000..2248f690b861
> --- /dev/null
> +++ b/drivers/phy/phy-dw-dphy.c
> @@ -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 <kpoduval@lab126.com>");
> +MODULE_AUTHOR("Jason Xiong <jyxiong@amazon.com>");
> +MODULE_AUTHOR("Miguel Lopes <miguel.lopes@synopsys.com>");
> +MODULE_DESCRIPTION("DW D-PHY RX Driver");
> +MODULE_LICENSE("GPL");
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX
2025-07-10 4:08 ` Frank Li
@ 2025-07-10 5:12 ` Poduval, Karthik
2025-07-10 19:48 ` Frank Li
0 siblings, 1 reply; 18+ messages in thread
From: Poduval, Karthik @ 2025-07-10 5:12 UTC (permalink / raw)
To: Frank.li@nxp.com
Cc: vkoul@kernel.org, Xiong, Jason, devicetree@vger.kernel.org,
robh@kernel.org, linux-kernel@vger.kernel.org, Anish Kumar, FNU,
miguel.lopes@synopsys.com, linux-phy@lists.infradead.org,
kishon@kernel.org, conor+dt@kernel.org, krzk+dt@kernel.org
On Thu, 2025-07-10 at 00:08 -0400, Frank Li wrote:
> 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.
>
>
>
> On Wed, Jul 09, 2025 at 07:42:20PM -0700, Karthik Poduval wrote:
> > Add support for Synopsys DesignWare MIPI D-PHY RX v1.2. The driver
> > supports data rates from 80Mbps to 2500Mbps.
> >
> > Signed-off-by: Karthik Poduval <kpoduval@lab126.com>
> > ---
> > 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
> >
> > diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> > index 58c911e1b2d2..34c245ca5d12 100644
> > --- a/drivers/phy/Kconfig
> > +++ b/drivers/phy/Kconfig
> > @@ -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"
> > diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> > index c670a8dac468..ed0836adb835 100644
> > --- a/drivers/phy/Makefile
> > +++ b/drivers/phy/Makefile
> > @@ -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/ \
> > diff --git a/drivers/phy/phy-dw-dphy.c b/drivers/phy/phy-dw-dphy.c
> > new file mode 100644
> > index 000000000000..2248f690b861
> > --- /dev/null
> > +++ b/drivers/phy/phy-dw-dphy.c
> > @@ -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);
>
> 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.
>
> Please CC me for next version. I am working on DW MIPI-CSI2 work.
>
> https://lore.kernel.org/imx/20250701-95_cam-v1-5-c5172bab387b@nxp.com/
>
> Frank
Sure, Frank, perhaps loop in Miguel as he might be able to know about
all the variants out there for this IP.
> > +
> > + 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 <kpoduval@lab126.com>");
> > +MODULE_AUTHOR("Jason Xiong <jyxiong@amazon.com>");
> > +MODULE_AUTHOR("Miguel Lopes <miguel.lopes@synopsys.com>");
> > +MODULE_DESCRIPTION("DW D-PHY RX Driver");
> > +MODULE_LICENSE("GPL");
> > --
> > 2.43.0
> >
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX
2025-07-10 4:14 ` Frank Li
@ 2025-07-10 5:15 ` Poduval, Karthik
0 siblings, 0 replies; 18+ messages in thread
From: Poduval, Karthik @ 2025-07-10 5:15 UTC (permalink / raw)
To: Frank.li@nxp.com
Cc: linux-media@vger.kernel.org, vkoul@kernel.org, Xiong, Jason,
devicetree@vger.kernel.org, robh@kernel.org,
linux-kernel@vger.kernel.org, Anish Kumar, FNU,
miguel.lopes@synopsys.com, linux-phy@lists.infradead.org,
kishon@kernel.org, conor+dt@kernel.org, krzk+dt@kernel.org
On Thu, 2025-07-10 at 00:14 -0400, Frank Li wrote:
> 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.
>
>
>
> On Wed, Jul 09, 2025 at 07:42:20PM -0700, Karthik Poduval wrote:
> > 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: linux-media@vger.kernel.org
Sure.
>
> In
> https://lore.kernel.org/imx/20250702093806.GF16835@pendragon.ideasonboard.com/
>
> drivers/media/platform/raspberrypi/rp1-cfe/dphy.c do similar work.
>
> Frank
>
> > Signed-off-by: Karthik Poduval <kpoduval@lab126.com>
> > ---
> > 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
> >
> > diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> > index 58c911e1b2d2..34c245ca5d12 100644
> > --- a/drivers/phy/Kconfig
> > +++ b/drivers/phy/Kconfig
> > @@ -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"
> > diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> > index c670a8dac468..ed0836adb835 100644
> > --- a/drivers/phy/Makefile
> > +++ b/drivers/phy/Makefile
> > @@ -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/ \
> > diff --git a/drivers/phy/phy-dw-dphy.c b/drivers/phy/phy-dw-dphy.c
> > new file mode 100644
> > index 000000000000..2248f690b861
> > --- /dev/null
> > +++ b/drivers/phy/phy-dw-dphy.c
> > @@ -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 <kpoduval@lab126.com>");
> > +MODULE_AUTHOR("Jason Xiong <jyxiong@amazon.com>");
> > +MODULE_AUTHOR("Miguel Lopes <miguel.lopes@synopsys.com>");
> > +MODULE_DESCRIPTION("DW D-PHY RX Driver");
> > +MODULE_LICENSE("GPL");
> > --
> > 2.43.0
> >
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 2/2] phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI D-PHY RX
2025-07-10 2:42 ` [PATCH v2 2/2] phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI " Karthik Poduval
2025-07-10 3:32 ` Rob Herring (Arm)
2025-07-10 4:02 ` Frank Li
@ 2025-07-10 7:24 ` Krzysztof Kozlowski
2025-07-10 21:24 ` Poduval, Karthik
2025-07-10 7:27 ` Krzysztof Kozlowski
3 siblings, 1 reply; 18+ messages in thread
From: Krzysztof Kozlowski @ 2025-07-10 7:24 UTC (permalink / raw)
To: Karthik Poduval
Cc: jyxiong, miguel.lopes, anishkmr, vkoul, kishon, linux-kernel,
linux-phy, robh, krzk+dt, conor+dt, devicetree
On Wed, Jul 09, 2025 at 07:42:21PM -0700, Karthik Poduval wrote:
> +---
> +$id: http://devicetree.org/schemas/phy/snps,dw-dphy-rx.yaml#
Filename and id should match compatible.
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Synopsys Designware MIPI D-PHY RX
> +
> +maintainers:
> + - Karthik Poduval <kpoduval@lab126.com>
> + - Jason Xiong <jyxiong@amazon.com>
> + - Miguel Lopes <miguel.lopes@synopsys.com
> +
> +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.
> +
> + '#phy-cells':
> + const: 0
> +
> + reg:
> + minItems: 2
> + maxItems: 2
List the items instead
And fix the order, reg goes second.
> +
> +required:
> + - compatible
> + - '#phy-cells'
> + - reg
Here as well
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + dw_dphy_rx: dw-dphy@900000040 {
phy@
> + 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.
> + };
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX
2025-07-10 2:42 ` [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX Karthik Poduval
2025-07-10 4:08 ` Frank Li
2025-07-10 4:14 ` Frank Li
@ 2025-07-10 7:26 ` Krzysztof Kozlowski
2025-07-10 22:13 ` kernel test robot
2025-07-11 7:13 ` kernel test robot
4 siblings, 0 replies; 18+ messages in thread
From: Krzysztof Kozlowski @ 2025-07-10 7:26 UTC (permalink / raw)
To: Karthik Poduval
Cc: jyxiong, miguel.lopes, anishkmr, vkoul, kishon, linux-kernel,
linux-phy, robh, krzk+dt, conor+dt, devicetree
On Wed, Jul 09, 2025 at 07:42:20PM -0700, Karthik Poduval wrote:
> +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
> + *
> + **/
Drop
> +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
> + *
> + **/
Drop
> +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")
> + *
> + **/
Drop
> +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
> + *
> + **/
Drop all such useless generic kerneldocs. Not helpful. Keep useful ones,
so ones not saying obvious parts of core
> +static struct platform_driver dw_dphy_platform_driver = {
> + .probe = dw_dphy_probe,
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 2/2] phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI D-PHY RX
2025-07-10 2:42 ` [PATCH v2 2/2] phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI " Karthik Poduval
` (2 preceding siblings ...)
2025-07-10 7:24 ` Krzysztof Kozlowski
@ 2025-07-10 7:27 ` Krzysztof Kozlowski
3 siblings, 0 replies; 18+ messages in thread
From: Krzysztof Kozlowski @ 2025-07-10 7:27 UTC (permalink / raw)
To: Karthik Poduval, jyxiong, miguel.lopes, anishkmr, vkoul, kishon,
linux-kernel, linux-phy, robh, krzk+dt, conor+dt, devicetree
On 10/07/2025 04:42, Karthik Poduval wrote:
> Add DT Bindings for Synopsys D-PHY RX, presently tested on version 1.2
>
> Signed-off-by: Karthik Poduval <kpoduval@lab126.com>
> ---
> .../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
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX
2025-07-10 5:12 ` Poduval, Karthik
@ 2025-07-10 19:48 ` Frank Li
0 siblings, 0 replies; 18+ messages in thread
From: Frank Li @ 2025-07-10 19:48 UTC (permalink / raw)
To: Poduval, Karthik
Cc: vkoul@kernel.org, Xiong, Jason, devicetree@vger.kernel.org,
robh@kernel.org, linux-kernel@vger.kernel.org, Anish Kumar, FNU,
miguel.lopes@synopsys.com, linux-phy@lists.infradead.org,
kishon@kernel.org, conor+dt@kernel.org, krzk+dt@kernel.org, imx,
linux-media
On Thu, Jul 10, 2025 at 05:12:57AM +0000, Poduval, Karthik wrote:
> On Thu, 2025-07-10 at 00:08 -0400, Frank Li wrote:
> > 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.
> >
> >
> >
...
> > > +
> > > + 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.
> 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
> >
> > Please CC me for next version. I am working on DW MIPI-CSI2 work.
> >
> > https://lore.kernel.org/imx/20250701-95_cam-v1-5-c5172bab387b@nxp.com/
> >
> > Frank
> Sure, Frank, perhaps loop in Miguel as he might be able to know about
> all the variants out there for this IP.
...
> > > +MODULE_LICENSE("GPL");
> > > --
> > > 2.43.0
> > >
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 2/2] phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI D-PHY RX
2025-07-10 7:24 ` Krzysztof Kozlowski
@ 2025-07-10 21:24 ` Poduval, Karthik
2025-07-11 7:09 ` Krzysztof Kozlowski
0 siblings, 1 reply; 18+ messages in thread
From: Poduval, Karthik @ 2025-07-10 21:24 UTC (permalink / raw)
To: krzk@kernel.org
Cc: linux-media@vger.kernel.org, vkoul@kernel.org, Xiong, Jason,
devicetree@vger.kernel.org, robh@kernel.org,
linux-kernel@vger.kernel.org, Anish Kumar, FNU,
miguel.lopes@synopsys.com, linux-phy@lists.infradead.org,
kishon@kernel.org, conor+dt@kernel.org, krzk+dt@kernel.org
Hi Krzysztof,
Thanks for your comments.
On Thu, 2025-07-10 at 09:24 +0200, Krzysztof Kozlowski wrote:
> 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.
>
>
>
> On Wed, Jul 09, 2025 at 07:42:21PM -0700, Karthik Poduval wrote:
> > +---
> > +$id: http://devicetree.org/schemas/phy/snps,dw-dphy-rx.yaml#
>
> Filename and id should match compatible.
>
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Synopsys Designware MIPI D-PHY RX
> > +
> > +maintainers:
> > + - Karthik Poduval <kpoduval@lab126.com>
> > + - Jason Xiong <jyxiong@amazon.com>
> > + - Miguel Lopes <miguel.lopes@synopsys.com
> > +
> > +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.
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.
>
> > +
> > + '#phy-cells':
> > + const: 0
> > +
> > + reg:
> > + minItems: 2
> > + maxItems: 2
>
> List the items instead
>
> And fix the order, reg goes second.
ack
>
> > +
> > +required:
> > + - compatible
> > + - '#phy-cells'
> > + - reg
>
> Here as well
ack
>
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > + - |
> > + dw_dphy_rx: dw-dphy@900000040 {
>
> phy@
>
> > + 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.
>
> > + };
>
> Best regards,
> Krzysztof
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX
2025-07-10 2:42 ` [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX Karthik Poduval
` (2 preceding siblings ...)
2025-07-10 7:26 ` Krzysztof Kozlowski
@ 2025-07-10 22:13 ` kernel test robot
2025-07-11 7:13 ` kernel test robot
4 siblings, 0 replies; 18+ messages in thread
From: kernel test robot @ 2025-07-10 22:13 UTC (permalink / raw)
To: Karthik Poduval, jyxiong, miguel.lopes, anishkmr, vkoul, kishon,
linux-kernel, linux-phy, robh, krzk+dt, conor+dt, devicetree
Cc: oe-kbuild-all, Karthik Poduval
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/202507110611.wdky6fjF-lkp@intel.com/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/202507110611.wdky6fjF-lkp@intel.com/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 <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202507110611.wdky6fjF-lkp@intel.com/
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
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 2/2] phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI D-PHY RX
2025-07-10 21:24 ` Poduval, Karthik
@ 2025-07-11 7:09 ` Krzysztof Kozlowski
0 siblings, 0 replies; 18+ messages in thread
From: Krzysztof Kozlowski @ 2025-07-11 7:09 UTC (permalink / raw)
To: Poduval, Karthik
Cc: linux-media@vger.kernel.org, vkoul@kernel.org, Xiong, Jason,
devicetree@vger.kernel.org, robh@kernel.org,
linux-kernel@vger.kernel.org, Anish Kumar, FNU,
miguel.lopes@synopsys.com, linux-phy@lists.infradead.org,
kishon@kernel.org, conor+dt@kernel.org, krzk+dt@kernel.org
On 10/07/2025 23:24, Poduval, Karthik wrote:
>>> +maintainers:
>>> + - Karthik Poduval <kpoduval@lab126.com>
>>> + - Jason Xiong <jyxiong@amazon.com>
>>> + - Miguel Lopes <miguel.lopes@synopsys.com
>>> +
>>> +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.
> 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.
> 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
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX
2025-07-10 2:42 ` [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX Karthik Poduval
` (3 preceding siblings ...)
2025-07-10 22:13 ` kernel test robot
@ 2025-07-11 7:13 ` kernel test robot
4 siblings, 0 replies; 18+ messages in thread
From: kernel test robot @ 2025-07-11 7:13 UTC (permalink / raw)
To: Karthik Poduval, jyxiong, miguel.lopes, anishkmr, vkoul, kishon,
linux-kernel, linux-phy, robh, krzk+dt, conor+dt, devicetree
Cc: oe-kbuild-all, Karthik Poduval
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/202507111412.83Oiz7hO-lkp@intel.com/config)
compiler: sparc-linux-gcc (GCC) 12.4.0
reproduce: (https://download.01.org/0day-ci/archive/20250711/202507111412.83Oiz7hO-lkp@intel.com/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 <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202507111412.83Oiz7hO-lkp@intel.com/
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
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2025-07-11 7:13 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-10 2:42 [PATCH v2 0/2] Synopsys DW DPHY Driver Karthik Poduval
2025-07-10 2:42 ` [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX Karthik Poduval
2025-07-10 4:08 ` Frank Li
2025-07-10 5:12 ` Poduval, Karthik
2025-07-10 19:48 ` Frank Li
2025-07-10 4:14 ` Frank Li
2025-07-10 5:15 ` Poduval, Karthik
2025-07-10 7:26 ` Krzysztof Kozlowski
2025-07-10 22:13 ` kernel test robot
2025-07-11 7:13 ` kernel test robot
2025-07-10 2:42 ` [PATCH v2 2/2] phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI " Karthik Poduval
2025-07-10 3:32 ` Rob Herring (Arm)
2025-07-10 4:02 ` Frank Li
2025-07-10 7:24 ` Krzysztof Kozlowski
2025-07-10 21:24 ` Poduval, Karthik
2025-07-11 7:09 ` Krzysztof Kozlowski
2025-07-10 7:27 ` Krzysztof Kozlowski
2025-07-10 3:56 ` [PATCH v2 0/2] Synopsys DW DPHY Driver Frank Li
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).