Synopsys DW DPHY Driver
v2 cover Synopsys DW DPHY Driver
v2: fix dt_binding_check errors
Karthik Poduval (2):
phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX
phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI D-PHY RX
.../bindings/phy/snps,dw-dphy-rx.yaml | 44 ++ MAINTAINERS | 7 + drivers/phy/Kconfig | 11 + drivers/phy/Makefile | 1 + drivers/phy/phy-dw-dphy.c | 575 ++++++++++++++++++ 5 files changed, 638 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml create mode 100644 drivers/phy/phy-dw-dphy.c
Signature · 1 line
2.43.0
PATCH v2 1/2 phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX
Add support for Synopsys DesignWare MIPI D-PHY RX v1.2. The driver supports data rates from 80Mbps to 2500Mbps.
--- drivers/phy/Kconfig | 11 + drivers/phy/Makefile | 1 + drivers/phy/phy-dw-dphy.c | 575 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 587 insertions(+) create mode 100644 drivers/phy/phy-dw-dphy.c
drivers/phy/Kconfig +11 -0
@@ -101,6 +101,17 @@ config PHY_NXP_PTN3222 schemes. It supports all three USB 2.0 data rates: Low Speed, Full Speed and High Speed. +config PHY_SYNOPSYS_DW_DPHY_RX + tristate "Synopsys DesignWare D-PHY Rx Support" + depends on HAS_IOMEM && REGMAP_MMIO + select GENERIC_PHY + select GENERIC_PHY_MIPI_DPHY + help + This option enables support for Synopsys DW MIPI D-PHY RX IP. This driver + provides D-PHY functionality using Generic PHY framework and is meant to + be used by MIPI CSI2 receivers over the PPI hardware interface. MIPI CSI2 + receivers may find this driver and use it via Generic PHY Framework API. + source "drivers/phy/allwinner/Kconfig" source "drivers/phy/amlogic/Kconfig" source "drivers/phy/broadcom/Kconfig"
drivers/phy/Makefile +1 -0
@@ -13,6 +13,7 @@ obj-$(CONFIG_PHY_SNPS_EUSB2) += phy-snps-eusb2.o obj-$(CONFIG_USB_LGM_PHY) += phy-lgm-usb.o obj-$(CONFIG_PHY_AIROHA_PCIE) += phy-airoha-pcie.o obj-$(CONFIG_PHY_NXP_PTN3222) += phy-nxp-ptn3222.o +obj-$(CONFIG_PHY_SYNOPSYS_DW_DPHY_RX) += phy-dw-dphy.o obj-y += allwinner/ \ amlogic/ \ broadcom/ \
drivers/phy/phy-dw-dphy.c new file +575 -0
575 lines not on this page · raw message
Signature · 1 line
2.43.0
Frank Li
maintainerRe: [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX
Quoted 534 lines · Karthik Poduval
Add support for Synopsys DesignWare MIPI D-PHY RX v1.2. The driver supports data rates from 80Mbps to 2500Mbps.
Signed-off-by Karthik Poduval <[email protected]>--- 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.cdrivers/phy/Kconfig +11
-0@@ -101,6 +101,17 @@ config PHY_NXP_PTN3222 schemes. It supports all three USB 2.0 data rates: Low Speed, Full Speed and High Speed. +config PHY_SYNOPSYS_DW_DPHY_RX + tristate "Synopsys DesignWare D-PHY Rx Support" + depends on HAS_IOMEM && REGMAP_MMIO + select GENERIC_PHY + select GENERIC_PHY_MIPI_DPHY + help + This option enables support for Synopsys DW MIPI D-PHY RX IP. This driver + provides D-PHY functionality using Generic PHY framework and is meant to + be used by MIPI CSI2 receivers over the PPI hardware interface. MIPI CSI2 + receivers may find this driver and use it via Generic PHY Framework API. + source "drivers/phy/allwinner/Kconfig" source "drivers/phy/amlogic/Kconfig" source "drivers/phy/broadcom/Kconfig"drivers/phy/Makefile +1
-0@@ -13,6 +13,7 @@ obj-$(CONFIG_PHY_SNPS_EUSB2) += phy-snps-eusb2.o obj-$(CONFIG_USB_LGM_PHY) += phy-lgm-usb.o obj-$(CONFIG_PHY_AIROHA_PCIE) += phy-airoha-pcie.o obj-$(CONFIG_PHY_NXP_PTN3222) += phy-nxp-ptn3222.o +obj-$(CONFIG_PHY_SYNOPSYS_DW_DPHY_RX) += phy-dw-dphy.o obj-y += allwinner/ \ amlogic/ \ broadcom/ \drivers/phy/phy-dw-dphy.c new file +483
-0@@ -0,0 +1,575 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* +* Copyright © 2025 Amazon.com, Inc. or its affiliates. +* Copyright © 2025 Synopsys, Inc. (www.synopsys.com) +*/ +#include <linux/bitops.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/reset.h> +#include <linux/regmap.h> + +#include <linux/phy/phy.h> +#include <linux/phy/phy-mipi-dphy.h> + +#define KHZ (1000) +#define MHZ (KHZ * KHZ) + +enum dw_dphy_reg_fields_cfg1 { +PHY_SHUTDOWNZ , +DPHY_RSTZ , +TEST_CLR , +TEST_CLK , +TEST_IN , +TEST_OUT , +TEST_EN , +DW_DPHY_RF_CFG1_MAX +}; + +enum dw_dphy_reg_fields_cfg2 { +EN_CONT_REG_UPDATE , +TURN_REQUEST_0 , +TURN_DISABLE_0 , +ENABLE_CLK , +FORCE_TX_STOP_MODE_0 , +FORCE_RX_MODE , +BASE_DIR_0 , +CFG_CLK_FREQ_RANGE , +HS_FREQ_RANGE , +CONT_EN , +DW_DPHY_RF_CFG2_MAX +}; + +static const struct reg_field dw_dphy_v1_2_cfg1[DW_DPHY_RF_CFG1_MAX ] = { + [PHY_SHUTDOWNZ ] =REG_FIELD (0x0 ,0 ,0 ), + [DPHY_RSTZ ] =REG_FIELD (0x4 ,0 ,0 ), + [TEST_CLR ] =REG_FIELD (0x10 ,0 ,0 ), + [TEST_CLK ] =REG_FIELD (0x10 ,1 ,1 ), + [TEST_IN ] =REG_FIELD (0x14 ,0 ,7 ), + [TEST_OUT ] =REG_FIELD (0x14 ,8 ,15 ), + [TEST_EN ] =REG_FIELD (0x14 ,16 ,16 ), +}; + +static const struct reg_field dw_dphy_v1_2_cfg2[DW_DPHY_RF_CFG2_MAX ] = { + [EN_CONT_REG_UPDATE ] =REG_FIELD (0x0 ,23 ,23 ), + [TURN_REQUEST_0 ] =REG_FIELD (0x0 ,22 ,22 ), + [TURN_DISABLE_0 ] =REG_FIELD (0x0 ,21 ,21 ), + [ENABLE_CLK ] =REG_FIELD (0x0 ,20 ,20 ), + [FORCE_TX_STOP_MODE_0 ] =REG_FIELD (0x0 ,19 ,19 ), + [FORCE_RX_MODE ] =REG_FIELD (0x0 ,15 ,18 ), + [BASE_DIR_0 ] =REG_FIELD (0x0 ,14 ,14 ), + [CFG_CLK_FREQ_RANGE ] =REG_FIELD (0x0 ,8 ,13 ), + [HS_FREQ_RANGE ] =REG_FIELD (0x0 ,1 ,7 ), + [CONT_EN ] =REG_FIELD (0x0 ,0 ,0 ), +}; + +enum dphy_12bit_interface_addr { +RX_SYS_0 =0x01 , +RX_SYS_1 =0x02 , +RX_SYS_7 =0x08 , +RX_RX_STARTUP_OVR_0 =0xe0 , +RX_RX_STARTUP_OVR_1 =0xe1 , +RX_RX_STARTUP_OVR_2 =0xe2 , +RX_RX_STARTUP_OVR_3 =0xe3 , +RX_RX_STARTUP_OVR_4 =0xe4 , +}; + +/** +* struct range_dphy_gen3 - frequency range calibration structure +* +* @freq: input freqency to calibration table +* @hsfregrange: corresponding clock to configure DW D-PHY IP +* @osc_freq_target: corresponding clock to configure DW D-PHY IP +* +**/ +struct range_dphy_gen3 { +u32 freq; +u8 hsfregrange; +u32 osc_freq_target; +}; + +/** +* struct dt_data_dw_dphy - DPHY configuration data structure +* @table: Pointer to array of DPHY Gen3 timing range configurations +* @table_size: Number of entries in the timing range table +* @phy_ops: Pointer to PHY operations structure containing callback functions +* +**/ +struct dt_data_dw_dphy { +struct range_dphy_gen3 *table; +int table_size; +const struct phy_ops *phy_ops; +}; + +/* +* DW DPHY Gen3 calibration table +* +*/ +struct range_dphy_gen3 range_gen3[] = { + {80 ,0b0000000 ,460 }, {90 ,0b0010000 ,460 }, + {100 ,0b0100000 ,460 }, {110 ,0b0110000 ,460 }, + {120 ,0b0000001 ,460 }, {130 ,0b0010001 ,460 }, + {140 ,0b0100001 ,460 }, {150 ,0b0110001 ,460 }, + {160 ,0b0000010 ,460 }, {170 ,0b0010010 ,460 }, + {180 ,0b0100010 ,460 }, {190 ,0b0110010 ,460 }, + {205 ,0b0000011 ,460 }, {220 ,0b0010011 ,460 }, + {235 ,0b0100011 ,460 }, {250 ,0b0110011 ,460 }, + {275 ,0b0000100 ,460 }, {300 ,0b0010100 ,460 }, + {325 ,0b0100101 ,460 }, {350 ,0b0110101 ,460 }, + {400 ,0b0000101 ,460 }, {450 ,0b0010110 ,460 }, + {500 ,0b0100110 ,460 }, {550 ,0b0110111 ,460 }, + {600 ,0b0000111 ,460 }, {650 ,0b0011000 ,460 }, + {700 ,0b0101000 ,460 }, {750 ,0b0111001 ,460 }, + {800 ,0b0001001 ,460 }, {850 ,0b0011001 ,460 }, + {900 ,0b0101001 ,460 }, {950 ,0b0111010 ,460 }, + {1000 ,0b0001010 ,460 }, {1050 ,0b0011010 ,460 }, + {1110 ,0b0101010 ,460 }, {1150 ,0b0111011 ,460 }, + {1200 ,0b0001011 ,460 }, {1250 ,0b0011011 ,460 }, + {1300 ,0b0101011 ,460 }, {1350 ,0b0111100 ,460 }, + {1400 ,0b0001100 ,460 }, {1450 ,0b0011100 ,460 }, + {1500 ,0b0101100 ,460 }, {1550 ,0b0111101 ,285 }, + {1600 ,0b0001101 ,295 }, {1650 ,0b0011101 ,304 }, + {1700 ,0b0101110 ,313 }, {1750 ,0b0111110 ,322 }, + {1800 ,0b0001110 ,331 }, {1850 ,0b0011110 ,341 }, + {1900 ,0b0101111 ,350 }, {1950 ,0b0111111 ,359 }, + {2000 ,0b0001111 ,368 }, {2050 ,0b1000000 ,377 }, + {2100 ,0b1000001 ,387 }, {2150 ,0b1000010 ,396 }, + {2200 ,0b1000011 ,405 }, {2250 ,0b1000100 ,414 }, + {2300 ,0b1000101 ,423 }, {2350 ,0b1000110 ,432 }, + {2400 ,0b1000111 ,442 }, {2450 ,0b1001000 ,451 }, + {2500 ,0b1001001 ,460 } +}; + +/** +* struct dw_dphy - DW D-PHY driver private structure +* +* @regmap: pointer to regmap +* @regmap_cfg1: pointer to config1 regmap +* @regmap_cfg2: pointer to config2 regmap +* @rf_cfg1: array of regfields for config1 +* @rf_cfg2: array of regfields for config2 +* @iomem_cfg1: MMIO address for cfg1 section +* @iomem_cfg2: MMIO address for cfg2 section +* @phy: pointer to the phy data structure +* @hs_clk_rate: high speed clock rate as per image sensor configuration +* @dt_data_dw_dphy: device tree specific data +* +**/ +struct dw_dphy { +struct regmap *regmap_cfg1; +struct regmap *regmap_cfg2; +struct regmap_field *rf_cfg1[DW_DPHY_RF_CFG1_MAX ]; +struct regmap_field *rf_cfg2[DW_DPHY_RF_CFG2_MAX ]; +void __iomem *iomem_cfg1; +void __iomem *iomem_cfg2; +struct phy *phy; +struct device *dev; +unsigned long hs_clk_rate; +struct dt_data_dw_dphy *dt_data; +}; + +/** +* dw_dphy_te_write - write register into test enable interface +* +* @dphy: pointer to the dw_dphy private data structure +* @addr: 12 bit TE address register (16 bit container) +* @data: 8 bit data to be written to TE register +* +**/ +static void dw_dphy_te_write (struct dw_dphy *dphy,u16 addr,u8 data) +{ +/* For writing the 4-bit testcode MSBs */ + +/* Ensure that testclk and testen is set to low */ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],0 ); +regmap_field_write (dphy->rf_cfg1[TEST_EN ],0 ); + +/* Set testen to high */ +regmap_field_write (dphy->rf_cfg1[TEST_EN ],1 ); + +/* Set testclk to high */ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],1 ); + +/* Place 0x00 in testdin */ +regmap_field_write (dphy->rf_cfg1[TEST_IN ],0 ); + +/* +* Set testclk to low (with the falling edge on testclk, the testdin signal +* content is latched internally) +*/ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],0 ); + +/* Set testen to low */ +regmap_field_write (dphy->rf_cfg1[TEST_EN ],0 ); + +/* Place the 8-bit word corresponding to the testcode MSBs in testdin */ +regmap_field_write (dphy->rf_cfg1[TEST_IN ], (addr >>8 )); + +/* Set testclk to high */ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],1 ); + +/* For writing the 8-bit testcode LSBs */ + +/* Set testclk to low */ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],0 ); + +/* Set testen to high */ +regmap_field_write (dphy->rf_cfg1[TEST_EN ],1 ); + +/* Set testclk to high */ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],1 ); + +/* Place the 8-bit word test data in testdin */ +regmap_field_write (dphy->rf_cfg1[TEST_IN ], (addr &0xff )); + +/* +* Set testclk to low (with the falling edge on testclk, the testdin signal +* content is latched internally) +*/ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],0 ); + +/* Set testen to low */ +regmap_field_write (dphy->rf_cfg1[TEST_EN ],0 ); + +/* For writing the data */ + +/* Place the 8-bit word corresponding to the page offset in testdin */ +regmap_field_write (dphy->rf_cfg1[TEST_IN ], data); + +/* Set testclk to high (test data is programmed internally) */ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],1 ); +} + +/** +* dw_dphy_te_read - read register from test enable interface +* +* @dphy: pointer to the dw_dphy private data structure +* @addr: 12 bit TE address register (16 bit container) +* @returns: 8 bit data from TE register +**/ +static u8 dw_dphy_te_read (struct dw_dphy *dphy,u16 addr) +{ +u32 data; + +/* For writing the 4-bit testcode MSBs */ + +/* Ensure that testclk and testen is set to low */ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],0 ); +regmap_field_write (dphy->rf_cfg1[TEST_EN ],0 ); + +/* Set testen to high */ +regmap_field_write (dphy->rf_cfg1[TEST_EN ],1 ); + +/* Set testclk to high */ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],1 ); + +/* Place 0x00 in testdin */ +regmap_field_write (dphy->rf_cfg1[TEST_IN ],0 ); + +/* +* Set testclk to low (with the falling edge on testclk, the testdin signal +* content is latched internally) +*/ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],0 ); + +/* Set testen to low */ +regmap_field_write (dphy->rf_cfg1[TEST_EN ],0 ); + +/* Place the 8-bit word corresponding to the testcode MSBs in testdin */ +regmap_field_write (dphy->rf_cfg1[TEST_IN ], (addr >>8 )); + +/* Set testclk to high */ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],1 ); + +/* For writing the 8-bit testcode LSBs */ + +/* Set testclk to low */ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],0 ); + +/* Set testen to high */ +regmap_field_write (dphy->rf_cfg1[TEST_EN ],1 ); + +/* Set testclk to high */ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],1 ); + +/* Place the 8-bit word test data in testdin */ +regmap_field_write (dphy->rf_cfg1[TEST_IN ], (addr &0xff )); + +/* +* Set testclk to low (with the falling edge on testclk, the testdin signal +* content is latched internally) +*/ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],0 ); + +/* Set testen to low */ +regmap_field_write (dphy->rf_cfg1[TEST_EN ],0 ); + +regmap_field_read (dphy->rf_cfg1[TEST_OUT ], &data); + +return (u8 )data; +} + +/** +* dw_dphy_configure - configure the D-PHY +* +* @phy: pointer to the phy data structure +* @opts: pointer to the phy configuration options +* @returns 0 if success else appropriate error code +* +**/ +static int dw_dphy_configure (struct phy *phy,union phy_configure_opts *opts) +{ +struct dw_dphy *dphy =phy_get_drvdata (phy); + + dphy->hs_clk_rate = opts->mipi_dphy.hs_clk_rate; +dev_dbg (dphy->dev,"hs_clk_rate=%ld\n" , dphy->hs_clk_rate); + +return 0 ; +} + +/** +* dw_dphy_power_on_1p2 - power on the DPHY version 1.2 +* +* @phy: pointer to the phy data structure +* @returns 0 if success else appropriate error code +* +**/ +static int dw_dphy_power_on_1p2 (struct phy *phy) +{ +struct dw_dphy *dphy =phy_get_drvdata (phy); + +uint8_t counter_for_des_en_config_if_rw =0x1 ; +u8 range =0 ; + +for (range =0 ; + (range < dphy->dt_data->table_size -1 ) && + ((dphy->hs_clk_rate) > dphy->dt_data->table[range].freq); + range++) + ; + +/* in case requested hs_clk_rate is out of range, return -EINVAL */ +if (range >= dphy->dt_data->table_size) +return -EINVAL ; + +dev_dbg (dphy->dev,"12bit: PHY GEN 3: Freq: %ld %x\n" , dphy->hs_clk_rate, + range_gen3[range].hsfregrange); + +regmap_field_write (dphy->rf_cfg1[DPHY_RSTZ ],0 ); +regmap_field_write (dphy->rf_cfg1[PHY_SHUTDOWNZ ],0 ); +regmap_field_write (dphy->rf_cfg1[TEST_CLR ],0 ); +regmap_field_write (dphy->rf_cfg1[TEST_CLR ],1 ); +regmap_field_write (dphy->rf_cfg1[TEST_CLR ],0 ); +regmap_field_write (dphy->rf_cfg2[CFG_CLK_FREQ_RANGE ],0x28 ); +dw_dphy_te_write (dphy,RX_SYS_1 , + dphy->dt_data->table[range].hsfregrange); +dw_dphy_te_write (dphy,RX_SYS_0 ,0x20 ); +dw_dphy_te_write (dphy,RX_RX_STARTUP_OVR_2 , + (u8 )dphy->dt_data->table[range].osc_freq_target); +dw_dphy_te_write (dphy,RX_RX_STARTUP_OVR_3 , + (u8)(dphy->dt_data->table[range].osc_freq_target >> +8 )); +dw_dphy_te_write (dphy,0xe4 , + (counter_for_des_en_config_if_rw <<4 ) |0b1 ); + +dw_dphy_te_write (dphy,RX_RX_STARTUP_OVR_1 ,0x01 ); +dw_dphy_te_write (dphy,RX_RX_STARTUP_OVR_0 ,0x80 ); + +regmap_field_write (dphy->rf_cfg2[BASE_DIR_0 ],1 ); +regmap_field_write (dphy->rf_cfg2[ENABLE_CLK ],1 ); +regmap_field_write (dphy->rf_cfg2[FORCE_RX_MODE ],0x0 ); + +regmap_field_write (dphy->rf_cfg1[PHY_SHUTDOWNZ ],1 ); +regmap_field_write (dphy->rf_cfg1[DPHY_RSTZ ],1 ); + +return 0 ; +} + +/** +* dw_dphy_power_off - power off the DPHY +* +* @phy: pointer to the phy data structure +* @returns 0 if success else appropriate error code +* +**/ +static int dw_dphy_power_off (struct phy *phy) +{ +struct dw_dphy *dphy =phy_get_drvdata (phy); + +regmap_field_write (dphy->rf_cfg1[DPHY_RSTZ ],0 ); +regmap_field_write (dphy->rf_cfg1[PHY_SHUTDOWNZ ],0 ); +return 0 ; +} + +/** +* dw_dphy_ops_1p2 - PHY operations for DWC DPHY v1.2 +* @configure: Configures DPHY timing and operation parameters +* @power_on: Powers on the DPHY using v1.2 specific sequence +* @power_off: Powers off the DPHY +* +**/ +static const struct phy_ops dw_dphy_ops_1p2 = { + .configure = dw_dphy_configure, + .power_on = dw_dphy_power_on_1p2, + .power_off = dw_dphy_power_off, +}; + +/** +* dw_dphy_1p2 - DWC DPHY v1.2 configuration instance +* @table: Points to range_gen3 timing parameters table +* @table_size: Size of range_gen3 table calculated at compile time +* @phy_ops: Points to v1.2 specific PHY operations structure +* +**/ +struct dt_data_dw_dphy dw_dphy_1p2 = { + .table = range_gen3, + .table_size =ARRAY_SIZE (range_gen3), + .phy_ops = &dw_dphy_ops_1p2, +}; + +/** +* dw_dphy_regmap_cfg1 - Register map configuration for DW DPHY +* @reg_bits: Width of register address in bits (32) +* @val_bits: Width of register value in bits (32) +* @reg_stride: Number of bytes between registers (4) +* @name: Name identifier for this register map +* @fast_io: Flag to indicate fast I/O operations are supported +* +**/ +static const struct regmap_config dw_dphy_regmap_cfg1 = { + .reg_bits =32 , + .val_bits =32 , + .reg_stride =4 , + .name ="dw-dhpy-cfg1" , + .fast_io = true, +}; + +/** +* dw_dphy_regmap_cfg2 - Register map configuration for DW DPHY +* @reg_bits: Width of register address in bits (32) +* @val_bits: Width of register value in bits (32) +* @reg_stride: Number of bytes between registers (4) +* @name: Name identifier for this register map +* @fast_io: Flag to indicate fast I/O operations are supported +* +**/ +static const struct regmap_config dw_dphy_regmap_cfg2 = { + .reg_bits =32 , + .val_bits =32 , + .reg_stride =4 , + .name ="dw-dhpy-cfg2" , + .fast_io = true, +}; + +/** +* dw_dphy_probe - Probe and initialize DW DPHY device +* @pdev: Platform device pointer +* Return: 0 on success, negative error code on failure +* +**/ +static int dw_dphy_probe (struct platform_device *pdev) +{ +struct dw_dphy *dphy; +struct resource *res; +struct device *dev = &pdev->dev; +struct phy_provider *phy_provider; +int ret; + + dphy =devm_kzalloc (&pdev->dev,sizeof (*dphy),GFP_KERNEL ); +if (!dphy) +return -ENOMEM ;
drivers/phy/phy-dw-dphy.c line 493
Quoted 10 lines
drivers/phy/phy-dw-dphy.c new file +10
-0+ + dphy->dt_data = + (struct dt_data_dw_dphy *)of_device_get_match_data (&pdev->dev); +dev_set_drvdata (&pdev->dev, dphy); + dphy->dev = &pdev->dev; + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); + dphy->iomem_cfg1 =devm_ioremap_resource (&pdev->dev, res); +if (IS_ERR (dphy->iomem_cfg1)) +return PTR_ERR (dphy->iomem_cfg1);
cfg1 is part of DW MIPI-CSI2 MMIO space. how to cooperate with dw MIPI-CSI2 controller.
Please CC me for next version. I am working on DW MIPI-CSI2 work.
https://lore.kernel.org/imx/[email protected]/
Frank
Quoted 85 lines
drivers/phy/phy-dw-dphy.c new file +82
-1+ + dphy->regmap_cfg1 = +devm_regmap_init_mmio (dev, dphy->iomem_cfg1, &dw_dphy_regmap_cfg1); +if (IS_ERR (dphy->regmap_cfg1)) +return PTR_ERR (dphy->regmap_cfg1); + + ret =devm_regmap_field_bulk_alloc (dev, dphy->regmap_cfg1, dphy->rf_cfg1, + dw_dphy_v1_2_cfg1,DW_DPHY_RF_CFG1_MAX ); +if (ret <0 ) { +dev_err (dev,"Could not alloc RF\n" ); +return ret; + } + + res =platform_get_resource (pdev,IORESOURCE_MEM ,1 ); + dphy->iomem_cfg2 =devm_ioremap_resource (&pdev->dev, res); +if (IS_ERR (dphy->iomem_cfg2)) +return PTR_ERR (dphy->iomem_cfg2); + + dphy->regmap_cfg2 =devm_regmap_init_mmio (dev, dphy->iomem_cfg2, + &dw_dphy_regmap_cfg2); +if (IS_ERR (dphy->regmap_cfg2)) +return PTR_ERR (dphy->regmap_cfg2); + + ret =devm_regmap_field_bulk_alloc (dev, dphy->regmap_cfg2, dphy->rf_cfg2, + dw_dphy_v1_2_cfg2,DW_DPHY_RF_CFG2_MAX ); +if (ret <0 ) { +dev_err (dev,"Could not alloc RF\n" ); +return ret; + } + + dphy->phy =devm_phy_create (&pdev->dev,NULL , dphy->dt_data->phy_ops); +if (IS_ERR (dphy->phy)) { +dev_err (dev,"failed to create PHY\n" ); +return PTR_ERR (dphy->phy); + } + +phy_set_drvdata (dphy->phy, dphy); + phy_provider = +devm_of_phy_provider_register (&pdev->dev, of_phy_simple_xlate); + +return PTR_ERR_OR_ZERO (phy_provider); +} + +/** +* dw_dphy_of_match - Device tree match table for DW DPHY +* @compatible: Compatible string to match device tree node +* @data: Pointer to configuration data for matched device +* +* Table of compatible strings and associated configuration data +* for supported DW DPHY variants. +* Currently supports: +* - DW DPHY v1.2 ("snps,dw-dphy-1p2") +* +**/ +static const struct of_device_id dw_dphy_of_match[] = { + { .compatible ="snps,dw-dphy-1p2" , .data = &dw_dphy_1p2 }, + {/* sentinel */ }, +}; +MODULE_DEVICE_TABLE (of, dw_dphy_of_match); + +/** +* dw_dphy_platform_driver - Platform driver structure for DW DPHY +* @probe: Pointer to probe function called on device discovery +* @driver: Core driver structure containing: +* - name: Driver name used for matching and debugging +* - of_match_table: Table of compatible device tree matches +* +**/ +static struct platform_driver dw_dphy_platform_driver = { + .probe = dw_dphy_probe, + .driver = { + .name ="dw-dphy" , + .of_match_table = dw_dphy_of_match, + }, +}; +module_platform_driver (dw_dphy_platform_driver); + +MODULE_AUTHOR ("Karthik Poduval <[email protected]>" ); +MODULE_AUTHOR ("Jason Xiong <[email protected]>" ); +MODULE_AUTHOR ("Miguel Lopes <[email protected]>" ); +MODULE_DESCRIPTION ("DW D-PHY RX Driver" ); +MODULE_LICENSE ("GPL" ); --2.43.0
Re: [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX
Quoted 577 lines · Frank Li
CAUTION: This email originated from outside of the organization. Do not click links or open attachments unless you can confirm the sender and know the content is safe.
Quoted 570 lines · Karthik Poduval
Add support for Synopsys DesignWare MIPI D-PHY RX v1.2. The driver supports data rates from 80Mbps to 2500Mbps.
Signed-off-by Karthik Poduval <[email protected]>---
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.cdrivers/phy/Kconfig +0
-0@@ -101,6 +101,17 @@ config PHY_NXP_PTN3222schemes. 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 onHAS_IOMEM&®MAP_MMIO
+ selectGENERIC_PHY
+ selectGENERIC_PHY_MIPI_DPHY
+ help
+ This option enables support for Synopsys DW MIPI D-PHY RX IP. This driver
+ provides D-PHY functionality using Generic PHY framework and is meant to
+ be used by MIPI CSI2 receivers over the PPI hardware interface. MIPI CSI2
+ receivers may find this driver and use it via Generic PHY Framework API.
+
source "drivers/phy/allwinner/Kconfig"
source "drivers/phy/amlogic/Kconfig"
source "drivers/phy/broadcom/Kconfig"drivers/phy/Makefile +0
-0@@ -13,6 +13,7 @@ obj-$(CONFIG_PHY_SNPS_EUSB2) +=phy-snps-eusb2.o
obj-$(CONFIG_USB_LGM_PHY) += phy-lgm-usb.o obj-$(CONFIG_PHY_AIROHA_PCIE) += phy-airoha-pcie.o obj-$(CONFIG_PHY_NXP_PTN3222) += phy-nxp-ptn3222.o +obj-$(CONFIG_PHY_SYNOPSYS_DW_DPHY_RX) += phy-dw-dphy.o obj-y += allwinner/ \
amlogic/ \
broadcom/ \drivers/phy/phy-dw-dphy.c new file +47
-0@@ -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_fielddw_dphy_v1_2_cfg1[DW_DPHY_RF_CFG1_MAX] = {
+ [PHY_SHUTDOWNZ] =REG_FIELD(0x0, 0, 0),
+ [DPHY_RSTZ] =REG_FIELD(0x4, 0, 0),
+ [TEST_CLR] =REG_FIELD(0x10, 0, 0),
+ [TEST_CLK] =REG_FIELD(0x10, 1, 1),
+ [TEST_IN] =REG_FIELD(0x14, 0, 7),
+ [TEST_OUT] =REG_FIELD(0x14, 8, 15),
+ [TEST_EN] =REG_FIELD(0x14, 16, 16),drivers/phy/phy-dw-dphy.c new file +3
-0+}; + +static const struct reg_fielddw_dphy_v1_2_cfg2[DW_DPHY_RF_CFG2_MAX] = {
+ [EN_CONT_REG_UPDATE] =REG_FIELD(0x0, 23, 23), + [TURN_REQUEST_0] =REG_FIELD(0x0, 22, 22), + [TURN_DISABLE_0] =REG_FIELD(0x0, 21, 21), + [ENABLE_CLK] =REG_FIELD(0x0, 20, 20), + [FORCE_TX_STOP_MODE_0] =REG_FIELD(0x0, 19, 19), + [FORCE_RX_MODE] =REG_FIELD(0x0, 15, 18), + [BASE_DIR_0] =REG_FIELD(0x0, 14, 14), + [CFG_CLK_FREQ_RANGE] =REG_FIELD(0x0, 8, 13), + [HS_FREQ_RANGE] =REG_FIELD(0x0, 1, 7), + [CONT_EN] =REG_FIELD(0x0, 0, 0),drivers/phy/phy-dw-dphy.c new file +30
-0+}; + +enum dphy_12bit_interface_addr { + RX_SYS_0 = 0x01, + RX_SYS_1 = 0x02, + RX_SYS_7 = 0x08, + RX_RX_STARTUP_OVR_0 = 0xe0, + RX_RX_STARTUP_OVR_1 = 0xe1, + RX_RX_STARTUP_OVR_2 = 0xe2, + RX_RX_STARTUP_OVR_3 = 0xe3, + RX_RX_STARTUP_OVR_4 = 0xe4, +}; + +/** +* struct range_dphy_gen3 - frequency range calibration structure +* +* @freq: input freqency to calibration table +* @hsfregrange: corresponding clock to configure DW D-PHY IP +* @osc_freq_target: corresponding clock to configure DW D-PHY IP +* +**/ +struct range_dphy_gen3 { + u32 freq; + u8 hsfregrange; + u32 osc_freq_target; +}; + +/** +* struct dt_data_dw_dphy - DPHY configuration data structure +* @table: Pointer to array of DPHY Gen3 timing range configurations
+ * @table_size: Number of entries in the timing range table
+ * @phy_ops: Pointer to PHY operations structure containing callback functions
+ *
+ **/drivers/phy/phy-dw-dphy.c new file +57
-0+struct dt_data_dw_dphy { + struct range_dphy_gen3 *table; + int table_size; + const struct phy_ops *phy_ops; +}; + +/* +* DW DPHY Gen3 calibration table +* +*/ +struct range_dphy_gen3 range_gen3[] = { + { 80, 0b0000000, 460 }, { 90, 0b0010000, 460 }, + { 100, 0b0100000, 460 }, { 110, 0b0110000, 460 }, + { 120, 0b0000001, 460 }, { 130, 0b0010001, 460 }, + { 140, 0b0100001, 460 }, { 150, 0b0110001, 460 }, + { 160, 0b0000010, 460 }, { 170, 0b0010010, 460 }, + { 180, 0b0100010, 460 }, { 190, 0b0110010, 460 }, + { 205, 0b0000011, 460 }, { 220, 0b0010011, 460 }, + { 235, 0b0100011, 460 }, { 250, 0b0110011, 460 }, + { 275, 0b0000100, 460 }, { 300, 0b0010100, 460 }, + { 325, 0b0100101, 460 }, { 350, 0b0110101, 460 }, + { 400, 0b0000101, 460 }, { 450, 0b0010110, 460 }, + { 500, 0b0100110, 460 }, { 550, 0b0110111, 460 }, + { 600, 0b0000111, 460 }, { 650, 0b0011000, 460 }, + { 700, 0b0101000, 460 }, { 750, 0b0111001, 460 }, + { 800, 0b0001001, 460 }, { 850, 0b0011001, 460 }, + { 900, 0b0101001, 460 }, { 950, 0b0111010, 460 }, + { 1000, 0b0001010, 460 }, { 1050, 0b0011010, 460 }, + { 1110, 0b0101010, 460 }, { 1150, 0b0111011, 460 }, + { 1200, 0b0001011, 460 }, { 1250, 0b0011011, 460 }, + { 1300, 0b0101011, 460 }, { 1350, 0b0111100, 460 }, + { 1400, 0b0001100, 460 }, { 1450, 0b0011100, 460 }, + { 1500, 0b0101100, 460 }, { 1550, 0b0111101, 285 }, + { 1600, 0b0001101, 295 }, { 1650, 0b0011101, 304 }, + { 1700, 0b0101110, 313 }, { 1750, 0b0111110, 322 }, + { 1800, 0b0001110, 331 }, { 1850, 0b0011110, 341 }, + { 1900, 0b0101111, 350 }, { 1950, 0b0111111, 359 }, + { 2000, 0b0001111, 368 }, { 2050, 0b1000000, 377 }, + { 2100, 0b1000001, 387 }, { 2150, 0b1000010, 396 }, + { 2200, 0b1000011, 405 }, { 2250, 0b1000100, 414 }, + { 2300, 0b1000101, 423 }, { 2350, 0b1000110, 432 }, + { 2400, 0b1000111, 442 }, { 2450, 0b1001000, 451 }, + { 2500, 0b1001001, 460 } +}; + +/** +* struct dw_dphy - DW D-PHY driver private structure +* +* @regmap: pointer to regmap +* @regmap_cfg1: pointer to config1 regmap +* @regmap_cfg2: pointer to config2 regmap +* @rf_cfg1: array of regfields for config1 +* @rf_cfg2: array of regfields for config2 +* @iomem_cfg1: MMIO address for cfg1 section +* @iomem_cfg2: MMIO address for cfg2 section +* @phy: pointer to the phy data structure +* @hs_clk_rate: high speed clock rate as per image sensor configuration
+ * @dt_data_dw_dphy: device tree specific data
+ *
+ **/drivers/phy/phy-dw-dphy.c new file +22
-0+struct dw_dphy { + struct regmap *regmap_cfg1; + struct regmap *regmap_cfg2; + struct regmap_field *rf_cfg1[DW_DPHY_RF_CFG1_MAX]; + struct regmap_field *rf_cfg2[DW_DPHY_RF_CFG2_MAX]; + void __iomem *iomem_cfg1; + void __iomem *iomem_cfg2; + struct phy *phy; + struct device *dev; + unsigned long hs_clk_rate; + struct dt_data_dw_dphy *dt_data; +}; + +/** +* dw_dphy_te_write - write register into test enable interface +* +* @dphy: pointer to the dw_dphy private data structure +* @addr: 12 bit TE address register (16 bit container) +* @data: 8 bit data to be written to TE register +* +**/ +static void dw_dphy_te_write(struct dw_dphy *dphy, u16 addr, u8data)
drivers/phy/phy-dw-dphy.c new file +18
-0+{ + /* For writing the 4-bit testcode MSBs */ + + /* Ensure that testclk and testen is set to low */ + regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0); + regmap_field_write(dphy->rf_cfg1[TEST_EN], 0); + + /* Set testen to high */ + regmap_field_write(dphy->rf_cfg1[TEST_EN], 1); + + /* Set testclk to high */ + regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1); + + /* Place 0x00 in testdin */ + regmap_field_write(dphy->rf_cfg1[TEST_IN], 0); + + /* +* Set testclk to low (with the falling edge on testclk, the testdin signal
+ * content is latched internally)
+ */
+regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);drivers/phy/phy-dw-dphy.c new file +5
-0+ + /* Set testen to low */ + regmap_field_write(dphy->rf_cfg1[TEST_EN], 0); + + /* Place the 8-bit word corresponding to the testcode MSBs intestdin */
+regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr >> 8));drivers/phy/phy-dw-dphy.c new file +20
-0+ + /* Set testclk to high */ + regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1); + + /* For writing the 8-bit testcode LSBs */ + + /* Set testclk to low */ + regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0); + + /* Set testen to high */ + regmap_field_write(dphy->rf_cfg1[TEST_EN], 1); + + /* Set testclk to high */ + regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1); + + /* Place the 8-bit word test data in testdin */ + regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr & 0xff)); + + /* +* Set testclk to low (with the falling edge on testclk, the testdin signal
+ * content is latched internally)
+ */
+regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);drivers/phy/phy-dw-dphy.c new file +7
-0+ + /* Set testen to low */ + regmap_field_write(dphy->rf_cfg1[TEST_EN], 0); + + /* For writing the data */ + + /* Place the 8-bit word corresponding to the page offset intestdin */
+regmap_field_write(dphy->rf_cfg1[TEST_IN], data); +
+ /* Set testclk to high (test data is programmed internally) */
+regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);drivers/phy/phy-dw-dphy.c new file +30
-0+} + +/** +* dw_dphy_te_read - read register from test enable interface +* +* @dphy: pointer to the dw_dphy private data structure +* @addr: 12 bit TE address register (16 bit container) +* @returns: 8 bit data from TE register +**/ +static u8 dw_dphy_te_read (struct dw_dphy *dphy,u16 addr) +{ + u32 data; + + /* For writing the 4-bit testcode MSBs */ + + /* Ensure that testclk and testen is set to low */ + regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0); + regmap_field_write(dphy->rf_cfg1[TEST_EN], 0); + + /* Set testen to high */ + regmap_field_write(dphy->rf_cfg1[TEST_EN], 1); + + /* Set testclk to high */ + regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1); + + /* Place 0x00 in testdin */ + regmap_field_write(dphy->rf_cfg1[TEST_IN], 0); + + /* +* Set testclk to low (with the falling edge on testclk, the testdin signal
+ * content is latched internally)
+ */
+regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);drivers/phy/phy-dw-dphy.c new file +5
-0+ + /* Set testen to low */ + regmap_field_write(dphy->rf_cfg1[TEST_EN], 0); + + /* Place the 8-bit word corresponding to the testcode MSBs intestdin */
+regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr >> 8));drivers/phy/phy-dw-dphy.c new file +20
-0+ + /* Set testclk to high */ + regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1); + + /* For writing the 8-bit testcode LSBs */ + + /* Set testclk to low */ + regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0); + + /* Set testen to high */ + regmap_field_write(dphy->rf_cfg1[TEST_EN], 1); + + /* Set testclk to high */ + regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1); + + /* Place the 8-bit word test data in testdin */ + regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr & 0xff)); + + /* +* Set testclk to low (with the falling edge on testclk, the testdin signal
+ * content is latched internally)
+ */
+regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);drivers/phy/phy-dw-dphy.c new file +18
-0+ + /* Set testen to low */ + regmap_field_write(dphy->rf_cfg1[TEST_EN], 0); + + regmap_field_read(dphy->rf_cfg1[TEST_OUT], &data); + + return (u8)data; +} + +/** +* dw_dphy_configure - configure the D-PHY +* +* @phy: pointer to the phy data structure +* @opts: pointer to the phy configuration options +* @returns 0 if success else appropriate error code +* +**/ +static int dw_dphy_configure(struct phy *phy, union
phy_configure_opts*opts)drivers/phy/phy-dw-dphy.c new file +26
-0+{ + struct dw_dphy *dphy = phy_get_drvdata(phy); + + dphy->hs_clk_rate = opts->mipi_dphy.hs_clk_rate; + dev_dbg(dphy->dev, "hs_clk_rate=%ld\n", dphy->hs_clk_rate); + + return 0; +} + +/** +* dw_dphy_power_on_1p2 - power on the DPHY version 1.2 +* +* @phy: pointer to the phy data structure +* @returns 0 if success else appropriate error code +* +**/ +static int dw_dphy_power_on_1p2(struct phy *phy) +{ + struct dw_dphy *dphy = phy_get_drvdata(phy); + + uint8_t counter_for_des_en_config_if_rw = 0x1; + u8 range = 0; + + for (range = 0; + (range < dphy->dt_data->table_size - 1) && + ((dphy->hs_clk_rate) > dphy->dt_data-Quoted 1 line
table[range].freq);
+ range++)
+ ;
+
+ /* in case requestedhs_clk_rateis out of range, return - EINVAL */
+ if (range >=dphy->dt_data->table_size)
+ return-EINVAL;
+
+ dev_dbg(dphy->dev, "12bit: PHY GEN 3: Freq: %ld %x\n", dphy-Quoted 1 line
hs_clk_rate,+ range_gen3[range].hsfregrange);
+
+regmap_field_write(dphy->rf_cfg1[DPHY_RSTZ], 0); +regmap_field_write(dphy->rf_cfg1[PHY_SHUTDOWNZ], 0); +regmap_field_write(dphy->rf_cfg1[TEST_CLR], 0);
+regmap_field_write(dphy->rf_cfg1[TEST_CLR], 1);
+regmap_field_write(dphy->rf_cfg1[TEST_CLR], 0);
+regmap_field_write(dphy->rf_cfg2[CFG_CLK_FREQ_RANGE], 0x28); + dw_dphy_te_write(dphy,RX_SYS_1,
+ dphy->dt_data->table[range].hsfregrange); +dw_dphy_te_write(dphy, RX_SYS_0, 0x20);
+ dw_dphy_te_write(dphy,RX_RX_STARTUP_OVR_2,
+ (u8)dphy->dt_data-Quoted 1 line
table[range].osc_freq_target);
+ dw_dphy_te_write(dphy,
RX_RX_STARTUP_OVR_3,
+ (u8)(dphy->dt_data-Quoted 1 line
table[range].osc_freq_target >>
+ 8));
+ dw_dphy_te_write(dphy,0xe4,
+ (counter_for_des_en_config_if_rw<< 4) | 0b1);drivers/phy/phy-dw-dphy.c new file +47
-0+ + dw_dphy_te_write(dphy, RX_RX_STARTUP_OVR_1, 0x01); + dw_dphy_te_write(dphy, RX_RX_STARTUP_OVR_0, 0x80); + + regmap_field_write(dphy->rf_cfg2[BASE_DIR_0], 1); + regmap_field_write(dphy->rf_cfg2[ENABLE_CLK], 1); + regmap_field_write(dphy->rf_cfg2[FORCE_RX_MODE], 0x0); + + regmap_field_write(dphy->rf_cfg1[PHY_SHUTDOWNZ], 1); + regmap_field_write(dphy->rf_cfg1[DPHY_RSTZ], 1); + + return 0; +} + +/** +* dw_dphy_power_off - power off the DPHY +* +* @phy: pointer to the phy data structure +* @returns 0 if success else appropriate error code +* +**/ +static int dw_dphy_power_off (struct phy *phy) +{ + struct dw_dphy *dphy = phy_get_drvdata(phy); + + regmap_field_write(dphy->rf_cfg1[DPHY_RSTZ], 0); + regmap_field_write(dphy->rf_cfg1[PHY_SHUTDOWNZ], 0); + return 0; +} + +/** +* dw_dphy_ops_1p2 - PHY operations for DWC DPHY v1.2 +* @configure: Configures DPHY timing and operation parameters +* @power_on: Powers on the DPHY using v1.2 specific sequence +* @power_off: Powers off the DPHY +* +**/ +static const struct phy_ops dw_dphy_ops_1p2 = { + .configure = dw_dphy_configure, + .power_on = dw_dphy_power_on_1p2, + .power_off = dw_dphy_power_off, +}; + +/** +* dw_dphy_1p2 - DWC DPHY v1.2 configuration instance +* @table: Points to range_gen3 timing parameters table +* @table_size: Size of range_gen3 table calculated at compile time
+ * @phy_ops: Points to v1.2 specific PHY operations structure
+ *
+ **/drivers/phy/phy-dw-dphy.c new file +60
-0+struct dt_data_dw_dphy dw_dphy_1p2 = { + .table = range_gen3, + .table_size = ARRAY_SIZE(range_gen3), + .phy_ops = &dw_dphy_ops_1p2, +}; + +/** +* dw_dphy_regmap_cfg1 - Register map configuration for DW DPHY +* @reg_bits: Width of register address in bits (32) +* @val_bits: Width of register value in bits (32) +* @reg_stride: Number of bytes between registers (4) +* @name: Name identifier for this register map +* @fast_io: Flag to indicate fast I/O operations are supported +* +**/ +static const struct regmap_config dw_dphy_regmap_cfg1 = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .name = "dw-dhpy-cfg1", + .fast_io = true, +}; + +/** +* dw_dphy_regmap_cfg2 - Register map configuration for DW DPHY +* @reg_bits: Width of register address in bits (32) +* @val_bits: Width of register value in bits (32) +* @reg_stride: Number of bytes between registers (4) +* @name: Name identifier for this register map +* @fast_io: Flag to indicate fast I/O operations are supported +* +**/ +static const struct regmap_config dw_dphy_regmap_cfg2 = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .name = "dw-dhpy-cfg2", + .fast_io = true, +}; + +/** +* dw_dphy_probe - Probe and initialize DW DPHY device +* @pdev: Platform device pointer +* Return: 0 on success, negative error code on failure +* +**/ +static int dw_dphy_probe (struct platform_device *pdev) +{ + struct dw_dphy *dphy; + struct resource *res; + struct device *dev = &pdev->dev; + struct phy_provider *phy_provider; + int ret; + + dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL); + if (!dphy) + return -ENOMEM; + + dphy->dt_data = + (struct dt_data_dw_dphy*)of_device_get_match_data(&pdev->dev);
+dev_set_drvdata(&pdev->dev, dphy);
+dphy->dev=&pdev->dev;
+
Quoted 8 lines
Quoted 4 lines
+ res =
platform_get_resource(pdev, IORESOURCE_MEM, 0); +dphy->iomem_cfg1=devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(dphy->iomem_cfg1))
+ returnPTR_ERR(dphy->iomem_cfg1);cfg1 is part of DW MIPI-CSI2 MMIO space. how to cooperate with dw MIPI-CSI2
controller.
This is essentially why we created two MMIO spaces as CSI2 and D-PHY are intermixed in the MMIO space and regmap driver detects the conflict.
Quoted 6 lines
Please CC me for next version. I am working on DW MIPI-CSI2 work.
https://lore.kernel.org/imx/[email protected]/
Frank
Sure, Frank, perhaps loop in Miguel as he might be able to know about all the variants out there for this IP.
Quoted 95 lines
Quoted 95 lines
+
+dphy->regmap_cfg1=
+devm_regmap_init_mmio(dev, dphy->iomem_cfg1, &dw_dphy_regmap_cfg1);
+ if (IS_ERR(dphy->regmap_cfg1))
+ returnPTR_ERR(dphy->regmap_cfg1);
+
+ ret = devm_regmap_field_bulk_alloc(dev,dphy->regmap_cfg1,dphy->rf_cfg1,
+dw_dphy_v1_2_cfg1,DW_DPHY_RF_CFG1_MAX);
+ if (ret < 0) {
+dev_err(dev, "Could not alloc RF\n");
+ return ret;
+ }drivers/phy/phy-dw-dphy.c new file +7
-0+ + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + dphy->iomem_cfg2 = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(dphy->iomem_cfg2)) + return PTR_ERR(dphy->iomem_cfg2); + + dphy->regmap_cfg2 = devm_regmap_init_mmio(dev, dphy-Quoted 1 line
iomem_cfg2,+
&dw_dphy_regmap_cfg2);
+ if (IS_ERR(dphy->regmap_cfg2))
+ returnPTR_ERR(dphy->regmap_cfg2);
+
+ ret = devm_regmap_field_bulk_alloc(dev,dphy->regmap_cfg2,dphy->rf_cfg2,
+dw_dphy_v1_2_cfg2,DW_DPHY_RF_CFG2_MAX);
+ if (ret < 0) {
+dev_err(dev, "Could not alloc RF\n");
+ return ret;
+ }
+
+dphy->phy= devm_phy_create(&pdev->dev, NULL, dphy->dt_data-Quoted 1 line
phy_ops);+ if (
IS_ERR(dphy->phy)) {
+dev_err(dev, "failed to create PHY\n"); + returnPTR_ERR(dphy->phy);
+ }
+
+phy_set_drvdata(dphy->phy, dphy);
+phy_provider=
+devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);drivers/phy/phy-dw-dphy.c new file +27
-0+ + return PTR_ERR_OR_ZERO(phy_provider); +} + +/** +* dw_dphy_of_match - Device tree match table for DW DPHY +* @compatible: Compatible string to match device tree node +* @data: Pointer to configuration data for matched device +* +* Table of compatible strings and associated configuration data +* for supported DW DPHY variants. +* Currently supports: +* - DW DPHY v1.2 ("snps,dw-dphy-1p2") +* +**/ +static const struct of_device_id dw_dphy_of_match[] = { + { .compatible = "snps,dw-dphy-1p2", .data = &dw_dphy_1p2 }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE (of, dw_dphy_of_match); + +/** +* dw_dphy_platform_driver - Platform driver structure for DW DPHY +* @probe: Pointer to probe function called on device discovery +* @driver: Core driver structure containing: +* - name: Driver name used for matching and debugging +* - of_match_table: Table of compatible device tree matches
+ *
+ **/drivers/phy/phy-dw-dphy.c new file +14
-1+static struct platform_driver dw_dphy_platform_driver = { + .probe = dw_dphy_probe, + .driver = { + .name = "dw-dphy", + .of_match_table = dw_dphy_of_match, + }, +}; +module_platform_driver (dw_dphy_platform_driver); + +MODULE_AUTHOR ("Karthik Poduval <[email protected]>" ); +MODULE_AUTHOR ("Jason Xiong <[email protected]>" ); +MODULE_AUTHOR ("Miguel Lopes <[email protected]>" ); +MODULE_DESCRIPTION ("DW D-PHY RX Driver" ); +MODULE_LICENSE ("GPL" ); --2.43.0
Frank Li
maintainerRe: [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX
Quoted 7 lines · Karthik
Quoted 6 lines · Frank Li
CAUTION: This email originated from outside of the organization. Do not click links or open attachments unless you can confirm the sender and know the content is safe.
...
Quoted 15 lines
Quoted 7 lines
Quoted 7 lines
+
+dphy->dt_data=
+ (structdt_data_dw_dphy
*)of_device_get_match_data(&pdev->dev);
+dev_set_drvdata(&pdev->dev, dphy);
+dphy->dev=&pdev->dev;
+Quoted 8 lines
Quoted 4 lines
+ res =
platform_get_resource(pdev, IORESOURCE_MEM, 0); +dphy->iomem_cfg1=devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(dphy->iomem_cfg1))
+ returnPTR_ERR(dphy->iomem_cfg1);cfg1 is part of DW MIPI-CSI2 MMIO space. how to cooperate with dw MIPI-CSI2
controller.
Quoted 3 lines
This is essentially why we created two MMIO spaces as CSI2 and D-PHY are intermixed in the MMIO space and regmap driver detects the conflict.
Because there are not CSI2 part code, It is not clear how to avoid this problem by use cfg1 and cfg2.
CSI2 register look like
version
n_lan
...
phy_tst_ctrl1
phy_tst_ctrl2
...
other register like irqs
Frank
Quoted 8 lines
Quoted 6 lines
Please CC me for next version. I am working on DW MIPI-CSI2 work.
https://lore.kernel.org/imx/[email protected]/
Frank
Sure, Frank, perhaps loop in Miguel as he might be able to know about all the variants out there for this IP.
...
Quoted 5 lines
Quoted 4 lines
Quoted 4 lines
+MODULE_LICENSE("GPL");
--
2.43.0
Frank Li
maintainerRe: [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX
In reply to Karthik PoduvalQuoted 3 lines · Karthik Poduval
Add support for Synopsys DesignWare MIPI D-PHY RX v1.2. The driver supports data rates from 80Mbps to 2500Mbps.
where download spec?
And I think you should cc: [email protected]
In https://lore.kernel.org/imx/[email protected]/
drivers/media/platform/raspberrypi/rp1-cfe/dphy.c do similar work.
Frank
Quoted 626 lines
Signed-off-by Karthik Poduval <[email protected]>--- 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.cdrivers/phy/Kconfig +11
-0@@ -101,6 +101,17 @@ config PHY_NXP_PTN3222 schemes. It supports all three USB 2.0 data rates: Low Speed, Full Speed and High Speed. +config PHY_SYNOPSYS_DW_DPHY_RX + tristate "Synopsys DesignWare D-PHY Rx Support" + depends on HAS_IOMEM && REGMAP_MMIO + select GENERIC_PHY + select GENERIC_PHY_MIPI_DPHY + help + This option enables support for Synopsys DW MIPI D-PHY RX IP. This driver + provides D-PHY functionality using Generic PHY framework and is meant to + be used by MIPI CSI2 receivers over the PPI hardware interface. MIPI CSI2 + receivers may find this driver and use it via Generic PHY Framework API. + source "drivers/phy/allwinner/Kconfig" source "drivers/phy/amlogic/Kconfig" source "drivers/phy/broadcom/Kconfig"drivers/phy/Makefile +1
-0@@ -13,6 +13,7 @@ obj-$(CONFIG_PHY_SNPS_EUSB2) += phy-snps-eusb2.o obj-$(CONFIG_USB_LGM_PHY) += phy-lgm-usb.o obj-$(CONFIG_PHY_AIROHA_PCIE) += phy-airoha-pcie.o obj-$(CONFIG_PHY_NXP_PTN3222) += phy-nxp-ptn3222.o +obj-$(CONFIG_PHY_SYNOPSYS_DW_DPHY_RX) += phy-dw-dphy.o obj-y += allwinner/ \ amlogic/ \ broadcom/ \drivers/phy/phy-dw-dphy.c new file +575
-1@@ -0,0 +1,575 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* +* Copyright © 2025 Amazon.com, Inc. or its affiliates. +* Copyright © 2025 Synopsys, Inc. (www.synopsys.com) +*/ +#include <linux/bitops.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/reset.h> +#include <linux/regmap.h> + +#include <linux/phy/phy.h> +#include <linux/phy/phy-mipi-dphy.h> + +#define KHZ (1000) +#define MHZ (KHZ * KHZ) + +enum dw_dphy_reg_fields_cfg1 { +PHY_SHUTDOWNZ , +DPHY_RSTZ , +TEST_CLR , +TEST_CLK , +TEST_IN , +TEST_OUT , +TEST_EN , +DW_DPHY_RF_CFG1_MAX +}; + +enum dw_dphy_reg_fields_cfg2 { +EN_CONT_REG_UPDATE , +TURN_REQUEST_0 , +TURN_DISABLE_0 , +ENABLE_CLK , +FORCE_TX_STOP_MODE_0 , +FORCE_RX_MODE , +BASE_DIR_0 , +CFG_CLK_FREQ_RANGE , +HS_FREQ_RANGE , +CONT_EN , +DW_DPHY_RF_CFG2_MAX +}; + +static const struct reg_field dw_dphy_v1_2_cfg1[DW_DPHY_RF_CFG1_MAX ] = { + [PHY_SHUTDOWNZ ] =REG_FIELD (0x0 ,0 ,0 ), + [DPHY_RSTZ ] =REG_FIELD (0x4 ,0 ,0 ), + [TEST_CLR ] =REG_FIELD (0x10 ,0 ,0 ), + [TEST_CLK ] =REG_FIELD (0x10 ,1 ,1 ), + [TEST_IN ] =REG_FIELD (0x14 ,0 ,7 ), + [TEST_OUT ] =REG_FIELD (0x14 ,8 ,15 ), + [TEST_EN ] =REG_FIELD (0x14 ,16 ,16 ), +}; + +static const struct reg_field dw_dphy_v1_2_cfg2[DW_DPHY_RF_CFG2_MAX ] = { + [EN_CONT_REG_UPDATE ] =REG_FIELD (0x0 ,23 ,23 ), + [TURN_REQUEST_0 ] =REG_FIELD (0x0 ,22 ,22 ), + [TURN_DISABLE_0 ] =REG_FIELD (0x0 ,21 ,21 ), + [ENABLE_CLK ] =REG_FIELD (0x0 ,20 ,20 ), + [FORCE_TX_STOP_MODE_0 ] =REG_FIELD (0x0 ,19 ,19 ), + [FORCE_RX_MODE ] =REG_FIELD (0x0 ,15 ,18 ), + [BASE_DIR_0 ] =REG_FIELD (0x0 ,14 ,14 ), + [CFG_CLK_FREQ_RANGE ] =REG_FIELD (0x0 ,8 ,13 ), + [HS_FREQ_RANGE ] =REG_FIELD (0x0 ,1 ,7 ), + [CONT_EN ] =REG_FIELD (0x0 ,0 ,0 ), +}; + +enum dphy_12bit_interface_addr { +RX_SYS_0 =0x01 , +RX_SYS_1 =0x02 , +RX_SYS_7 =0x08 , +RX_RX_STARTUP_OVR_0 =0xe0 , +RX_RX_STARTUP_OVR_1 =0xe1 , +RX_RX_STARTUP_OVR_2 =0xe2 , +RX_RX_STARTUP_OVR_3 =0xe3 , +RX_RX_STARTUP_OVR_4 =0xe4 , +}; + +/** +* struct range_dphy_gen3 - frequency range calibration structure +* +* @freq: input freqency to calibration table +* @hsfregrange: corresponding clock to configure DW D-PHY IP +* @osc_freq_target: corresponding clock to configure DW D-PHY IP +* +**/ +struct range_dphy_gen3 { +u32 freq; +u8 hsfregrange; +u32 osc_freq_target; +}; + +/** +* struct dt_data_dw_dphy - DPHY configuration data structure +* @table: Pointer to array of DPHY Gen3 timing range configurations +* @table_size: Number of entries in the timing range table +* @phy_ops: Pointer to PHY operations structure containing callback functions +* +**/ +struct dt_data_dw_dphy { +struct range_dphy_gen3 *table; +int table_size; +const struct phy_ops *phy_ops; +}; + +/* +* DW DPHY Gen3 calibration table +* +*/ +struct range_dphy_gen3 range_gen3[] = { + {80 ,0b0000000 ,460 }, {90 ,0b0010000 ,460 }, + {100 ,0b0100000 ,460 }, {110 ,0b0110000 ,460 }, + {120 ,0b0000001 ,460 }, {130 ,0b0010001 ,460 }, + {140 ,0b0100001 ,460 }, {150 ,0b0110001 ,460 }, + {160 ,0b0000010 ,460 }, {170 ,0b0010010 ,460 }, + {180 ,0b0100010 ,460 }, {190 ,0b0110010 ,460 }, + {205 ,0b0000011 ,460 }, {220 ,0b0010011 ,460 }, + {235 ,0b0100011 ,460 }, {250 ,0b0110011 ,460 }, + {275 ,0b0000100 ,460 }, {300 ,0b0010100 ,460 }, + {325 ,0b0100101 ,460 }, {350 ,0b0110101 ,460 }, + {400 ,0b0000101 ,460 }, {450 ,0b0010110 ,460 }, + {500 ,0b0100110 ,460 }, {550 ,0b0110111 ,460 }, + {600 ,0b0000111 ,460 }, {650 ,0b0011000 ,460 }, + {700 ,0b0101000 ,460 }, {750 ,0b0111001 ,460 }, + {800 ,0b0001001 ,460 }, {850 ,0b0011001 ,460 }, + {900 ,0b0101001 ,460 }, {950 ,0b0111010 ,460 }, + {1000 ,0b0001010 ,460 }, {1050 ,0b0011010 ,460 }, + {1110 ,0b0101010 ,460 }, {1150 ,0b0111011 ,460 }, + {1200 ,0b0001011 ,460 }, {1250 ,0b0011011 ,460 }, + {1300 ,0b0101011 ,460 }, {1350 ,0b0111100 ,460 }, + {1400 ,0b0001100 ,460 }, {1450 ,0b0011100 ,460 }, + {1500 ,0b0101100 ,460 }, {1550 ,0b0111101 ,285 }, + {1600 ,0b0001101 ,295 }, {1650 ,0b0011101 ,304 }, + {1700 ,0b0101110 ,313 }, {1750 ,0b0111110 ,322 }, + {1800 ,0b0001110 ,331 }, {1850 ,0b0011110 ,341 }, + {1900 ,0b0101111 ,350 }, {1950 ,0b0111111 ,359 }, + {2000 ,0b0001111 ,368 }, {2050 ,0b1000000 ,377 }, + {2100 ,0b1000001 ,387 }, {2150 ,0b1000010 ,396 }, + {2200 ,0b1000011 ,405 }, {2250 ,0b1000100 ,414 }, + {2300 ,0b1000101 ,423 }, {2350 ,0b1000110 ,432 }, + {2400 ,0b1000111 ,442 }, {2450 ,0b1001000 ,451 }, + {2500 ,0b1001001 ,460 } +}; + +/** +* struct dw_dphy - DW D-PHY driver private structure +* +* @regmap: pointer to regmap +* @regmap_cfg1: pointer to config1 regmap +* @regmap_cfg2: pointer to config2 regmap +* @rf_cfg1: array of regfields for config1 +* @rf_cfg2: array of regfields for config2 +* @iomem_cfg1: MMIO address for cfg1 section +* @iomem_cfg2: MMIO address for cfg2 section +* @phy: pointer to the phy data structure +* @hs_clk_rate: high speed clock rate as per image sensor configuration +* @dt_data_dw_dphy: device tree specific data +* +**/ +struct dw_dphy { +struct regmap *regmap_cfg1; +struct regmap *regmap_cfg2; +struct regmap_field *rf_cfg1[DW_DPHY_RF_CFG1_MAX ]; +struct regmap_field *rf_cfg2[DW_DPHY_RF_CFG2_MAX ]; +void __iomem *iomem_cfg1; +void __iomem *iomem_cfg2; +struct phy *phy; +struct device *dev; +unsigned long hs_clk_rate; +struct dt_data_dw_dphy *dt_data; +}; + +/** +* dw_dphy_te_write - write register into test enable interface +* +* @dphy: pointer to the dw_dphy private data structure +* @addr: 12 bit TE address register (16 bit container) +* @data: 8 bit data to be written to TE register +* +**/ +static void dw_dphy_te_write (struct dw_dphy *dphy,u16 addr,u8 data) +{ +/* For writing the 4-bit testcode MSBs */ + +/* Ensure that testclk and testen is set to low */ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],0 ); +regmap_field_write (dphy->rf_cfg1[TEST_EN ],0 ); + +/* Set testen to high */ +regmap_field_write (dphy->rf_cfg1[TEST_EN ],1 ); + +/* Set testclk to high */ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],1 ); + +/* Place 0x00 in testdin */ +regmap_field_write (dphy->rf_cfg1[TEST_IN ],0 ); + +/* +* Set testclk to low (with the falling edge on testclk, the testdin signal +* content is latched internally) +*/ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],0 ); + +/* Set testen to low */ +regmap_field_write (dphy->rf_cfg1[TEST_EN ],0 ); + +/* Place the 8-bit word corresponding to the testcode MSBs in testdin */ +regmap_field_write (dphy->rf_cfg1[TEST_IN ], (addr >>8 )); + +/* Set testclk to high */ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],1 ); + +/* For writing the 8-bit testcode LSBs */ + +/* Set testclk to low */ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],0 ); + +/* Set testen to high */ +regmap_field_write (dphy->rf_cfg1[TEST_EN ],1 ); + +/* Set testclk to high */ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],1 ); + +/* Place the 8-bit word test data in testdin */ +regmap_field_write (dphy->rf_cfg1[TEST_IN ], (addr &0xff )); + +/* +* Set testclk to low (with the falling edge on testclk, the testdin signal +* content is latched internally) +*/ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],0 ); + +/* Set testen to low */ +regmap_field_write (dphy->rf_cfg1[TEST_EN ],0 ); + +/* For writing the data */ + +/* Place the 8-bit word corresponding to the page offset in testdin */ +regmap_field_write (dphy->rf_cfg1[TEST_IN ], data); + +/* Set testclk to high (test data is programmed internally) */ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],1 ); +} + +/** +* dw_dphy_te_read - read register from test enable interface +* +* @dphy: pointer to the dw_dphy private data structure +* @addr: 12 bit TE address register (16 bit container) +* @returns: 8 bit data from TE register +**/ +static u8 dw_dphy_te_read (struct dw_dphy *dphy,u16 addr) +{ +u32 data; + +/* For writing the 4-bit testcode MSBs */ + +/* Ensure that testclk and testen is set to low */ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],0 ); +regmap_field_write (dphy->rf_cfg1[TEST_EN ],0 ); + +/* Set testen to high */ +regmap_field_write (dphy->rf_cfg1[TEST_EN ],1 ); + +/* Set testclk to high */ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],1 ); + +/* Place 0x00 in testdin */ +regmap_field_write (dphy->rf_cfg1[TEST_IN ],0 ); + +/* +* Set testclk to low (with the falling edge on testclk, the testdin signal +* content is latched internally) +*/ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],0 ); + +/* Set testen to low */ +regmap_field_write (dphy->rf_cfg1[TEST_EN ],0 ); + +/* Place the 8-bit word corresponding to the testcode MSBs in testdin */ +regmap_field_write (dphy->rf_cfg1[TEST_IN ], (addr >>8 )); + +/* Set testclk to high */ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],1 ); + +/* For writing the 8-bit testcode LSBs */ + +/* Set testclk to low */ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],0 ); + +/* Set testen to high */ +regmap_field_write (dphy->rf_cfg1[TEST_EN ],1 ); + +/* Set testclk to high */ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],1 ); + +/* Place the 8-bit word test data in testdin */ +regmap_field_write (dphy->rf_cfg1[TEST_IN ], (addr &0xff )); + +/* +* Set testclk to low (with the falling edge on testclk, the testdin signal +* content is latched internally) +*/ +regmap_field_write (dphy->rf_cfg1[TEST_CLK ],0 ); + +/* Set testen to low */ +regmap_field_write (dphy->rf_cfg1[TEST_EN ],0 ); + +regmap_field_read (dphy->rf_cfg1[TEST_OUT ], &data); + +return (u8 )data; +} + +/** +* dw_dphy_configure - configure the D-PHY +* +* @phy: pointer to the phy data structure +* @opts: pointer to the phy configuration options +* @returns 0 if success else appropriate error code +* +**/ +static int dw_dphy_configure (struct phy *phy,union phy_configure_opts *opts) +{ +struct dw_dphy *dphy =phy_get_drvdata (phy); + + dphy->hs_clk_rate = opts->mipi_dphy.hs_clk_rate; +dev_dbg (dphy->dev,"hs_clk_rate=%ld\n" , dphy->hs_clk_rate); + +return 0 ; +} + +/** +* dw_dphy_power_on_1p2 - power on the DPHY version 1.2 +* +* @phy: pointer to the phy data structure +* @returns 0 if success else appropriate error code +* +**/ +static int dw_dphy_power_on_1p2 (struct phy *phy) +{ +struct dw_dphy *dphy =phy_get_drvdata (phy); + +uint8_t counter_for_des_en_config_if_rw =0x1 ; +u8 range =0 ; + +for (range =0 ; + (range < dphy->dt_data->table_size -1 ) && + ((dphy->hs_clk_rate) > dphy->dt_data->table[range].freq); + range++) + ; + +/* in case requested hs_clk_rate is out of range, return -EINVAL */ +if (range >= dphy->dt_data->table_size) +return -EINVAL ; + +dev_dbg (dphy->dev,"12bit: PHY GEN 3: Freq: %ld %x\n" , dphy->hs_clk_rate, + range_gen3[range].hsfregrange); + +regmap_field_write (dphy->rf_cfg1[DPHY_RSTZ ],0 ); +regmap_field_write (dphy->rf_cfg1[PHY_SHUTDOWNZ ],0 ); +regmap_field_write (dphy->rf_cfg1[TEST_CLR ],0 ); +regmap_field_write (dphy->rf_cfg1[TEST_CLR ],1 ); +regmap_field_write (dphy->rf_cfg1[TEST_CLR ],0 ); +regmap_field_write (dphy->rf_cfg2[CFG_CLK_FREQ_RANGE ],0x28 ); +dw_dphy_te_write (dphy,RX_SYS_1 , + dphy->dt_data->table[range].hsfregrange); +dw_dphy_te_write (dphy,RX_SYS_0 ,0x20 ); +dw_dphy_te_write (dphy,RX_RX_STARTUP_OVR_2 , + (u8 )dphy->dt_data->table[range].osc_freq_target); +dw_dphy_te_write (dphy,RX_RX_STARTUP_OVR_3 , + (u8)(dphy->dt_data->table[range].osc_freq_target >> +8 )); +dw_dphy_te_write (dphy,0xe4 , + (counter_for_des_en_config_if_rw <<4 ) |0b1 ); + +dw_dphy_te_write (dphy,RX_RX_STARTUP_OVR_1 ,0x01 ); +dw_dphy_te_write (dphy,RX_RX_STARTUP_OVR_0 ,0x80 ); + +regmap_field_write (dphy->rf_cfg2[BASE_DIR_0 ],1 ); +regmap_field_write (dphy->rf_cfg2[ENABLE_CLK ],1 ); +regmap_field_write (dphy->rf_cfg2[FORCE_RX_MODE ],0x0 ); + +regmap_field_write (dphy->rf_cfg1[PHY_SHUTDOWNZ ],1 ); +regmap_field_write (dphy->rf_cfg1[DPHY_RSTZ ],1 ); + +return 0 ; +} + +/** +* dw_dphy_power_off - power off the DPHY +* +* @phy: pointer to the phy data structure +* @returns 0 if success else appropriate error code +* +**/ +static int dw_dphy_power_off (struct phy *phy) +{ +struct dw_dphy *dphy =phy_get_drvdata (phy); + +regmap_field_write (dphy->rf_cfg1[DPHY_RSTZ ],0 ); +regmap_field_write (dphy->rf_cfg1[PHY_SHUTDOWNZ ],0 ); +return 0 ; +} + +/** +* dw_dphy_ops_1p2 - PHY operations for DWC DPHY v1.2 +* @configure: Configures DPHY timing and operation parameters +* @power_on: Powers on the DPHY using v1.2 specific sequence +* @power_off: Powers off the DPHY +* +**/ +static const struct phy_ops dw_dphy_ops_1p2 = { + .configure = dw_dphy_configure, + .power_on = dw_dphy_power_on_1p2, + .power_off = dw_dphy_power_off, +}; + +/** +* dw_dphy_1p2 - DWC DPHY v1.2 configuration instance +* @table: Points to range_gen3 timing parameters table +* @table_size: Size of range_gen3 table calculated at compile time +* @phy_ops: Points to v1.2 specific PHY operations structure +* +**/ +struct dt_data_dw_dphy dw_dphy_1p2 = { + .table = range_gen3, + .table_size =ARRAY_SIZE (range_gen3), + .phy_ops = &dw_dphy_ops_1p2, +}; + +/** +* dw_dphy_regmap_cfg1 - Register map configuration for DW DPHY +* @reg_bits: Width of register address in bits (32) +* @val_bits: Width of register value in bits (32) +* @reg_stride: Number of bytes between registers (4) +* @name: Name identifier for this register map +* @fast_io: Flag to indicate fast I/O operations are supported +* +**/ +static const struct regmap_config dw_dphy_regmap_cfg1 = { + .reg_bits =32 , + .val_bits =32 , + .reg_stride =4 , + .name ="dw-dhpy-cfg1" , + .fast_io = true, +}; + +/** +* dw_dphy_regmap_cfg2 - Register map configuration for DW DPHY +* @reg_bits: Width of register address in bits (32) +* @val_bits: Width of register value in bits (32) +* @reg_stride: Number of bytes between registers (4) +* @name: Name identifier for this register map +* @fast_io: Flag to indicate fast I/O operations are supported +* +**/ +static const struct regmap_config dw_dphy_regmap_cfg2 = { + .reg_bits =32 , + .val_bits =32 , + .reg_stride =4 , + .name ="dw-dhpy-cfg2" , + .fast_io = true, +}; + +/** +* dw_dphy_probe - Probe and initialize DW DPHY device +* @pdev: Platform device pointer +* Return: 0 on success, negative error code on failure +* +**/ +static int dw_dphy_probe (struct platform_device *pdev) +{ +struct dw_dphy *dphy; +struct resource *res; +struct device *dev = &pdev->dev; +struct phy_provider *phy_provider; +int ret; + + dphy =devm_kzalloc (&pdev->dev,sizeof (*dphy),GFP_KERNEL ); +if (!dphy) +return -ENOMEM ; + + dphy->dt_data = + (struct dt_data_dw_dphy *)of_device_get_match_data (&pdev->dev); +dev_set_drvdata (&pdev->dev, dphy); + dphy->dev = &pdev->dev; + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); + dphy->iomem_cfg1 =devm_ioremap_resource (&pdev->dev, res); +if (IS_ERR (dphy->iomem_cfg1)) +return PTR_ERR (dphy->iomem_cfg1); + + dphy->regmap_cfg1 = +devm_regmap_init_mmio (dev, dphy->iomem_cfg1, &dw_dphy_regmap_cfg1); +if (IS_ERR (dphy->regmap_cfg1)) +return PTR_ERR (dphy->regmap_cfg1); + + ret =devm_regmap_field_bulk_alloc (dev, dphy->regmap_cfg1, dphy->rf_cfg1, + dw_dphy_v1_2_cfg1,DW_DPHY_RF_CFG1_MAX ); +if (ret <0 ) { +dev_err (dev,"Could not alloc RF\n" ); +return ret; + } + + res =platform_get_resource (pdev,IORESOURCE_MEM ,1 ); + dphy->iomem_cfg2 =devm_ioremap_resource (&pdev->dev, res); +if (IS_ERR (dphy->iomem_cfg2)) +return PTR_ERR (dphy->iomem_cfg2); + + dphy->regmap_cfg2 =devm_regmap_init_mmio (dev, dphy->iomem_cfg2, + &dw_dphy_regmap_cfg2); +if (IS_ERR (dphy->regmap_cfg2)) +return PTR_ERR (dphy->regmap_cfg2); + + ret =devm_regmap_field_bulk_alloc (dev, dphy->regmap_cfg2, dphy->rf_cfg2, + dw_dphy_v1_2_cfg2,DW_DPHY_RF_CFG2_MAX ); +if (ret <0 ) { +dev_err (dev,"Could not alloc RF\n" ); +return ret; + } + + dphy->phy =devm_phy_create (&pdev->dev,NULL , dphy->dt_data->phy_ops); +if (IS_ERR (dphy->phy)) { +dev_err (dev,"failed to create PHY\n" ); +return PTR_ERR (dphy->phy); + } + +phy_set_drvdata (dphy->phy, dphy); + phy_provider = +devm_of_phy_provider_register (&pdev->dev, of_phy_simple_xlate); + +return PTR_ERR_OR_ZERO (phy_provider); +} + +/** +* dw_dphy_of_match - Device tree match table for DW DPHY +* @compatible: Compatible string to match device tree node +* @data: Pointer to configuration data for matched device +* +* Table of compatible strings and associated configuration data +* for supported DW DPHY variants. +* Currently supports: +* - DW DPHY v1.2 ("snps,dw-dphy-1p2") +* +**/ +static const struct of_device_id dw_dphy_of_match[] = { + { .compatible ="snps,dw-dphy-1p2" , .data = &dw_dphy_1p2 }, + {/* sentinel */ }, +}; +MODULE_DEVICE_TABLE (of, dw_dphy_of_match); + +/** +* dw_dphy_platform_driver - Platform driver structure for DW DPHY +* @probe: Pointer to probe function called on device discovery +* @driver: Core driver structure containing: +* - name: Driver name used for matching and debugging +* - of_match_table: Table of compatible device tree matches +* +**/ +static struct platform_driver dw_dphy_platform_driver = { + .probe = dw_dphy_probe, + .driver = { + .name ="dw-dphy" , + .of_match_table = dw_dphy_of_match, + }, +}; +module_platform_driver (dw_dphy_platform_driver); + +MODULE_AUTHOR ("Karthik Poduval <[email protected]>" ); +MODULE_AUTHOR ("Jason Xiong <[email protected]>" ); +MODULE_AUTHOR ("Miguel Lopes <[email protected]>" ); +MODULE_DESCRIPTION ("DW D-PHY RX Driver" ); +MODULE_LICENSE ("GPL" ); --2.43.0
Re: [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX
Quoted 6 lines · Frank Li
CAUTION: This email originated from outside of the organization. Do not click links or open attachments unless you can confirm the sender and know the content is safe.
Quoted 8 lines
Quoted 3 lines · Karthik Poduval
Add support for Synopsys DesignWare MIPI D-PHY RX v1.2. The driver supports data rates from 80Mbps to 2500Mbps.
where download spec?
And I think you should cc: [email protected]
Sure.
Quoted 674 lines
In
https://lore.kernel.org/imx/[email protected]/
drivers/media/platform/raspberrypi/rp1-cfe/dphy.cdo similar work.Frank
Quoted 666 lines
Signed-off-by Karthik Poduval <[email protected]>---
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.cdrivers/phy/Kconfig +0
-0@@ -101,6 +101,17 @@ config PHY_NXP_PTN3222schemes. 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 onHAS_IOMEM&®MAP_MMIO
+ selectGENERIC_PHY
+ selectGENERIC_PHY_MIPI_DPHY
+ help
+ This option enables support for Synopsys DW MIPI D-PHY RX IP. This driver
+ provides D-PHY functionality using Generic PHY framework and is meant to
+ be used by MIPI CSI2 receivers over the PPI hardware interface. MIPI CSI2
+ receivers may find this driver and use it via Generic PHY Framework API.
+
source "drivers/phy/allwinner/Kconfig"
source "drivers/phy/amlogic/Kconfig"
source "drivers/phy/broadcom/Kconfig"drivers/phy/Makefile +0
-0@@ -13,6 +13,7 @@ obj-$(CONFIG_PHY_SNPS_EUSB2) +=phy-snps-eusb2.o
obj-$(CONFIG_USB_LGM_PHY) += phy-lgm-usb.o obj-$(CONFIG_PHY_AIROHA_PCIE) += phy-airoha-pcie.o obj-$(CONFIG_PHY_NXP_PTN3222) += phy-nxp-ptn3222.o +obj-$(CONFIG_PHY_SYNOPSYS_DW_DPHY_RX) += phy-dw-dphy.o obj-y += allwinner/ \
amlogic/ \
broadcom/ \drivers/phy/phy-dw-dphy.c new file +47
-0@@ -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_fielddw_dphy_v1_2_cfg1[DW_DPHY_RF_CFG1_MAX] = {
+ [PHY_SHUTDOWNZ] =REG_FIELD(0x0, 0, 0),
+ [DPHY_RSTZ] =REG_FIELD(0x4, 0, 0),
+ [TEST_CLR] =REG_FIELD(0x10, 0, 0),
+ [TEST_CLK] =REG_FIELD(0x10, 1, 1),
+ [TEST_IN] =REG_FIELD(0x14, 0, 7),
+ [TEST_OUT] =REG_FIELD(0x14, 8, 15),
+ [TEST_EN] =REG_FIELD(0x14, 16, 16),drivers/phy/phy-dw-dphy.c new file +3
-0+}; + +static const struct reg_fielddw_dphy_v1_2_cfg2[DW_DPHY_RF_CFG2_MAX] = {
+ [EN_CONT_REG_UPDATE] =REG_FIELD(0x0, 23, 23), + [TURN_REQUEST_0] =REG_FIELD(0x0, 22, 22), + [TURN_DISABLE_0] =REG_FIELD(0x0, 21, 21), + [ENABLE_CLK] =REG_FIELD(0x0, 20, 20), + [FORCE_TX_STOP_MODE_0] =REG_FIELD(0x0, 19, 19), + [FORCE_RX_MODE] =REG_FIELD(0x0, 15, 18), + [BASE_DIR_0] =REG_FIELD(0x0, 14, 14), + [CFG_CLK_FREQ_RANGE] =REG_FIELD(0x0, 8, 13), + [HS_FREQ_RANGE] =REG_FIELD(0x0, 1, 7), + [CONT_EN] =REG_FIELD(0x0, 0, 0),drivers/phy/phy-dw-dphy.c new file +30
-0+}; + +enum dphy_12bit_interface_addr { + RX_SYS_0 = 0x01, + RX_SYS_1 = 0x02, + RX_SYS_7 = 0x08, + RX_RX_STARTUP_OVR_0 = 0xe0, + RX_RX_STARTUP_OVR_1 = 0xe1, + RX_RX_STARTUP_OVR_2 = 0xe2, + RX_RX_STARTUP_OVR_3 = 0xe3, + RX_RX_STARTUP_OVR_4 = 0xe4, +}; + +/** +* struct range_dphy_gen3 - frequency range calibration structure +* +* @freq: input freqency to calibration table +* @hsfregrange: corresponding clock to configure DW D-PHY IP +* @osc_freq_target: corresponding clock to configure DW D-PHY IP +* +**/ +struct range_dphy_gen3 { + u32 freq; + u8 hsfregrange; + u32 osc_freq_target; +}; + +/** +* struct dt_data_dw_dphy - DPHY configuration data structure +* @table: Pointer to array of DPHY Gen3 timing range configurations
+ * @table_size: Number of entries in the timing range table
+ * @phy_ops: Pointer to PHY operations structure containing callback functions
+ *
+ **/drivers/phy/phy-dw-dphy.c new file +57
-0+struct dt_data_dw_dphy { + struct range_dphy_gen3 *table; + int table_size; + const struct phy_ops *phy_ops; +}; + +/* +* DW DPHY Gen3 calibration table +* +*/ +struct range_dphy_gen3 range_gen3[] = { + { 80, 0b0000000, 460 }, { 90, 0b0010000, 460 }, + { 100, 0b0100000, 460 }, { 110, 0b0110000, 460 }, + { 120, 0b0000001, 460 }, { 130, 0b0010001, 460 }, + { 140, 0b0100001, 460 }, { 150, 0b0110001, 460 }, + { 160, 0b0000010, 460 }, { 170, 0b0010010, 460 }, + { 180, 0b0100010, 460 }, { 190, 0b0110010, 460 }, + { 205, 0b0000011, 460 }, { 220, 0b0010011, 460 }, + { 235, 0b0100011, 460 }, { 250, 0b0110011, 460 }, + { 275, 0b0000100, 460 }, { 300, 0b0010100, 460 }, + { 325, 0b0100101, 460 }, { 350, 0b0110101, 460 }, + { 400, 0b0000101, 460 }, { 450, 0b0010110, 460 }, + { 500, 0b0100110, 460 }, { 550, 0b0110111, 460 }, + { 600, 0b0000111, 460 }, { 650, 0b0011000, 460 }, + { 700, 0b0101000, 460 }, { 750, 0b0111001, 460 }, + { 800, 0b0001001, 460 }, { 850, 0b0011001, 460 }, + { 900, 0b0101001, 460 }, { 950, 0b0111010, 460 }, + { 1000, 0b0001010, 460 }, { 1050, 0b0011010, 460 }, + { 1110, 0b0101010, 460 }, { 1150, 0b0111011, 460 }, + { 1200, 0b0001011, 460 }, { 1250, 0b0011011, 460 }, + { 1300, 0b0101011, 460 }, { 1350, 0b0111100, 460 }, + { 1400, 0b0001100, 460 }, { 1450, 0b0011100, 460 }, + { 1500, 0b0101100, 460 }, { 1550, 0b0111101, 285 }, + { 1600, 0b0001101, 295 }, { 1650, 0b0011101, 304 }, + { 1700, 0b0101110, 313 }, { 1750, 0b0111110, 322 }, + { 1800, 0b0001110, 331 }, { 1850, 0b0011110, 341 }, + { 1900, 0b0101111, 350 }, { 1950, 0b0111111, 359 }, + { 2000, 0b0001111, 368 }, { 2050, 0b1000000, 377 }, + { 2100, 0b1000001, 387 }, { 2150, 0b1000010, 396 }, + { 2200, 0b1000011, 405 }, { 2250, 0b1000100, 414 }, + { 2300, 0b1000101, 423 }, { 2350, 0b1000110, 432 }, + { 2400, 0b1000111, 442 }, { 2450, 0b1001000, 451 }, + { 2500, 0b1001001, 460 } +}; + +/** +* struct dw_dphy - DW D-PHY driver private structure +* +* @regmap: pointer to regmap +* @regmap_cfg1: pointer to config1 regmap +* @regmap_cfg2: pointer to config2 regmap +* @rf_cfg1: array of regfields for config1 +* @rf_cfg2: array of regfields for config2 +* @iomem_cfg1: MMIO address for cfg1 section +* @iomem_cfg2: MMIO address for cfg2 section +* @phy: pointer to the phy data structure +* @hs_clk_rate: high speed clock rate as per image sensor configuration
+ * @dt_data_dw_dphy: device tree specific data
+ *
+ **/drivers/phy/phy-dw-dphy.c new file +22
-0+struct dw_dphy { + struct regmap *regmap_cfg1; + struct regmap *regmap_cfg2; + struct regmap_field *rf_cfg1[DW_DPHY_RF_CFG1_MAX]; + struct regmap_field *rf_cfg2[DW_DPHY_RF_CFG2_MAX]; + void __iomem *iomem_cfg1; + void __iomem *iomem_cfg2; + struct phy *phy; + struct device *dev; + unsigned long hs_clk_rate; + struct dt_data_dw_dphy *dt_data; +}; + +/** +* dw_dphy_te_write - write register into test enable interface +* +* @dphy: pointer to the dw_dphy private data structure +* @addr: 12 bit TE address register (16 bit container) +* @data: 8 bit data to be written to TE register +* +**/ +static void dw_dphy_te_write(struct dw_dphy *dphy, u16 addr, u8data)
drivers/phy/phy-dw-dphy.c new file +18
-0+{ + /* For writing the 4-bit testcode MSBs */ + + /* Ensure that testclk and testen is set to low */ + regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0); + regmap_field_write(dphy->rf_cfg1[TEST_EN], 0); + + /* Set testen to high */ + regmap_field_write(dphy->rf_cfg1[TEST_EN], 1); + + /* Set testclk to high */ + regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1); + + /* Place 0x00 in testdin */ + regmap_field_write(dphy->rf_cfg1[TEST_IN], 0); + + /* +* Set testclk to low (with the falling edge on testclk, the testdin signal
+ * content is latched internally)
+ */
+regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);drivers/phy/phy-dw-dphy.c new file +5
-0+ + /* Set testen to low */ + regmap_field_write(dphy->rf_cfg1[TEST_EN], 0); + + /* Place the 8-bit word corresponding to the testcode MSBs intestdin */
+regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr >> 8));drivers/phy/phy-dw-dphy.c new file +20
-0+ + /* Set testclk to high */ + regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1); + + /* For writing the 8-bit testcode LSBs */ + + /* Set testclk to low */ + regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0); + + /* Set testen to high */ + regmap_field_write(dphy->rf_cfg1[TEST_EN], 1); + + /* Set testclk to high */ + regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1); + + /* Place the 8-bit word test data in testdin */ + regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr & 0xff)); + + /* +* Set testclk to low (with the falling edge on testclk, the testdin signal
+ * content is latched internally)
+ */
+regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);drivers/phy/phy-dw-dphy.c new file +7
-0+ + /* Set testen to low */ + regmap_field_write(dphy->rf_cfg1[TEST_EN], 0); + + /* For writing the data */ + + /* Place the 8-bit word corresponding to the page offset intestdin */
+regmap_field_write(dphy->rf_cfg1[TEST_IN], data); +
+ /* Set testclk to high (test data is programmed internally) */
+regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);drivers/phy/phy-dw-dphy.c new file +30
-0+} + +/** +* dw_dphy_te_read - read register from test enable interface +* +* @dphy: pointer to the dw_dphy private data structure +* @addr: 12 bit TE address register (16 bit container) +* @returns: 8 bit data from TE register +**/ +static u8 dw_dphy_te_read (struct dw_dphy *dphy,u16 addr) +{ + u32 data; + + /* For writing the 4-bit testcode MSBs */ + + /* Ensure that testclk and testen is set to low */ + regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0); + regmap_field_write(dphy->rf_cfg1[TEST_EN], 0); + + /* Set testen to high */ + regmap_field_write(dphy->rf_cfg1[TEST_EN], 1); + + /* Set testclk to high */ + regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1); + + /* Place 0x00 in testdin */ + regmap_field_write(dphy->rf_cfg1[TEST_IN], 0); + + /* +* Set testclk to low (with the falling edge on testclk, the testdin signal
+ * content is latched internally)
+ */
+regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);drivers/phy/phy-dw-dphy.c new file +5
-0+ + /* Set testen to low */ + regmap_field_write(dphy->rf_cfg1[TEST_EN], 0); + + /* Place the 8-bit word corresponding to the testcode MSBs intestdin */
+regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr >> 8));drivers/phy/phy-dw-dphy.c new file +20
-0+ + /* Set testclk to high */ + regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1); + + /* For writing the 8-bit testcode LSBs */ + + /* Set testclk to low */ + regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0); + + /* Set testen to high */ + regmap_field_write(dphy->rf_cfg1[TEST_EN], 1); + + /* Set testclk to high */ + regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1); + + /* Place the 8-bit word test data in testdin */ + regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr & 0xff)); + + /* +* Set testclk to low (with the falling edge on testclk, the testdin signal
+ * content is latched internally)
+ */
+regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);drivers/phy/phy-dw-dphy.c new file +18
-0+ + /* Set testen to low */ + regmap_field_write(dphy->rf_cfg1[TEST_EN], 0); + + regmap_field_read(dphy->rf_cfg1[TEST_OUT], &data); + + return (u8)data; +} + +/** +* dw_dphy_configure - configure the D-PHY +* +* @phy: pointer to the phy data structure +* @opts: pointer to the phy configuration options +* @returns 0 if success else appropriate error code +* +**/ +static int dw_dphy_configure(struct phy *phy, union
phy_configure_opts*opts)drivers/phy/phy-dw-dphy.c new file +26
-0+{ + struct dw_dphy *dphy = phy_get_drvdata(phy); + + dphy->hs_clk_rate = opts->mipi_dphy.hs_clk_rate; + dev_dbg(dphy->dev, "hs_clk_rate=%ld\n", dphy->hs_clk_rate); + + return 0; +} + +/** +* dw_dphy_power_on_1p2 - power on the DPHY version 1.2 +* +* @phy: pointer to the phy data structure +* @returns 0 if success else appropriate error code +* +**/ +static int dw_dphy_power_on_1p2(struct phy *phy) +{ + struct dw_dphy *dphy = phy_get_drvdata(phy); + + uint8_t counter_for_des_en_config_if_rw = 0x1; + u8 range = 0; + + for (range = 0; + (range < dphy->dt_data->table_size - 1) && + ((dphy->hs_clk_rate) > dphy->dt_data-Quoted 1 line
table[range].freq);
+ range++)
+ ;
+
+ /* in case requestedhs_clk_rateis out of range, return - EINVAL */
+ if (range >=dphy->dt_data->table_size)
+ return-EINVAL;
+
+ dev_dbg(dphy->dev, "12bit: PHY GEN 3: Freq: %ld %x\n", dphy-Quoted 1 line
hs_clk_rate,+ range_gen3[range].hsfregrange);
+
+regmap_field_write(dphy->rf_cfg1[DPHY_RSTZ], 0); +regmap_field_write(dphy->rf_cfg1[PHY_SHUTDOWNZ], 0); +regmap_field_write(dphy->rf_cfg1[TEST_CLR], 0);
+regmap_field_write(dphy->rf_cfg1[TEST_CLR], 1);
+regmap_field_write(dphy->rf_cfg1[TEST_CLR], 0);
+regmap_field_write(dphy->rf_cfg2[CFG_CLK_FREQ_RANGE], 0x28); + dw_dphy_te_write(dphy,RX_SYS_1,
+ dphy->dt_data->table[range].hsfregrange); +dw_dphy_te_write(dphy, RX_SYS_0, 0x20);
+ dw_dphy_te_write(dphy,RX_RX_STARTUP_OVR_2,
+ (u8)dphy->dt_data-Quoted 1 line
table[range].osc_freq_target);
+ dw_dphy_te_write(dphy,
RX_RX_STARTUP_OVR_3,
+ (u8)(dphy->dt_data-Quoted 1 line
table[range].osc_freq_target >>
+ 8));
+ dw_dphy_te_write(dphy,0xe4,
+ (counter_for_des_en_config_if_rw<< 4) | 0b1);drivers/phy/phy-dw-dphy.c new file +47
-0+ + dw_dphy_te_write(dphy, RX_RX_STARTUP_OVR_1, 0x01); + dw_dphy_te_write(dphy, RX_RX_STARTUP_OVR_0, 0x80); + + regmap_field_write(dphy->rf_cfg2[BASE_DIR_0], 1); + regmap_field_write(dphy->rf_cfg2[ENABLE_CLK], 1); + regmap_field_write(dphy->rf_cfg2[FORCE_RX_MODE], 0x0); + + regmap_field_write(dphy->rf_cfg1[PHY_SHUTDOWNZ], 1); + regmap_field_write(dphy->rf_cfg1[DPHY_RSTZ], 1); + + return 0; +} + +/** +* dw_dphy_power_off - power off the DPHY +* +* @phy: pointer to the phy data structure +* @returns 0 if success else appropriate error code +* +**/ +static int dw_dphy_power_off (struct phy *phy) +{ + struct dw_dphy *dphy = phy_get_drvdata(phy); + + regmap_field_write(dphy->rf_cfg1[DPHY_RSTZ], 0); + regmap_field_write(dphy->rf_cfg1[PHY_SHUTDOWNZ], 0); + return 0; +} + +/** +* dw_dphy_ops_1p2 - PHY operations for DWC DPHY v1.2 +* @configure: Configures DPHY timing and operation parameters +* @power_on: Powers on the DPHY using v1.2 specific sequence +* @power_off: Powers off the DPHY +* +**/ +static const struct phy_ops dw_dphy_ops_1p2 = { + .configure = dw_dphy_configure, + .power_on = dw_dphy_power_on_1p2, + .power_off = dw_dphy_power_off, +}; + +/** +* dw_dphy_1p2 - DWC DPHY v1.2 configuration instance +* @table: Points to range_gen3 timing parameters table +* @table_size: Size of range_gen3 table calculated at compile time
+ * @phy_ops: Points to v1.2 specific PHY operations structure
+ *
+ **/drivers/phy/phy-dw-dphy.c new file +60
-0+struct dt_data_dw_dphy dw_dphy_1p2 = { + .table = range_gen3, + .table_size = ARRAY_SIZE(range_gen3), + .phy_ops = &dw_dphy_ops_1p2, +}; + +/** +* dw_dphy_regmap_cfg1 - Register map configuration for DW DPHY +* @reg_bits: Width of register address in bits (32) +* @val_bits: Width of register value in bits (32) +* @reg_stride: Number of bytes between registers (4) +* @name: Name identifier for this register map +* @fast_io: Flag to indicate fast I/O operations are supported +* +**/ +static const struct regmap_config dw_dphy_regmap_cfg1 = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .name = "dw-dhpy-cfg1", + .fast_io = true, +}; + +/** +* dw_dphy_regmap_cfg2 - Register map configuration for DW DPHY +* @reg_bits: Width of register address in bits (32) +* @val_bits: Width of register value in bits (32) +* @reg_stride: Number of bytes between registers (4) +* @name: Name identifier for this register map +* @fast_io: Flag to indicate fast I/O operations are supported +* +**/ +static const struct regmap_config dw_dphy_regmap_cfg2 = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .name = "dw-dhpy-cfg2", + .fast_io = true, +}; + +/** +* dw_dphy_probe - Probe and initialize DW DPHY device +* @pdev: Platform device pointer +* Return: 0 on success, negative error code on failure +* +**/ +static int dw_dphy_probe (struct platform_device *pdev) +{ + struct dw_dphy *dphy; + struct resource *res; + struct device *dev = &pdev->dev; + struct phy_provider *phy_provider; + int ret; + + dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL); + if (!dphy) + return -ENOMEM; + + dphy->dt_data = + (struct dt_data_dw_dphy*)of_device_get_match_data(&pdev->dev);
+dev_set_drvdata(&pdev->dev, dphy);
+dphy->dev=&pdev->dev;drivers/phy/phy-dw-dphy.c new file +8
-0+ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + dphy->iomem_cfg1 = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(dphy->iomem_cfg1)) + return PTR_ERR(dphy->iomem_cfg1); + + dphy->regmap_cfg1 = + devm_regmap_init_mmio(dev, dphy->iomem_cfg1,
&dw_dphy_regmap_cfg1);
+ if (IS_ERR(dphy->regmap_cfg1))
+ returnPTR_ERR(dphy->regmap_cfg1);
+
+ ret = devm_regmap_field_bulk_alloc(dev,dphy->regmap_cfg1,dphy->rf_cfg1,
+dw_dphy_v1_2_cfg1,DW_DPHY_RF_CFG1_MAX);
+ if (ret < 0) {
+dev_err(dev, "Could not alloc RF\n");
+ return ret;
+ }drivers/phy/phy-dw-dphy.c new file +7
-0+ + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + dphy->iomem_cfg2 = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(dphy->iomem_cfg2)) + return PTR_ERR(dphy->iomem_cfg2); + + dphy->regmap_cfg2 = devm_regmap_init_mmio(dev, dphy-Quoted 1 line
iomem_cfg2,+
&dw_dphy_regmap_cfg2);
+ if (IS_ERR(dphy->regmap_cfg2))
+ returnPTR_ERR(dphy->regmap_cfg2);
+
+ ret = devm_regmap_field_bulk_alloc(dev,dphy->regmap_cfg2,dphy->rf_cfg2,
+dw_dphy_v1_2_cfg2,DW_DPHY_RF_CFG2_MAX);
+ if (ret < 0) {
+dev_err(dev, "Could not alloc RF\n");
+ return ret;
+ }
+
+dphy->phy= devm_phy_create(&pdev->dev, NULL, dphy->dt_data-Quoted 1 line
phy_ops);+ if (
IS_ERR(dphy->phy)) {
+dev_err(dev, "failed to create PHY\n"); + returnPTR_ERR(dphy->phy);
+ }
+
+phy_set_drvdata(dphy->phy, dphy);
+phy_provider=
+devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);drivers/phy/phy-dw-dphy.c new file +27
-0+ + return PTR_ERR_OR_ZERO(phy_provider); +} + +/** +* dw_dphy_of_match - Device tree match table for DW DPHY +* @compatible: Compatible string to match device tree node +* @data: Pointer to configuration data for matched device +* +* Table of compatible strings and associated configuration data +* for supported DW DPHY variants. +* Currently supports: +* - DW DPHY v1.2 ("snps,dw-dphy-1p2") +* +**/ +static const struct of_device_id dw_dphy_of_match[] = { + { .compatible = "snps,dw-dphy-1p2", .data = &dw_dphy_1p2 }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE (of, dw_dphy_of_match); + +/** +* dw_dphy_platform_driver - Platform driver structure for DW DPHY +* @probe: Pointer to probe function called on device discovery +* @driver: Core driver structure containing: +* - name: Driver name used for matching and debugging +* - of_match_table: Table of compatible device tree matches
+ *
+ **/drivers/phy/phy-dw-dphy.c new file +14
-1+static struct platform_driver dw_dphy_platform_driver = { + .probe = dw_dphy_probe, + .driver = { + .name = "dw-dphy", + .of_match_table = dw_dphy_of_match, + }, +}; +module_platform_driver (dw_dphy_platform_driver); + +MODULE_AUTHOR ("Karthik Poduval <[email protected]>" ); +MODULE_AUTHOR ("Jason Xiong <[email protected]>" ); +MODULE_AUTHOR ("Miguel Lopes <[email protected]>" ); +MODULE_DESCRIPTION ("DW D-PHY RX Driver" ); +MODULE_LICENSE ("GPL" ); --2.43.0
Re: [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX
In reply to Karthik PoduvalQuoted 7 lines · Karthik Poduval
drivers/phy/phy-dw-dphy.c new file +7
-0+static const struct regmap_config dw_dphy_regmap_cfg1 = { + .reg_bits =32 , + .val_bits =32 , + .reg_stride =4 , + .name ="dw-dhpy-cfg1" , + .fast_io = true, +};
drivers/phy/phy-dw-dphy.c line 458
Quoted 10 lines
drivers/phy/phy-dw-dphy.c new file +10
-0+ +/** +* dw_dphy_regmap_cfg2 - Register map configuration for DW DPHY +* @reg_bits: Width of register address in bits (32) +* @val_bits: Width of register value in bits (32) +* @reg_stride: Number of bytes between registers (4) +* @name: Name identifier for this register map +* @fast_io: Flag to indicate fast I/O operations are supported +* +**/
Drop
Quoted 4 lines
drivers/phy/phy-dw-dphy.c new file +4
-0+static const struct regmap_config dw_dphy_regmap_cfg2 = { + .reg_bits =32 , + .val_bits =32 , + .reg_stride =4 ,
drivers/phy/phy-dw-dphy.c line 472
Quoted 10 lines
drivers/phy/phy-dw-dphy.c new file +10
-0+ .name = "dw-dhpy-cfg2", + .fast_io = true, +}; + +/** +* dw_dphy_probe - Probe and initialize DW DPHY device +* @pdev: Platform device pointer +* Return: 0 on success, negative error code on failure +* +**/
Drop
Quoted 65 lines
drivers/phy/phy-dw-dphy.c new file +65
-0+static int dw_dphy_probe (struct platform_device *pdev) +{ +struct dw_dphy *dphy; +struct resource *res; +struct device *dev = &pdev->dev; +struct phy_provider *phy_provider; +int ret; + + dphy =devm_kzalloc (&pdev->dev,sizeof (*dphy),GFP_KERNEL ); +if (!dphy) +return -ENOMEM ; + + dphy->dt_data = + (struct dt_data_dw_dphy *)of_device_get_match_data (&pdev->dev); +dev_set_drvdata (&pdev->dev, dphy); + dphy->dev = &pdev->dev; + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); + dphy->iomem_cfg1 =devm_ioremap_resource (&pdev->dev, res); +if (IS_ERR (dphy->iomem_cfg1)) +return PTR_ERR (dphy->iomem_cfg1); + + dphy->regmap_cfg1 = +devm_regmap_init_mmio (dev, dphy->iomem_cfg1, &dw_dphy_regmap_cfg1); +if (IS_ERR (dphy->regmap_cfg1)) +return PTR_ERR (dphy->regmap_cfg1); + + ret =devm_regmap_field_bulk_alloc (dev, dphy->regmap_cfg1, dphy->rf_cfg1, + dw_dphy_v1_2_cfg1,DW_DPHY_RF_CFG1_MAX ); +if (ret <0 ) { +dev_err (dev,"Could not alloc RF\n" ); +return ret; + } + + res =platform_get_resource (pdev,IORESOURCE_MEM ,1 ); + dphy->iomem_cfg2 =devm_ioremap_resource (&pdev->dev, res); +if (IS_ERR (dphy->iomem_cfg2)) +return PTR_ERR (dphy->iomem_cfg2); + + dphy->regmap_cfg2 =devm_regmap_init_mmio (dev, dphy->iomem_cfg2, + &dw_dphy_regmap_cfg2); +if (IS_ERR (dphy->regmap_cfg2)) +return PTR_ERR (dphy->regmap_cfg2); + + ret =devm_regmap_field_bulk_alloc (dev, dphy->regmap_cfg2, dphy->rf_cfg2, + dw_dphy_v1_2_cfg2,DW_DPHY_RF_CFG2_MAX ); +if (ret <0 ) { +dev_err (dev,"Could not alloc RF\n" ); +return ret; + } + + dphy->phy =devm_phy_create (&pdev->dev,NULL , dphy->dt_data->phy_ops); +if (IS_ERR (dphy->phy)) { +dev_err (dev,"failed to create PHY\n" ); +return PTR_ERR (dphy->phy); + } + +phy_set_drvdata (dphy->phy, dphy); + phy_provider = +devm_of_phy_provider_register (&pdev->dev, of_phy_simple_xlate); + +return PTR_ERR_OR_ZERO (phy_provider); +} + +/**
drivers/phy/phy-dw-dphy.c line 547
Quoted 10 lines
drivers/phy/phy-dw-dphy.c new file +10
-0+* dw_dphy_of_match - Device tree match table for DW DPHY +* @compatible: Compatible string to match device tree node +* @data: Pointer to configuration data for matched device +* +* Table of compatible strings and associated configuration data +* for supported DW DPHY variants. +* Currently supports: +* - DW DPHY v1.2 ("snps,dw-dphy-1p2") +* +**/
Drop
Quoted 4 lines
drivers/phy/phy-dw-dphy.c new file +4
-0+static const struct of_device_id dw_dphy_of_match[] = { + { .compatible ="snps,dw-dphy-1p2" , .data = &dw_dphy_1p2 }, + {/* sentinel */ }, +};
drivers/phy/phy-dw-dphy.c line 561
Quoted 10 lines
drivers/phy/phy-dw-dphy.c new file +10
-0+MODULE_DEVICE_TABLE (of, dw_dphy_of_match); + +/** +* dw_dphy_platform_driver - Platform driver structure for DW DPHY +* @probe: Pointer to probe function called on device discovery +* @driver: Core driver structure containing: +* - name: Driver name used for matching and debugging +* - of_match_table: Table of compatible device tree matches +* +**/
Drop all such useless generic kerneldocs. Not helpful. Keep useful ones, so ones not saying obvious parts of core
drivers/phy/phy-dw-dphy.c line 563
Quoted 2 lines
drivers/phy/phy-dw-dphy.c new file +2
-0+static struct platform_driver dw_dphy_platform_driver = { + .probe = dw_dphy_probe,
Best regards,
Krzysztof
kernel test robot
build botRe: [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX
In reply to Karthik Poduvalkernel test robot noticed the following build warnings:
Hi Karthik,
kernel test robot noticed the following build warnings:
[auto build test WARNING on robh/for-next]
[also build test WARNING on linus/master v6.16-rc5 next-20250710] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Karthik-Poduval/phy-dw-dphy-rx-Add-Synopsys-DesignWare-D-PHY-RX/20250710-104505 base: https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next patch link: https://lore.kernel.org/r/2383f8cf2a8f5e1b914d4cf9bd11674ed55876d2.1752106239.git.kpoduval%40lab126.com patch subject: [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX config: x86_64-randconfig-002-20250711 (https://download.01.org/0day-ci/archive/20250711/[email protected]/config) compiler: gcc-12 (Debian 12.2.0-14+deb12u1) 12.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250711/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All warnings (new ones prefixed by >>):
>> drivers/phy/phy-dw-dphy.c:254:11: warning: 'dw_dphy_te_read' defined but not used [-Wunused-function]
254 | static u8 dw_dphy_te_read(struct dw_dphy *dphy, u16 addr)
| ^~~~~~~~~~~~~~~
--
>> Warning: drivers/phy/phy-dw-dphy.c:172 struct member 'dev' not described in 'dw_dphy'
>> Warning: drivers/phy/phy-dw-dphy.c:172 struct member 'dt_data' not described in 'dw_dphy'
>> Warning: drivers/phy/phy-dw-dphy.c:172 Excess struct member 'regmap' description in 'dw_dphy'
>> Warning: drivers/phy/phy-dw-dphy.c:172 Excess struct member 'dt_data_dw_dphy' description in 'dw_dphy'vim +/dw_dphy_te_read +254 drivers/phy/phy-dw-dphy.c
146
147 /**
148 * struct dw_dphy - DW D-PHY driver private structure
149 *
150 * @regmap: pointer to regmap
151 * @regmap_cfg1: pointer to config1 regmap
152 * @regmap_cfg2: pointer to config2 regmap
153 * @rf_cfg1: array of regfields for config1
154 * @rf_cfg2: array of regfields for config2
155 * @iomem_cfg1: MMIO address for cfg1 section
156 * @iomem_cfg2: MMIO address for cfg2 section
157 * @phy: pointer to the phy data structure
158 * @hs_clk_rate: high speed clock rate as per image sensor configuration
159 * @dt_data_dw_dphy: device tree specific data
160 *
161 **/
162 struct dw_dphy {
163 struct regmap *regmap_cfg1;
164 struct regmap *regmap_cfg2;
165 struct regmap_field *rf_cfg1[DW_DPHY_RF_CFG1_MAX];
166 struct regmap_field *rf_cfg2[DW_DPHY_RF_CFG2_MAX];
167 void __iomem *iomem_cfg1;
168 void __iomem *iomem_cfg2;
169 struct phy *phy;
170 struct device *dev;
171 unsigned long hs_clk_rate;
> 172 struct dt_data_dw_dphy *dt_data;
173 };
174
175 /**
176 * dw_dphy_te_write - write register into test enable interface
177 *
178 * @dphy: pointer to the dw_dphy private data structure
179 * @addr: 12 bit TE address register (16 bit container)
180 * @data: 8 bit data to be written to TE register
181 *
182 **/
183 static void dw_dphy_te_write(struct dw_dphy *dphy, u16 addr, u8 data)
184 {
185 /* For writing the 4-bit testcode MSBs */
186
187 /* Ensure that testclk and testen is set to low */
188 regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
189 regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
190
191 /* Set testen to high */
192 regmap_field_write(dphy->rf_cfg1[TEST_EN], 1);
193
194 /* Set testclk to high */
195 regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
196
197 /* Place 0x00 in testdin */
198 regmap_field_write(dphy->rf_cfg1[TEST_IN], 0);
199
200 /*
201 * Set testclk to low (with the falling edge on testclk, the testdin signal
202 * content is latched internally)
203 */
204 regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
205
206 /* Set testen to low */
207 regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
208
209 /* Place the 8-bit word corresponding to the testcode MSBs in testdin */
210 regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr >> 8));
211
212 /* Set testclk to high */
213 regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
214
215 /* For writing the 8-bit testcode LSBs */
216
217 /* Set testclk to low */
218 regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
219
220 /* Set testen to high */
221 regmap_field_write(dphy->rf_cfg1[TEST_EN], 1);
222
223 /* Set testclk to high */
224 regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
225
226 /* Place the 8-bit word test data in testdin */
227 regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr & 0xff));
228
229 /*
230 * Set testclk to low (with the falling edge on testclk, the testdin signal
231 * content is latched internally)
232 */
233 regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
234
235 /* Set testen to low */
236 regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
237
238 /* For writing the data */
239
240 /* Place the 8-bit word corresponding to the page offset in testdin */
241 regmap_field_write(dphy->rf_cfg1[TEST_IN], data);
242
243 /* Set testclk to high (test data is programmed internally) */
244 regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
245 }
246
247 /**
248 * dw_dphy_te_read - read register from test enable interface
249 *
250 * @dphy: pointer to the dw_dphy private data structure
251 * @addr: 12 bit TE address register (16 bit container)
252 * @returns: 8 bit data from TE register
253 **/
> 254 static u8 dw_dphy_te_read(struct dw_dphy *dphy, u16 addr) 255 {
256 u32 data;
257
258 /* For writing the 4-bit testcode MSBs */
259
260 /* Ensure that testclk and testen is set to low */
261 regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
262 regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
263
264 /* Set testen to high */
265 regmap_field_write(dphy->rf_cfg1[TEST_EN], 1);
266
267 /* Set testclk to high */
268 regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
269
270 /* Place 0x00 in testdin */
271 regmap_field_write(dphy->rf_cfg1[TEST_IN], 0);
272
273 /*
274 * Set testclk to low (with the falling edge on testclk, the testdin signal
275 * content is latched internally)
276 */
277 regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
278
279 /* Set testen to low */
280 regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
281
282 /* Place the 8-bit word corresponding to the testcode MSBs in testdin */
283 regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr >> 8));
284
285 /* Set testclk to high */
286 regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
287
288 /* For writing the 8-bit testcode LSBs */
289
290 /* Set testclk to low */
291 regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
292
293 /* Set testen to high */
294 regmap_field_write(dphy->rf_cfg1[TEST_EN], 1);
295
296 /* Set testclk to high */
297 regmap_field_write(dphy->rf_cfg1[TEST_CLK], 1);
298
299 /* Place the 8-bit word test data in testdin */
300 regmap_field_write(dphy->rf_cfg1[TEST_IN], (addr & 0xff));
301
302 /*
303 * Set testclk to low (with the falling edge on testclk, the testdin signal
304 * content is latched internally)
305 */
306 regmap_field_write(dphy->rf_cfg1[TEST_CLK], 0);
307
308 /* Set testen to low */
309 regmap_field_write(dphy->rf_cfg1[TEST_EN], 0);
310
311 regmap_field_read(dphy->rf_cfg1[TEST_OUT], &data);
312
313 return (u8)data;
314 }
315
Signature · 2 lines
0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
kernel test robot
build botRe: [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX
In reply to Karthik Poduvalkernel test robot noticed the following build warnings:
Hi Karthik,
kernel test robot noticed the following build warnings:
[auto build test WARNING on robh/for-next]
[also build test WARNING on linus/master v6.16-rc5 next-20250710] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Karthik-Poduval/phy-dw-dphy-rx-Add-Synopsys-DesignWare-D-PHY-RX/20250710-104505 base: https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next patch link: https://lore.kernel.org/r/2383f8cf2a8f5e1b914d4cf9bd11674ed55876d2.1752106239.git.kpoduval%40lab126.com patch subject: [PATCH v2 1/2] phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX config: sparc-randconfig-r123-20250711 (https://download.01.org/0day-ci/archive/20250711/[email protected]/config) compiler: sparc-linux-gcc (GCC) 12.4.0 reproduce: (https://download.01.org/0day-ci/archive/20250711/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
sparse warnings: (new ones prefixed by >>)
>> drivers/phy/phy-dw-dphy.c:112:24: sparse: sparse: symbol 'range_gen3' was not declared. Should it be static? >> drivers/phy/phy-dw-dphy.c:427:24: sparse: sparse: symbol 'dw_dphy_1p2' was not declared. Should it be static?
vim +/range_gen3 +112 drivers/phy/phy-dw-dphy.c
107
108 /*
109 * DW DPHY Gen3 calibration table
110 *
111 */
> 112 struct range_dphy_gen3 range_gen3[] = {
113 { 80, 0b0000000, 460 }, { 90, 0b0010000, 460 },
114 { 100, 0b0100000, 460 }, { 110, 0b0110000, 460 },
115 { 120, 0b0000001, 460 }, { 130, 0b0010001, 460 },
116 { 140, 0b0100001, 460 }, { 150, 0b0110001, 460 },
117 { 160, 0b0000010, 460 }, { 170, 0b0010010, 460 },
118 { 180, 0b0100010, 460 }, { 190, 0b0110010, 460 },
119 { 205, 0b0000011, 460 }, { 220, 0b0010011, 460 },
120 { 235, 0b0100011, 460 }, { 250, 0b0110011, 460 },
121 { 275, 0b0000100, 460 }, { 300, 0b0010100, 460 },
122 { 325, 0b0100101, 460 }, { 350, 0b0110101, 460 },
123 { 400, 0b0000101, 460 }, { 450, 0b0010110, 460 },
124 { 500, 0b0100110, 460 }, { 550, 0b0110111, 460 },
125 { 600, 0b0000111, 460 }, { 650, 0b0011000, 460 },
126 { 700, 0b0101000, 460 }, { 750, 0b0111001, 460 },
127 { 800, 0b0001001, 460 }, { 850, 0b0011001, 460 },
128 { 900, 0b0101001, 460 }, { 950, 0b0111010, 460 }, 129 { 1000, 0b0001010, 460 }, { 1050, 0b0011010, 460 },
130 { 1110, 0b0101010, 460 }, { 1150, 0b0111011, 460 },
131 { 1200, 0b0001011, 460 }, { 1250, 0b0011011, 460 },
132 { 1300, 0b0101011, 460 }, { 1350, 0b0111100, 460 },
133 { 1400, 0b0001100, 460 }, { 1450, 0b0011100, 460 },
134 { 1500, 0b0101100, 460 }, { 1550, 0b0111101, 285 },
135 { 1600, 0b0001101, 295 }, { 1650, 0b0011101, 304 },
136 { 1700, 0b0101110, 313 }, { 1750, 0b0111110, 322 },
137 { 1800, 0b0001110, 331 }, { 1850, 0b0011110, 341 },
138 { 1900, 0b0101111, 350 }, { 1950, 0b0111111, 359 },
139 { 2000, 0b0001111, 368 }, { 2050, 0b1000000, 377 },
140 { 2100, 0b1000001, 387 }, { 2150, 0b1000010, 396 },
141 { 2200, 0b1000011, 405 }, { 2250, 0b1000100, 414 },
142 { 2300, 0b1000101, 423 }, { 2350, 0b1000110, 432 },
143 { 2400, 0b1000111, 442 }, { 2450, 0b1001000, 451 },
144 { 2500, 0b1001001, 460 }
145 };
146
Signature · 2 lines
0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
PATCH v2 2/2 phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI D-PHY RX
In reply to Karthik PoduvalAdd DT Bindings for Synopsys D-PHY RX, presently tested on version 1.2
--- .../bindings/phy/snps,dw-dphy-rx.yaml | 44 +++++++++++++++++++ MAINTAINERS | 7 +++ 2 files changed, 51 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +44 -0
@@ -0,0 +1,44 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/snps,dw-dphy-rx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Synopsys Designware MIPI D-PHY RX + +maintainers: + - Karthik Poduval <[email protected]> + - Jason Xiong <[email protected]> + - Miguel Lopes <[email protected] + +description: | + These are the bindings for Synopsys Designware MIPI DPHY RX phy driver. + Currently only supported phy version is v1.2. + +properties: + compatible: + const: snps,dw-dphy-1p2 + + '#phy-cells': + const: 0 + + reg: + minItems: 2 + maxItems: 2 + +required: + - compatible + - '#phy-cells' + - reg + +additionalProperties: false + +examples: + - | + dw_dphy_rx: dw-dphy@900000040 { + compatible = "snps,dw-dphy-1p2"; + #phy-cells = <0>; + reg = <0x0 0x90000040 0x0 0x20>, <0x0 0x90001000 0x0 0x8>; + status = "disabled"; + }; +
MAINTAINERS +7 -0
@@ -24217,6 +24217,13 @@ S: Maintained F: Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml F: drivers/dma/dw-axi-dmac/ +SYNOPSYS DESIGNWARE MIPI D-PHY RX DRIVER +M: Karthik Poduval <[email protected]> +M: Jason Xiong <[email protected]> +M: Miguel Lopes <[email protected]> +S: Supported +F: Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml + SYNOPSYS DESIGNWARE DMAC DRIVER M: Viresh Kumar <[email protected]> R: Andy Shevchenko <[email protected]>
Signature · 1 line
2.43.0
Rob Herring (Arm)
maintainerRe: [PATCH v2 2/2] phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI D-PHY RX
Quoted 9 lines · Karthik Poduval
Add DT Bindings for Synopsys D-PHY RX, presently tested on version 1.2
Signed-off-by Karthik Poduval <[email protected]>--- .../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):
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.
Frank Li
maintainerRe: [PATCH v2 2/2] phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI D-PHY RX
In reply to Karthik PoduvalQuoted 19 lines · Karthik Poduval
Add DT Bindings for Synopsys D-PHY RX, presently tested on version 1.2
Signed-off-by Karthik Poduval <[email protected]>--- .../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.yamlDocumentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +4
-0@@ -0,0 +1,44 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/snps,dw-dphy-rx.yaml#
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml line 14
Quoted 10 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +10
-0+$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Synopsys Designware MIPI D-PHY RX + +maintainers: + - Karthik Poduval <[email protected]> + - Jason Xiong <[email protected]> + - Miguel Lopes <[email protected] + +description: |
Needn't |
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml line 27
Quoted 13 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +13
-0+ These are the bindings for Synopsys Designware MIPI DPHY RX phy driver. + Currently only supported phy version is v1.2. + +properties: + compatible: + const: snps,dw-dphy-1p2 + + '#phy-cells': + const: 0 + + reg: + minItems: 2 + maxItems: 2
items:
- description: ....
- description: ....
Not all dphy have second register.
Quoted 4 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +4
-0+ +required: + - compatible + - '#phy-cells'
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml line 41
Quoted 10 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +10
-0+ - reg + +additionalProperties: false + +examples: + - | + dw_dphy_rx: dw-dphy@900000040 { + compatible = "snps,dw-dphy-1p2"; + #phy-cells = <0>; + reg = <0x0 0x90000040 0x0 0x20>, <0x0 0x90001000 0x0 0x8>;
Some DW MIPI CSI2 test1/test2 register is not tail part of whole MMIO space
such as imx93.
Frank
Quoted 24 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +3
-0+ status = "disabled"; + }; +MAINTAINERS +7
-1@@ -24217,6 +24217,13 @@ S: Maintained F: Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml F: drivers/dma/dw-axi-dmac/ +SYNOPSYS DESIGNWARE MIPI D-PHY RX DRIVER +M: Karthik Poduval <[email protected]> +M: Jason Xiong <[email protected]> +M: Miguel Lopes <[email protected]> +S: Supported +F: Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml + SYNOPSYS DESIGNWARE DMAC DRIVER M: Viresh Kumar <[email protected]> R: Andy Shevchenko <[email protected]> --2.43.0
Re: [PATCH v2 2/2] phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI D-PHY RX
In reply to Karthik PoduvalQuoted 2 lines · Karthik Poduval
+---
+$id: http://devicetree.org/schemas/phy/snps,dw-dphy-rx.yaml#
Filename and id should match compatible.
Quoted 6 lines
+$schema: http://devicetree.org/meta-schemas/core.yaml#
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +5
-0+ +title: Synopsys Designware MIPI D-PHY RX + +maintainers: + - Karthik Poduval <[email protected]>
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml line 20
Quoted 10 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +10
-0+ - Jason Xiong <[email protected]> + - Miguel Lopes <[email protected] + +description: | + These are the bindings for Synopsys Designware MIPI DPHY RX phy driver. + Currently only supported phy version is v1.2. + +properties: + compatible: + const: snps,dw-dphy-1p2
You should rather use SoC compatibles.
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml line 27
Quoted 7 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +7
-0+ + '#phy-cells': + const: 0 + + reg: + minItems: 2 + maxItems: 2
List the items instead
And fix the order, reg goes second.
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml line 32
Quoted 5 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +5
-0+ +required: + - compatible + - '#phy-cells' + - reg
Here as well
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml line 38
Quoted 6 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +6
-0+ +additionalProperties: false + +examples: + - | + dw_dphy_rx: dw-dphy@900000040 {
phy@
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml line 42
Quoted 4 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +4
-0+ compatible = "snps,dw-dphy-1p2"; + #phy-cells = <0>; + reg = <0x0 0x90000040 0x0 0x20>, <0x0 0x90001000 0x0 0x8>; + status = "disabled";
No, drop. And fix the order of properties, see DTS coding style.
Quoted 1 line
+ };
Best regards,
Krzysztof
Re: [PATCH v2 2/2] phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI D-PHY RX
Hi Krzysztof,
Thanks for your comments.
Quoted 23 lines · Krzysztof Kozlowski
CAUTION: This email originated from outside of the organization. Do not click links or open attachments unless you can confirm the sender and know the content is safe.
Quoted 2 lines · Karthik Poduval
+---
+$id: http://devicetree.org/schemas/phy/snps,dw-dphy-rx.yaml#Filename and id should match compatible.
Quoted 11 lines
+$schema: http://devicetree.org/meta-schemas/core.yaml#
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +10
-0+ +title: Synopsys Designware MIPI D-PHY RX + +maintainers: + - Karthik Poduval <[email protected]> + - Jason Xiong <[email protected]> + - Miguel Lopes <[email protected] + +description: | + These are the bindings for Synopsys Designware MIPI DPHY RX phy
Quoted 8 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml line 20
Quoted 6 lines
driver.
+ Currently only supported phy version is v1.2.Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +4
-0+ +properties: + compatible: + const: snps,dw-dphy-1p2You should rather use SoC compatibles.
If similar Synopsys D-PHY is used in multiple SoCs with slight variations, should each SoC have its own D-PHY driver or is it better to have a common one that works for all SoCs like arm,smmu-v3 or like the EEPROM driver below ?
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/misc/eeprom/eeprom_93xx46.c?h=v6.16-rc5#n391
where driver specific driver_data could support multiple versions or SoC variations.
Our team thought of the common driver approach however looking for general guidance from PHY subsystem maintainers and contributors.
Quoted 11 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml line 27
Quoted 8 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +7
-0+ + '#phy-cells': + const: 0 + + reg: + minItems: 2 + maxItems: 2List the items instead
Quoted 1 line
And fix the order, reg goes second.
ack
Quoted 8 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml line 32
Quoted 6 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +5
-0+ +required: + - compatible + - '#phy-cells' + - regHere as well
ack
Quoted 22 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml line 38
Quoted 7 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +6
-0+ +additionalProperties: false + +examples: + - | + dw_dphy_rx: dw-dphy@900000040 {phy@
Quoted 4 lines
+ compatible = "snps,dw-dphy-1p2";
+ #phy-cells = <0>;
+ reg = <0x00x900000400x00x20>, <0x00x900010000x00x8>; + status = "disabled";No, drop. And fix the order of properties, see DTS coding style.
Quoted 1 line
+ };
Best regards,
Krzysztof
Re: [PATCH v2 2/2] phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI D-PHY RX
Quoted 15 lines · Karthik
Quoted 7 lines
Quoted 7 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +7
-0+maintainers: + - Karthik Poduval <[email protected]> + - Jason Xiong <[email protected]> + - Miguel Lopes <[email protected] + +description: | + These are the bindings for Synopsys Designware MIPI DPHY RX phyQuoted 8 lines
Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml line 20
Quoted 6 lines
driver.
+ Currently only supported phy version is v1.2.Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml new file +4
-0+ +properties: + compatible: + const: snps,dw-dphy-1p2You should rather use SoC compatibles.
Quoted 2 lines
If similar Synopsys D-PHY is used in multiple SoCs with slight variations, should each SoC have its own D-PHY driver or is it better
Your incorrect subject probably mislead you, but this is not a driver patch. These are DT bindings.
SoC specific compatibles are almost always preferred.
Quoted 7 lines
to have a common one that works for all SoCs like arm,smmu-v3 or like the EEPROM driver below ?
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/misc/eeprom/eeprom_93xx46.c?h=v6.16-rc5#n391
where driver specificdriver_datacould 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
Re: [PATCH v2 2/2] phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI D-PHY RX
In reply to Karthik PoduvalQuoted 7 lines · Karthik Poduval
Add DT Bindings for Synopsys D-PHY RX, presently tested on version 1.2
Signed-off-by Karthik Poduval <[email protected]>--- .../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
Frank Li
maintainerQuoted 5 lines · Karthik Poduval
v2: fix
dt_binding_checkerrorsKarthik Poduval (2):
phy: dw-dphy-rx: Add Synopsys DesignWare D-PHY RX
phy: dw-dphy-rx: Add dt bindings for Synopsys MIPI D-PHY RX
Can you post patches or link, which use this phy?
There were many attempt to try to support this PHY.
Frank
Quoted 13 lines
.../bindings/phy/snps,dw-dphy-rx.yaml | 44 ++ MAINTAINERS | 7 + drivers/phy/Kconfig | 11 + drivers/phy/Makefile | 1 + drivers/phy/phy-dw-dphy.c | 575 ++++++++++++++++++ 5 files changed, 638 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/snps,dw-dphy-rx.yaml create mode 100644 drivers/phy/phy-dw-dphy.c--
2.43.0