2018-02-02 14:06:31

by Gabriel FERNANDEZ

[permalink] [raw]
Subject: [PATCH 00/14] Introduce STM32MP1 clock driver

From: Gabriel Fernandez <[email protected]>

This patch-set introduces clock driver for STM32MP157 based on Arm Cortex-A7.
The driver patch is splitted in several patches (by kind of clock) to facilitate
code reviewing.

Gabriel Fernandez (14):
dt-bindings: Document STM32MP1 Reset Clock Controller (RCC) bindings
dt-bindings: clock: add STM32MP1 clocks
clk: stm32mp1: Introduce STM32MP1 clock driver
clk: stm32mp1: add MP1 gate for osc hse/hsi/csi oscillators
clk: stm32mp1: add Source Clocks for PLLs
clk: stm32mp1: add PLL clocks
clk: stm32mp1: add Post-dividers for PLL
clk: stm32mp1: add Sub System clocks
clk: stm32mp1: add Kernel timers
clk: stm32mp1: add Peripheral clocks
clk: stm32mp1: add Kernel clocks
clk: stm32mp1: add RTC clock
clk: stm32mp1: add MCO clocks
clk: stm32mp1: add Debug clocks

.../devicetree/bindings/mfd/st,stm32-rcc.txt | 85 +
drivers/clk/Kconfig | 6 +
drivers/clk/Makefile | 1 +
drivers/clk/clk-stm32mp1.c | 1705 ++++++++++++++++++++
include/dt-bindings/clock/stm32mp1-clks.h | 248 +++
5 files changed, 2045 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mfd/st,stm32-rcc.txt
create mode 100644 drivers/clk/clk-stm32mp1.c
create mode 100644 include/dt-bindings/clock/stm32mp1-clks.h

--
1.9.1



2018-02-02 14:05:46

by Gabriel FERNANDEZ

[permalink] [raw]
Subject: [PATCH 09/14] clk: stm32mp1: add Kernel timers

From: Gabriel Fernandez <[email protected]>

This patch adds Kernel timers.
This patch adds timers kernel clock.
Timers are gather into two groups corresponding to the APB bus
they are attached to.
Each group has its own prescaler, managed in this patch.

Signed-off-by: Gabriel Fernandez <[email protected]>
---
drivers/clk/clk-stm32mp1.c | 185 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 185 insertions(+)

diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c
index d85c619..13d74f3 100644
--- a/drivers/clk/clk-stm32mp1.c
+++ b/drivers/clk/clk-stm32mp1.c
@@ -854,6 +854,138 @@ static struct clk_hw *clk_register_pll(struct device *dev, const char *name,
return hw;
}

+/* Kernel Timer */
+struct timer_cker {
+ /* lock the kernel output divider register */
+ spinlock_t *lock;
+ void __iomem *apbdiv;
+ void __iomem *timpre;
+ struct clk_hw hw;
+};
+
+#define to_timer_cker(_hw) container_of(_hw, struct timer_cker, hw)
+
+#define APB_DIV_MASK 0x07
+#define TIM_PRE_MASK 0x01
+
+static unsigned long __bestmult(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct timer_cker *tim_ker = to_timer_cker(hw);
+ u32 prescaler;
+ unsigned int mult = 0;
+
+ prescaler = readl_relaxed(tim_ker->apbdiv) & APB_DIV_MASK;
+ if (prescaler < 2)
+ return 1;
+
+ mult = 2;
+
+ if (rate / parent_rate >= 4)
+ mult = 4;
+
+ return mult;
+}
+
+static long timer_ker_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ unsigned long factor = __bestmult(hw, rate, *parent_rate);
+
+ return *parent_rate * factor;
+}
+
+static int timer_ker_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct timer_cker *tim_ker = to_timer_cker(hw);
+ unsigned long flags = 0;
+ unsigned long factor = __bestmult(hw, rate, parent_rate);
+ int ret = 0;
+
+ spin_lock_irqsave(tim_ker->lock, flags);
+
+ switch (factor) {
+ case 1:
+ break;
+ case 2:
+ writel_relaxed(0, tim_ker->timpre);
+ break;
+ case 4:
+ writel_relaxed(1, tim_ker->timpre);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ spin_unlock_irqrestore(tim_ker->lock, flags);
+
+ return ret;
+}
+
+static unsigned long timer_ker_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct timer_cker *tim_ker = to_timer_cker(hw);
+ u32 prescaler, timpre;
+ u32 mul;
+
+ prescaler = readl_relaxed(tim_ker->apbdiv) & APB_DIV_MASK;
+
+ timpre = readl_relaxed(tim_ker->timpre) & TIM_PRE_MASK;
+
+ if (!prescaler)
+ return parent_rate;
+
+ mul = (timpre + 1) * 2;
+
+ return parent_rate * mul;
+}
+
+static const struct clk_ops timer_ker_ops = {
+ .recalc_rate = timer_ker_recalc_rate,
+ .round_rate = timer_ker_round_rate,
+ .set_rate = timer_ker_set_rate,
+
+};
+
+static struct clk_hw *clk_register_cktim(struct device *dev, const char *name,
+ const char *parent_name,
+ unsigned long flags,
+ void __iomem *apbdiv,
+ void __iomem *timpre,
+ spinlock_t *lock)
+{
+ struct timer_cker *tim_ker;
+ struct clk_init_data init;
+ struct clk_hw *hw;
+ int err;
+
+ tim_ker = kzalloc(sizeof(*tim_ker), GFP_KERNEL);
+ if (!tim_ker)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &timer_ker_ops;
+ init.flags = flags;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ tim_ker->hw.init = &init;
+ tim_ker->lock = lock;
+ tim_ker->apbdiv = apbdiv;
+ tim_ker->timpre = timpre;
+
+ hw = &tim_ker->hw;
+ err = clk_hw_register(dev, hw);
+
+ if (err) {
+ kfree(tim_ker);
+ return ERR_PTR(err);
+ }
+
+ return hw;
+}
+
static struct clk_hw *
_clk_register_mp1_gate(struct device *dev,
struct clk_hw_onecell_data *clk_data,
@@ -887,6 +1019,23 @@ struct clk_hw *_clk_register_pll(struct device *dev,
base + stm_pll_cfg->offset, cfg->flags, lock);
}

+struct stm32_cktim_cfg {
+ u32 offset_apbdiv;
+ u32 offset_timpre;
+};
+
+static struct clk_hw *_clk_register_cktim(struct device *dev,
+ struct clk_hw_onecell_data *clk_data,
+ void __iomem *base, spinlock_t *lock,
+ const struct clock_config *cfg)
+{
+ struct stm32_cktim_cfg *cktim_cfg = cfg->cfg;
+
+ return clk_register_cktim(dev, cfg->name, cfg->parent_name, cfg->flags,
+ cktim_cfg->offset_apbdiv + base,
+ cktim_cfg->offset_timpre + base, lock);
+}
+
#define GATE(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\
{\
.id = _id,\
@@ -1056,6 +1205,23 @@ struct clk_hw *_clk_register_pll(struct device *dev,
.func = _clk_register_pll,\
}

+#define STM32_CKTIM(_name, _parent, _flags, _offset_apbdiv, _offset_timpre)\
+{\
+ .id = NO_ID,\
+ .name = _name,\
+ .parent_name = _parent,\
+ .flags = _flags,\
+ .cfg = &(struct stm32_cktim_cfg) {\
+ .offset_apbdiv = _offset_apbdiv,\
+ .offset_timpre = _offset_timpre,\
+ },\
+ .func = _clk_register_cktim,\
+}
+
+#define STM32_TIM(_id, _name, _parent, _offset_set, _bit_idx)\
+ MP1_GATE(_id, _name, _parent, CLK_SET_RATE_PARENT,\
+ _offset_set, _bit_idx, 0)
+
static const struct clock_config stm32mp1_clock_cfg[] = {
/* Oscillator divider */
DIV(NO_ID, "clk-hsi-div", "clk-hsi", 0, RCC_HSICFGR, 0, 2,
@@ -1152,6 +1318,25 @@ struct clk_hw *_clk_register_pll(struct device *dev,

DIV_TABLE(NO_ID, "pclk5", "ck_axi", CLK_IGNORE_UNUSED, RCC_APB5DIVR, 0,
3, CLK_DIVIDER_READ_ONLY, apb_div_table),
+
+ /* Kernel Timers */
+ STM32_CKTIM("ck1_tim", "pclk1", 0, RCC_APB1DIVR, RCC_TIMG1PRER),
+ STM32_CKTIM("ck2_tim", "pclk2", 0, RCC_APB2DIVR, RCC_TIMG2PRER),
+
+ STM32_TIM(TIM2_K, "tim2_k", "ck1_tim", RCC_APB1ENSETR, 0),
+ STM32_TIM(TIM3_K, "tim3_k", "ck1_tim", RCC_APB1ENSETR, 1),
+ STM32_TIM(TIM4_K, "tim4_k", "ck1_tim", RCC_APB1ENSETR, 2),
+ STM32_TIM(TIM5_K, "tim5_k", "ck1_tim", RCC_APB1ENSETR, 3),
+ STM32_TIM(TIM6_K, "tim6_k", "ck1_tim", RCC_APB1ENSETR, 4),
+ STM32_TIM(TIM7_K, "tim7_k", "ck1_tim", RCC_APB1ENSETR, 5),
+ STM32_TIM(TIM12_K, "tim12_k", "ck1_tim", RCC_APB1ENSETR, 6),
+ STM32_TIM(TIM13_K, "tim13_k", "ck1_tim", RCC_APB1ENSETR, 7),
+ STM32_TIM(TIM14_K, "tim14_k", "ck1_tim", RCC_APB1ENSETR, 8),
+ STM32_TIM(TIM1_K, "tim1_k", "ck2_tim", RCC_APB2ENSETR, 0),
+ STM32_TIM(TIM8_K, "tim8_k", "ck2_tim", RCC_APB2ENSETR, 1),
+ STM32_TIM(TIM15_K, "tim15_k", "ck2_tim", RCC_APB2ENSETR, 2),
+ STM32_TIM(TIM16_K, "tim16_k", "ck2_tim", RCC_APB2ENSETR, 3),
+ STM32_TIM(TIM17_K, "tim17_k", "ck2_tim", RCC_APB2ENSETR, 4),
};

struct stm32_clock_match_data {
--
1.9.1


2018-02-02 14:06:20

by Gabriel FERNANDEZ

[permalink] [raw]
Subject: [PATCH 13/14] clk: stm32mp1: add MCO clocks

From: Gabriel Fernandez <[email protected]>

Two micro-controller clock output (MCO) pins are available: MCO1 and MCO2.
For each output, it is possible to select a clock source.
The selected clock can be divided thanks to configurable prescaler.

Signed-off-by: Gabriel Fernandez <[email protected]>
---
drivers/clk/clk-stm32mp1.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)

diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c
index 1cb06b0..0402a0e 100644
--- a/drivers/clk/clk-stm32mp1.c
+++ b/drivers/clk/clk-stm32mp1.c
@@ -1188,6 +1188,16 @@ static struct clk_hw *_clk_register_cktim(struct device *dev,
_MUX(_mux_offset, _mux_bit, _mux_width, 0),\
}

+#define _GATEMUXDIV(_gate_offset, _bit_idx,\
+ _mux_offset, _mux_bit, _mux_width,\
+ _div_offset, _div_bit, _div_width\
+ )\
+{\
+ _DIV(_div_offset, _div_bit, _div_width, 0),\
+ _GATE(_gate_offset, _bit_idx, 0),\
+ _MUX(_mux_offset, _mux_bit, _mux_width, 0),\
+}
+
#define _MP1_GATE(_gate_offset, _bit_idx, _flags)\
_GATE_OPS(_gate_offset, _bit_idx, _flags, &mp1_gate_clk_ops)

@@ -1543,6 +1553,19 @@ static struct clk_hw *_clk_register_cktim(struct device *dev,
COMPOSITE(RTC, "ck_rtc", rtc_src, CLK_OPS_PARENT_ENABLE |
CLK_SET_RATE_PARENT,
_GATEMUX(RCC_BDCR, 20, RCC_BDCR, 16, 2)),
+
+ /* MCO clocks */
+ COMPOSITE(CK_MCO1, "ck_mco1", mco1_src, CLK_OPS_PARENT_ENABLE |
+ CLK_SET_RATE_NO_REPARENT,
+ _GATEMUXDIV(RCC_MCO1CFGR, 12,
+ RCC_MCO1CFGR, 0, 3,
+ RCC_MCO1CFGR, 4, 4)),
+
+ COMPOSITE(CK_MCO2, "ck_mco2", mco2_src, CLK_OPS_PARENT_ENABLE |
+ CLK_SET_RATE_NO_REPARENT,
+ _GATEMUXDIV(RCC_MCO2CFGR, 12,
+ RCC_MCO2CFGR, 0, 3,
+ RCC_MCO2CFGR, 4, 4)),
};

struct stm32_clock_match_data {
--
1.9.1


2018-02-02 14:06:35

by Gabriel FERNANDEZ

[permalink] [raw]
Subject: [PATCH 11/14] clk: stm32mp1: add Kernel clocks

From: Gabriel Fernandez <[email protected]>

Some peripherals need also a dedicated clock for their communication
interface, this clock is generally asynchronous with respect to the bus
interface clock (peripheral clock), and is named kernel clock.

Signed-off-by: Gabriel Fernandez <[email protected]>
---
drivers/clk/clk-stm32mp1.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 75 insertions(+)

diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c
index ea78a6a..5a1142c 100644
--- a/drivers/clk/clk-stm32mp1.c
+++ b/drivers/clk/clk-stm32mp1.c
@@ -1179,6 +1179,17 @@ static struct clk_hw *_clk_register_cktim(struct device *dev,
_MUX(_mux_offset, _mux_bit, _mux_width, 0),\
}

+#define _MP1_GATE(_gate_offset, _bit_idx, _flags)\
+ _GATE_OPS(_gate_offset, _bit_idx, _flags, &mp1_gate_clk_ops)
+
+#define _MP1_GATEMUX(_gate_offset, _bit_idx,\
+ _mux_offset, _mux_bit, _mux_width)\
+{\
+ _NO_DIV,\
+ _MP1_GATE(_gate_offset, _bit_idx, 0),\
+ _MUX(_mux_offset, _mux_bit, _mux_width, 0),\
+}
+
#define MP1_GATE(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\
{\
.id = _id,\
@@ -1226,6 +1237,11 @@ static struct clk_hw *_clk_register_cktim(struct device *dev,
MP1_GATE(_id, _name, _parent, _flags,\
RCC_##_reg##ENSETR, _gate_idx, 0)

+#define KCLK(_reg, _id, _bit_idx, _mux_offset, _name, _parents, _flags)\
+ COMPOSITE(_id, _name, _parents, CLK_OPS_PARENT_ENABLE | _flags,\
+ _MP1_GATEMUX(RCC_##_reg##ENSETR, _bit_idx,\
+ _mux_offset, 0, 3))
+
static const struct clock_config stm32mp1_clock_cfg[] = {
/* Oscillator divider */
DIV(NO_ID, "clk-hsi-div", "clk-hsi", 0, RCC_HSICFGR, 0, 2,
@@ -1451,6 +1467,65 @@ static struct clk_hw *_clk_register_cktim(struct device *dev,
PCLK(AHB6, CRC1, "crc1", "ck_axi", 20, 0),
PCLK(AHB6, USBH, "usbh", "ck_axi", 24, 0),
PCLK(AHB6LP, ETHSTP, "ethstp", "ck_axi", 11, 0),
+
+ /* Kernel clocks */
+ KCLK(AHB6, SDMMC1_K, 16, RCC_SDMMC12CKSELR, "sdmmc1_k", sdmmc1_src, 0),
+ KCLK(AHB6, SDMMC2_K, 17, RCC_SDMMC12CKSELR, "sdmmc2_k", sdmmc2_src, 0),
+ KCLK(AHB2, SDMMC3_K, 16, RCC_SDMMC3CKSELR, "sdmmc3_k", sdmmc3_src, 0),
+ KCLK(AHB6, FMC_K, 12, RCC_FMCCKSELR, "fmc_k", fmc_src, 0),
+ KCLK(AHB6, QSPI_K, 14, RCC_QSPICKSELR, "qspi_k", qspi_src, 0),
+ KCLK(AHB6, ETHMAC_K, 10, RCC_ETHCKSELR, "ethmac_k", eth_src, 0),
+ KCLK(AHB5, RNG1_K, 6, RCC_RNG1CKSELR, "rng1_k", rng_src, 0),
+ KCLK(AHB3, RNG2_K, 6, RCC_RNG2CKSELR, "rng2_k", rng_src, 0),
+ KCLK(APB4, USBPHY_K, 16, RCC_USBCKSELR, "usbphy_k", usbphy_src, 0),
+ KCLK(APB5, STGEN_K, 20, RCC_STGENCKSELR, "stgen_k", stgen_src,
+ CLK_IGNORE_UNUSED),
+ KCLK(APB1, SPDIF_K, 26, RCC_SPDIFCKSELR, "spdif_k", spdif_src, 0),
+ KCLK(APB2, SPI1_K, 8, RCC_SPI2S1CKSELR, "spi1_k", spi1_src, 0),
+ KCLK(APB1, SPI2_K, 11, RCC_SPI2S23CKSELR, "spi2_k", spi2_src, 0),
+ KCLK(APB1, SPI3_K, 12, RCC_SPI2S23CKSELR, "spi3_k", spi3_src, 0),
+ KCLK(APB2, SPI4_K, 9, RCC_SPI2S45CKSELR, "spi4_k", spi4_src, 0),
+ KCLK(APB2, SPI5_K, 10, RCC_SPI2S45CKSELR, "spi5_k", spi5_src, 0),
+ KCLK(APB5, SPI6_K, 0, RCC_SPI6CKSELR, "spi6_k", spi6_src, 0),
+ KCLK(APB1, CEC_K, 27, RCC_CECCKSELR, "cec_k", cec_src, 0),
+ KCLK(APB1, I2C1_K, 21, RCC_I2C12CKSELR, "i2c1_k", i2c1_src, 0),
+ KCLK(APB1, I2C2_K, 22, RCC_I2C12CKSELR, "i2c2_k", i2c2_src, 0),
+ KCLK(APB1, I2C3_K, 23, RCC_I2C35CKSELR, "i2c3_k", i2c3_src, 0),
+ KCLK(APB5, I2C4_K, 2, RCC_I2C4CKSELR, "i2c4_k", i2c4_src, 0),
+ KCLK(APB1, I2C5_K, 24, RCC_I2C35CKSELR, "i2c5_k", i2c5_src, 0),
+ KCLK(APB5, I2C6_K, 3, RCC_I2C4CKSELR, "i2c6_k", i2c6_src, 0),
+ KCLK(APB1, LPTIM1_K, 9, RCC_LPTIM1CKSELR, "lptim1_k", lptim1_src, 0),
+ KCLK(APB3, LPTIM2_K, 0, RCC_LPTIM23CKSELR, "lptim2_k", lptim2_src, 0),
+ KCLK(APB3, LPTIM3_K, 1, RCC_LPTIM23CKSELR, "lptim3_k", lptim3_src, 0),
+ KCLK(APB3, LPTIM4_K, 2, RCC_LPTIM45CKSELR, "lptim4_k", lptim4_src, 0),
+ KCLK(APB3, LPTIM5_K, 3, RCC_LPTIM45CKSELR, "lptim5_k", lptim5_src, 0),
+ KCLK(APB5, USART1_K, 4, RCC_UART1CKSELR, "usart1_k", usart1_src, 0),
+ KCLK(APB1, USART2_K, 14, RCC_UART24CKSELR, "usart2_k", usart2_src, 0),
+ KCLK(APB1, USART3_K, 15, RCC_UART35CKSELR, "usart3_k", usart3_src, 0),
+ KCLK(APB1, UART4_K, 16, RCC_UART24CKSELR, "uart4_k", uart4_src, 0),
+ KCLK(APB1, UART5_K, 17, RCC_UART35CKSELR, "uart5_k", uart5_src, 0),
+ KCLK(APB2, USART6_K, 13, RCC_UART6CKSELR, "uart6_k", usart6_src, 0),
+ KCLK(APB1, UART7_K, 18, RCC_UART78CKSELR, "uart7_k", uart7_src, 0),
+ KCLK(APB1, UART8_K, 19, RCC_UART78CKSELR, "uart8_k", uart8_src, 0),
+ KCLK(APB2, DFSDM_K, 20, RCC_DFSDMCKSELR, "dfsdm_k", dfsdm_src, 0),
+ KCLK(APB2, FDCAN_K, 24, RCC_FDCANCKSELR, "fdcan_k", fdcan_src, 0),
+ KCLK(APB2, SAI1_K, 16, RCC_SAI1CKSELR, "sai1_k", sai_src, 0),
+ KCLK(APB2, SAI2_K, 17, RCC_SAI2CKSELR, "sai2_k", sai2_src, 0),
+ KCLK(APB2, SAI3_K, 18, RCC_SAI3CKSELR, "sai3_k", sai_src, 0),
+ KCLK(APB3, SAI4_K, 8, RCC_SAI4CKSELR, "sai4_k", sai_src, 0),
+ KCLK(AHB2, ADC12_K, 5, RCC_ADCCKSELR, "adc12_k", adc12_src,
+ CLK_IGNORE_UNUSED),
+ KCLK(APB4, DSI_K, 4, RCC_DSICKSELR, "dsi_k", dsi_src, 0),
+ KCLK(APB2, ADFSDM_K, 21, RCC_SAI1CKSELR, "adfsdm_k", adfsdm_src, 0),
+
+ /* particulary Kernel clocks */
+ COMPOSITE(USBO_K, "usbo_k", usbo_src, CLK_OPS_PARENT_ENABLE,
+ _MP1_GATEMUX(RCC_AHB2ENSETR, 8, RCC_USBCKSELR, 4, 1)),
+
+ MP1_GATE(LTDC_K, "ltdc_k", "pll4_q", CLK_SET_RATE_PARENT,
+ RCC_APB4ENSETR, 0, 0),
+
+ MP1_GATE(GPU_K, "gpu_k", "pll2_q", 0, RCC_AHB6ENSETR, 5, 0),
};

struct stm32_clock_match_data {
--
1.9.1


2018-02-02 14:06:52

by Gabriel FERNANDEZ

[permalink] [raw]
Subject: [PATCH 10/14] clk: stm32mp1: add Peripheral clocks

From: Gabriel Fernandez <[email protected]>

Each peripheral requires a bus interface clock.

Signed-off-by: Gabriel Fernandez <[email protected]>
---
drivers/clk/clk-stm32mp1.c | 114 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 114 insertions(+)

diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c
index 13d74f3..ea78a6a 100644
--- a/drivers/clk/clk-stm32mp1.c
+++ b/drivers/clk/clk-stm32mp1.c
@@ -1222,6 +1222,10 @@ static struct clk_hw *_clk_register_cktim(struct device *dev,
MP1_GATE(_id, _name, _parent, CLK_SET_RATE_PARENT,\
_offset_set, _bit_idx, 0)

+#define PCLK(_reg, _id, _name, _parent, _gate_idx, _flags)\
+ MP1_GATE(_id, _name, _parent, _flags,\
+ RCC_##_reg##ENSETR, _gate_idx, 0)
+
static const struct clock_config stm32mp1_clock_cfg[] = {
/* Oscillator divider */
DIV(NO_ID, "clk-hsi-div", "clk-hsi", 0, RCC_HSICFGR, 0, 2,
@@ -1337,6 +1341,116 @@ static struct clk_hw *_clk_register_cktim(struct device *dev,
STM32_TIM(TIM15_K, "tim15_k", "ck2_tim", RCC_APB2ENSETR, 2),
STM32_TIM(TIM16_K, "tim16_k", "ck2_tim", RCC_APB2ENSETR, 3),
STM32_TIM(TIM17_K, "tim17_k", "ck2_tim", RCC_APB2ENSETR, 4),
+
+ /* Peripheral clocks */
+ PCLK(APB1, TIM2, "tim2", "pclk1", 0, CLK_IGNORE_UNUSED),
+ PCLK(APB1, TIM3, "tim3", "pclk1", 1, CLK_IGNORE_UNUSED),
+ PCLK(APB1, TIM4, "tim4", "pclk1", 2, CLK_IGNORE_UNUSED),
+ PCLK(APB1, TIM5, "tim5", "pclk1", 3, CLK_IGNORE_UNUSED),
+ PCLK(APB1, TIM6, "tim6", "pclk1", 4, CLK_IGNORE_UNUSED),
+ PCLK(APB1, TIM7, "tim7", "pclk1", 5, CLK_IGNORE_UNUSED),
+ PCLK(APB1, TIM12, "tim12", "pclk1", 6, CLK_IGNORE_UNUSED),
+ PCLK(APB1, TIM13, "tim13", "pclk1", 7, CLK_IGNORE_UNUSED),
+ PCLK(APB1, TIM14, "tim14", "pclk1", 8, CLK_IGNORE_UNUSED),
+ PCLK(APB1, LPTIM1, "lptim1", "pclk1", 9, CLK_IGNORE_UNUSED),
+ PCLK(APB1, SPI2, "spi2", "pclk1", 11, CLK_IGNORE_UNUSED),
+ PCLK(APB1, SPI3, "spi3", "pclk1", 12, CLK_IGNORE_UNUSED),
+ PCLK(APB1, USART2, "usart2", "pclk1", 14, CLK_IGNORE_UNUSED),
+ PCLK(APB1, USART3, "usart3", "pclk1", 15, CLK_IGNORE_UNUSED),
+ PCLK(APB1, UART4, "uart4", "pclk1", 16, CLK_IGNORE_UNUSED),
+ PCLK(APB1, UART5, "uart5", "pclk1", 17, CLK_IGNORE_UNUSED),
+ PCLK(APB1, UART7, "uart7", "pclk1", 18, CLK_IGNORE_UNUSED),
+ PCLK(APB1, UART8, "uart8", "pclk1", 19, CLK_IGNORE_UNUSED),
+ PCLK(APB1, I2C1, "i2c1", "pclk1", 21, CLK_IGNORE_UNUSED),
+ PCLK(APB1, I2C2, "i2c2", "pclk1", 22, CLK_IGNORE_UNUSED),
+ PCLK(APB1, I2C3, "i2c3", "pclk1", 23, CLK_IGNORE_UNUSED),
+ PCLK(APB1, I2C5, "i2c5", "pclk1", 24, CLK_IGNORE_UNUSED),
+ PCLK(APB1, SPDIF, "spdif", "pclk1", 26, CLK_IGNORE_UNUSED),
+ PCLK(APB1, CEC, "cec", "pclk1", 27, CLK_IGNORE_UNUSED),
+ PCLK(APB1, DAC12, "dac12", "pclk1", 29, 0),
+ PCLK(APB1, MDIO, "mdio", "pclk1", 31, 0),
+ PCLK(APB2, TIM1, "tim1", "pclk2", 0, CLK_IGNORE_UNUSED),
+ PCLK(APB2, TIM8, "tim8", "pclk2", 1, CLK_IGNORE_UNUSED),
+ PCLK(APB2, TIM15, "tim15", "pclk2", 2, CLK_IGNORE_UNUSED),
+ PCLK(APB2, TIM16, "tim16", "pclk2", 3, CLK_IGNORE_UNUSED),
+ PCLK(APB2, TIM17, "tim17", "pclk2", 4, CLK_IGNORE_UNUSED),
+ PCLK(APB2, SPI1, "spi1", "pclk2", 8, CLK_IGNORE_UNUSED),
+ PCLK(APB2, SPI4, "spi4", "pclk2", 9, CLK_IGNORE_UNUSED),
+ PCLK(APB2, SPI5, "spi5", "pclk2", 10, CLK_IGNORE_UNUSED),
+ PCLK(APB2, USART6, "usart6", "pclk2", 13, CLK_IGNORE_UNUSED),
+ PCLK(APB2, SAI1, "sai1", "pclk2", 16, CLK_IGNORE_UNUSED),
+ PCLK(APB2, SAI2, "sai2", "pclk2", 17, CLK_IGNORE_UNUSED),
+ PCLK(APB2, SAI3, "sai3", "pclk2", 18, CLK_IGNORE_UNUSED),
+ PCLK(APB2, DFSDM, "dfsdm", "pclk2", 20, CLK_IGNORE_UNUSED),
+ PCLK(APB2, FDCAN, "fdcan", "pclk2", 24, CLK_IGNORE_UNUSED),
+ PCLK(APB3, LPTIM2, "lptim2", "pclk3", 0, CLK_IGNORE_UNUSED),
+ PCLK(APB3, LPTIM3, "lptim3", "pclk3", 1, CLK_IGNORE_UNUSED),
+ PCLK(APB3, LPTIM4, "lptim4", "pclk3", 2, CLK_IGNORE_UNUSED),
+ PCLK(APB3, LPTIM5, "lptim5", "pclk3", 3, CLK_IGNORE_UNUSED),
+ PCLK(APB3, SAI4, "sai4", "pclk3", 8, CLK_IGNORE_UNUSED),
+ PCLK(APB3, SYSCFG, "syscfg", "pclk3", 11, 0),
+ PCLK(APB3, VREF, "vref", "pclk3", 13, 0),
+ PCLK(APB3, TMPSENS, "tmpsens", "pclk3", 16, 0),
+ PCLK(APB3, PMBCTRL, "pmbctrl", "pclk3", 17, 0),
+ PCLK(APB3, HDP, "hdp", "pclk3", 20, 0),
+ PCLK(APB4, LTDC, "ltdc", "pclk4", 0, CLK_IGNORE_UNUSED),
+ PCLK(APB4, DSI, "dsi", "pclk4", 4, CLK_IGNORE_UNUSED),
+ PCLK(APB4, IWDG2, "iwdg2", "pclk4", 15, 0),
+ PCLK(APB4, USBPHY, "usbphy", "pclk4", 16, CLK_IGNORE_UNUSED),
+ PCLK(APB4, STGENRO, "stgenro", "pclk4", 20, 0),
+ PCLK(APB5, SPI6, "spi6", "pclk5", 0, CLK_IGNORE_UNUSED),
+ PCLK(APB5, I2C4, "i2c4", "pclk5", 2, CLK_IGNORE_UNUSED),
+ PCLK(APB5, I2C6, "i2c6", "pclk5", 3, CLK_IGNORE_UNUSED),
+ PCLK(APB5, USART1, "usart1", "pclk5", 4, CLK_IGNORE_UNUSED),
+ PCLK(APB5, RTCAPB, "rtcapb", "pclk5", 8, CLK_IGNORE_UNUSED |
+ CLK_IS_CRITICAL),
+ PCLK(APB5, TZC, "tzc", "pclk5", 12, CLK_IGNORE_UNUSED),
+ PCLK(APB5, TZPC, "tzpc", "pclk5", 13, CLK_IGNORE_UNUSED),
+ PCLK(APB5, IWDG1, "iwdg1", "pclk5", 15, 0),
+ PCLK(APB5, BSEC, "bsec", "pclk5", 16, CLK_IGNORE_UNUSED),
+ PCLK(APB5, STGEN, "stgen", "pclk5", 20, CLK_IGNORE_UNUSED),
+ PCLK(AHB2, DMA1, "dma1", "ck_mcu", 0, 0),
+ PCLK(AHB2, DMA2, "dma2", "ck_mcu", 1, 0),
+ PCLK(AHB2, DMAMUX, "dmamux", "ck_mcu", 2, 0),
+ PCLK(AHB2, ADC12, "adc12", "ck_mcu", 5, CLK_IGNORE_UNUSED),
+ PCLK(AHB2, USBO, "usbo", "ck_mcu", 8, CLK_IGNORE_UNUSED),
+ PCLK(AHB2, SDMMC3, "sdmmc3", "ck_mcu", 16, CLK_IGNORE_UNUSED),
+ PCLK(AHB3, DCMI, "dcmi", "ck_mcu", 0, 0),
+ PCLK(AHB3, CRYP2, "cryp2", "ck_mcu", 4, 0),
+ PCLK(AHB3, HASH2, "hash2", "ck_mcu", 5, 0),
+ PCLK(AHB3, RNG2, "rng2", "ck_mcu", 6, CLK_IGNORE_UNUSED),
+ PCLK(AHB3, CRC2, "crc2", "ck_mcu", 7, 0),
+ PCLK(AHB3, HSEM, "hsem", "ck_mcu", 11, 0),
+ PCLK(AHB3, IPCC, "ipcc", "ck_mcu", 12, 0),
+ PCLK(AHB4, GPIOA, "gpioa", "ck_mcu", 0, 0),
+ PCLK(AHB4, GPIOB, "gpiob", "ck_mcu", 1, 0),
+ PCLK(AHB4, GPIOC, "gpioc", "ck_mcu", 2, 0),
+ PCLK(AHB4, GPIOD, "gpiod", "ck_mcu", 3, 0),
+ PCLK(AHB4, GPIOE, "gpioe", "ck_mcu", 4, 0),
+ PCLK(AHB4, GPIOF, "gpiof", "ck_mcu", 5, 0),
+ PCLK(AHB4, GPIOG, "gpiog", "ck_mcu", 6, 0),
+ PCLK(AHB4, GPIOH, "gpioh", "ck_mcu", 7, 0),
+ PCLK(AHB4, GPIOI, "gpioi", "ck_mcu", 8, 0),
+ PCLK(AHB4, GPIOJ, "gpioj", "ck_mcu", 9, 0),
+ PCLK(AHB4, GPIOK, "gpiok", "ck_mcu", 10, 0),
+ PCLK(AHB5, GPIOZ, "gpioz", "ck_axi", 0, CLK_IGNORE_UNUSED),
+ PCLK(AHB5, CRYP1, "cryp1", "ck_axi", 4, CLK_IGNORE_UNUSED),
+ PCLK(AHB5, HASH1, "hash1", "ck_axi", 5, CLK_IGNORE_UNUSED),
+ PCLK(AHB5, RNG1, "rng1", "ck_axi", 6, CLK_IGNORE_UNUSED),
+ PCLK(AHB5, BKPSRAM, "bkpsram", "ck_axi", 8, CLK_IGNORE_UNUSED),
+ PCLK(AHB6, MDMA, "mdma", "ck_axi", 0, 0),
+ PCLK(AHB6, GPU, "gpu", "ck_axi", 5, CLK_IGNORE_UNUSED),
+ PCLK(AHB6, ETHCK, "ethck", "ck_axi", 7, 0),
+ PCLK(AHB6, ETHTX, "ethtx", "ck_axi", 8, 0),
+ PCLK(AHB6, ETHRX, "ethrx", "ck_axi", 9, 0),
+ PCLK(AHB6, ETHMAC, "ethmac", "ck_axi", 10, CLK_IGNORE_UNUSED),
+ PCLK(AHB6, FMC, "fmc", "ck_axi", 12, CLK_IGNORE_UNUSED),
+ PCLK(AHB6, QSPI, "qspi", "ck_axi", 14, CLK_IGNORE_UNUSED),
+ PCLK(AHB6, SDMMC1, "sdmmc1", "ck_axi", 16, CLK_IGNORE_UNUSED),
+ PCLK(AHB6, SDMMC2, "sdmmc2", "ck_axi", 17, CLK_IGNORE_UNUSED),
+ PCLK(AHB6, CRC1, "crc1", "ck_axi", 20, 0),
+ PCLK(AHB6, USBH, "usbh", "ck_axi", 24, 0),
+ PCLK(AHB6LP, ETHSTP, "ethstp", "ck_axi", 11, 0),
};

struct stm32_clock_match_data {
--
1.9.1


2018-02-02 14:07:21

by Gabriel FERNANDEZ

[permalink] [raw]
Subject: [PATCH 07/14] clk: stm32mp1: add Post-dividers for PLL

From: Gabriel Fernandez <[email protected]>

Each PLL has 3 outputs with post-dividers.

pll1_p is dedicated for Cortex-A7
pll1_q is not connected
pll1_r is not connected

pll2_p is dedicated for AXI
pll2_q is dedicated for GPU
pll2_r is dedicated for DDR

pll3_p is dedicated for mcu
pll3_q is for Peripheral Kernel Clock
pll3_r is for Peripheral Kernel Clock

pll4_p is for Peripheral Kernel Clock
pll4_q is for Peripheral Kernel Clock
pll4_r is for Peripheral Kernel Clock

Signed-off-by: Gabriel Fernandez <[email protected]>
---
drivers/clk/clk-stm32mp1.c | 257 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 257 insertions(+)

diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c
index 33f0d09..15cd488 100644
--- a/drivers/clk/clk-stm32mp1.c
+++ b/drivers/clk/clk-stm32mp1.c
@@ -377,6 +377,147 @@ struct mux_cfg {
u32 *table;
};

+/* STM32 Composite clock */
+struct composite_cfg {
+ struct gate_cfg *gate;
+ struct mux_cfg *mux;
+ struct div_cfg *div;
+ const struct clk_ops *mux_ops;
+ const struct clk_ops *div_ops;
+ const struct clk_ops *gate_ops;
+};
+
+static struct clk_mux *_get_cmux(void __iomem *reg, u8 shift, u8 width,
+ u32 flags, u32 *table, spinlock_t *lock)
+{
+ struct clk_mux *mux;
+
+ mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+ if (!mux)
+ return ERR_PTR(-ENOMEM);
+
+ mux->reg = reg;
+ mux->shift = shift;
+ mux->mask = (1 << width) - 1;
+ mux->flags = flags;
+ mux->lock = lock;
+ mux->table = table;
+
+ return mux;
+}
+
+static struct clk_divider *_get_cdiv(void __iomem *reg, u8 shift, u8 width,
+ u32 flags,
+ const struct clk_div_table *table,
+ spinlock_t *lock)
+{
+ struct clk_divider *div;
+
+ div = kzalloc(sizeof(*div), GFP_KERNEL);
+
+ if (!div)
+ return ERR_PTR(-ENOMEM);
+
+ div->reg = reg;
+ div->shift = shift;
+ div->width = width;
+ div->flags = flags;
+ div->lock = lock;
+ div->table = table;
+
+ return div;
+}
+
+static struct clk_gate *_get_cgate(void __iomem *reg, u8 bit_idx, u32 flags,
+ spinlock_t *lock)
+{
+ struct clk_gate *gate;
+
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate)
+ return ERR_PTR(-ENOMEM);
+
+ gate->reg = reg;
+ gate->bit_idx = bit_idx;
+ gate->flags = flags;
+ gate->lock = lock;
+
+ return gate;
+}
+
+static struct clk_hw *
+clk_stm_register_composite(struct device *dev,
+ const char *name, const char * const *parent_names,
+ int num_parents, void __iomem *base,
+ const struct composite_cfg *cfg,
+ unsigned long flags, spinlock_t *lock)
+{
+ struct clk_mux *mux = NULL;
+ struct clk_divider *div = NULL;
+ struct clk_gate *gate = NULL;
+ const struct clk_ops *mux_ops, *div_ops, *gate_ops;
+ struct clk_hw *hw;
+ struct clk_hw *mux_hw;
+ struct clk_hw *div_hw;
+ struct clk_hw *gate_hw;
+
+ mux_hw = NULL;
+ div_hw = NULL;
+ gate_hw = NULL;
+ mux_ops = NULL;
+ div_ops = NULL;
+ gate_ops = NULL;
+
+ if (cfg->mux) {
+ mux = _get_cmux(base + cfg->mux->reg_off,
+ cfg->mux->shift,
+ cfg->mux->width,
+ cfg->mux->mux_flags,
+ cfg->mux->table,
+ lock);
+
+ if (!IS_ERR(mux)) {
+ mux_hw = &mux->hw;
+ mux_ops = cfg->mux_ops ?
+ cfg->mux_ops : &clk_mux_ops;
+ }
+ }
+
+ if (cfg->div) {
+ div = _get_cdiv(base + cfg->div->reg_off,
+ cfg->div->shift,
+ cfg->div->width,
+ cfg->div->div_flags,
+ cfg->div->table,
+ lock);
+
+ if (!IS_ERR(div)) {
+ div_hw = &div->hw;
+ div_ops = cfg->div_ops ?
+ cfg->div_ops : &clk_divider_ops;
+ }
+ }
+
+ if (cfg->gate) {
+ gate = _get_cgate(base + cfg->gate->reg_off,
+ cfg->gate->bit_idx,
+ cfg->gate->gate_flags,
+ lock);
+
+ if (!IS_ERR(gate)) {
+ gate_hw = &gate->hw;
+ gate_ops = cfg->gate_ops ?
+ cfg->gate_ops : &clk_gate_ops;
+ }
+ }
+
+ hw = clk_hw_register_composite(dev, name, parent_names, num_parents,
+ mux_hw, mux_ops, div_hw, div_ops,
+ gate_hw, gate_ops, flags);
+
+ return hw;
+}
+
static struct clk_hw *
_clk_hw_register_gate(struct device *dev,
struct clk_hw_onecell_data *clk_data,
@@ -442,6 +583,17 @@ struct mux_cfg {
mux_cfg->width, mux_cfg->mux_flags, lock);
}

+static struct clk_hw *
+_clk_stm_register_composite(struct device *dev,
+ struct clk_hw_onecell_data *clk_data,
+ void __iomem *base, spinlock_t *lock,
+ const struct clock_config *cfg)
+{
+ return clk_stm_register_composite(dev, cfg->name, cfg->parent_names,
+ cfg->num_parents, base, cfg->cfg,
+ cfg->flags, lock);
+}
+
/* MP1 Gate clock with set & clear registers */

static int mp1_gate_clk_enable(struct clk_hw *hw)
@@ -779,6 +931,76 @@ struct clk_hw *_clk_register_pll(struct device *dev,
.func = _clk_hw_register_mux,\
}

+#define COMPOSITE(_id, _name, _parents, _flags, _cfg)\
+{\
+ .id = _id,\
+ .name = _name,\
+ .parent_names = _parents,\
+ .num_parents = ARRAY_SIZE(_parents),\
+ .flags = _flags,\
+ .cfg = &(struct composite_cfg)_cfg,\
+ .func = _clk_stm_register_composite,\
+}
+
+#define PARENT(_parent) ((const char *[]) { _parent})
+
+#define _NO_MUX .mux = NULL, .mux_ops = NULL
+#define _NO_DIV .div = NULL, .div_ops = NULL
+#define _NO_GATE .gate = NULL, .gate_ops = NULL
+
+#define _GATE_OPS(_offset, _bit_idx, _gate_flags, _gate_ops) \
+ .gate = &(struct gate_cfg) {\
+ .reg_off = _offset,\
+ .bit_idx = _bit_idx,\
+ },\
+ .gate_ops = _gate_ops
+
+#define _GATE(_offset, _bit_idx, _gate_flags)\
+ _GATE_OPS(_offset, _bit_idx, _gate_flags, NULL)
+
+#define _DIV_TABLE_OPS(_offset, _shift, _width, _div_flags, _div_table,\
+ _div_ops)\
+ .div = &(struct div_cfg) {\
+ .reg_off = _offset,\
+ .shift = _shift,\
+ .width = _width,\
+ .div_flags = _div_flags,\
+ .table = _div_table,\
+ },\
+ .div_ops = _div_ops
+
+#define _DIV_TABLE(_offset, _shift, _width, _div_flags, _div_table)\
+ _DIV_TABLE_OPS(_offset, _shift, _width, _div_flags,\
+ _div_table, NULL)
+
+#define _DIV_OPS(_offset, _shift, _width, _div_flags, _div_ops)\
+ _DIV_TABLE_OPS(_offset, _shift, _width, _div_flags, NULL, _div_ops)
+
+#define _DIV(_offset, _shift, _width, _div_flags)\
+ _DIV_OPS(_offset, _shift, _width, _div_flags, NULL)
+
+#define _MUX(_offset, _shift, _width, _mux_flags)\
+ .mux = &(struct mux_cfg) {\
+ .reg_off = _offset,\
+ .shift = _shift,\
+ .width = _width,\
+ .mux_flags = _mux_flags,\
+ .table = NULL,\
+ },\
+ .mux_ops = NULL
+
+#define _GATEDIV(_gate_offset,\
+ _bit_idx,\
+ _div_offset,\
+ _div_shift,\
+ _div_width,\
+ _div_table)\
+{\
+ _DIV_TABLE(_div_offset, _div_shift, _div_width, 0, _div_table),\
+ _GATE(_gate_offset, _bit_idx, 0),\
+ _NO_MUX,\
+}
+
#define MP1_GATE(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\
{\
.id = _id,\
@@ -834,6 +1056,41 @@ struct clk_hw *_clk_register_pll(struct device *dev,
PLL(PLL2, "pll2", "ref1", CLK_IGNORE_UNUSED, RCC_PLL2CR),
PLL(PLL3, "pll3", "ref3", CLK_IGNORE_UNUSED, RCC_PLL3CR),
PLL(PLL4, "pll4", "ref4", CLK_IGNORE_UNUSED, RCC_PLL4CR),
+
+ /* ODF */
+ COMPOSITE(PLL1_P, "pll1_p", PARENT("pll1"), 0,
+ _GATEDIV(RCC_PLL1CR, 4,
+ RCC_PLL1CFGR2, 0, 7, NULL)),
+
+ COMPOSITE(PLL2_P, "pll2_p", PARENT("pll2"), 0,
+ _GATEDIV(RCC_PLL2CR, 4,
+ RCC_PLL2CFGR2, 0, 7, NULL)),
+ COMPOSITE(PLL2_Q, "pll2_q", PARENT("pll2"), 0,
+ _GATEDIV(RCC_PLL2CR, 5,
+ RCC_PLL2CFGR2, 8, 7, NULL)),
+ COMPOSITE(PLL2_R, "pll2_r", PARENT("pll2"), CLK_IS_CRITICAL,
+ _GATEDIV(RCC_PLL2CR, 6,
+ RCC_PLL2CFGR2, 16, 7, NULL)),
+
+ COMPOSITE(PLL3_P, "pll3_p", PARENT("pll3"), 0,
+ _GATEDIV(RCC_PLL3CR, 4,
+ RCC_PLL3CFGR2, 0, 7, NULL)),
+ COMPOSITE(PLL3_Q, "pll3_q", PARENT("pll3"), 0,
+ _GATEDIV(RCC_PLL3CR, 5,
+ RCC_PLL3CFGR2, 8, 7, NULL)),
+ COMPOSITE(PLL3_R, "pll3_r", PARENT("pll3"), 0,
+ _GATEDIV(RCC_PLL3CR, 6,
+ RCC_PLL3CFGR2, 16, 7, NULL)),
+
+ COMPOSITE(PLL4_P, "pll4_p", PARENT("pll4"), 0,
+ _GATEDIV(RCC_PLL4CR, 4,
+ RCC_PLL4CFGR2, 0, 7, NULL)),
+ COMPOSITE(PLL4_Q, "pll4_q", PARENT("pll4"), 0,
+ _GATEDIV(RCC_PLL4CR, 5,
+ RCC_PLL4CFGR2, 8, 7, NULL)),
+ COMPOSITE(PLL4_R, "pll4_r", PARENT("pll4"), 0,
+ _GATEDIV(RCC_PLL4CR, 6,
+ RCC_PLL4CFGR2, 16, 7, NULL)),
};

struct stm32_clock_match_data {
--
1.9.1


2018-02-02 14:07:29

by Gabriel FERNANDEZ

[permalink] [raw]
Subject: [PATCH 14/14] clk: stm32mp1: add Debug clocks

From: Gabriel Fernandez <[email protected]>

RCC manages clock for debug and trace.

Signed-off-by: Gabriel Fernandez <[email protected]>
---
drivers/clk/clk-stm32mp1.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)

diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c
index 0402a0e..eafc95a 100644
--- a/drivers/clk/clk-stm32mp1.c
+++ b/drivers/clk/clk-stm32mp1.c
@@ -352,6 +352,12 @@
{ 0 },
};

+static const struct clk_div_table ck_trace_div_table[] = {
+ { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 },
+ { 4, 16 }, { 5, 16 }, { 6, 16 }, { 7, 16 },
+ { 0 },
+};
+
struct clock_config {
u32 id;
const char *name;
@@ -1566,6 +1572,17 @@ static struct clk_hw *_clk_register_cktim(struct device *dev,
_GATEMUXDIV(RCC_MCO2CFGR, 12,
RCC_MCO2CFGR, 0, 3,
RCC_MCO2CFGR, 4, 4)),
+
+ /* Debug clocks */
+ FIXED_FACTOR(NO_ID, "ck_axi_div2", "ck_axi", 0, 1, 2),
+
+ GATE(DBG, "ck_apb_dbg", "ck_axi_div2", 0, RCC_DBGCFGR, 8, 0),
+
+ GATE(CK_DBG, "ck_sys_dbg", "ck_axi", 0, RCC_DBGCFGR, 8, 0),
+
+ COMPOSITE(CK_TRACE, "ck_trace", ck_trace_src, CLK_OPS_PARENT_ENABLE,
+ _GATEDIV(RCC_DBGCFGR, 9,
+ RCC_DBGCFGR, 0, 3, ck_trace_div_table)),
};

struct stm32_clock_match_data {
--
1.9.1


2018-02-02 14:07:39

by Gabriel FERNANDEZ

[permalink] [raw]
Subject: [PATCH 08/14] clk: stm32mp1: add Sub System clocks

From: Gabriel Fernandez <[email protected]>

The RCC handles three sub-system clocks: ck_mpuss, ck_axiss and ck_mcuss.
This patch adds also some MUX system and several prescalers.

Signed-off-by: Gabriel Fernandez <[email protected]>
---
drivers/clk/clk-stm32mp1.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 61 insertions(+)

diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c
index 15cd488..d85c619 100644
--- a/drivers/clk/clk-stm32mp1.c
+++ b/drivers/clk/clk-stm32mp1.c
@@ -332,6 +332,26 @@
"ck_mpu", "ck_axi", "ck_mcu", "pll4_p", "ck_hse", "ck_hsi"
};

+static const struct clk_div_table axi_div_table[] = {
+ { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
+ { 4, 4 }, { 5, 4 }, { 6, 4 }, { 7, 4 },
+ { 0 },
+};
+
+static const struct clk_div_table mcu_div_table[] = {
+ { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 },
+ { 4, 16 }, { 5, 32 }, { 6, 64 }, { 7, 128 },
+ { 8, 512 }, { 9, 512 }, { 10, 512}, { 11, 512 },
+ { 12, 512 }, { 13, 512 }, { 14, 512}, { 15, 512 },
+ { 0 },
+};
+
+static const struct clk_div_table apb_div_table[] = {
+ { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 },
+ { 4, 16 }, { 5, 16 }, { 6, 16 }, { 7, 16 },
+ { 0 },
+};
+
struct clock_config {
u32 id;
const char *name;
@@ -1001,6 +1021,15 @@ struct clk_hw *_clk_register_pll(struct device *dev,
_NO_MUX,\
}

+#define _MUXDIV(_mux_offset, _mux_bit, _mux_width,\
+ _div_offset, _div_shift, _div_width,\
+ _div_table)\
+{\
+ _DIV_TABLE(_div_offset, _div_shift, _div_width, 0, _div_table),\
+ _NO_GATE,\
+ _MUX(_mux_offset, _mux_bit, _mux_width, 0),\
+}
+
#define MP1_GATE(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\
{\
.id = _id,\
@@ -1091,6 +1120,38 @@ struct clk_hw *_clk_register_pll(struct device *dev,
COMPOSITE(PLL4_R, "pll4_r", PARENT("pll4"), 0,
_GATEDIV(RCC_PLL4CR, 6,
RCC_PLL4CFGR2, 16, 7, NULL)),
+
+ /* MUX system clocks */
+ MUX(CK_PER, "ck_per", per_src, CLK_OPS_PARENT_ENABLE,
+ RCC_CPERCKSELR, 0, 2, 0),
+
+ MUX(CK_MPU, "ck_mpu", cpu_src, CLK_OPS_PARENT_ENABLE | CLK_IS_CRITICAL,
+ RCC_MPCKSELR, 0, 2, 0),
+
+ COMPOSITE(CK_AXI, "ck_axi", axi_src, CLK_IS_CRITICAL |
+ CLK_OPS_PARENT_ENABLE,
+ _MUXDIV(RCC_ASSCKSELR, 0, 2,
+ RCC_AXIDIVR, 0, 3, axi_div_table)),
+
+ COMPOSITE(CK_MCU, "ck_mcu", mcu_src, CLK_IS_CRITICAL |
+ CLK_OPS_PARENT_ENABLE,
+ _MUXDIV(RCC_MSSCKSELR, 0, 2,
+ RCC_MCUDIVR, 0, 4, mcu_div_table)),
+
+ DIV_TABLE(NO_ID, "pclk1", "ck_mcu", CLK_IGNORE_UNUSED, RCC_APB1DIVR, 0,
+ 3, CLK_DIVIDER_READ_ONLY, apb_div_table),
+
+ DIV_TABLE(NO_ID, "pclk2", "ck_mcu", CLK_IGNORE_UNUSED, RCC_APB2DIVR, 0,
+ 3, CLK_DIVIDER_READ_ONLY, apb_div_table),
+
+ DIV_TABLE(NO_ID, "pclk3", "ck_mcu", CLK_IGNORE_UNUSED, RCC_APB3DIVR, 0,
+ 3, CLK_DIVIDER_READ_ONLY, apb_div_table),
+
+ DIV_TABLE(NO_ID, "pclk4", "ck_axi", CLK_IGNORE_UNUSED, RCC_APB4DIVR, 0,
+ 3, CLK_DIVIDER_READ_ONLY, apb_div_table),
+
+ DIV_TABLE(NO_ID, "pclk5", "ck_axi", CLK_IGNORE_UNUSED, RCC_APB5DIVR, 0,
+ 3, CLK_DIVIDER_READ_ONLY, apb_div_table),
};

struct stm32_clock_match_data {
--
1.9.1


2018-02-02 14:07:45

by Gabriel FERNANDEZ

[permalink] [raw]
Subject: [PATCH 01/14] dt-bindings: Document STM32MP1 Reset Clock Controller (RCC) bindings

From: Gabriel Fernandez <[email protected]>

The RCC block is responsible of the management of the clock and reset
generation for the complete circuit.

Signed-off-by: Gabriel Fernandez <[email protected]>
---
.../devicetree/bindings/mfd/st,stm32-rcc.txt | 85 ++++++++++++++++++++++
1 file changed, 85 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mfd/st,stm32-rcc.txt

diff --git a/Documentation/devicetree/bindings/mfd/st,stm32-rcc.txt b/Documentation/devicetree/bindings/mfd/st,stm32-rcc.txt
new file mode 100644
index 0000000..28017a1
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/st,stm32-rcc.txt
@@ -0,0 +1,85 @@
+STMicroelectronics STM32 Peripheral Reset Clock Controller
+==========================================================
+
+The RCC IP is both a reset and a clock controller.
+
+Please also refer to reset.txt for common reset controller binding usage.
+
+Please also refer to clock-bindings.txt for common clock controller
+binding usage.
+
+
+Required properties:
+- compatible: "simple-mfd", "syscon"
+- reg: should be register base and length as documented in the datasheet
+
+- Sub-nodes:
+ - compatible: "st,stm32mp1-rcc-clk"
+ - #clock-cells: 1, device nodes should specify the clock in their
+ "clocks" property, containing a phandle to the clock device node,
+ an index specifying the clock to use.
+
+ - compatible: "st,stm32mp1-rcc-rst"
+ - #reset-cells: Shall be 1
+
+Example:
+ rcc: rcc@50000000 {
+ compatible = "syscon", "simple-mfd";
+ reg = <0x50000000 0x1000>;
+
+ rcc_clk: rcc-clk@50000000 {
+ #clock-cells = <1>;
+ compatible = "st,stm32mp1-rcc-clk";
+ };
+
+ rcc_rst: rcc-reset@50000000 {
+ #reset-cells = <1>;
+ compatible = "st,stm32mp1-rcc-rst";
+ };
+ };
+
+Specifying clocks
+=================
+
+All available clocks are defined as preprocessor macros in
+dt-bindings/clock/stm32mp1-clks.h header and can be used in device
+tree sources.
+
+Example:
+
+ /* Accessing DMA1 clock */
+ ... {
+ clocks = <&rcc_clk DMA1>
+ };
+
+ /* Accessing SPI6 kernel clock */
+ ... {
+ clocks = <&rcc_clk SPI6_K>
+ };
+
+Specifying softreset control of devices
+=======================================
+
+Device nodes should specify the reset channel required in their "resets"
+property, containing a phandle to the reset device node and an index specifying
+which channel to use.
+The index is the bit number within the RCC registers bank, starting from RCC
+base address.
+It is calculated as: index = register_offset / 4 * 32 + bit_offset.
+Where bit_offset is the bit offset within the register.
+
+For example on STM32MP1, for LTDC reset:
+ ltdc = APB4_RSTSETR_offset / 4 * 32 + LTDC_bit_offset
+ = 0x180 / 4 * 32 + 0 = 3072
+
+The list of valid indices for STM32MP1 is available in:
+include/dt-bindings/reset-controller/stm32mp1-resets.h
+
+This file implements defines like:
+#define LTDC_R 3072
+
+example:
+
+ ltdc {
+ resets = <&rcc_rst LTDC_R>;
+ };
--
1.9.1


2018-02-02 14:07:58

by Gabriel FERNANDEZ

[permalink] [raw]
Subject: [PATCH 05/14] clk: stm32mp1: add Source Clocks for PLLs

From: Gabriel Fernandez <[email protected]>

This patch adds source clocks for PLLs
This patch also introduces MUX clock API.

Signed-off-by: Gabriel Fernandez <[email protected]>
---
drivers/clk/clk-stm32mp1.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 48 insertions(+)

diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c
index be5a4e5..1c9a84a 100644
--- a/drivers/clk/clk-stm32mp1.c
+++ b/drivers/clk/clk-stm32mp1.c
@@ -368,6 +368,14 @@ struct div_cfg {
const struct clk_div_table *table;
};

+struct mux_cfg {
+ u32 reg_off;
+ u8 shift;
+ u8 width;
+ u8 mux_flags;
+ u32 *table;
+};
+
static struct clk_hw *
_clk_hw_register_gate(struct device *dev,
struct clk_hw_onecell_data *clk_data,
@@ -419,6 +427,20 @@ struct div_cfg {
lock);
}

+static struct clk_hw *
+_clk_hw_register_mux(struct device *dev,
+ struct clk_hw_onecell_data *clk_data,
+ void __iomem *base, spinlock_t *lock,
+ const struct clock_config *cfg)
+{
+ struct mux_cfg *mux_cfg = cfg->cfg;
+
+ return clk_hw_register_mux(dev, cfg->name, cfg->parent_names,
+ cfg->num_parents, cfg->flags,
+ mux_cfg->reg_off + base, mux_cfg->shift,
+ mux_cfg->width, mux_cfg->mux_flags, lock);
+}
+
/* MP1 Gate clock with set & clear registers */

static int mp1_gate_clk_enable(struct clk_hw *hw)
@@ -550,6 +572,22 @@ static struct clk_hw *clk_register_mp1_gate(struct device *dev,
DIV_TABLE(_id, _name, _parent, _flags, _offset, _shift, _width,\
_div_flags, NULL)

+#define MUX(_id, _name, _parents, _flags, _offset, _shift, _width, _mux_flags)\
+{\
+ .id = _id,\
+ .name = _name,\
+ .parent_names = _parents,\
+ .num_parents = ARRAY_SIZE(_parents),\
+ .flags = _flags,\
+ .cfg = &(struct mux_cfg) {\
+ .reg_off = _offset,\
+ .shift = _shift,\
+ .width = _width,\
+ .mux_flags = _mux_flags,\
+ },\
+ .func = _clk_hw_register_mux,\
+}
+
#define MP1_GATE(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\
{\
.id = _id,\
@@ -577,6 +615,16 @@ static struct clk_hw *clk_register_mp1_gate(struct device *dev,
GATE(CK_LSE, "ck_lse", "clk-lse", 0, RCC_BDCR, 0, 0),

FIXED_FACTOR(CK_HSE_DIV2, "clk-hse-div2", "ck_hse", 0, 1, 2),
+
+ /* ref clock pll */
+ MUX(NO_ID, "ref1", ref12_parents, CLK_OPS_PARENT_ENABLE, RCC_RCK12SELR,
+ 0, 2, CLK_MUX_READ_ONLY),
+
+ MUX(NO_ID, "ref3", ref3_parents, CLK_OPS_PARENT_ENABLE, RCC_RCK3SELR,
+ 0, 2, CLK_MUX_READ_ONLY),
+
+ MUX(NO_ID, "ref4", ref4_parents, CLK_OPS_PARENT_ENABLE, RCC_RCK4SELR,
+ 0, 2, CLK_MUX_READ_ONLY),
};

struct stm32_clock_match_data {
--
1.9.1


2018-02-02 14:08:49

by Gabriel FERNANDEZ

[permalink] [raw]
Subject: [PATCH 03/14] clk: stm32mp1: Introduce STM32MP1 clock driver

From: Gabriel Fernandez <[email protected]>

This patch introduces the mechanism to probe stm32mp1 driver.

It also defines registers and clocks source definition.

This patch also introduces the generic mechanism to register
a clock (a simple gate).

All clocks will be defined in one table.

Signed-off-by: Gabriel Fernandez <[email protected]>
---
drivers/clk/Kconfig | 6 +
drivers/clk/Makefile | 1 +
drivers/clk/clk-stm32mp1.c | 513 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 520 insertions(+)
create mode 100644 drivers/clk/clk-stm32mp1.c

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 1c4e1aa..517c4b3 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -226,6 +226,12 @@ config COMMON_CLK_VC5
This driver supports the IDT VersaClock 5 and VersaClock 6
programmable clock generators.

+config COMMON_CLK_STM32MP157
+ def_bool COMMON_CLK && MACH_STM32MP157
+ help
+ ---help---
+ Support for stm32mp157 SoC family clocks
+
source "drivers/clk/bcm/Kconfig"
source "drivers/clk/hisilicon/Kconfig"
source "drivers/clk/imgtec/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index f7f761b..69f6f59 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_COMMON_CLK_SI514) += clk-si514.o
obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o
obj-$(CONFIG_ARCH_STM32) += clk-stm32f4.o
obj-$(CONFIG_ARCH_STM32) += clk-stm32h7.o
+obj-$(CONFIG_COMMON_CLK_STM32MP157) += clk-stm32mp1.o
obj-$(CONFIG_ARCH_TANGO) += clk-tango4.o
obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o
obj-$(CONFIG_ARCH_U300) += clk-u300.o
diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c
new file mode 100644
index 0000000..6e39e85
--- /dev/null
+++ b/drivers/clk/clk-stm32mp1.c
@@ -0,0 +1,513 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: Olivier Bideau <[email protected]> for STMicroelectronics.
+ * Author: Gabriel Fernandez <[email protected]> for STMicroelectronics.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include <dt-bindings/clock/stm32mp1-clks.h>
+
+static DEFINE_SPINLOCK(rlock);
+
+#define RCC_OCENSETR 0x0C
+#define RCC_OCENCLRR 0x10
+#define RCC_OCRDYR 0x808
+#define RCC_HSICFGR 0x18
+#define RCC_RDLSICR 0x144
+#define RCC_PLL1CR 0x80
+#define RCC_PLL1CFGR1 0x84
+#define RCC_PLL1CFGR2 0x88
+#define RCC_PLL2CR 0x94
+#define RCC_PLL2CFGR1 0x98
+#define RCC_PLL2CFGR2 0x9C
+#define RCC_PLL3CR 0x880
+#define RCC_PLL3CFGR1 0x884
+#define RCC_PLL3CFGR2 0x888
+#define RCC_PLL4CR 0x894
+#define RCC_PLL4CFGR1 0x898
+#define RCC_PLL4CFGR2 0x89C
+#define RCC_APB1ENSETR 0xA00
+#define RCC_APB2ENSETR 0xA08
+#define RCC_APB3ENSETR 0xA10
+#define RCC_APB4ENSETR 0x200
+#define RCC_APB5ENSETR 0x208
+#define RCC_AHB2ENSETR 0xA18
+#define RCC_AHB3ENSETR 0xA20
+#define RCC_AHB4ENSETR 0xA28
+#define RCC_AHB5ENSETR 0x210
+#define RCC_AHB6ENSETR 0x218
+#define RCC_AHB6LPENSETR 0x318
+#define RCC_RCK12SELR 0x28
+#define RCC_RCK3SELR 0x820
+#define RCC_RCK4SELR 0x824
+#define RCC_MPCKSELR 0x20
+#define RCC_ASSCKSELR 0x24
+#define RCC_MSSCKSELR 0x48
+#define RCC_SPI6CKSELR 0xC4
+#define RCC_SDMMC12CKSELR 0x8F4
+#define RCC_SDMMC3CKSELR 0x8F8
+#define RCC_FMCCKSELR 0x904
+#define RCC_I2C4CKSELR 0xC0
+#define RCC_I2C12CKSELR 0x8C0
+#define RCC_I2C35CKSELR 0x8C4
+#define RCC_UART1CKSELR 0xC8
+#define RCC_QSPICKSELR 0x900
+#define RCC_ETHCKSELR 0x8FC
+#define RCC_RNG1CKSELR 0xCC
+#define RCC_RNG2CKSELR 0x920
+#define RCC_GPUCKSELR 0x938
+#define RCC_USBCKSELR 0x91C
+#define RCC_STGENCKSELR 0xD4
+#define RCC_SPDIFCKSELR 0x914
+#define RCC_SPI2S1CKSELR 0x8D8
+#define RCC_SPI2S23CKSELR 0x8DC
+#define RCC_SPI2S45CKSELR 0x8E0
+#define RCC_CECCKSELR 0x918
+#define RCC_LPTIM1CKSELR 0x934
+#define RCC_LPTIM23CKSELR 0x930
+#define RCC_LPTIM45CKSELR 0x92C
+#define RCC_UART24CKSELR 0x8E8
+#define RCC_UART35CKSELR 0x8EC
+#define RCC_UART6CKSELR 0x8E4
+#define RCC_UART78CKSELR 0x8F0
+#define RCC_DFSDMCKSELR 0x910
+#define RCC_FDCANCKSELR 0x90C
+#define RCC_SAI1CKSELR 0x8C8
+#define RCC_SAI2CKSELR 0x8CC
+#define RCC_SAI3CKSELR 0x8D0
+#define RCC_SAI4CKSELR 0x8D4
+#define RCC_ADCCKSELR 0x928
+#define RCC_MPCKDIVR 0x2C
+#define RCC_DSICKSELR 0x924
+#define RCC_CPERCKSELR 0xD0
+#define RCC_GRSTCSETR 0x404
+#define RCC_MCO1CFGR 0x800
+#define RCC_MCO2CFGR 0x804
+#define RCC_BDCR 0x140
+#define RCC_AXIDIVR 0x30
+#define RCC_MCUDIVR 0x830
+#define RCC_APB1DIVR 0x834
+#define RCC_APB2DIVR 0x838
+#define RCC_APB3DIVR 0x83C
+#define RCC_APB4DIVR 0x3C
+#define RCC_APB5DIVR 0x40
+#define RCC_TIMG1PRER 0x828
+#define RCC_TIMG2PRER 0x82C
+#define RCC_RTCDIVR 0x44
+#define RCC_DBGCFGR 0x80C
+
+#define RCC_CLR 0x4
+
+static const char * const ref12_parents[] = {
+ "ck_hsi", "ck_hse"
+};
+
+static const char * const ref3_parents[] = {
+ "ck_hsi", "ck_hse", "ck_csi"
+};
+
+static const char * const ref4_parents[] = {
+ "ck_hsi", "ck_hse", "ck_csi"
+};
+
+static const char * const cpu_src[] = {
+ "ck_hsi", "ck_hse", "pll1_p"
+};
+
+static const char * const axi_src[] = {
+ "ck_hsi", "ck_hse", "pll2_p", "pll3_p"
+};
+
+static const char * const per_src[] = {
+ "ck_hsi", "ck_csi", "ck_hse"
+};
+
+static const char * const mcu_src[] = {
+ "ck_hsi", "ck_hse", "ck_csi", "pll3_p"
+};
+
+static const char * const sdmmc1_src[] = {
+ "ck_axi", "pll3_r", "pll4_p", "ck_hsi"
+};
+
+static const char * const sdmmc2_src[] = {
+ "ck_axi", "pll3_r", "pll4_p", "ck_hsi"
+};
+
+static const char * const sdmmc3_src[] = {
+ "ck_mcu", "pll3_r", "pll4_p", "ck_hsi"
+};
+
+static const char * const fmc_src[] = {
+ "ck_axi", "pll3_r", "pll4_p", "ck_per"
+};
+
+static const char * const qspi_src[] = {
+ "ck_axi", "pll3_r", "pll4_p", "ck_per"
+};
+
+static const char * const eth_src[] = {
+ "pll4_p", "pll3_q"
+};
+
+static const char * const rng_src[] = {
+ "ck_csi", "pll4_r", "ck_lse", "ck_lsi"
+};
+
+static const char * const usbphy_src[] = {
+ "ck_hse", "pll4_r", "clk-hse-div2"
+};
+
+static const char * const usbo_src[] = {
+ "pll4_r", "ck_usbo_48m"
+};
+
+static const char * const stgen_src[] = {
+ "ck_hsi", "ck_hse"
+};
+
+static const char * const spdif_src[] = {
+ "pll4_p", "pll3_q", "ck_hsi"
+};
+
+static const char * const spi1_src[] = {
+ "pll4_p", "pll3_q", "i2s_ckin", "ck_per"
+};
+
+static const char * const spi2_src[] = {
+ "pll4_p", "pll3_q", "i2s_ckin", "ck_per"
+};
+
+static const char * const spi3_src[] = {
+ "pll4_p", "pll3_q", "i2s_ckin", "ck_per"
+};
+
+static const char * const spi4_src[] = {
+ "pclk2", "pll4_q", "ck_hsi", "ck_csi", "ck_hse"
+};
+
+const char * const spi5_src[] = {
+ "pclk2", "pll4_q", "ck_hsi", "ck_csi", "ck_hse"
+};
+
+static const char * const spi6_src[] = {
+ "pclk5", "pll4_q", "ck_hsi", "ck_csi", "ck_hse", "pll3_q"
+};
+
+static const char * const cec_src[] = {
+ "ck_lse", "ck_lsi", "ck_csi"
+};
+
+static const char * const i2c1_src[] = {
+ "pclk1", "pll4_r", "ck_hsi", "ck_csi"
+};
+
+static const char * const i2c2_src[] = {
+ "pclk1", "pll4_r", "ck_hsi", "ck_csi"
+};
+
+static const char * const i2c3_src[] = {
+ "pclk1", "pll4_r", "ck_hsi", "ck_csi"
+};
+
+static const char * const i2c4_src[] = {
+ "pclk5", "pll3_q", "ck_hsi", "ck_csi"
+};
+
+static const char * const i2c5_src[] = {
+ "pclk1", "pll4_r", "ck_hsi", "ck_csi"
+};
+
+static const char * const i2c6_src[] = {
+ "pclk5", "pll3_q", "ck_hsi", "ck_csi"
+};
+
+static const char * const lptim1_src[] = {
+ "pclk1", "pll4_p", "pll3_q", "ck_lse", "ck_lsi", "ck_per"
+};
+
+static const char * const lptim2_src[] = {
+ "pclk3", "pll4_q", "ck_per", "ck_lse", "ck_lsi"
+};
+
+static const char * const lptim3_src[] = {
+ "pclk3", "pll4_q", "ck_per", "ck_lse", "ck_lsi"
+};
+
+static const char * const lptim4_src[] = {
+ "pclk3", "pll4_p", "pll3_q", "ck_lse", "ck_lsi", "ck_per"
+};
+
+static const char * const lptim5_src[] = {
+ "pclk3", "pll4_p", "pll3_q", "ck_lse", "ck_lsi", "ck_per"
+};
+
+static const char * const usart1_src[] = {
+ "pclk5", "pll3_q", "ck_hsi", "ck_csi", "pll4_q", "ck_hse"
+};
+
+const char * const usart2_src[] = {
+ "pclk1", "pll4_q", "ck_hsi", "ck_csi", "ck_hse"
+};
+
+static const char * const usart3_src[] = {
+ "pclk1", "pll4_q", "ck_hsi", "ck_csi", "ck_hse"
+};
+
+static const char * const uart4_src[] = {
+ "pclk1", "pll4_q", "ck_hsi", "ck_csi", "ck_hse"
+};
+
+static const char * const uart5_src[] = {
+ "pclk1", "pll4_q", "ck_hsi", "ck_csi", "ck_hse"
+};
+
+static const char * const usart6_src[] = {
+ "pclk2", "pll4_q", "ck_hsi", "ck_csi", "ck_hse"
+};
+
+static const char * const uart7_src[] = {
+ "pclk1", "pll4_q", "ck_hsi", "ck_csi", "ck_hse"
+};
+
+static const char * const uart8_src[] = {
+ "pclk1", "pll4_q", "ck_hsi", "ck_csi", "ck_hse"
+};
+
+static const char * const adfsdm_src[] = {
+ "pll4_q", "pll3_q", "i2s_ckin", "ck_per"
+};
+
+static const char * const dfsdm_src[] = {
+ "pclk2", "ck_mcu"
+};
+
+static const char * const fdcan_src[] = {
+ "ck_hse", "pll3_q", "pll4_q"
+};
+
+static const char * const sai_src[] = {
+ "pll4_q", "pll3_q", "i2s_ckin", "ck_per"
+};
+
+static const char * const sai2_src[] = {
+ "pll4_q", "pll3_q", "i2s_ckin", "ck_per", "spdif_ck_symb"
+};
+
+static const char * const adc12_src[] = {
+ "pll4_q", "ck_per"
+};
+
+static const char * const dsi_src[] = {
+ "ck_dsi_phy", "pll4_p"
+};
+
+static const char * const rtc_src[] = {
+ "off", "ck_lse", "ck_lsi", "ck_hse_rtc"
+};
+
+static const char * const ltdc_src[] = {
+ "pll4_q"
+};
+
+static const char * const ck_trace_src[] = {
+ "ck_axi"
+};
+
+static const char * const mco1_src[] = {
+ "ck_hsi", "ck_hse", "ck_csi", "ck_lsi", "ck_lse"
+};
+
+static const char * const mco2_src[] = {
+ "ck_mpu", "ck_axi", "ck_mcu", "pll4_p", "ck_hse", "ck_hsi"
+};
+
+struct clock_config {
+ u32 id;
+ const char *name;
+ union {
+ const char *parent_name;
+ const char * const *parent_names;
+ };
+ int num_parents;
+ unsigned long flags;
+ void *cfg;
+ struct clk_hw * (*func)(struct device *dev,
+ struct clk_hw_onecell_data *clk_data,
+ void __iomem *base, spinlock_t *lock,
+ const struct clock_config *cfg);
+};
+
+#define NO_ID ~0
+
+struct gate_cfg {
+ u32 reg_off;
+ u8 bit_idx;
+ u8 gate_flags;
+};
+
+static struct clk_hw *
+_clk_hw_register_gate(struct device *dev,
+ struct clk_hw_onecell_data *clk_data,
+ void __iomem *base, spinlock_t *lock,
+ const struct clock_config *cfg)
+{
+ struct gate_cfg *gate_cfg = cfg->cfg;
+
+ return clk_hw_register_gate(dev,
+ cfg->name,
+ cfg->parent_name,
+ cfg->flags,
+ gate_cfg->reg_off + base,
+ gate_cfg->bit_idx,
+ gate_cfg->gate_flags,
+ lock);
+}
+
+#define GATE(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\
+{\
+ .id = _id,\
+ .name = _name,\
+ .parent_name = _parent,\
+ .flags = _flags,\
+ .cfg = &(struct gate_cfg) {\
+ .reg_off = _offset,\
+ .bit_idx = _bit_idx,\
+ .gate_flags = _gate_flags,\
+ },\
+ .func = _clk_hw_register_gate,\
+}
+
+static const struct clock_config stm32mp1_clock_cfg[] = {
+ /* External / Internal Oscillators */
+ GATE(CK_LSI, "ck_lsi", "clk-lsi", 0, RCC_RDLSICR, 0, 0),
+ GATE(CK_LSE, "ck_lse", "clk-lse", 0, RCC_BDCR, 0, 0),
+};
+
+struct stm32_clock_match_data {
+ const struct clock_config *cfg;
+ unsigned int num;
+ unsigned int maxbinding;
+};
+
+static struct stm32_clock_match_data stm32mp1_data = {
+ .cfg = stm32mp1_clock_cfg,
+ .num = ARRAY_SIZE(stm32mp1_clock_cfg),
+ .maxbinding = STM32MP1_LAST_CLK,
+};
+
+static const struct of_device_id stm32mp1_match_data[] = {
+ {
+ .compatible = "st,stm32mp1-rcc-clk",
+ .data = &stm32mp1_data,
+ },
+ { }
+};
+
+static int stm32_register_hw_clk(struct device *dev,
+ struct clk_hw_onecell_data *clk_data,
+ void __iomem *base, spinlock_t *lock,
+ const struct clock_config *cfg)
+{
+ static struct clk_hw **hws;
+ struct clk_hw *hw = ERR_PTR(-ENOENT);
+
+ hws = clk_data->hws;
+
+ if (cfg->func)
+ hw = (*cfg->func)(dev, clk_data, base, lock, cfg);
+
+ if (IS_ERR(hw)) {
+ pr_err("Unable to register %s\n", cfg->name);
+ return PTR_ERR(hw);
+ }
+
+ if (cfg->id != NO_ID)
+ hws[cfg->id] = hw;
+
+ return 0;
+}
+
+static int stm32_rcc_init(struct device_node *np,
+ void __iomem *base,
+ const struct of_device_id *match_data)
+{
+ struct clk_hw_onecell_data *clk_data;
+ struct clk_hw **hws;
+ const struct of_device_id *match;
+ const struct stm32_clock_match_data *data;
+ int err, n, max_binding;
+
+ match = of_match_node(match_data, np);
+ if (!match) {
+ pr_err("%s: match data not found\n", __func__);
+ return -ENODEV;
+ }
+
+ data = match->data;
+
+ max_binding = data->maxbinding;
+
+ clk_data = kzalloc(sizeof(*clk_data) +
+ sizeof(*clk_data->hws) * max_binding,
+ GFP_KERNEL);
+ if (!clk_data)
+ return -ENOMEM;
+
+ clk_data->num = max_binding;
+
+ hws = clk_data->hws;
+
+ for (n = 0; n < max_binding; n++)
+ hws[n] = ERR_PTR(-ENOENT);
+
+ for (n = 0; n < data->num; n++) {
+ err = stm32_register_hw_clk(NULL, clk_data, base, &rlock,
+ &data->cfg[n]);
+ if (err) {
+ pr_err("%s: can't register %s\n", __func__,
+ data->cfg[n].name);
+
+ kfree(clk_data);
+
+ return err;
+ }
+ }
+
+ return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
+}
+
+static void stm32mp1_rcc_init(struct device_node *np)
+{
+ struct device_node *parent;
+ void __iomem *base;
+
+ parent = of_get_parent(np);
+ if (!parent) {
+ pr_err("%s: parent should be syscon node\n", __func__);
+ return;
+ }
+
+ base = of_iomap(parent, 0);
+ if (!base) {
+ pr_err("%s: unable to map resource", parent->name);
+ of_node_put(parent);
+ return;
+ }
+
+ if (stm32_rcc_init(np, base, stm32mp1_match_data)) {
+ iounmap(base);
+ of_node_put(parent);
+ }
+}
+
+CLK_OF_DECLARE(stm32mp1_rcc, "st,stm32mp1-rcc-clk", stm32mp1_rcc_init);
--
1.9.1


2018-02-02 14:09:13

by Gabriel FERNANDEZ

[permalink] [raw]
Subject: [PATCH 12/14] clk: stm32mp1: add RTC clock

From: Gabriel Fernandez <[email protected]>

This patch adds the RTC clock.

Signed-off-by: Gabriel Fernandez <[email protected]>
---
drivers/clk/clk-stm32mp1.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)

diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c
index 5a1142c..1cb06b0 100644
--- a/drivers/clk/clk-stm32mp1.c
+++ b/drivers/clk/clk-stm32mp1.c
@@ -1179,6 +1179,15 @@ static struct clk_hw *_clk_register_cktim(struct device *dev,
_MUX(_mux_offset, _mux_bit, _mux_width, 0),\
}

+#define _GATEMUX(_gate_offset,\
+ _bit_idx,\
+ _mux_offset, _mux_bit, _mux_width)\
+{\
+ _NO_DIV,\
+ _GATE(_gate_offset, _bit_idx, 0),\
+ _MUX(_mux_offset, _mux_bit, _mux_width, 0),\
+}
+
#define _MP1_GATE(_gate_offset, _bit_idx, _flags)\
_GATE_OPS(_gate_offset, _bit_idx, _flags, &mp1_gate_clk_ops)

@@ -1526,6 +1535,14 @@ static struct clk_hw *_clk_register_cktim(struct device *dev,
RCC_APB4ENSETR, 0, 0),

MP1_GATE(GPU_K, "gpu_k", "pll2_q", 0, RCC_AHB6ENSETR, 5, 0),
+
+ /* RTC clock */
+ DIV(NO_ID, "ck_hse_rtc", "ck_hse", 0, RCC_RTCDIVR, 0, 7,
+ CLK_DIVIDER_ALLOW_ZERO),
+
+ COMPOSITE(RTC, "ck_rtc", rtc_src, CLK_OPS_PARENT_ENABLE |
+ CLK_SET_RATE_PARENT,
+ _GATEMUX(RCC_BDCR, 20, RCC_BDCR, 16, 2)),
};

struct stm32_clock_match_data {
--
1.9.1


2018-02-02 14:09:22

by Gabriel FERNANDEZ

[permalink] [raw]
Subject: [PATCH 02/14] dt-bindings: clock: add STM32MP1 clocks

From: Gabriel Fernandez <[email protected]>

This patch adds the clock binding entry for STM32MP1

Signed-off-by: Gabriel Fernandez <[email protected]>
---
include/dt-bindings/clock/stm32mp1-clks.h | 248 ++++++++++++++++++++++++++++++
1 file changed, 248 insertions(+)
create mode 100644 include/dt-bindings/clock/stm32mp1-clks.h

diff --git a/include/dt-bindings/clock/stm32mp1-clks.h b/include/dt-bindings/clock/stm32mp1-clks.h
new file mode 100644
index 0000000..11978f7
--- /dev/null
+++ b/include/dt-bindings/clock/stm32mp1-clks.h
@@ -0,0 +1,248 @@
+/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: Gabriel Fernandez <[email protected]> for STMicroelectronics.
+ */
+
+#ifndef _DT_BINDINGS_STM32MP1_CLKS_H_
+#define _DT_BINDINGS_STM32MP1_CLKS_H_
+
+/* OSCILLATOR clocks */
+#define CK_HSE 0
+#define CK_CSI 1
+#define CK_LSI 2
+#define CK_LSE 3
+#define CK_HSI 4
+#define CK_HSE_DIV2 5
+
+/* Bus clocks */
+#define TIM2 6
+#define TIM3 7
+#define TIM4 8
+#define TIM5 9
+#define TIM6 10
+#define TIM7 11
+#define TIM12 12
+#define TIM13 13
+#define TIM14 14
+#define LPTIM1 15
+#define SPI2 16
+#define SPI3 17
+#define USART2 18
+#define USART3 19
+#define UART4 20
+#define UART5 21
+#define UART7 22
+#define UART8 23
+#define I2C1 24
+#define I2C2 25
+#define I2C3 26
+#define I2C5 27
+#define SPDIF 28
+#define CEC 29
+#define DAC12 30
+#define MDIO 31
+#define TIM1 32
+#define TIM8 33
+#define TIM15 34
+#define TIM16 35
+#define TIM17 36
+#define SPI1 37
+#define SPI4 38
+#define SPI5 39
+#define USART6 40
+#define SAI1 41
+#define SAI2 42
+#define SAI3 43
+#define DFSDM 44
+#define FDCAN 45
+#define LPTIM2 46
+#define LPTIM3 47
+#define LPTIM4 48
+#define LPTIM5 49
+#define SAI4 50
+#define SYSCFG 51
+#define VREF 52
+#define TMPSENS 53
+#define PMBCTRL 54
+#define HDP 55
+#define LTDC 56
+#define DSI 57
+#define IWDG2 58
+#define USBPHY 59
+#define STGENRO 60
+#define SPI6 61
+#define I2C4 62
+#define I2C6 63
+#define USART1 64
+#define RTCAPB 65
+#define TZC 66
+#define TZPC 67
+#define IWDG1 68
+#define BSEC 69
+#define STGEN 70
+#define DMA1 71
+#define DMA2 72
+#define DMAMUX 73
+#define ADC12 74
+#define USBO 75
+#define SDMMC3 76
+#define DCMI 77
+#define CRYP2 78
+#define HASH2 79
+#define RNG2 80
+#define CRC2 81
+#define HSEM 82
+#define IPCC 83
+#define GPIOA 84
+#define GPIOB 85
+#define GPIOC 86
+#define GPIOD 87
+#define GPIOE 88
+#define GPIOF 89
+#define GPIOG 90
+#define GPIOH 91
+#define GPIOI 92
+#define GPIOJ 93
+#define GPIOK 94
+#define GPIOZ 95
+#define CRYP1 96
+#define HASH1 97
+#define RNG1 98
+#define BKPSRAM 99
+#define MDMA 100
+#define GPU 102
+#define ETHCK 103
+#define ETHTX 104
+#define ETHRX 105
+#define ETHMAC 106
+#define FMC 107
+#define QSPI 108
+#define SDMMC1 109
+#define SDMMC2 110
+#define CRC1 111
+#define USBH 112
+#define ETHSTP 113
+
+/* Kernel clocks */
+#define SDMMC1_K 114
+#define SDMMC2_K 115
+#define SDMMC3_K 116
+#define FMC_K 117
+#define QSPI_K 118
+#define ETHMAC_K 119
+#define RNG1_K 120
+#define RNG2_K 121
+#define GPU_K 122
+#define USBPHY_K 123
+#define STGEN_K 124
+#define SPDIF_K 125
+#define SPI1_K 126
+#define SPI2_K 127
+#define SPI3_K 128
+#define SPI4_K 129
+#define SPI5_K 130
+#define SPI6_K 131
+#define CEC_K 132
+#define I2C1_K 133
+#define I2C2_K 134
+#define I2C3_K 135
+#define I2C4_K 136
+#define I2C5_K 137
+#define I2C6_K 138
+#define LPTIM1_K 139
+#define LPTIM2_K 140
+#define LPTIM3_K 141
+#define LPTIM4_K 142
+#define LPTIM5_K 143
+#define USART1_K 144
+#define USART2_K 145
+#define USART3_K 146
+#define UART4_K 147
+#define UART5_K 148
+#define USART6_K 149
+#define UART7_K 150
+#define UART8_K 151
+#define DFSDM_K 152
+#define FDCAN_K 153
+#define SAI1_K 154
+#define SAI2_K 155
+#define SAI3_K 156
+#define SAI4_K 157
+#define ADC12_K 158
+#define DSI_K 159
+#define ADFSDM_K 160
+#define USBO_K 161
+#define LTDC_K 162
+
+/* PLL */
+#define PLL1 163
+#define PLL2 164
+#define PLL3 165
+#define PLL4 166
+
+/* ODF */
+#define PLL1_P 167
+#define PLL1_Q 168
+#define PLL1_R 169
+#define PLL2_P 170
+#define PLL2_Q 171
+#define PLL2_R 172
+#define PLL3_P 173
+#define PLL3_Q 174
+#define PLL3_R 175
+#define PLL4_P 176
+#define PLL4_Q 177
+#define PLL4_R 178
+
+/* AUX */
+#define RTC 179
+
+/* MCLK */
+#define CK_PER 180
+#define CK_MPU 181
+#define CK_AXI 182
+#define CK_MCU 183
+
+/* Time base */
+#define TIM2_K 184
+#define TIM3_K 185
+#define TIM4_K 186
+#define TIM5_K 187
+#define TIM6_K 188
+#define TIM7_K 189
+#define TIM12_K 190
+#define TIM13_K 191
+#define TIM14_K 192
+#define TIM1_K 193
+#define TIM8_K 194
+#define TIM15_K 195
+#define TIM16_K 196
+#define TIM17_K 197
+
+/* MCO clocks */
+#define CK_MCO1 198
+#define CK_MCO2 199
+
+/* TRACE & DEBUG clocks */
+#define DBG 200
+#define CK_DBG 201
+#define CK_TRACE 202
+
+/* DDR */
+#define DDRC1 203
+#define DDRC1LP 204
+#define DDRC2 205
+#define DDRC2LP 206
+#define DDRPHYC 207
+#define DDRPHYCLP 208
+#define DDRCAPB 209
+#define DDRCAPBLP 210
+#define AXIDCG 211
+#define DDRPHYCAPB 212
+#define DDRPHYCAPBLP 213
+#define DDRPERFM 214
+
+#define STM32MP1_LAST_CLK 215
+
+#endif /* _DT_BINDINGS_STM32MP1_CLKS_H_ */
--
1.9.1


2018-02-02 14:10:06

by Gabriel FERNANDEZ

[permalink] [raw]
Subject: [PATCH 06/14] clk: stm32mp1: add PLL clocks

From: Gabriel Fernandez <[email protected]>

STMP32MP1 has 4 PLLs.
PLL supports integer and fractional mode.
Each PLL has 3 output dividers (p, q, r)

Signed-off-by: Gabriel Fernandez <[email protected]>
---
drivers/clk/clk-stm32mp1.c | 209 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 209 insertions(+)

diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c
index 1c9a84a..33f0d09 100644
--- a/drivers/clk/clk-stm32mp1.c
+++ b/drivers/clk/clk-stm32mp1.c
@@ -7,6 +7,7 @@

#include <linux/clk.h>
#include <linux/clk-provider.h>
+#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of.h>
@@ -506,6 +507,181 @@ static struct clk_hw *clk_register_mp1_gate(struct device *dev,
return hw;
}

+/* STM32 PLL */
+
+struct stm32_pll_obj {
+ /* lock pll enable/disable registers */
+ spinlock_t *lock;
+ void __iomem *reg;
+ struct clk_hw hw;
+};
+
+#define to_pll(_hw) container_of(_hw, struct stm32_pll_obj, hw)
+
+#define PLL_ON BIT(0)
+#define PLL_RDY BIT(1)
+#define DIVN_MASK 0x1FF
+#define DIVM_MASK 0x3F
+#define DIVM_SHIFT 16
+#define DIVN_SHIFT 0
+#define FRAC_OFFSET 0xC
+#define FRAC_MASK 0x1FFF
+#define FRAC_SHIFT 3
+#define FRACLE BIT(16)
+
+static int __pll_is_enabled(struct clk_hw *hw)
+{
+ struct stm32_pll_obj *clk_elem = to_pll(hw);
+
+ return readl_relaxed(clk_elem->reg) & PLL_ON;
+}
+
+#define TIMEOUT 5
+
+static int pll_enable(struct clk_hw *hw)
+{
+ struct stm32_pll_obj *clk_elem = to_pll(hw);
+ u32 reg;
+ unsigned long flags = 0;
+ unsigned int timeout = TIMEOUT;
+ int bit_status = 0;
+
+ spin_lock_irqsave(clk_elem->lock, flags);
+
+ if (__pll_is_enabled(hw))
+ goto unlock;
+
+ reg = readl_relaxed(clk_elem->reg);
+ reg |= PLL_ON;
+ writel_relaxed(reg, clk_elem->reg);
+
+ /* We can't use readl_poll_timeout() because we can be blocked if
+ * someone enables this clock before clocksource changes.
+ * Only jiffies counter is available. Jiffies are incremented by
+ * interruptions and enable op does not allow to be interrupted.
+ */
+ do {
+ bit_status = !(readl_relaxed(clk_elem->reg) & PLL_RDY);
+
+ if (bit_status)
+ udelay(120);
+
+ } while (bit_status && --timeout);
+
+unlock:
+ spin_unlock_irqrestore(clk_elem->lock, flags);
+
+ return bit_status;
+}
+
+static void pll_disable(struct clk_hw *hw)
+{
+ struct stm32_pll_obj *clk_elem = to_pll(hw);
+ u32 reg;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(clk_elem->lock, flags);
+
+ reg = readl_relaxed(clk_elem->reg);
+ reg &= ~PLL_ON;
+ writel_relaxed(reg, clk_elem->reg);
+
+ spin_unlock_irqrestore(clk_elem->lock, flags);
+}
+
+static u32 pll_frac_val(struct clk_hw *hw)
+{
+ struct stm32_pll_obj *clk_elem = to_pll(hw);
+ u32 reg, frac = 0;
+
+ reg = readl_relaxed(clk_elem->reg + FRAC_OFFSET);
+ if (reg & FRACLE)
+ frac = (reg >> FRAC_SHIFT) & FRAC_MASK;
+
+ return frac;
+}
+
+static unsigned long pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct stm32_pll_obj *clk_elem = to_pll(hw);
+ u32 reg;
+ u32 frac, divm, divn;
+ u64 rate, rate_frac = 0;
+
+ reg = readl_relaxed(clk_elem->reg + 4);
+
+ divm = ((reg >> DIVM_SHIFT) & DIVM_MASK) + 1;
+ divn = ((reg >> DIVN_SHIFT) & DIVN_MASK) + 1;
+ rate = (u64)parent_rate * divn;
+
+ do_div(rate, divm);
+
+ frac = pll_frac_val(hw);
+ if (frac) {
+ rate_frac = (u64)parent_rate * (u64)frac;
+ do_div(rate_frac, (divm * 8192));
+ }
+
+ return rate + rate_frac;
+}
+
+static int pll_is_enabled(struct clk_hw *hw)
+{
+ struct stm32_pll_obj *clk_elem = to_pll(hw);
+ unsigned long flags = 0;
+ int ret;
+
+ spin_lock_irqsave(clk_elem->lock, flags);
+ ret = __pll_is_enabled(hw);
+ spin_unlock_irqrestore(clk_elem->lock, flags);
+
+ return ret;
+}
+
+static const struct clk_ops pll_ops = {
+ .enable = pll_enable,
+ .disable = pll_disable,
+ .recalc_rate = pll_recalc_rate,
+ .is_enabled = pll_is_enabled,
+};
+
+static struct clk_hw *clk_register_pll(struct device *dev, const char *name,
+ const char *parent_name,
+ void __iomem *reg,
+ unsigned long flags,
+ spinlock_t *lock)
+{
+ struct stm32_pll_obj *element;
+ struct clk_init_data init;
+ struct clk_hw *hw;
+ int err;
+
+ element = kzalloc(sizeof(*element), GFP_KERNEL);
+ if (!element)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &pll_ops;
+ init.flags = flags;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ element->hw.init = &init;
+ element->reg = reg;
+ element->lock = lock;
+
+ hw = &element->hw;
+ err = clk_hw_register(dev, hw);
+
+ if (err) {
+ kfree(element);
+ return ERR_PTR(err);
+ }
+
+ return hw;
+}
+
static struct clk_hw *
_clk_register_mp1_gate(struct device *dev,
struct clk_hw_onecell_data *clk_data,
@@ -524,6 +700,21 @@ static struct clk_hw *clk_register_mp1_gate(struct device *dev,
lock);
}

+struct stm32_pll_cfg {
+ u32 offset;
+};
+
+struct clk_hw *_clk_register_pll(struct device *dev,
+ struct clk_hw_onecell_data *clk_data,
+ void __iomem *base, spinlock_t *lock,
+ const struct clock_config *cfg)
+{
+ struct stm32_pll_cfg *stm_pll_cfg = cfg->cfg;
+
+ return clk_register_pll(dev, cfg->name, cfg->parent_name,
+ base + stm_pll_cfg->offset, cfg->flags, lock);
+}
+
#define GATE(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\
{\
.id = _id,\
@@ -602,6 +793,18 @@ static struct clk_hw *clk_register_mp1_gate(struct device *dev,
.func = _clk_register_mp1_gate,\
}

+#define PLL(_id, _name, _parent, _flags, _offset)\
+{\
+ .id = _id,\
+ .name = _name,\
+ .parent_name = _parent,\
+ .flags = _flags,\
+ .cfg = &(struct stm32_pll_cfg) {\
+ .offset = _offset,\
+ },\
+ .func = _clk_register_pll,\
+}
+
static const struct clock_config stm32mp1_clock_cfg[] = {
/* Oscillator divider */
DIV(NO_ID, "clk-hsi-div", "clk-hsi", 0, RCC_HSICFGR, 0, 2,
@@ -625,6 +828,12 @@ static struct clk_hw *clk_register_mp1_gate(struct device *dev,

MUX(NO_ID, "ref4", ref4_parents, CLK_OPS_PARENT_ENABLE, RCC_RCK4SELR,
0, 2, CLK_MUX_READ_ONLY),
+
+ /* PLLs */
+ PLL(PLL1, "pll1", "ref1", CLK_IGNORE_UNUSED, RCC_PLL1CR),
+ PLL(PLL2, "pll2", "ref1", CLK_IGNORE_UNUSED, RCC_PLL2CR),
+ PLL(PLL3, "pll3", "ref3", CLK_IGNORE_UNUSED, RCC_PLL3CR),
+ PLL(PLL4, "pll4", "ref4", CLK_IGNORE_UNUSED, RCC_PLL4CR),
};

struct stm32_clock_match_data {
--
1.9.1


2018-02-02 14:10:39

by Gabriel FERNANDEZ

[permalink] [raw]
Subject: [PATCH 04/14] clk: stm32mp1: add MP1 gate for osc hse/hsi/csi oscillators

From: Gabriel Fernandez <[email protected]>

MP1 Gate is a gate with a set and a clear register.
This patch also introduces divider and fixed factor clocks.

Signed-off-by: Gabriel Fernandez <[email protected]>
---
drivers/clk/clk-stm32mp1.c | 186 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 186 insertions(+)

diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c
index 6e39e85..be5a4e5 100644
--- a/drivers/clk/clk-stm32mp1.c
+++ b/drivers/clk/clk-stm32mp1.c
@@ -355,6 +355,19 @@ struct gate_cfg {
u8 gate_flags;
};

+struct fixed_factor_cfg {
+ unsigned int mult;
+ unsigned int div;
+};
+
+struct div_cfg {
+ u32 reg_off;
+ u8 shift;
+ u8 width;
+ u8 div_flags;
+ const struct clk_div_table *table;
+};
+
static struct clk_hw *
_clk_hw_register_gate(struct device *dev,
struct clk_hw_onecell_data *clk_data,
@@ -373,6 +386,122 @@ struct gate_cfg {
lock);
}

+static struct clk_hw *
+_clk_hw_register_fixed_factor(struct device *dev,
+ struct clk_hw_onecell_data *clk_data,
+ void __iomem *base, spinlock_t *lock,
+ const struct clock_config *cfg)
+{
+ struct fixed_factor_cfg *ff_cfg = cfg->cfg;
+
+ return clk_hw_register_fixed_factor(dev, cfg->name, cfg->parent_name,
+ cfg->flags, ff_cfg->mult,
+ ff_cfg->div);
+}
+
+static struct clk_hw *
+_clk_hw_register_divider_table(struct device *dev,
+ struct clk_hw_onecell_data *clk_data,
+ void __iomem *base, spinlock_t *lock,
+ const struct clock_config *cfg)
+{
+ struct div_cfg *div_cfg = cfg->cfg;
+
+ return clk_hw_register_divider_table(dev,
+ cfg->name,
+ cfg->parent_name,
+ cfg->flags,
+ div_cfg->reg_off + base,
+ div_cfg->shift,
+ div_cfg->width,
+ div_cfg->div_flags,
+ div_cfg->table,
+ lock);
+}
+
+/* MP1 Gate clock with set & clear registers */
+
+static int mp1_gate_clk_enable(struct clk_hw *hw)
+{
+ if (!clk_gate_ops.is_enabled(hw))
+ clk_gate_ops.enable(hw);
+
+ return 0;
+}
+
+static void mp1_gate_clk_disable(struct clk_hw *hw)
+{
+ struct clk_gate *gate = to_clk_gate(hw);
+ unsigned long flags = 0;
+
+ if (clk_gate_ops.is_enabled(hw)) {
+ spin_lock_irqsave(gate->lock, flags);
+ writel_relaxed(BIT(gate->bit_idx), gate->reg + RCC_CLR);
+ spin_unlock_irqrestore(gate->lock, flags);
+ }
+}
+
+const struct clk_ops mp1_gate_clk_ops = {
+ .enable = mp1_gate_clk_enable,
+ .disable = mp1_gate_clk_disable,
+ .is_enabled = clk_gate_is_enabled,
+};
+
+static struct clk_hw *clk_register_mp1_gate(struct device *dev,
+ const char *name,
+ const char *parent_name,
+ unsigned long flags,
+ void __iomem *reg, u8 bit_idx,
+ u8 clk_gate_flags, spinlock_t *lock)
+{
+ struct clk_init_data init = { NULL };
+ struct clk_gate *gate;
+ int ret;
+ struct clk_hw *hw;
+
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &mp1_gate_clk_ops;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+ init.flags = flags;
+
+ gate->reg = reg;
+ gate->bit_idx = bit_idx;
+ gate->lock = lock;
+
+ gate->hw.init = &init;
+ hw = &gate->hw;
+
+ ret = clk_hw_register(dev, hw);
+ if (ret) {
+ kfree(gate);
+ hw = ERR_PTR(ret);
+ }
+ return hw;
+}
+
+static struct clk_hw *
+_clk_register_mp1_gate(struct device *dev,
+ struct clk_hw_onecell_data *clk_data,
+ void __iomem *base, spinlock_t *lock,
+ const struct clock_config *cfg)
+{
+ struct gate_cfg *gate_cfg = cfg->cfg;
+
+ return clk_register_mp1_gate(dev,
+ cfg->name,
+ cfg->parent_name,
+ cfg->flags,
+ gate_cfg->reg_off + base,
+ gate_cfg->bit_idx,
+ gate_cfg->gate_flags,
+ lock);
+}
+
#define GATE(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\
{\
.id = _id,\
@@ -387,10 +516,67 @@ struct gate_cfg {
.func = _clk_hw_register_gate,\
}

+#define FIXED_FACTOR(_id, _name, _parent, _flags, _mult, _div)\
+{\
+ .id = _id,\
+ .name = _name,\
+ .parent_name = _parent,\
+ .flags = _flags,\
+ .cfg = &(struct fixed_factor_cfg) {\
+ .mult = _mult,\
+ .div = _div,\
+ },\
+ .func = _clk_hw_register_fixed_factor,\
+}
+
+#define DIV_TABLE(_id, _name, _parent, _flags, _offset, _shift, _width,\
+ _div_flags, _div_table)\
+{\
+ .id = _id,\
+ .name = _name,\
+ .parent_name = _parent,\
+ .flags = _flags,\
+ .cfg = &(struct div_cfg) {\
+ .reg_off = _offset,\
+ .shift = _shift,\
+ .width = _width,\
+ .div_flags = _div_flags,\
+ .table = _div_table,\
+ },\
+ .func = _clk_hw_register_divider_table,\
+}
+
+#define DIV(_id, _name, _parent, _flags, _offset, _shift, _width, _div_flags)\
+ DIV_TABLE(_id, _name, _parent, _flags, _offset, _shift, _width,\
+ _div_flags, NULL)
+
+#define MP1_GATE(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\
+{\
+ .id = _id,\
+ .name = _name,\
+ .parent_name = _parent,\
+ .flags = _flags,\
+ .cfg = &(struct gate_cfg) {\
+ .reg_off = _offset,\
+ .bit_idx = _bit_idx,\
+ .gate_flags = _gate_flags,\
+ },\
+ .func = _clk_register_mp1_gate,\
+}
+
static const struct clock_config stm32mp1_clock_cfg[] = {
+ /* Oscillator divider */
+ DIV(NO_ID, "clk-hsi-div", "clk-hsi", 0, RCC_HSICFGR, 0, 2,
+ CLK_DIVIDER_READ_ONLY),
+
/* External / Internal Oscillators */
+ MP1_GATE(CK_HSE, "ck_hse", "clk-hse", 0, RCC_OCENSETR, 8, 0),
+ MP1_GATE(CK_CSI, "ck_csi", "clk-csi", 0, RCC_OCENSETR, 4, 0),
+ MP1_GATE(CK_HSI, "ck_hsi", "clk-hsi-div", 0, RCC_OCENSETR, 0, 0),
GATE(CK_LSI, "ck_lsi", "clk-lsi", 0, RCC_RDLSICR, 0, 0),
GATE(CK_LSE, "ck_lse", "clk-lse", 0, RCC_BDCR, 0, 0),
+
+ FIXED_FACTOR(CK_HSE_DIV2, "clk-hse-div2", "ck_hse", 0, 1, 2),
};

struct stm32_clock_match_data {
--
1.9.1


2018-02-05 06:11:38

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH 02/14] dt-bindings: clock: add STM32MP1 clocks

On Fri, Feb 02, 2018 at 03:03:30PM +0100, [email protected] wrote:
> From: Gabriel Fernandez <[email protected]>
>
> This patch adds the clock binding entry for STM32MP1
>
> Signed-off-by: Gabriel Fernandez <[email protected]>
> ---
> include/dt-bindings/clock/stm32mp1-clks.h | 248 ++++++++++++++++++++++++++++++
> 1 file changed, 248 insertions(+)
> create mode 100644 include/dt-bindings/clock/stm32mp1-clks.h

You can squash this into the previous patch.

2018-02-05 06:12:22

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH 01/14] dt-bindings: Document STM32MP1 Reset Clock Controller (RCC) bindings

On Fri, Feb 02, 2018 at 03:03:29PM +0100, [email protected] wrote:
> From: Gabriel Fernandez <[email protected]>
>
> The RCC block is responsible of the management of the clock and reset
> generation for the complete circuit.
>
> Signed-off-by: Gabriel Fernandez <[email protected]>
> ---
> .../devicetree/bindings/mfd/st,stm32-rcc.txt | 85 ++++++++++++++++++++++
> 1 file changed, 85 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/mfd/st,stm32-rcc.txt
>
> diff --git a/Documentation/devicetree/bindings/mfd/st,stm32-rcc.txt b/Documentation/devicetree/bindings/mfd/st,stm32-rcc.txt
> new file mode 100644
> index 0000000..28017a1
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mfd/st,stm32-rcc.txt
> @@ -0,0 +1,85 @@
> +STMicroelectronics STM32 Peripheral Reset Clock Controller
> +==========================================================
> +
> +The RCC IP is both a reset and a clock controller.
> +
> +Please also refer to reset.txt for common reset controller binding usage.
> +
> +Please also refer to clock-bindings.txt for common clock controller
> +binding usage.
> +
> +
> +Required properties:
> +- compatible: "simple-mfd", "syscon"


> +- reg: should be register base and length as documented in the datasheet
> +
> +- Sub-nodes:
> + - compatible: "st,stm32mp1-rcc-clk"
> + - #clock-cells: 1, device nodes should specify the clock in their
> + "clocks" property, containing a phandle to the clock device node,
> + an index specifying the clock to use.
> +
> + - compatible: "st,stm32mp1-rcc-rst"
> + - #reset-cells: Shall be 1
> +
> +Example:
> + rcc: rcc@50000000 {
> + compatible = "syscon", "simple-mfd";
> + reg = <0x50000000 0x1000>;
> +
> + rcc_clk: rcc-clk@50000000 {
> + #clock-cells = <1>;
> + compatible = "st,stm32mp1-rcc-clk";
> + };
> +
> + rcc_rst: rcc-reset@50000000 {

You should not have the same unit-address twice.

IMO, this should just be:

rcc: rcc@50000000 {
compatible = "st-stm32mp1-rcc";
reg = <0x50000000 0x1000>;
#clock-cells = <1>;
#reset-cells = <1>;
};

There's no reason a node can't provide more than 1 function.


> + #reset-cells = <1>;
> + compatible = "st,stm32mp1-rcc-rst";
> + };
> + };
> +
> +Specifying clocks
> +=================
> +
> +All available clocks are defined as preprocessor macros in
> +dt-bindings/clock/stm32mp1-clks.h header and can be used in device
> +tree sources.
> +
> +Example:
> +
> + /* Accessing DMA1 clock */
> + ... {
> + clocks = <&rcc_clk DMA1>
> + };
> +
> + /* Accessing SPI6 kernel clock */
> + ... {
> + clocks = <&rcc_clk SPI6_K>
> + };

Other than the path to header, the clock binding explains all this. No
need to duplicate here.

> +
> +Specifying softreset control of devices
> +=======================================
> +
> +Device nodes should specify the reset channel required in their "resets"
> +property, containing a phandle to the reset device node and an index specifying
> +which channel to use.
> +The index is the bit number within the RCC registers bank, starting from RCC
> +base address.
> +It is calculated as: index = register_offset / 4 * 32 + bit_offset.
> +Where bit_offset is the bit offset within the register.
> +
> +For example on STM32MP1, for LTDC reset:
> + ltdc = APB4_RSTSETR_offset / 4 * 32 + LTDC_bit_offset
> + = 0x180 / 4 * 32 + 0 = 3072
> +
> +The list of valid indices for STM32MP1 is available in:
> +include/dt-bindings/reset-controller/stm32mp1-resets.h
> +
> +This file implements defines like:
> +#define LTDC_R 3072
> +
> +example:
> +
> + ltdc {
> + resets = <&rcc_rst LTDC_R>;
> + };
> --
> 1.9.1
>

2018-02-05 07:03:03

by Gabriel FERNANDEZ

[permalink] [raw]
Subject: Re: [PATCH 01/14] dt-bindings: Document STM32MP1 Reset Clock Controller (RCC) bindings

Hi Rob,

Thanks for reviewing.


On 02/05/2018 07:09 AM, Rob Herring wrote:
> On Fri, Feb 02, 2018 at 03:03:29PM +0100, [email protected] wrote:
>> From: Gabriel Fernandez <[email protected]>
>>
>> The RCC block is responsible of the management of the clock and reset
>> generation for the complete circuit.
>>
>> Signed-off-by: Gabriel Fernandez <[email protected]>
>> ---
>> .../devicetree/bindings/mfd/st,stm32-rcc.txt | 85 ++++++++++++++++++++++
>> 1 file changed, 85 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/mfd/st,stm32-rcc.txt
>>
>> diff --git a/Documentation/devicetree/bindings/mfd/st,stm32-rcc.txt b/Documentation/devicetree/bindings/mfd/st,stm32-rcc.txt
>> new file mode 100644
>> index 0000000..28017a1
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mfd/st,stm32-rcc.txt
>> @@ -0,0 +1,85 @@
>> +STMicroelectronics STM32 Peripheral Reset Clock Controller
>> +==========================================================
>> +
>> +The RCC IP is both a reset and a clock controller.
>> +
>> +Please also refer to reset.txt for common reset controller binding usage.
>> +
>> +Please also refer to clock-bindings.txt for common clock controller
>> +binding usage.
>> +
>> +
>> +Required properties:
>> +- compatible: "simple-mfd", "syscon"
>
>> +- reg: should be register base and length as documented in the datasheet
>> +
>> +- Sub-nodes:
>> + - compatible: "st,stm32mp1-rcc-clk"
>> + - #clock-cells: 1, device nodes should specify the clock in their
>> + "clocks" property, containing a phandle to the clock device node,
>> + an index specifying the clock to use.
>> +
>> + - compatible: "st,stm32mp1-rcc-rst"
>> + - #reset-cells: Shall be 1
>> +
>> +Example:
>> + rcc: rcc@50000000 {
>> + compatible = "syscon", "simple-mfd";
>> + reg = <0x50000000 0x1000>;
>> +
>> + rcc_clk: rcc-clk@50000000 {
>> + #clock-cells = <1>;
>> + compatible = "st,stm32mp1-rcc-clk";
>> + };
>> +
>> + rcc_rst: rcc-reset@50000000 {
> You should not have the same unit-address twice.
>
> IMO, this should just be:
>
> rcc: rcc@50000000 {
> compatible = "st-stm32mp1-rcc";
> reg = <0x50000000 0x1000>;
> #clock-cells = <1>;
> #reset-cells = <1>;
> };
>
> There's no reason a node can't provide more than 1 function.
RCC is an dedicated IP for clocks and resets, but also for power
management (patches will be sent later)
Then i need to probe 3 drivers with same IP.
It's also a way to avoid use of 'CLK_OF_DECLARE_DRIVER' and i need it to
probe the 3th driver.

BR
Gabriel

>
>
>> + #reset-cells = <1>;
>> + compatible = "st,stm32mp1-rcc-rst";
>> + };
>> + };
>> +
>> +Specifying clocks
>> +=================
>> +
>> +All available clocks are defined as preprocessor macros in
>> +dt-bindings/clock/stm32mp1-clks.h header and can be used in device
>> +tree sources.
>> +
>> +Example:
>> +
>> + /* Accessing DMA1 clock */
>> + ... {
>> + clocks = <&rcc_clk DMA1>
>> + };
>> +
>> + /* Accessing SPI6 kernel clock */
>> + ... {
>> + clocks = <&rcc_clk SPI6_K>
>> + };
> Other than the path to header, the clock binding explains all this. No
> need to duplicate here.
ok
>> +
>> +Specifying softreset control of devices
>> +=======================================
>> +
>> +Device nodes should specify the reset channel required in their "resets"
>> +property, containing a phandle to the reset device node and an index specifying
>> +which channel to use.
>> +The index is the bit number within the RCC registers bank, starting from RCC
>> +base address.
>> +It is calculated as: index = register_offset / 4 * 32 + bit_offset.
>> +Where bit_offset is the bit offset within the register.
>> +
>> +For example on STM32MP1, for LTDC reset:
>> + ltdc = APB4_RSTSETR_offset / 4 * 32 + LTDC_bit_offset
>> + = 0x180 / 4 * 32 + 0 = 3072
>> +
>> +The list of valid indices for STM32MP1 is available in:
>> +include/dt-bindings/reset-controller/stm32mp1-resets.h
>> +
>> +This file implements defines like:
>> +#define LTDC_R 3072
>> +
>> +example:
>> +
>> + ltdc {
>> + resets = <&rcc_rst LTDC_R>;
>> + };
>> --
>> 1.9.1
>>

2018-02-05 07:04:49

by Gabriel FERNANDEZ

[permalink] [raw]
Subject: Re: [PATCH 02/14] dt-bindings: clock: add STM32MP1 clocks



On 02/05/2018 07:09 AM, Rob Herring wrote:
> On Fri, Feb 02, 2018 at 03:03:30PM +0100, [email protected] wrote:
>> From: Gabriel Fernandez <[email protected]>
>>
>> This patch adds the clock binding entry for STM32MP1
>>
>> Signed-off-by: Gabriel Fernandez <[email protected]>
>> ---
>> include/dt-bindings/clock/stm32mp1-clks.h | 248 ++++++++++++++++++++++++++++++
>> 1 file changed, 248 insertions(+)
>> create mode 100644 include/dt-bindings/clock/stm32mp1-clks.h
> You can squash this into the previous patch.
Ok Thanks!

BR
Gabriel

2018-02-05 07:17:41

by Gabriel FERNANDEZ

[permalink] [raw]
Subject: Re: [PATCH 01/14] dt-bindings: Document STM32MP1 Reset Clock Controller (RCC) bindings



On 02/05/2018 07:09 AM, Rob Herring wrote:
> On Fri, Feb 02, 2018 at 03:03:29PM +0100, [email protected] wrote:
>> From: Gabriel Fernandez <[email protected]>
>>
>> The RCC block is responsible of the management of the clock and reset
>> generation for the complete circuit.
>>
>> Signed-off-by: Gabriel Fernandez <[email protected]>
>> ---
>> .../devicetree/bindings/mfd/st,stm32-rcc.txt | 85 ++++++++++++++++++++++
>> 1 file changed, 85 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/mfd/st,stm32-rcc.txt
>>
>> diff --git a/Documentation/devicetree/bindings/mfd/st,stm32-rcc.txt b/Documentation/devicetree/bindings/mfd/st,stm32-rcc.txt
>> new file mode 100644
>> index 0000000..28017a1
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mfd/st,stm32-rcc.txt
>> @@ -0,0 +1,85 @@
>> +STMicroelectronics STM32 Peripheral Reset Clock Controller
>> +==========================================================
>> +
>> +The RCC IP is both a reset and a clock controller.
>> +
>> +Please also refer to reset.txt for common reset controller binding usage.
>> +
>> +Please also refer to clock-bindings.txt for common clock controller
>> +binding usage.
>> +
>> +
>> +Required properties:
>> +- compatible: "simple-mfd", "syscon"
>
>> +- reg: should be register base and length as documented in the datasheet
>> +
>> +- Sub-nodes:
>> + - compatible: "st,stm32mp1-rcc-clk"
>> + - #clock-cells: 1, device nodes should specify the clock in their
>> + "clocks" property, containing a phandle to the clock device node,
>> + an index specifying the clock to use.
>> +
>> + - compatible: "st,stm32mp1-rcc-rst"
>> + - #reset-cells: Shall be 1
>> +
>> +Example:
>> + rcc: rcc@50000000 {
>> + compatible = "syscon", "simple-mfd";
>> + reg = <0x50000000 0x1000>;
>> +
>> + rcc_clk: rcc-clk@50000000 {
>> + #clock-cells = <1>;
>> + compatible = "st,stm32mp1-rcc-clk";
>> + };
>> +
>> + rcc_rst: rcc-reset@50000000 {
> You should not have the same unit-address twice.
i can change if you want into:

        rcc: rcc@50000000 {
            compatible = "syscon", "simple-mfd";

            reg = <0x50000000 0x1000>;

            rcc_clk: rcc-clk {
                #clock-cells = <1>;
                compatible = "st,stm32mp1-rcc-clk";
            };

            rcc_rst: rcc-reset {
                #reset-cells = <1>;
                compatible = "st,stm32mp1-rcc-rst";
            };
BR
Gabriel

> IMO, this should just be:
>
> rcc: rcc@50000000 {
> compatible = "st-stm32mp1-rcc";
> reg = <0x50000000 0x1000>;
> #clock-cells = <1>;
> #reset-cells = <1>;
> };
>
> There's no reason a node can't provide more than 1 function.
>
>
>> + #reset-cells = <1>;
>> + compatible = "st,stm32mp1-rcc-rst";
>> + };
>> + };
>> +
>> +Specifying clocks
>> +=================
>> +
>> +All available clocks are defined as preprocessor macros in
>> +dt-bindings/clock/stm32mp1-clks.h header and can be used in device
>> +tree sources.
>> +
>> +Example:
>> +
>> + /* Accessing DMA1 clock */
>> + ... {
>> + clocks = <&rcc_clk DMA1>
>> + };
>> +
>> + /* Accessing SPI6 kernel clock */
>> + ... {
>> + clocks = <&rcc_clk SPI6_K>
>> + };
> Other than the path to header, the clock binding explains all this. No
> need to duplicate here.
>
>> +
>> +Specifying softreset control of devices
>> +=======================================
>> +
>> +Device nodes should specify the reset channel required in their "resets"
>> +property, containing a phandle to the reset device node and an index specifying
>> +which channel to use.
>> +The index is the bit number within the RCC registers bank, starting from RCC
>> +base address.
>> +It is calculated as: index = register_offset / 4 * 32 + bit_offset.
>> +Where bit_offset is the bit offset within the register.
>> +
>> +For example on STM32MP1, for LTDC reset:
>> + ltdc = APB4_RSTSETR_offset / 4 * 32 + LTDC_bit_offset
>> + = 0x180 / 4 * 32 + 0 = 3072
>> +
>> +The list of valid indices for STM32MP1 is available in:
>> +include/dt-bindings/reset-controller/stm32mp1-resets.h
>> +
>> +This file implements defines like:
>> +#define LTDC_R 3072
>> +
>> +example:
>> +
>> + ltdc {
>> + resets = <&rcc_rst LTDC_R>;
>> + };
>> --
>> 1.9.1
>>

2018-02-07 18:05:13

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH 01/14] dt-bindings: Document STM32MP1 Reset Clock Controller (RCC) bindings

On Mon, Feb 5, 2018 at 1:01 AM, Gabriel FERNANDEZ
<[email protected]> wrote:
> Hi Rob,
>
> Thanks for reviewing.
>
>
> On 02/05/2018 07:09 AM, Rob Herring wrote:
>> On Fri, Feb 02, 2018 at 03:03:29PM +0100, [email protected] wrote:
>>> From: Gabriel Fernandez <[email protected]>
>>>
>>> The RCC block is responsible of the management of the clock and reset
>>> generation for the complete circuit.
>>>
>>> Signed-off-by: Gabriel Fernandez <[email protected]>
>>> ---
>>> .../devicetree/bindings/mfd/st,stm32-rcc.txt | 85 ++++++++++++++++++++++
>>> 1 file changed, 85 insertions(+)
>>> create mode 100644 Documentation/devicetree/bindings/mfd/st,stm32-rcc.txt
>>>
>>> diff --git a/Documentation/devicetree/bindings/mfd/st,stm32-rcc.txt b/Documentation/devicetree/bindings/mfd/st,stm32-rcc.txt
>>> new file mode 100644
>>> index 0000000..28017a1
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/mfd/st,stm32-rcc.txt
>>> @@ -0,0 +1,85 @@
>>> +STMicroelectronics STM32 Peripheral Reset Clock Controller
>>> +==========================================================
>>> +
>>> +The RCC IP is both a reset and a clock controller.
>>> +
>>> +Please also refer to reset.txt for common reset controller binding usage.
>>> +
>>> +Please also refer to clock-bindings.txt for common clock controller
>>> +binding usage.
>>> +
>>> +
>>> +Required properties:
>>> +- compatible: "simple-mfd", "syscon"
>>
>>> +- reg: should be register base and length as documented in the datasheet
>>> +
>>> +- Sub-nodes:
>>> + - compatible: "st,stm32mp1-rcc-clk"
>>> + - #clock-cells: 1, device nodes should specify the clock in their
>>> + "clocks" property, containing a phandle to the clock device node,
>>> + an index specifying the clock to use.
>>> +
>>> + - compatible: "st,stm32mp1-rcc-rst"
>>> + - #reset-cells: Shall be 1
>>> +
>>> +Example:
>>> + rcc: rcc@50000000 {
>>> + compatible = "syscon", "simple-mfd";
>>> + reg = <0x50000000 0x1000>;
>>> +
>>> + rcc_clk: rcc-clk@50000000 {
>>> + #clock-cells = <1>;
>>> + compatible = "st,stm32mp1-rcc-clk";
>>> + };
>>> +
>>> + rcc_rst: rcc-reset@50000000 {
>> You should not have the same unit-address twice.
>>
>> IMO, this should just be:
>>
>> rcc: rcc@50000000 {
>> compatible = "st-stm32mp1-rcc";
>> reg = <0x50000000 0x1000>;
>> #clock-cells = <1>;
>> #reset-cells = <1>;
>> };
>>
>> There's no reason a node can't provide more than 1 function.
> RCC is an dedicated IP for clocks and resets, but also for power
> management (patches will be sent later)

If there's additional functions, they should be part of the binding
now, not later. bindings should not unnecessarily evolve.

> Then i need to probe 3 drivers with same IP.

Drivers and DT nodes don't have to be 1-1. A parent driver can create
additional child devices.

Also, looking at your existing bindings for RCC IP, it is done as I suggested.

> It's also a way to avoid use of 'CLK_OF_DECLARE_DRIVER' and i need it to
> probe the 3th driver.

Sounds like a Linux problem, not a DT issue.

Rob

2018-02-13 14:39:38

by Gabriel FERNANDEZ

[permalink] [raw]
Subject: Re: [PATCH 01/14] dt-bindings: Document STM32MP1 Reset Clock Controller (RCC) bindings



On 02/07/2018 07:03 PM, Rob Herring wrote:
> On Mon, Feb 5, 2018 at 1:01 AM, Gabriel FERNANDEZ
> <[email protected]> wrote:
>> Hi Rob,
>>
>> Thanks for reviewing.
>>
>>
>> On 02/05/2018 07:09 AM, Rob Herring wrote:
>>> On Fri, Feb 02, 2018 at 03:03:29PM +0100,[email protected] wrote:
>>>> From: Gabriel Fernandez<[email protected]>
>>>>
>>>> The RCC block is responsible of the management of the clock and reset
>>>> generation for the complete circuit.
>>>>
>>>> Signed-off-by: Gabriel Fernandez<[email protected]>
>>>> ---
>>>> .../devicetree/bindings/mfd/st,stm32-rcc.txt | 85 ++++++++++++++++++++++
>>>> 1 file changed, 85 insertions(+)
>>>> create mode 100644 Documentation/devicetree/bindings/mfd/st,stm32-rcc.txt
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/mfd/st,stm32-rcc.txt b/Documentation/devicetree/bindings/mfd/st,stm32-rcc.txt
>>>> new file mode 100644
>>>> index 0000000..28017a1
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/mfd/st,stm32-rcc.txt
>>>> @@ -0,0 +1,85 @@
>>>> +STMicroelectronics STM32 Peripheral Reset Clock Controller
>>>> +==========================================================
>>>> +
>>>> +The RCC IP is both a reset and a clock controller.
>>>> +
>>>> +Please also refer to reset.txt for common reset controller binding usage.
>>>> +
>>>> +Please also refer to clock-bindings.txt for common clock controller
>>>> +binding usage.
>>>> +
>>>> +
>>>> +Required properties:
>>>> +- compatible: "simple-mfd", "syscon"
>>>> +- reg: should be register base and length as documented in the datasheet
>>>> +
>>>> +- Sub-nodes:
>>>> + - compatible: "st,stm32mp1-rcc-clk"
>>>> + - #clock-cells: 1, device nodes should specify the clock in their
>>>> + "clocks" property, containing a phandle to the clock device node,
>>>> + an index specifying the clock to use.
>>>> +
>>>> + - compatible: "st,stm32mp1-rcc-rst"
>>>> + - #reset-cells: Shall be 1
>>>> +
>>>> +Example:
>>>> + rcc: rcc@50000000 {
>>>> + compatible = "syscon", "simple-mfd";
>>>> + reg = <0x50000000 0x1000>;
>>>> +
>>>> + rcc_clk: rcc-clk@50000000 {
>>>> + #clock-cells = <1>;
>>>> + compatible = "st,stm32mp1-rcc-clk";
>>>> + };
>>>> +
>>>> + rcc_rst: rcc-reset@50000000 {
>>> You should not have the same unit-address twice.
>>>
>>> IMO, this should just be:
>>>
>>> rcc: rcc@50000000 {
>>> compatible = "st-stm32mp1-rcc";
>>> reg = <0x50000000 0x1000>;
>>> #clock-cells = <1>;
>>> #reset-cells = <1>;
>>> };
>>>
>>> There's no reason a node can't provide more than 1 function.
>> RCC is an dedicated IP for clocks and resets, but also for power
>> management (patches will be sent later)
> If there's additional functions, they should be part of the binding
> now, not later. bindings should not unnecessarily evolve.
Yes you're right i will do it.
>> Then i need to probe 3 drivers with same IP.
> Drivers and DT nodes don't have to be 1-1. A parent driver can create
> additional child devices.
>
> Also, looking at your existing bindings for RCC IP, it is done as I suggested.
>
>> It's also a way to avoid use of 'CLK_OF_DECLARE_DRIVER' and i need it to
>> probe the 3th driver.
> Sounds like a Linux problem, not a DT issue.
>
> Rob
RCC is an IP block wich exposed multiple functionalities (clock, reset,
power management),
mfd should be the best solution to populate each functionality in
natural way,
and to access to registers ?

Gabriel