From 4e445729dc103ff7780ed03da9f8310759ea5dae Mon Sep 17 00:00:00 2001 From: Kaustabh Chakraborty Date: Sun, 6 Jul 2025 23:55:35 +0530 Subject: [PATCH 01/12] drm/bridge: samsung-dsim: support separate LINK and DPHY status registers Exynos7870's DSIM has separate registers for LINK and DPHY status. This is in contrast to older variants in the driver which use a single register for both. Add a driver data flag which indicates that the device variant supports the legacy status register. Change the register read calls appropriately. Suggested-by: Inki Dae Signed-off-by: Kaustabh Chakraborty Signed-off-by: Inki Dae --- drivers/gpu/drm/bridge/samsung-dsim.c | 22 ++++++++++++++++++---- include/drm/bridge/samsung-dsim.h | 1 + 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index b5dd71f6a990..f41650ff7e13 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -31,7 +31,7 @@ /* returns true iff both arguments logically differs */ #define NEQV(a, b) (!(a) ^ !(b)) -/* DSIM_STATUS */ +/* DSIM_STATUS or DSIM_DPHY_STATUS */ #define DSIM_STOP_STATE_DAT(x) (((x) & 0xf) << 0) #define DSIM_STOP_STATE_CLK BIT(8) #define DSIM_TX_READY_HS_CLK BIT(10) @@ -240,7 +240,9 @@ enum samsung_dsim_transfer_type { }; enum reg_idx { - DSIM_STATUS_REG, /* Status register */ + DSIM_STATUS_REG, /* Status register (legacy) */ + DSIM_LINK_STATUS_REG, /* Link status register */ + DSIM_DPHY_STATUS_REG, /* D-PHY status register */ DSIM_SWRST_REG, /* Software reset register */ DSIM_CLKCTRL_REG, /* Clock control register */ DSIM_TIMEOUT_REG, /* Time out register */ @@ -405,6 +407,7 @@ static const unsigned int imx8mm_dsim_reg_values[] = { static const struct samsung_dsim_driver_data exynos3_dsi_driver_data = { .reg_ofs = exynos_reg_ofs, .plltmr_reg = 0x50, + .has_legacy_status_reg = 1, .has_freqband = 1, .has_clklane_stop = 1, .num_clks = 2, @@ -424,6 +427,7 @@ static const struct samsung_dsim_driver_data exynos3_dsi_driver_data = { static const struct samsung_dsim_driver_data exynos4_dsi_driver_data = { .reg_ofs = exynos_reg_ofs, .plltmr_reg = 0x50, + .has_legacy_status_reg = 1, .has_freqband = 1, .has_clklane_stop = 1, .num_clks = 2, @@ -443,6 +447,7 @@ static const struct samsung_dsim_driver_data exynos4_dsi_driver_data = { static const struct samsung_dsim_driver_data exynos5_dsi_driver_data = { .reg_ofs = exynos_reg_ofs, .plltmr_reg = 0x58, + .has_legacy_status_reg = 1, .num_clks = 2, .max_freq = 1000, .wait_for_reset = 1, @@ -459,6 +464,7 @@ static const struct samsung_dsim_driver_data exynos5_dsi_driver_data = { static const struct samsung_dsim_driver_data exynos5433_dsi_driver_data = { .reg_ofs = exynos5433_reg_ofs, .plltmr_reg = 0xa0, + .has_legacy_status_reg = 1, .has_clklane_stop = 1, .num_clks = 5, .max_freq = 1500, @@ -476,6 +482,7 @@ static const struct samsung_dsim_driver_data exynos5433_dsi_driver_data = { static const struct samsung_dsim_driver_data exynos5422_dsi_driver_data = { .reg_ofs = exynos5433_reg_ofs, .plltmr_reg = 0xa0, + .has_legacy_status_reg = 1, .has_clklane_stop = 1, .num_clks = 2, .max_freq = 1500, @@ -493,6 +500,7 @@ static const struct samsung_dsim_driver_data exynos5422_dsi_driver_data = { static const struct samsung_dsim_driver_data imx8mm_dsi_driver_data = { .reg_ofs = exynos5433_reg_ofs, .plltmr_reg = 0xa0, + .has_legacy_status_reg = 1, .has_clklane_stop = 1, .num_clks = 2, .max_freq = 2100, @@ -688,7 +696,10 @@ static unsigned long samsung_dsim_set_pll(struct samsung_dsim *dsi, dev_err(dsi->dev, "PLL failed to stabilize\n"); return 0; } - reg = samsung_dsim_read(dsi, DSIM_STATUS_REG); + if (driver_data->has_legacy_status_reg) + reg = samsung_dsim_read(dsi, DSIM_STATUS_REG); + else + reg = samsung_dsim_read(dsi, DSIM_LINK_STATUS_REG); } while ((reg & DSIM_PLL_STABLE) == 0); dsi->hs_clock = fout; @@ -962,7 +973,10 @@ static int samsung_dsim_init_link(struct samsung_dsim *dsi) return -EFAULT; } - reg = samsung_dsim_read(dsi, DSIM_STATUS_REG); + if (driver_data->has_legacy_status_reg) + reg = samsung_dsim_read(dsi, DSIM_STATUS_REG); + else + reg = samsung_dsim_read(dsi, DSIM_DPHY_STATUS_REG); if ((reg & DSIM_STOP_STATE_DAT(lanes_mask)) != DSIM_STOP_STATE_DAT(lanes_mask)) continue; diff --git a/include/drm/bridge/samsung-dsim.h b/include/drm/bridge/samsung-dsim.h index 9764d6eb5beb..d7877191bad1 100644 --- a/include/drm/bridge/samsung-dsim.h +++ b/include/drm/bridge/samsung-dsim.h @@ -53,6 +53,7 @@ struct samsung_dsim_transfer { struct samsung_dsim_driver_data { const unsigned int *reg_ofs; unsigned int plltmr_reg; + unsigned int has_legacy_status_reg:1; unsigned int has_freqband:1; unsigned int has_clklane_stop:1; unsigned int has_broken_fifoctrl_emptyhdr:1; From 7c9b998947f19457e32496ab9edeea798373c426 Mon Sep 17 00:00:00 2001 From: Kaustabh Chakraborty Date: Sun, 6 Jul 2025 23:55:36 +0530 Subject: [PATCH 02/12] drm/bridge: samsung-dsim: add SFRCTRL register On Exynos7870 devices, enabling the display requires disabling standby by writing to the SFRCTRL register. Add the register and related bit values. Since this behavior isn't available on other SoCs, implement a flag in the driver data struct indicating the availability of this feature. Signed-off-by: Kaustabh Chakraborty Signed-off-by: Inki Dae --- drivers/gpu/drm/bridge/samsung-dsim.c | 16 ++++++++++++++++ include/drm/bridge/samsung-dsim.h | 1 + 2 files changed, 17 insertions(+) diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index f41650ff7e13..49c4456ebd23 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -157,6 +157,11 @@ #define DSIM_INT_RX_ECC_ERR BIT(15) #define DSIM_INT_RX_CRC_ERR BIT(14) +/* DSIM_SFRCTRL */ +#define DSIM_SFR_CTRL_STAND_BY BIT(4) +#define DSIM_SFR_CTRL_SHADOW_UPDATE BIT(1) +#define DSIM_SFR_CTRL_SHADOW_EN BIT(0) + /* DSIM_FIFOCTRL */ #define DSIM_RX_DATA_FULL BIT(25) #define DSIM_RX_DATA_EMPTY BIT(24) @@ -257,6 +262,7 @@ enum reg_idx { DSIM_PKTHDR_REG, /* Packet Header FIFO register */ DSIM_PAYLOAD_REG, /* Payload FIFO register */ DSIM_RXFIFO_REG, /* Read FIFO register */ + DSIM_SFRCTRL_REG, /* SFR standby and shadow control register */ DSIM_FIFOCTRL_REG, /* FIFO status and control register */ DSIM_PLLCTRL_REG, /* PLL control register */ DSIM_PHYCTRL_REG, @@ -1037,6 +1043,7 @@ static void samsung_dsim_set_display_mode(struct samsung_dsim *dsi) static void samsung_dsim_set_display_enable(struct samsung_dsim *dsi, bool enable) { + const struct samsung_dsim_driver_data *driver_data = dsi->driver_data; u32 reg; reg = samsung_dsim_read(dsi, DSIM_MDRESOL_REG); @@ -1045,6 +1052,15 @@ static void samsung_dsim_set_display_enable(struct samsung_dsim *dsi, bool enabl else reg &= ~DSIM_MAIN_STAND_BY; samsung_dsim_write(dsi, DSIM_MDRESOL_REG, reg); + + if (driver_data->has_sfrctrl) { + reg = samsung_dsim_read(dsi, DSIM_SFRCTRL_REG); + if (enable) + reg |= DSIM_SFR_CTRL_STAND_BY; + else + reg &= ~DSIM_SFR_CTRL_STAND_BY; + samsung_dsim_write(dsi, DSIM_SFRCTRL_REG, reg); + } } static int samsung_dsim_wait_for_hdr_fifo(struct samsung_dsim *dsi) diff --git a/include/drm/bridge/samsung-dsim.h b/include/drm/bridge/samsung-dsim.h index d7877191bad1..f0c1e5c5ed49 100644 --- a/include/drm/bridge/samsung-dsim.h +++ b/include/drm/bridge/samsung-dsim.h @@ -57,6 +57,7 @@ struct samsung_dsim_driver_data { unsigned int has_freqband:1; unsigned int has_clklane_stop:1; unsigned int has_broken_fifoctrl_emptyhdr:1; + unsigned int has_sfrctrl:1; unsigned int num_clks; unsigned int min_freq; unsigned int max_freq; From 92beab1a397d80d04d90f511c6d0af696da67a33 Mon Sep 17 00:00:00 2001 From: Kaustabh Chakraborty Date: Sun, 6 Jul 2025 23:55:37 +0530 Subject: [PATCH 03/12] drm/bridge: samsung-dsim: add flag to control header FIFO wait Exynos7870's DSIM device doesn't require waiting for the header FIFO during a MIPI DSI transfer. Add a flag in the driver data in order to control said behavior. Signed-off-by: Kaustabh Chakraborty Signed-off-by: Inki Dae dev; struct mipi_dsi_packet *pkt = &xfer->packet; + const struct samsung_dsim_driver_data *driver_data = dsi->driver_data; const u8 *payload = pkt->payload + xfer->tx_done; u16 length = pkt->payload_length - xfer->tx_done; bool first = !xfer->tx_done; @@ -1157,9 +1164,11 @@ static void samsung_dsim_send_to_fifo(struct samsung_dsim *dsi, return; reg = get_unaligned_le32(pkt->header); - if (samsung_dsim_wait_for_hdr_fifo(dsi)) { - dev_err(dev, "waiting for header FIFO timed out\n"); - return; + if (driver_data->wait_for_hdr_fifo) { + if (samsung_dsim_wait_for_hdr_fifo(dsi)) { + dev_err(dev, "waiting for header FIFO timed out\n"); + return; + } } if (NEQV(xfer->flags & MIPI_DSI_MSG_USE_LPM, diff --git a/include/drm/bridge/samsung-dsim.h b/include/drm/bridge/samsung-dsim.h index f0c1e5c5ed49..62c07952bd00 100644 --- a/include/drm/bridge/samsung-dsim.h +++ b/include/drm/bridge/samsung-dsim.h @@ -61,6 +61,7 @@ struct samsung_dsim_driver_data { unsigned int num_clks; unsigned int min_freq; unsigned int max_freq; + unsigned int wait_for_hdr_fifo; unsigned int wait_for_reset; unsigned int num_bits_resol; unsigned int pll_p_offset; From f6ba4c1577a8184105133a79b5d1b6d465158362 Mon Sep 17 00:00:00 2001 From: Kaustabh Chakraborty Date: Sun, 6 Jul 2025 23:55:38 +0530 Subject: [PATCH 04/12] drm/bridge: samsung-dsim: allow configuring bits and offsets of CLKCTRL register DSIM_CLKCTRL bit and offset values hardcoded in the driver: name | bit/offset value --------------------------+----------------- DSIM_LANE_ESC_CLK_EN_CLK | 19 DSIM_LANE_ESC_CLK_EN_DATA | 20 DSIM_BYTE_CLKEN | 24 DSIM_ESC_CLKEN | 28 DSIM_TX_REQUEST_HSCLK | 31 DSIM_CLKCTRL bit and offset values in Exynos7870 DSIM as per downstream kernel sources: name | bit/offset value --------------------------+----------------- DSIM_LANE_ESC_CLK_EN_CLK | 8 DSIM_LANE_ESC_CLK_EN_DATA | 9 DSIM_BYTE_CLKEN | 17 DSIM_ESC_CLKEN | 16 DSIM_TX_REQUEST_HSCLK | 20 In order to support both, move all values to the driver data struct and define it for every driver compatible. Reference the values from there instead, in functions wherever required. Signed-off-by: Kaustabh Chakraborty Signed-off-by: Inki Dae --- drivers/gpu/drm/bridge/samsung-dsim.c | 76 +++++++++++++++++++-------- include/drm/bridge/samsung-dsim.h | 5 ++ 2 files changed, 59 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index dd6c99dada89..72190787ff13 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -46,17 +46,13 @@ #define DSIM_BTA_TIMEOUT(x) ((x) << 16) /* DSIM_CLKCTRL */ -#define DSIM_ESC_PRESCALER(x) (((x) & 0xffff) << 0) -#define DSIM_ESC_PRESCALER_MASK (0xffff << 0) -#define DSIM_LANE_ESC_CLK_EN_CLK BIT(19) -#define DSIM_LANE_ESC_CLK_EN_DATA(x) (((x) & 0xf) << 20) -#define DSIM_LANE_ESC_CLK_EN_DATA_MASK (0xf << 20) -#define DSIM_BYTE_CLKEN BIT(24) -#define DSIM_BYTE_CLK_SRC(x) (((x) & 0x3) << 25) -#define DSIM_BYTE_CLK_SRC_MASK (0x3 << 25) -#define DSIM_PLL_BYPASS BIT(27) -#define DSIM_ESC_CLKEN BIT(28) -#define DSIM_TX_REQUEST_HSCLK BIT(31) +#define DSIM_ESC_PRESCALER(x) (((x) & 0xffff) << 0) +#define DSIM_ESC_PRESCALER_MASK (0xffff << 0) +#define DSIM_LANE_ESC_CLK_EN_DATA(x, offset) (((x) & 0xf) << offset) +#define DSIM_LANE_ESC_CLK_EN_DATA_MASK(offset) (0xf << offset) +#define DSIM_BYTE_CLK_SRC(x) (((x) & 0x3) << 25) +#define DSIM_BYTE_CLK_SRC_MASK (0x3 << 25) +#define DSIM_PLL_BYPASS BIT(27) /* DSIM_CONFIG */ #define DSIM_LANE_EN_CLK BIT(0) @@ -421,6 +417,11 @@ static const struct samsung_dsim_driver_data exynos3_dsi_driver_data = { .wait_for_hdr_fifo = 1, .wait_for_reset = 1, .num_bits_resol = 11, + .esc_clken_bit = 28, + .byte_clken_bit = 24, + .tx_req_hsclk_bit = 31, + .lane_esc_clk_bit = 19, + .lane_esc_data_offset = 20, .pll_p_offset = 13, .reg_values = reg_values, .pll_fin_min = 6, @@ -442,6 +443,11 @@ static const struct samsung_dsim_driver_data exynos4_dsi_driver_data = { .wait_for_hdr_fifo = 1, .wait_for_reset = 1, .num_bits_resol = 11, + .esc_clken_bit = 28, + .byte_clken_bit = 24, + .tx_req_hsclk_bit = 31, + .lane_esc_clk_bit = 19, + .lane_esc_data_offset = 20, .pll_p_offset = 13, .reg_values = reg_values, .pll_fin_min = 6, @@ -461,6 +467,11 @@ static const struct samsung_dsim_driver_data exynos5_dsi_driver_data = { .wait_for_hdr_fifo = 1, .wait_for_reset = 1, .num_bits_resol = 11, + .esc_clken_bit = 28, + .byte_clken_bit = 24, + .tx_req_hsclk_bit = 31, + .lane_esc_clk_bit = 19, + .lane_esc_data_offset = 20, .pll_p_offset = 13, .reg_values = reg_values, .pll_fin_min = 6, @@ -480,6 +491,11 @@ static const struct samsung_dsim_driver_data exynos5433_dsi_driver_data = { .wait_for_hdr_fifo = 1, .wait_for_reset = 0, .num_bits_resol = 12, + .esc_clken_bit = 28, + .byte_clken_bit = 24, + .tx_req_hsclk_bit = 31, + .lane_esc_clk_bit = 19, + .lane_esc_data_offset = 20, .pll_p_offset = 13, .reg_values = exynos5433_reg_values, .pll_fin_min = 6, @@ -499,6 +515,11 @@ static const struct samsung_dsim_driver_data exynos5422_dsi_driver_data = { .wait_for_hdr_fifo = 1, .wait_for_reset = 1, .num_bits_resol = 12, + .esc_clken_bit = 28, + .byte_clken_bit = 24, + .tx_req_hsclk_bit = 31, + .lane_esc_clk_bit = 19, + .lane_esc_data_offset = 20, .pll_p_offset = 13, .reg_values = exynos5422_reg_values, .pll_fin_min = 6, @@ -518,6 +539,11 @@ static const struct samsung_dsim_driver_data imx8mm_dsi_driver_data = { .wait_for_hdr_fifo = 1, .wait_for_reset = 0, .num_bits_resol = 12, + .esc_clken_bit = 28, + .byte_clken_bit = 24, + .tx_req_hsclk_bit = 31, + .lane_esc_clk_bit = 19, + .lane_esc_data_offset = 20, /* * Unlike Exynos, PLL_P(PMS_P) offset 14 is used in i.MX8M Mini/Nano/Plus * downstream driver - drivers/gpu/drm/bridge/sec-dsim.c @@ -721,6 +747,7 @@ static unsigned long samsung_dsim_set_pll(struct samsung_dsim *dsi, static int samsung_dsim_enable_clock(struct samsung_dsim *dsi) { + const struct samsung_dsim_driver_data *driver_data = dsi->driver_data; unsigned long hs_clk, byte_clk, esc_clk, pix_clk; unsigned long esc_div; u32 reg; @@ -754,15 +781,17 @@ static int samsung_dsim_enable_clock(struct samsung_dsim *dsi) hs_clk, byte_clk, esc_clk); reg = samsung_dsim_read(dsi, DSIM_CLKCTRL_REG); - reg &= ~(DSIM_ESC_PRESCALER_MASK | DSIM_LANE_ESC_CLK_EN_CLK - | DSIM_LANE_ESC_CLK_EN_DATA_MASK | DSIM_PLL_BYPASS - | DSIM_BYTE_CLK_SRC_MASK); - reg |= DSIM_ESC_CLKEN | DSIM_BYTE_CLKEN - | DSIM_ESC_PRESCALER(esc_div) - | DSIM_LANE_ESC_CLK_EN_CLK - | DSIM_LANE_ESC_CLK_EN_DATA(BIT(dsi->lanes) - 1) - | DSIM_BYTE_CLK_SRC(0) - | DSIM_TX_REQUEST_HSCLK; + reg &= ~(DSIM_ESC_PRESCALER_MASK | BIT(driver_data->lane_esc_clk_bit) + | DSIM_LANE_ESC_CLK_EN_DATA_MASK(driver_data->lane_esc_data_offset) + | DSIM_PLL_BYPASS + | DSIM_BYTE_CLK_SRC_MASK); + reg |= BIT(driver_data->esc_clken_bit) | BIT(driver_data->byte_clken_bit) + | DSIM_ESC_PRESCALER(esc_div) + | BIT(driver_data->lane_esc_clk_bit) + | DSIM_LANE_ESC_CLK_EN_DATA(BIT(dsi->lanes) - 1, + driver_data->lane_esc_data_offset) + | DSIM_BYTE_CLK_SRC(0) + | BIT(driver_data->tx_req_hsclk_bit); samsung_dsim_write(dsi, DSIM_CLKCTRL_REG, reg); return 0; @@ -866,11 +895,14 @@ static void samsung_dsim_set_phy_ctrl(struct samsung_dsim *dsi) static void samsung_dsim_disable_clock(struct samsung_dsim *dsi) { + const struct samsung_dsim_driver_data *driver_data = dsi->driver_data; u32 reg; reg = samsung_dsim_read(dsi, DSIM_CLKCTRL_REG); - reg &= ~(DSIM_LANE_ESC_CLK_EN_CLK | DSIM_LANE_ESC_CLK_EN_DATA_MASK - | DSIM_ESC_CLKEN | DSIM_BYTE_CLKEN); + reg &= ~(BIT(driver_data->lane_esc_clk_bit) + | DSIM_LANE_ESC_CLK_EN_DATA_MASK(driver_data->lane_esc_data_offset) + | BIT(driver_data->esc_clken_bit) + | BIT(driver_data->byte_clken_bit)); samsung_dsim_write(dsi, DSIM_CLKCTRL_REG, reg); reg = samsung_dsim_read(dsi, DSIM_PLLCTRL_REG); diff --git a/include/drm/bridge/samsung-dsim.h b/include/drm/bridge/samsung-dsim.h index 62c07952bd00..b1e64c7f9931 100644 --- a/include/drm/bridge/samsung-dsim.h +++ b/include/drm/bridge/samsung-dsim.h @@ -64,6 +64,11 @@ struct samsung_dsim_driver_data { unsigned int wait_for_hdr_fifo; unsigned int wait_for_reset; unsigned int num_bits_resol; + unsigned int esc_clken_bit; + unsigned int byte_clken_bit; + unsigned int tx_req_hsclk_bit; + unsigned int lane_esc_clk_bit; + unsigned int lane_esc_data_offset; unsigned int pll_p_offset; const unsigned int *reg_values; unsigned int pll_fin_min; From 4d244122dd90c72f6c3f10eb7a53678d78d3b857 Mon Sep 17 00:00:00 2001 From: Kaustabh Chakraborty Date: Sun, 6 Jul 2025 23:55:39 +0530 Subject: [PATCH 05/12] drm/bridge: samsung-dsim: allow configuring the MAIN_VSA offset The MAIN_VSA offset of DSIM_MSYNC is hardcoded to a 22-bit offset, but Exynos7870's DSIM has it in a 16-bit offset as per the downstream kernel sources. In order to support both, move this offset value to the driver data struct and define it for every driver compatible. Reference the value from there instead, in functions wherever required. Signed-off-by: Kaustabh Chakraborty Signed-off-by: Inki Dae --- drivers/gpu/drm/bridge/samsung-dsim.c | 13 ++++++++++--- include/drm/bridge/samsung-dsim.h | 1 + 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index 72190787ff13..325acad1f577 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -125,9 +125,9 @@ #define DSIM_MAIN_HBP_MASK ((0xffff) << 0) /* DSIM_MSYNC */ -#define DSIM_MAIN_VSA(x) ((x) << 22) +#define DSIM_MAIN_VSA(x, offset) ((x) << offset) #define DSIM_MAIN_HSA(x) ((x) << 0) -#define DSIM_MAIN_VSA_MASK ((0x3ff) << 22) +#define DSIM_MAIN_VSA_MASK(offset) ((0x3ff) << offset) #define DSIM_MAIN_HSA_MASK ((0xffff) << 0) /* DSIM_SDRESOL */ @@ -423,6 +423,7 @@ static const struct samsung_dsim_driver_data exynos3_dsi_driver_data = { .lane_esc_clk_bit = 19, .lane_esc_data_offset = 20, .pll_p_offset = 13, + .main_vsa_offset = 22, .reg_values = reg_values, .pll_fin_min = 6, .pll_fin_max = 12, @@ -449,6 +450,7 @@ static const struct samsung_dsim_driver_data exynos4_dsi_driver_data = { .lane_esc_clk_bit = 19, .lane_esc_data_offset = 20, .pll_p_offset = 13, + .main_vsa_offset = 22, .reg_values = reg_values, .pll_fin_min = 6, .pll_fin_max = 12, @@ -473,6 +475,7 @@ static const struct samsung_dsim_driver_data exynos5_dsi_driver_data = { .lane_esc_clk_bit = 19, .lane_esc_data_offset = 20, .pll_p_offset = 13, + .main_vsa_offset = 22, .reg_values = reg_values, .pll_fin_min = 6, .pll_fin_max = 12, @@ -497,6 +500,7 @@ static const struct samsung_dsim_driver_data exynos5433_dsi_driver_data = { .lane_esc_clk_bit = 19, .lane_esc_data_offset = 20, .pll_p_offset = 13, + .main_vsa_offset = 22, .reg_values = exynos5433_reg_values, .pll_fin_min = 6, .pll_fin_max = 12, @@ -521,6 +525,7 @@ static const struct samsung_dsim_driver_data exynos5422_dsi_driver_data = { .lane_esc_clk_bit = 19, .lane_esc_data_offset = 20, .pll_p_offset = 13, + .main_vsa_offset = 22, .reg_values = exynos5422_reg_values, .pll_fin_min = 6, .pll_fin_max = 12, @@ -549,6 +554,7 @@ static const struct samsung_dsim_driver_data imx8mm_dsi_driver_data = { * downstream driver - drivers/gpu/drm/bridge/sec-dsim.c */ .pll_p_offset = 14, + .main_vsa_offset = 22, .reg_values = imx8mm_dsim_reg_values, .pll_fin_min = 2, .pll_fin_max = 30, @@ -1041,6 +1047,7 @@ static void samsung_dsim_set_display_mode(struct samsung_dsim *dsi) { struct drm_display_mode *m = &dsi->mode; unsigned int num_bits_resol = dsi->driver_data->num_bits_resol; + unsigned int main_vsa_offset = dsi->driver_data->main_vsa_offset; u32 reg; if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { @@ -1067,7 +1074,7 @@ static void samsung_dsim_set_display_mode(struct samsung_dsim *dsi) reg = DSIM_MAIN_HFP(hfp) | DSIM_MAIN_HBP(hbp); samsung_dsim_write(dsi, DSIM_MHPORCH_REG, reg); - reg = DSIM_MAIN_VSA(m->vsync_end - m->vsync_start) + reg = DSIM_MAIN_VSA(m->vsync_end - m->vsync_start, main_vsa_offset) | DSIM_MAIN_HSA(hsa); samsung_dsim_write(dsi, DSIM_MSYNC_REG, reg); } diff --git a/include/drm/bridge/samsung-dsim.h b/include/drm/bridge/samsung-dsim.h index b1e64c7f9931..7f6d353f34af 100644 --- a/include/drm/bridge/samsung-dsim.h +++ b/include/drm/bridge/samsung-dsim.h @@ -70,6 +70,7 @@ struct samsung_dsim_driver_data { unsigned int lane_esc_clk_bit; unsigned int lane_esc_data_offset; unsigned int pll_p_offset; + unsigned int main_vsa_offset; const unsigned int *reg_values; unsigned int pll_fin_min; unsigned int pll_fin_max; From d6dbefb2fed7d7f333c4241965296d84c202b6bf Mon Sep 17 00:00:00 2001 From: Kaustabh Chakraborty Date: Sun, 6 Jul 2025 23:55:40 +0530 Subject: [PATCH 06/12] drm/bridge: samsung-dsim: allow configuring the VIDEO_MODE bit The VIDEO_MODE bit of DSIM_CONFIG is hardcoded to BIT(25), but Exynos7870's DSIM has it in BIT(18) as per downstream kernel sources. In order to support both, move this bit value to the driver data struct and define it for every driver compatible. Reference the value from there instead, in functions wherever required. Signed-off-by: Kaustabh Chakraborty Signed-off-by: Inki Dae --- drivers/gpu/drm/bridge/samsung-dsim.c | 9 +++++++-- include/drm/bridge/samsung-dsim.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index 325acad1f577..db154418e446 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -87,7 +87,6 @@ */ #define DSIM_HSE_DISABLE_MODE BIT(23) #define DSIM_AUTO_MODE BIT(24) -#define DSIM_VIDEO_MODE BIT(25) #define DSIM_BURST_MODE BIT(26) #define DSIM_SYNC_INFORM BIT(27) #define DSIM_EOT_DISABLE BIT(28) @@ -417,6 +416,7 @@ static const struct samsung_dsim_driver_data exynos3_dsi_driver_data = { .wait_for_hdr_fifo = 1, .wait_for_reset = 1, .num_bits_resol = 11, + .video_mode_bit = 25, .esc_clken_bit = 28, .byte_clken_bit = 24, .tx_req_hsclk_bit = 31, @@ -444,6 +444,7 @@ static const struct samsung_dsim_driver_data exynos4_dsi_driver_data = { .wait_for_hdr_fifo = 1, .wait_for_reset = 1, .num_bits_resol = 11, + .video_mode_bit = 25, .esc_clken_bit = 28, .byte_clken_bit = 24, .tx_req_hsclk_bit = 31, @@ -469,6 +470,7 @@ static const struct samsung_dsim_driver_data exynos5_dsi_driver_data = { .wait_for_hdr_fifo = 1, .wait_for_reset = 1, .num_bits_resol = 11, + .video_mode_bit = 25, .esc_clken_bit = 28, .byte_clken_bit = 24, .tx_req_hsclk_bit = 31, @@ -494,6 +496,7 @@ static const struct samsung_dsim_driver_data exynos5433_dsi_driver_data = { .wait_for_hdr_fifo = 1, .wait_for_reset = 0, .num_bits_resol = 12, + .video_mode_bit = 25, .esc_clken_bit = 28, .byte_clken_bit = 24, .tx_req_hsclk_bit = 31, @@ -519,6 +522,7 @@ static const struct samsung_dsim_driver_data exynos5422_dsi_driver_data = { .wait_for_hdr_fifo = 1, .wait_for_reset = 1, .num_bits_resol = 12, + .video_mode_bit = 25, .esc_clken_bit = 28, .byte_clken_bit = 24, .tx_req_hsclk_bit = 31, @@ -544,6 +548,7 @@ static const struct samsung_dsim_driver_data imx8mm_dsi_driver_data = { .wait_for_hdr_fifo = 1, .wait_for_reset = 0, .num_bits_resol = 12, + .video_mode_bit = 25, .esc_clken_bit = 28, .byte_clken_bit = 24, .tx_req_hsclk_bit = 31, @@ -952,7 +957,7 @@ static int samsung_dsim_init_link(struct samsung_dsim *dsi) * mode, otherwise it will support command mode. */ if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { - reg |= DSIM_VIDEO_MODE; + reg |= BIT(driver_data->video_mode_bit); /* * The user manual describes that following bits are ignored in diff --git a/include/drm/bridge/samsung-dsim.h b/include/drm/bridge/samsung-dsim.h index 7f6d353f34af..9d11c3e39fe5 100644 --- a/include/drm/bridge/samsung-dsim.h +++ b/include/drm/bridge/samsung-dsim.h @@ -64,6 +64,7 @@ struct samsung_dsim_driver_data { unsigned int wait_for_hdr_fifo; unsigned int wait_for_reset; unsigned int num_bits_resol; + unsigned int video_mode_bit; unsigned int esc_clken_bit; unsigned int byte_clken_bit; unsigned int tx_req_hsclk_bit; From 9aa49c21aac071383353315036520ba753484c93 Mon Sep 17 00:00:00 2001 From: Kaustabh Chakraborty Date: Sun, 6 Jul 2025 23:55:41 +0530 Subject: [PATCH 07/12] drm/bridge: samsung-dsim: allow configuring PLL_M and PLL_S offsets Currently, PLL_P offset of DSIM_PLLCTRL is configurable in the driver data, while PLL_M and PLL_S offsets are hardcoded as 4-bit and 1-bit offsets respectively, but Exynos7870's DSIM have them at 3-bit and 0-bit offsets as per downstream kernel sources. In order to support both, move both offset values to the driver data struct and define it for every driver compatible. Reference the values from there instead, in functions wherever required. Signed-off-by: Kaustabh Chakraborty Signed-off-by: Inki Dae --- drivers/gpu/drm/bridge/samsung-dsim.c | 21 ++++++++++++++++----- include/drm/bridge/samsung-dsim.h | 2 ++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index db154418e446..2884b3b7dc73 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -191,9 +191,7 @@ #define DSIM_PLL_DPDNSWAP_DAT (1 << 24) #define DSIM_FREQ_BAND(x) ((x) << 24) #define DSIM_PLL_EN BIT(23) -#define DSIM_PLL_P(x, offset) ((x) << (offset)) -#define DSIM_PLL_M(x) ((x) << 4) -#define DSIM_PLL_S(x) ((x) << 1) +#define DSIM_PLL(x, offset) ((x) << (offset)) /* DSIM_PHYCTRL */ #define DSIM_PHYCTRL_ULPS_EXIT(x) (((x) & 0x1ff) << 0) @@ -423,6 +421,8 @@ static const struct samsung_dsim_driver_data exynos3_dsi_driver_data = { .lane_esc_clk_bit = 19, .lane_esc_data_offset = 20, .pll_p_offset = 13, + .pll_m_offset = 4, + .pll_s_offset = 1, .main_vsa_offset = 22, .reg_values = reg_values, .pll_fin_min = 6, @@ -451,6 +451,8 @@ static const struct samsung_dsim_driver_data exynos4_dsi_driver_data = { .lane_esc_clk_bit = 19, .lane_esc_data_offset = 20, .pll_p_offset = 13, + .pll_m_offset = 4, + .pll_s_offset = 1, .main_vsa_offset = 22, .reg_values = reg_values, .pll_fin_min = 6, @@ -477,6 +479,8 @@ static const struct samsung_dsim_driver_data exynos5_dsi_driver_data = { .lane_esc_clk_bit = 19, .lane_esc_data_offset = 20, .pll_p_offset = 13, + .pll_m_offset = 4, + .pll_s_offset = 1, .main_vsa_offset = 22, .reg_values = reg_values, .pll_fin_min = 6, @@ -503,6 +507,8 @@ static const struct samsung_dsim_driver_data exynos5433_dsi_driver_data = { .lane_esc_clk_bit = 19, .lane_esc_data_offset = 20, .pll_p_offset = 13, + .pll_m_offset = 4, + .pll_s_offset = 1, .main_vsa_offset = 22, .reg_values = exynos5433_reg_values, .pll_fin_min = 6, @@ -529,6 +535,8 @@ static const struct samsung_dsim_driver_data exynos5422_dsi_driver_data = { .lane_esc_clk_bit = 19, .lane_esc_data_offset = 20, .pll_p_offset = 13, + .pll_m_offset = 4, + .pll_s_offset = 1, .main_vsa_offset = 22, .reg_values = exynos5422_reg_values, .pll_fin_min = 6, @@ -559,6 +567,8 @@ static const struct samsung_dsim_driver_data imx8mm_dsi_driver_data = { * downstream driver - drivers/gpu/drm/bridge/sec-dsim.c */ .pll_p_offset = 14, + .pll_m_offset = 4, + .pll_s_offset = 1, .main_vsa_offset = 22, .reg_values = imx8mm_dsim_reg_values, .pll_fin_min = 2, @@ -710,8 +720,9 @@ static unsigned long samsung_dsim_set_pll(struct samsung_dsim *dsi, writel(driver_data->reg_values[PLL_TIMER], dsi->reg_base + driver_data->plltmr_reg); - reg = DSIM_PLL_EN | DSIM_PLL_P(p, driver_data->pll_p_offset) | - DSIM_PLL_M(m) | DSIM_PLL_S(s); + reg = DSIM_PLL_EN | DSIM_PLL(p, driver_data->pll_p_offset) + | DSIM_PLL(m, driver_data->pll_m_offset) + | DSIM_PLL(s, driver_data->pll_s_offset); if (driver_data->has_freqband) { static const unsigned long freq_bands[] = { diff --git a/include/drm/bridge/samsung-dsim.h b/include/drm/bridge/samsung-dsim.h index 9d11c3e39fe5..000ada3ece4d 100644 --- a/include/drm/bridge/samsung-dsim.h +++ b/include/drm/bridge/samsung-dsim.h @@ -71,6 +71,8 @@ struct samsung_dsim_driver_data { unsigned int lane_esc_clk_bit; unsigned int lane_esc_data_offset; unsigned int pll_p_offset; + unsigned int pll_m_offset; + unsigned int pll_s_offset; unsigned int main_vsa_offset; const unsigned int *reg_values; unsigned int pll_fin_min; From f7754d843a05c685ba453be176a29ae157f88b0c Mon Sep 17 00:00:00 2001 From: Kaustabh Chakraborty Date: Sun, 6 Jul 2025 23:55:42 +0530 Subject: [PATCH 08/12] drm/bridge: samsung-dsim: allow configuring the PLL_STABLE bit The PLL_STABLE bit of DSIM_DPHY_STATUS is hardcoded to BIT(31), but Exynos7870's DSIM has it in BIT(24) as per downstream kernel sources. In order to support both, move this bit value to the driver data struct and define it for every driver compatible. Reference the value from there instead, in functions wherever required. Signed-off-by: Kaustabh Chakraborty Signed-off-by: Inki Dae --- drivers/gpu/drm/bridge/samsung-dsim.c | 9 +++++++-- include/drm/bridge/samsung-dsim.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index 2884b3b7dc73..456d961abc05 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -35,7 +35,6 @@ #define DSIM_STOP_STATE_DAT(x) (((x) & 0xf) << 0) #define DSIM_STOP_STATE_CLK BIT(8) #define DSIM_TX_READY_HS_CLK BIT(10) -#define DSIM_PLL_STABLE BIT(31) /* DSIM_SWRST */ #define DSIM_FUNCRST BIT(16) @@ -415,6 +414,7 @@ static const struct samsung_dsim_driver_data exynos3_dsi_driver_data = { .wait_for_reset = 1, .num_bits_resol = 11, .video_mode_bit = 25, + .pll_stable_bit = 31, .esc_clken_bit = 28, .byte_clken_bit = 24, .tx_req_hsclk_bit = 31, @@ -445,6 +445,7 @@ static const struct samsung_dsim_driver_data exynos4_dsi_driver_data = { .wait_for_reset = 1, .num_bits_resol = 11, .video_mode_bit = 25, + .pll_stable_bit = 31, .esc_clken_bit = 28, .byte_clken_bit = 24, .tx_req_hsclk_bit = 31, @@ -473,6 +474,7 @@ static const struct samsung_dsim_driver_data exynos5_dsi_driver_data = { .wait_for_reset = 1, .num_bits_resol = 11, .video_mode_bit = 25, + .pll_stable_bit = 31, .esc_clken_bit = 28, .byte_clken_bit = 24, .tx_req_hsclk_bit = 31, @@ -501,6 +503,7 @@ static const struct samsung_dsim_driver_data exynos5433_dsi_driver_data = { .wait_for_reset = 0, .num_bits_resol = 12, .video_mode_bit = 25, + .pll_stable_bit = 31, .esc_clken_bit = 28, .byte_clken_bit = 24, .tx_req_hsclk_bit = 31, @@ -529,6 +532,7 @@ static const struct samsung_dsim_driver_data exynos5422_dsi_driver_data = { .wait_for_reset = 1, .num_bits_resol = 12, .video_mode_bit = 25, + .pll_stable_bit = 31, .esc_clken_bit = 28, .byte_clken_bit = 24, .tx_req_hsclk_bit = 31, @@ -557,6 +561,7 @@ static const struct samsung_dsim_driver_data imx8mm_dsi_driver_data = { .wait_for_reset = 0, .num_bits_resol = 12, .video_mode_bit = 25, + .pll_stable_bit = 31, .esc_clken_bit = 28, .byte_clken_bit = 24, .tx_req_hsclk_bit = 31, @@ -760,7 +765,7 @@ static unsigned long samsung_dsim_set_pll(struct samsung_dsim *dsi, reg = samsung_dsim_read(dsi, DSIM_STATUS_REG); else reg = samsung_dsim_read(dsi, DSIM_LINK_STATUS_REG); - } while ((reg & DSIM_PLL_STABLE) == 0); + } while ((reg & BIT(driver_data->pll_stable_bit)) == 0); dsi->hs_clock = fout; diff --git a/include/drm/bridge/samsung-dsim.h b/include/drm/bridge/samsung-dsim.h index 000ada3ece4d..04ed11787bbd 100644 --- a/include/drm/bridge/samsung-dsim.h +++ b/include/drm/bridge/samsung-dsim.h @@ -65,6 +65,7 @@ struct samsung_dsim_driver_data { unsigned int wait_for_reset; unsigned int num_bits_resol; unsigned int video_mode_bit; + unsigned int pll_stable_bit; unsigned int esc_clken_bit; unsigned int byte_clken_bit; unsigned int tx_req_hsclk_bit; From 7ef93667ab19370a2a05b8dbcad36d76b887ff38 Mon Sep 17 00:00:00 2001 From: Kaustabh Chakraborty Date: Sun, 6 Jul 2025 23:55:43 +0530 Subject: [PATCH 09/12] drm/bridge: samsung-dsim: increase timeout value for PLL_STABLE Exynos7870's DSIM requires more time to stabilize its PLL. The current timeout value, 1000, doesn't suffice. Increase the value to 3000, which is just about enough as observed experimentally. Signed-off-by: Kaustabh Chakraborty Signed-off-by: Inki Dae --- drivers/gpu/drm/bridge/samsung-dsim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index 456d961abc05..2e422f3ec103 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -755,7 +755,7 @@ static unsigned long samsung_dsim_set_pll(struct samsung_dsim *dsi, samsung_dsim_write(dsi, DSIM_PLLCTRL_REG, reg); - timeout = 1000; + timeout = 3000; do { if (timeout-- == 0) { dev_err(dsi->dev, "PLL failed to stabilize\n"); From f08051a4158fec363e1f33b75dd48131f524fa5f Mon Sep 17 00:00:00 2001 From: Kaustabh Chakraborty Date: Sun, 6 Jul 2025 23:55:44 +0530 Subject: [PATCH 10/12] drm/bridge: samsung-dsim: add ability to define clock names for every variant Presently, all devices refer to clock names from a single array. The only controlling parameter is the number of clocks (num_clks field of samsung_dsim_driver_data) which uses the first n clocks of that array. As new devices are added, this approach turns out to be cumbersome. Separate the clock names in individual arrays required by each variant, in a struct clk_bulk_data. Add a pointer field to the driver data struct which points to their respective clock names, and rework the clock usage code to use the clk_bulk_* API instead. Signed-off-by: Kaustabh Chakraborty Signed-off-by: Inki Dae --- drivers/gpu/drm/bridge/samsung-dsim.c | 88 +++++++++++++-------------- include/drm/bridge/samsung-dsim.h | 2 +- 2 files changed, 44 insertions(+), 46 deletions(-) diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index 2e422f3ec103..802164e6adff 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -219,23 +219,31 @@ #define DSI_XFER_TIMEOUT_MS 100 #define DSI_RX_FIFO_EMPTY 0x30800002 -#define OLD_SCLK_MIPI_CLK_NAME "pll_clk" - #define PS_TO_CYCLE(ps, hz) DIV64_U64_ROUND_CLOSEST(((ps) * (hz)), 1000000000000ULL) -static const char *const clk_names[5] = { - "bus_clk", - "sclk_mipi", - "phyclk_mipidphy0_bitclkdiv8", - "phyclk_mipidphy0_rxclkesc0", - "sclk_rgb_vclk_to_dsim0" -}; - enum samsung_dsim_transfer_type { EXYNOS_DSI_TX, EXYNOS_DSI_RX, }; +static struct clk_bulk_data exynos3_clk_bulk_data[] = { + { .id = "bus_clk" }, + { .id = "pll_clk" }, +}; + +static struct clk_bulk_data exynos4_clk_bulk_data[] = { + { .id = "bus_clk" }, + { .id = "sclk_mipi" }, +}; + +static struct clk_bulk_data exynos5433_clk_bulk_data[] = { + { .id = "bus_clk" }, + { .id = "sclk_mipi" }, + { .id = "phyclk_mipidphy0_bitclkdiv8" }, + { .id = "phyclk_mipidphy0_rxclkesc0" }, + { .id = "sclk_rgb_vclk_to_dsim0" }, +}; + enum reg_idx { DSIM_STATUS_REG, /* Status register (legacy) */ DSIM_LINK_STATUS_REG, /* Link status register */ @@ -408,7 +416,8 @@ static const struct samsung_dsim_driver_data exynos3_dsi_driver_data = { .has_legacy_status_reg = 1, .has_freqband = 1, .has_clklane_stop = 1, - .num_clks = 2, + .clk_data = exynos3_clk_bulk_data, + .num_clks = ARRAY_SIZE(exynos3_clk_bulk_data), .max_freq = 1000, .wait_for_hdr_fifo = 1, .wait_for_reset = 1, @@ -439,7 +448,8 @@ static const struct samsung_dsim_driver_data exynos4_dsi_driver_data = { .has_legacy_status_reg = 1, .has_freqband = 1, .has_clklane_stop = 1, - .num_clks = 2, + .clk_data = exynos4_clk_bulk_data, + .num_clks = ARRAY_SIZE(exynos4_clk_bulk_data), .max_freq = 1000, .wait_for_hdr_fifo = 1, .wait_for_reset = 1, @@ -468,7 +478,8 @@ static const struct samsung_dsim_driver_data exynos5_dsi_driver_data = { .reg_ofs = exynos_reg_ofs, .plltmr_reg = 0x58, .has_legacy_status_reg = 1, - .num_clks = 2, + .clk_data = exynos3_clk_bulk_data, + .num_clks = ARRAY_SIZE(exynos3_clk_bulk_data), .max_freq = 1000, .wait_for_hdr_fifo = 1, .wait_for_reset = 1, @@ -497,7 +508,8 @@ static const struct samsung_dsim_driver_data exynos5433_dsi_driver_data = { .plltmr_reg = 0xa0, .has_legacy_status_reg = 1, .has_clklane_stop = 1, - .num_clks = 5, + .clk_data = exynos5433_clk_bulk_data, + .num_clks = ARRAY_SIZE(exynos5433_clk_bulk_data), .max_freq = 1500, .wait_for_hdr_fifo = 1, .wait_for_reset = 0, @@ -526,7 +538,8 @@ static const struct samsung_dsim_driver_data exynos5422_dsi_driver_data = { .plltmr_reg = 0xa0, .has_legacy_status_reg = 1, .has_clklane_stop = 1, - .num_clks = 2, + .clk_data = exynos3_clk_bulk_data, + .num_clks = ARRAY_SIZE(exynos3_clk_bulk_data), .max_freq = 1500, .wait_for_hdr_fifo = 1, .wait_for_reset = 1, @@ -555,7 +568,8 @@ static const struct samsung_dsim_driver_data imx8mm_dsi_driver_data = { .plltmr_reg = 0xa0, .has_legacy_status_reg = 1, .has_clklane_stop = 1, - .num_clks = 2, + .clk_data = exynos4_clk_bulk_data, + .num_clks = ARRAY_SIZE(exynos4_clk_bulk_data), .max_freq = 2100, .wait_for_hdr_fifo = 1, .wait_for_reset = 0, @@ -2021,7 +2035,7 @@ int samsung_dsim_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct samsung_dsim *dsi; - int ret, i; + int ret; dsi = devm_drm_bridge_alloc(dev, struct samsung_dsim, bridge, &samsung_dsim_bridge_funcs); if (IS_ERR(dsi)) @@ -2045,23 +2059,11 @@ int samsung_dsim_probe(struct platform_device *pdev) if (ret) return dev_err_probe(dev, ret, "failed to get regulators\n"); - dsi->clks = devm_kcalloc(dev, dsi->driver_data->num_clks, - sizeof(*dsi->clks), GFP_KERNEL); - if (!dsi->clks) - return -ENOMEM; - - for (i = 0; i < dsi->driver_data->num_clks; i++) { - dsi->clks[i] = devm_clk_get(dev, clk_names[i]); - if (IS_ERR(dsi->clks[i])) { - if (strcmp(clk_names[i], "sclk_mipi") == 0) { - dsi->clks[i] = devm_clk_get(dev, OLD_SCLK_MIPI_CLK_NAME); - if (!IS_ERR(dsi->clks[i])) - continue; - } - - dev_info(dev, "failed to get the clock: %s\n", clk_names[i]); - return PTR_ERR(dsi->clks[i]); - } + ret = devm_clk_bulk_get(dev, dsi->driver_data->num_clks, + dsi->driver_data->clk_data); + if (ret) { + dev_err(dev, "failed to get clocks in bulk (%d)\n", ret); + return ret; } dsi->reg_base = devm_platform_ioremap_resource(pdev, 0); @@ -2134,7 +2136,7 @@ static int samsung_dsim_suspend(struct device *dev) { struct samsung_dsim *dsi = dev_get_drvdata(dev); const struct samsung_dsim_driver_data *driver_data = dsi->driver_data; - int ret, i; + int ret; usleep_range(10000, 20000); @@ -2150,8 +2152,7 @@ static int samsung_dsim_suspend(struct device *dev) phy_power_off(dsi->phy); - for (i = driver_data->num_clks - 1; i > -1; i--) - clk_disable_unprepare(dsi->clks[i]); + clk_bulk_disable_unprepare(driver_data->num_clks, driver_data->clk_data); ret = regulator_bulk_disable(ARRAY_SIZE(dsi->supplies), dsi->supplies); if (ret < 0) @@ -2164,7 +2165,7 @@ static int samsung_dsim_resume(struct device *dev) { struct samsung_dsim *dsi = dev_get_drvdata(dev); const struct samsung_dsim_driver_data *driver_data = dsi->driver_data; - int ret, i; + int ret; ret = regulator_bulk_enable(ARRAY_SIZE(dsi->supplies), dsi->supplies); if (ret < 0) { @@ -2172,11 +2173,9 @@ static int samsung_dsim_resume(struct device *dev) return ret; } - for (i = 0; i < driver_data->num_clks; i++) { - ret = clk_prepare_enable(dsi->clks[i]); - if (ret < 0) - goto err_clk; - } + ret = clk_bulk_prepare_enable(driver_data->num_clks, driver_data->clk_data); + if (ret < 0) + goto err_clk; ret = phy_power_on(dsi->phy); if (ret < 0) { @@ -2187,8 +2186,7 @@ static int samsung_dsim_resume(struct device *dev) return 0; err_clk: - while (--i > -1) - clk_disable_unprepare(dsi->clks[i]); + clk_bulk_disable_unprepare(driver_data->num_clks, driver_data->clk_data); regulator_bulk_disable(ARRAY_SIZE(dsi->supplies), dsi->supplies); return ret; diff --git a/include/drm/bridge/samsung-dsim.h b/include/drm/bridge/samsung-dsim.h index 04ed11787bbd..eb9fdbab1b34 100644 --- a/include/drm/bridge/samsung-dsim.h +++ b/include/drm/bridge/samsung-dsim.h @@ -58,6 +58,7 @@ struct samsung_dsim_driver_data { unsigned int has_clklane_stop:1; unsigned int has_broken_fifoctrl_emptyhdr:1; unsigned int has_sfrctrl:1; + struct clk_bulk_data *clk_data; unsigned int num_clks; unsigned int min_freq; unsigned int max_freq; @@ -104,7 +105,6 @@ struct samsung_dsim { void __iomem *reg_base; struct phy *phy; - struct clk **clks; struct clk *pll_clk; struct regulator_bulk_data supplies[2]; int irq; From 7f8d35b589c9f6acda0e36b184c193d38f092c36 Mon Sep 17 00:00:00 2001 From: Kaustabh Chakraborty Date: Sun, 6 Jul 2025 23:55:45 +0530 Subject: [PATCH 11/12] dt-bindings: samsung,mipi-dsim: document exynos7870 DSIM compatible Add compatible string for Exynos7870 DSIM bridge controller. The device requires four clock sources, in schema they're named as "bus", "pll", "byte", and "esc". Suggested-by: Krzysztof Kozlowski Reviewed-by: Rob Herring (Arm) Signed-off-by: Kaustabh Chakraborty Signed-off-by: Inki Dae --- .../display/bridge/samsung,mipi-dsim.yaml | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/Documentation/devicetree/bindings/display/bridge/samsung,mipi-dsim.yaml b/Documentation/devicetree/bindings/display/bridge/samsung,mipi-dsim.yaml index 1acad99f3965..ad279f0993fa 100644 --- a/Documentation/devicetree/bindings/display/bridge/samsung,mipi-dsim.yaml +++ b/Documentation/devicetree/bindings/display/bridge/samsung,mipi-dsim.yaml @@ -24,6 +24,7 @@ properties: - samsung,exynos5410-mipi-dsi - samsung,exynos5422-mipi-dsi - samsung,exynos5433-mipi-dsi + - samsung,exynos7870-mipi-dsi - fsl,imx8mm-mipi-dsim - fsl,imx8mp-mipi-dsim - items: @@ -144,6 +145,32 @@ required: allOf: - $ref: ../dsi-controller.yaml# + - if: + properties: + compatible: + contains: + const: samsung,exynos7870-mipi-dsi + + then: + properties: + clocks: + minItems: 4 + maxItems: 4 + + clock-names: + items: + - const: bus + - const: pll + - const: byte + - const: esc + + ports: + required: + - port@0 + + required: + - ports + - if: properties: compatible: From 77169a11d4e9916f6c22587df396d6128505dbfb Mon Sep 17 00:00:00 2001 From: Kaustabh Chakraborty Date: Sun, 6 Jul 2025 23:55:46 +0530 Subject: [PATCH 12/12] drm/bridge: samsung-dsim: add driver support for exynos7870 DSIM bridge Add support for Exynos7870's DSIM IP block in the bridge driver. Signed-off-by: Kaustabh Chakraborty Signed-off-by: Inki Dae --- drivers/gpu/drm/bridge/samsung-dsim.c | 82 +++++++++++++++++++++++++++ include/drm/bridge/samsung-dsim.h | 1 + 2 files changed, 83 insertions(+) diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index 802164e6adff..eabc4c32f6ab 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -244,6 +244,13 @@ static struct clk_bulk_data exynos5433_clk_bulk_data[] = { { .id = "sclk_rgb_vclk_to_dsim0" }, }; +static struct clk_bulk_data exynos7870_clk_bulk_data[] = { + { .id = "bus" }, + { .id = "pll" }, + { .id = "byte" }, + { .id = "esc" }, +}; + enum reg_idx { DSIM_STATUS_REG, /* Status register (legacy) */ DSIM_LINK_STATUS_REG, /* Link status register */ @@ -320,6 +327,32 @@ static const unsigned int exynos5433_reg_ofs[] = { [DSIM_PHYTIMING2_REG] = 0xBC, }; +static const unsigned int exynos7870_reg_ofs[] = { + [DSIM_LINK_STATUS_REG] = 0x04, + [DSIM_DPHY_STATUS_REG] = 0x08, + [DSIM_SWRST_REG] = 0x0C, + [DSIM_CLKCTRL_REG] = 0x10, + [DSIM_TIMEOUT_REG] = 0x14, + [DSIM_ESCMODE_REG] = 0x1C, + [DSIM_MDRESOL_REG] = 0x20, + [DSIM_MVPORCH_REG] = 0x24, + [DSIM_MHPORCH_REG] = 0x28, + [DSIM_MSYNC_REG] = 0x2C, + [DSIM_CONFIG_REG] = 0x30, + [DSIM_INTSRC_REG] = 0x34, + [DSIM_INTMSK_REG] = 0x38, + [DSIM_PKTHDR_REG] = 0x3C, + [DSIM_PAYLOAD_REG] = 0x40, + [DSIM_RXFIFO_REG] = 0x44, + [DSIM_SFRCTRL_REG] = 0x48, + [DSIM_FIFOCTRL_REG] = 0x4C, + [DSIM_PLLCTRL_REG] = 0x94, + [DSIM_PHYCTRL_REG] = 0xA4, + [DSIM_PHYTIMING_REG] = 0xB4, + [DSIM_PHYTIMING1_REG] = 0xB8, + [DSIM_PHYTIMING2_REG] = 0xBC, +}; + enum reg_value_idx { RESET_TYPE, PLL_TIMER, @@ -392,6 +425,24 @@ static const unsigned int exynos5433_reg_values[] = { [PHYTIMING_HS_TRAIL] = DSIM_PHYTIMING2_HS_TRAIL(0x0c), }; +static const unsigned int exynos7870_reg_values[] = { + [RESET_TYPE] = DSIM_SWRST, + [PLL_TIMER] = 80000, + [STOP_STATE_CNT] = 0xa, + [PHYCTRL_ULPS_EXIT] = DSIM_PHYCTRL_ULPS_EXIT(0x177), + [PHYCTRL_VREG_LP] = 0, + [PHYCTRL_SLEW_UP] = 0, + [PHYTIMING_LPX] = DSIM_PHYTIMING_LPX(0x07), + [PHYTIMING_HS_EXIT] = DSIM_PHYTIMING_HS_EXIT(0x0c), + [PHYTIMING_CLK_PREPARE] = DSIM_PHYTIMING1_CLK_PREPARE(0x08), + [PHYTIMING_CLK_ZERO] = DSIM_PHYTIMING1_CLK_ZERO(0x2b), + [PHYTIMING_CLK_POST] = DSIM_PHYTIMING1_CLK_POST(0x0d), + [PHYTIMING_CLK_TRAIL] = DSIM_PHYTIMING1_CLK_TRAIL(0x09), + [PHYTIMING_HS_PREPARE] = DSIM_PHYTIMING2_HS_PREPARE(0x09), + [PHYTIMING_HS_ZERO] = DSIM_PHYTIMING2_HS_ZERO(0x0f), + [PHYTIMING_HS_TRAIL] = DSIM_PHYTIMING2_HS_TRAIL(0x0c), +}; + static const unsigned int imx8mm_dsim_reg_values[] = { [RESET_TYPE] = DSIM_SWRST, [PLL_TIMER] = 500, @@ -563,6 +614,36 @@ static const struct samsung_dsim_driver_data exynos5422_dsi_driver_data = { .min_freq = 500, }; +static const struct samsung_dsim_driver_data exynos7870_dsi_driver_data = { + .reg_ofs = exynos7870_reg_ofs, + .plltmr_reg = 0xa0, + .has_clklane_stop = 1, + .has_sfrctrl = 1, + .clk_data = exynos7870_clk_bulk_data, + .num_clks = ARRAY_SIZE(exynos7870_clk_bulk_data), + .max_freq = 1500, + .wait_for_hdr_fifo = 0, + .wait_for_reset = 1, + .num_bits_resol = 12, + .video_mode_bit = 18, + .pll_stable_bit = 24, + .esc_clken_bit = 16, + .byte_clken_bit = 17, + .tx_req_hsclk_bit = 20, + .lane_esc_clk_bit = 8, + .lane_esc_data_offset = 9, + .pll_p_offset = 13, + .pll_m_offset = 3, + .pll_s_offset = 0, + .main_vsa_offset = 16, + .reg_values = exynos7870_reg_values, + .pll_fin_min = 6, + .pll_fin_max = 12, + .m_min = 41, + .m_max = 125, + .min_freq = 500, +}; + static const struct samsung_dsim_driver_data imx8mm_dsi_driver_data = { .reg_ofs = exynos5433_reg_ofs, .plltmr_reg = 0xa0, @@ -604,6 +685,7 @@ samsung_dsim_types[DSIM_TYPE_COUNT] = { [DSIM_TYPE_EXYNOS5410] = &exynos5_dsi_driver_data, [DSIM_TYPE_EXYNOS5422] = &exynos5422_dsi_driver_data, [DSIM_TYPE_EXYNOS5433] = &exynos5433_dsi_driver_data, + [DSIM_TYPE_EXYNOS7870] = &exynos7870_dsi_driver_data, [DSIM_TYPE_IMX8MM] = &imx8mm_dsi_driver_data, [DSIM_TYPE_IMX8MP] = &imx8mm_dsi_driver_data, }; diff --git a/include/drm/bridge/samsung-dsim.h b/include/drm/bridge/samsung-dsim.h index eb9fdbab1b34..31d7ed589233 100644 --- a/include/drm/bridge/samsung-dsim.h +++ b/include/drm/bridge/samsung-dsim.h @@ -29,6 +29,7 @@ enum samsung_dsim_type { DSIM_TYPE_EXYNOS5410, DSIM_TYPE_EXYNOS5422, DSIM_TYPE_EXYNOS5433, + DSIM_TYPE_EXYNOS7870, DSIM_TYPE_IMX8MM, DSIM_TYPE_IMX8MP, DSIM_TYPE_COUNT,