Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion drivers/clock_control/clock_stm32_ll_u5.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ int enabled_clock(uint32_t src_clk)
((src_clk == STM32_SRC_PLL2_R) && IS_ENABLED(STM32_PLL2_R_ENABLED)) ||
((src_clk == STM32_SRC_PLL3_P) && IS_ENABLED(STM32_PLL3_P_ENABLED)) ||
((src_clk == STM32_SRC_PLL3_Q) && IS_ENABLED(STM32_PLL3_Q_ENABLED)) ||
((src_clk == STM32_SRC_PLL3_R) && IS_ENABLED(STM32_PLL3_R_ENABLED))) {
((src_clk == STM32_SRC_PLL3_R) && IS_ENABLED(STM32_PLL3_R_ENABLED)) ||
(src_clk == STM32_SRC_DSIPHY)) {
return 0;
}

Expand Down
77 changes: 75 additions & 2 deletions drivers/mipi_dsi/dsi_stm32.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ struct mipi_dsi_stm32_config {
const struct device *rcc;
const struct reset_dt_spec reset;
struct stm32_pclken dsi_clk;
struct stm32_pclken dsisrc_clk;
struct stm32_pclken ref_clk;
struct stm32_pclken pix_clk;
uint32_t data_lanes;
Expand All @@ -56,6 +57,27 @@ struct mipi_dsi_stm32_data {
uint32_t pixel_clk_khz;
};

#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32u5_mipi_dsi)
/* Configures DSI PHY as DSI clock source (STM32U5 specific) */
static int stm32_dsi_clock_source_config(const struct device *dev)
{
const struct mipi_dsi_stm32_config *config = dev->config;
int ret;

ret = clock_control_configure(config->rcc, (clock_control_subsys_t)&config->dsisrc_clk,
NULL);
if (ret < 0) {
LOG_ERR("Failed to configure DSI clock source (%d)", ret);
return ret;
}

LOG_DBG("DSI kernel clock source selection, RCC_CCIPR2_DSIHOSTSEL: %u",
__HAL_RCC_GET_DSI_SOURCE() == RCC_DSICLKSOURCE_DSIPHY);

return 0;
}
#endif

static void mipi_dsi_stm32_log_config(const struct device *dev)
{
const struct mipi_dsi_stm32_config *config = dev->config;
Expand All @@ -66,9 +88,20 @@ static void mipi_dsi_stm32_log_config(const struct device *dev)
LOG_DBG(" AutomaticClockLaneControl 0x%x", data->hdsi.Init.AutomaticClockLaneControl);
LOG_DBG(" TXEscapeCkdiv %u", data->hdsi.Init.TXEscapeCkdiv);
LOG_DBG(" NumberOfLanes %u", data->hdsi.Init.NumberOfLanes);
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32u5_mipi_dsi)
LOG_DBG(" PHYFrequencyRange 0x%x", data->hdsi.Init.PHYFrequencyRange);
LOG_DBG(" PHYLowPowerOffset 0x%x", data->hdsi.Init.PHYLowPowerOffset);
#endif

LOG_DBG("PLLInit configuration:");
LOG_DBG(" PLLNDIV %u", data->pll_init.PLLNDIV);
LOG_DBG(" PLLIDF %u", data->pll_init.PLLIDF);
LOG_DBG(" PLLODF %u", data->pll_init.PLLODF);
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32u5_mipi_dsi)
LOG_DBG(" PLLVCORange 0x%x", data->pll_init.PLLVCORange);
LOG_DBG(" PLLChargePump 0x%x", data->pll_init.PLLChargePump);
LOG_DBG(" PLLTuning 0x%x", data->pll_init.PLLTuning);
#endif

LOG_DBG("HAL_DSI_ConfigVideoMode setup:");
LOG_DBG(" VirtualChannelID %u", data->vid_cfg.VirtualChannelID);
Expand Down Expand Up @@ -167,9 +200,15 @@ static int mipi_dsi_stm32_host_init(const struct device *dev)
return ret;
}

#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32u5_mipi_dsi)
/* LANE_BYTE_CLOCK = CLK_IN / PLLIDF * 2 * PLLNDIV / PLLODF / 8 */
data->lane_clk_khz = hse_clock / data->pll_init.PLLIDF * 2 * data->pll_init.PLLNDIV /
data->pll_init.PLLODF / 8 / 1000;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This highlight a change in the way to define pll-odf between U5 and other platforms. Considering that it is defined the same way in the DT yaml, I don't think it should be used differently between the U5 series and other series.
(or it should be highlighted why this is needed, and highlight in the yaml).
Could you share you dts configuration of your mipi-dsi node for this U5 ?
I haven't check the U5 DSI spec, why lane clock freq calculation has to be different between series ?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having checked the HAL code, my understanding is that PLLODF can have a value going from 1 to 9 (1 being divide by 1). So This seems to be ok as far as INIT is concerned, however the real divider factor a 1 << ODF

I am actually wondering if the original computation is correct ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @avolmat-st. Thanks for your review.

Please, take a look at the dts configuration here #94423

The lane_clk_khz calculation described in document AN4860 Rev 4 page 75 is different from what is described in RM0456 Rev 6 page 1782 as PHI. Additionally, this is also aligned with the STM32CudeIDE representation. Please let me know if I understood wrong.

AN4860 Rev 4 page 75
image

RM0456 Rev 6 page 1782
image

STM32CudeIDE for H7
image

STM32CudeIDE for U5
image

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @CharlesDias for the clarification. I didn't notice that important different. It make senses then.
U5 support is ok I think then. What might have to be reworked is thus more the H7 rather than the U5 in fact since in case of H7, the PLLODF is not really giving the divider factor by the value to be written into the register, which is not the divider factor. But that is not part of this PR.

#else
/* LANE_BYTE_CLOCK = CLK_IN / PLLIDF * 2 * PLLNDIV / 2 / PLLODF / 8 */
data->lane_clk_khz = hse_clock / data->pll_init.PLLIDF * 2 * data->pll_init.PLLNDIV / 2 /
(1UL << data->pll_init.PLLODF) / 8 / 1000;
#endif

/* stm32x_hal_dsi: The values 0 and 1 stop the TX_ESC clock generation */
data->hdsi.Init.TXEscapeCkdiv = 0;
Expand Down Expand Up @@ -212,13 +251,16 @@ static int mipi_dsi_stm32_host_init(const struct device *dev)
return -ret;
}

#ifndef CONFIG_SOC_SERIES_STM32U5X

Comment on lines +254 to +255
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non blocking:

Suggested change
#ifndef CONFIG_SOC_SERIES_STM32U5X
#if !DT_HAS_COMPAT_STATUS_OKAY(st_stm32u5_mipi_dsi)

if (config->lp_rx_filter_freq) {
ret = HAL_DSI_SetLowPowerRXFilter(&data->hdsi, config->lp_rx_filter_freq);
if (ret != HAL_OK) {
LOG_ERR("Setup DSI LP RX filter failed! (%d)", ret);
return -ret;
}
}
#endif

ret = HAL_DSI_ConfigErrorMonitor(&data->hdsi, config->active_errors);
if (ret != HAL_OK) {
Expand Down Expand Up @@ -289,6 +331,14 @@ static int mipi_dsi_stm32_attach(const struct device *dev, uint8_t channel,
return -ret;
}

#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32u5_mipi_dsi)
ret = stm32_dsi_clock_source_config(dev);
if (ret < 0) {
LOG_ERR("Failed to configure DSI clock source");
return ret;
}
#endif

if (IS_ENABLED(CONFIG_MIPI_DSI_LOG_LEVEL_DBG)) {
mipi_dsi_stm32_log_config(dev);
}
Expand Down Expand Up @@ -457,6 +507,12 @@ static int mipi_dsi_stm32_init(const struct device *dev)
.enr = DT_INST_CLOCKS_CELL_BY_NAME(inst, dsiclk, bits), \
.bus = DT_INST_CLOCKS_CELL_BY_NAME(inst, dsiclk, bus), \
}, \
COND_CODE_1(DT_INST_CLOCKS_HAS_NAME(inst, dsisrc), \
(.dsisrc_clk = { \
.enr = DT_INST_CLOCKS_CELL_BY_NAME(inst, dsisrc, bits), \
.bus = DT_INST_CLOCKS_CELL_BY_NAME(inst, dsisrc, bus), \
},), \
(.dsisrc_clk = {0},)) \
.ref_clk = { \
.enr = DT_INST_CLOCKS_CELL_BY_NAME(inst, refclk, bits), \
.bus = DT_INST_CLOCKS_CELL_BY_NAME(inst, refclk, bus), \
Expand All @@ -479,6 +535,13 @@ static int mipi_dsi_stm32_init(const struct device *dev)
DT_INST_PROP(inst, non_continuous) ? \
DSI_AUTO_CLK_LANE_CTRL_ENABLE : \
DSI_AUTO_CLK_LANE_CTRL_DISABLE, \
COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, phy_freq_range), \
(.PHYFrequencyRange = DT_INST_PROP(inst, phy_freq_range),),\
()) \
COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, phy_low_power_offset), \
(.PHYLowPowerOffset = \
DT_INST_PROP(inst, phy_low_power_offset),), \
()) \
}, \
}, \
.host_timeouts = COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, host_timeouts), \
Expand All @@ -494,15 +557,25 @@ static int mipi_dsi_stm32_init(const struct device *dev)
DSI_DATA_ENABLE_ACTIVE_HIGH : DSI_DATA_ENABLE_ACTIVE_LOW, \
.LooselyPacked = DT_INST_PROP(inst, loosely_packed) ? \
DSI_LOOSELY_PACKED_ENABLE : DSI_LOOSELY_PACKED_DISABLE, \
.LPLargestPacketSize = DT_INST_PROP_OR(inst, largest_packet_size, 4), \
.LPLargestPacketSize = DT_INST_PROP_OR(inst, largest_packet_size, 4), \
.LPVACTLargestPacketSize = DT_INST_PROP_OR(inst, largest_packet_size, 4), \
.FrameBTAAcknowledgeEnable = DT_INST_PROP(inst, bta_ack_disable) ? \
DSI_FBTAA_DISABLE : DSI_FBTAA_ENABLE, \
DSI_FBTAA_DISABLE : DSI_FBTAA_ENABLE, \
}, \
.pll_init = { \
.PLLNDIV = DT_INST_PROP(inst, pll_ndiv), \
.PLLIDF = DT_INST_PROP(inst, pll_idf), \
.PLLODF = DT_INST_PROP(inst, pll_odf), \
COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, pll_vco_range), \
(.PLLVCORange = DT_INST_PROP(inst, pll_vco_range),), \
()) \
COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, pll_charge_pump), \
(.PLLChargePump = \
DT_INST_PROP(inst, pll_charge_pump),), \
()) \
COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, pll_tuning), \
(.PLLTuning = DT_INST_PROP(inst, pll_tuning),), \
()) \
}, \
}; \
DEVICE_DT_INST_DEFINE(inst, &mipi_dsi_stm32_init, NULL, \
Expand Down
14 changes: 14 additions & 0 deletions dts/arm/st/u5/stm32u599.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,20 @@
status = "disabled";
};

mipi_dsi: dsihost@40016c00 {
compatible = "st,stm32u5-mipi-dsi", "st,stm32-mipi-dsi";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x40016C00 0x1000>;
clock-names = "dsiclk", "dsisrc", "refclk", "pixelclk";
clocks = <&rcc STM32_CLOCK(APB2, 27U)>,
<&rcc STM32_SRC_DSIPHY DSI_SEL(1)>,
<&rcc STM32_SRC_HSE NO_SEL>,
<&rcc STM32_SRC_PLL3_R NO_SEL>;
resets = <&rctl STM32_RESET(APB2, 27U)>;
status = "disabled";
};

xspi1: spi@420d3400 {
compatible = "st,stm32-xspi";
reg = <0x420d3400 0x400>,
Expand Down
132 changes: 132 additions & 0 deletions dts/bindings/mipi-dsi/st,stm32u5-mipi-dsi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#
# Copyright (c) 2025 Charles Dias
#
# SPDX-License-Identifier: Apache-2.0
#

description: |
STM32U5 series MIPI DSI controller.

compatible: "st,stm32u5-mipi-dsi"

include:
- name: st,stm32-mipi-dsi.yaml
property-blocklist:
- clock-names

properties:
clock-names:
type: string-array
required: true
description: |
"dsiclk" DSI clock enable.
"dsisrc" DSI clock source.
"refclk" External crystal or oscillator clock.
"pixelclk" LTDC pixel clock.
"refclk" and "pixelclk" are only used to retrieve the frequency for timing calculation.

phy-freq-range:
required: true
type: int
enum:
- 0x0
- 0x1
- 0x2
- 0x3
- 0x4
- 0x5
- 0x6
- 0x7
- 0x8
description: |
D-PHY PLL input frequency range. This is used to select the appropriate
frequency range for the D-PHY PLL operation.
0x0 : DSI_DPHY_FRANGE_80MHZ_100MHZ
0x1 : DSI_DPHY_FRANGE_100MHZ_120MHZ
0x2 : DSI_DPHY_FRANGE_120MHZ_160MHZ
0x3 : DSI_DPHY_FRANGE_160MHZ_200MHZ
0x4 : DSI_DPHY_FRANGE_200MHZ_240MHZ
0x5 : DSI_DPHY_FRANGE_240MHZ_320MHZ
0x6 : DSI_DPHY_FRANGE_320MHZ_390MHZ
0x7 : DSI_DPHY_FRANGE_390MHZ_450MHZ
0x8 : DSI_DPHY_FRANGE_450MHZ_510MHZ

phy-low-power-offset:
required: true
type: int
enum:
- 0x0
- 0x1
- 0x2
- 0x3
- 0x4
- 0x5
- 0x6
- 0x7
- 0x8
- 0x9
- 0xA
- 0xB
- 0xC
- 0xD
- 0xE
- 0xF
description: |
D-PHY low power offset configuration specific to STM32U5 series.
0x0 : PHY_LP_OFFSSET_0_CLKP (0 CLKP)
0x1 : PHY_LP_OFFSSET_1_CLKP (+1 CLKP)
0x2 : PHY_LP_OFFSSET_2_CLKP (+2 CLKP)
0x3 : PHY_LP_OFFSSET_3_CLKP (+3 CLKP)
0x4 : PHY_LP_OFFSSET_4_CLKP (+4 CLKP)
0x5 : PHY_LP_OFFSSET_5_CLKP (+5 CLKP)
0x6 : PHY_LP_OFFSSET_6_CLKP (+6 CLKP)
0x7 : PHY_LP_OFFSSET_7_CLKP (+7 CLKP)
0x8 : PHY_LP_OFFSSET_MINUS_1_CLKP (-1 CLKP)
0x9 : PHY_LP_OFFSSET_MINUS_2_CLKP (-2 CLKP)
0xA : PHY_LP_OFFSSET_MINUS_3_CLKP (-3 CLKP)
0xB : PHY_LP_OFFSSET_MINUS_4_CLKP (-4 CLKP)
0xC : PHY_LP_OFFSSET_MINUS_5_CLKP (-5 CLKP)
0xD : PHY_LP_OFFSSET_MINUS_6_CLKP (-6 CLKP)
0xE : PHY_LP_OFFSSET_MINUS_7_CLKP (-7 CLKP)
0xF : PHY_LP_OFFSSET_MINUS_8_CLKP (-8 CLKP)

pll-vco-range:
required: true
type: int
enum:
- 0x0
- 0x1
description: |
PLL VCO frequency range configuration for STM32U5 D-PHY.
0x0 : DSI_DPHY_VCO_FRANGE_500MHZ_800MHZ
0x1 : DSI_DPHY_VCO_FRANGE_800MHZ_1GHZ

pll-charge-pump:
required: true
type: int
enum:
- 0x0
- 0x1
- 0x2
- 0x3
description: |
PLL charge pump configuration for STM32U5 D-PHY.
Valid values:
0x0 : DSI_PLL_CHARGE_PUMP_2000HZ_4400HZ
0x1 : DSI_PLL_CHARGE_PUMP_4400HZ_14100HZ
0x0 : DSI_PLL_CHARGE_PUMP_14100HZ_30900HZ
0x3 : DSI_PLL_CHARGE_PUMP_30900HZ_45700HZ
0x2 : DSI_PLL_CHARGE_PUMP_45700HZ_50000HZ

pll-tuning:
required: true
type: int
enum:
- 0x0
- 0x1
- 0x2
description: |
PLL tuning parameter (loop filter) for STM32U5 D-PHY.
0x0 : DSI_PLL_LOOP_FILTER_2000HZ_4400HZ
0x1 : DSI_PLL_LOOP_FILTER_4400HZ_30900HZ
0x2 : DSI_PLL_LOOP_FILTER_30900HZ_50000HZ
4 changes: 3 additions & 1 deletion include/zephyr/dt-bindings/clock/stm32u5_clock.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
#define STM32_SRC_PLL3_P (STM32_SRC_PLL2_R + 1)
#define STM32_SRC_PLL3_Q (STM32_SRC_PLL3_P + 1)
#define STM32_SRC_PLL3_R (STM32_SRC_PLL3_Q + 1)
/** DSI PHY clock */
#define STM32_SRC_DSIPHY (STM32_SRC_PLL3_R + 1)
/** Clock muxes */
/* #define STM32_SRC_ICLK TBD */

Expand Down Expand Up @@ -89,7 +91,7 @@
#define SAE_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 11, CCIPR2_REG)
#define RNG_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 12, CCIPR2_REG)
#define SDMMC_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 14, CCIPR2_REG)
#define DSIHOST_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 15, CCIPR2_REG)
#define DSI_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 15, CCIPR2_REG)
#define USART6_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 16, CCIPR2_REG)
#define LTDC_SEL(val) STM32_DT_CLOCK_SELECT((val), 1, 18, CCIPR2_REG)
#define OCTOSPI_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 20, CCIPR2_REG)
Expand Down