mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 04:31:50 +00:00
clk: stm32: Introduce STM32MP13 RCC drivers (Reset Clock Controller)
This driver manages Reset and Clock of STM32MP13 soc. It uses a clk-stm32-core module to manage stm32 gate, mux and divider for STM32MP13 and for new future soc. All gates, muxes, dividers are identify by an index and information are stored in array (register address, shift, with, flags...) This is useful when we have two clocks with the same gate or when one mux manages two output clocks. Signed-off-by: Gabriel Fernandez <gabriel.fernandez@foss.st.com> Link: https://lore.kernel.org/r/20220516070600.7692-3-gabriel.fernandez@foss.st.com Signed-off-by: Stephen Boyd <sboyd@kernel.org>
This commit is contained in:
parent
722dc8a1d5
commit
637cee5ffc
@ -368,6 +368,11 @@ config COMMON_CLK_VC5
|
||||
This driver supports the IDT VersaClock 5 and VersaClock 6
|
||||
programmable clock generators.
|
||||
|
||||
config COMMON_CLK_STM32MP135
|
||||
def_bool COMMON_CLK && MACH_STM32MP13
|
||||
help
|
||||
Support for stm32mp135 SoC family clocks
|
||||
|
||||
config COMMON_CLK_STM32MP157
|
||||
def_bool COMMON_CLK && MACH_STM32MP157
|
||||
help
|
||||
|
@ -115,6 +115,7 @@ obj-y += socfpga/
|
||||
obj-$(CONFIG_PLAT_SPEAR) += spear/
|
||||
obj-y += sprd/
|
||||
obj-$(CONFIG_ARCH_STI) += st/
|
||||
obj-$(CONFIG_ARCH_STM32) += stm32/
|
||||
obj-$(CONFIG_SOC_STARFIVE) += starfive/
|
||||
obj-$(CONFIG_ARCH_SUNXI) += sunxi/
|
||||
obj-y += sunxi-ng/
|
||||
|
1
drivers/clk/stm32/Makefile
Normal file
1
drivers/clk/stm32/Makefile
Normal file
@ -0,0 +1 @@
|
||||
obj-$(CONFIG_COMMON_CLK_STM32MP135) += clk-stm32mp13.o clk-stm32-core.o reset-stm32.o
|
93
drivers/clk/stm32/clk-stm32-core.c
Normal file
93
drivers/clk/stm32/clk-stm32-core.c
Normal file
@ -0,0 +1,93 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) STMicroelectronics 2022 - All Rights Reserved
|
||||
* Author: Gabriel Fernandez <gabriel.fernandez@foss.st.com> for STMicroelectronics.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.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 "clk-stm32-core.h"
|
||||
#include "reset-stm32.h"
|
||||
|
||||
static DEFINE_SPINLOCK(rlock);
|
||||
|
||||
static int stm32_rcc_clock_init(struct device *dev,
|
||||
const struct of_device_id *match,
|
||||
void __iomem *base)
|
||||
{
|
||||
const struct stm32_rcc_match_data *data = match->data;
|
||||
struct clk_hw_onecell_data *clk_data = data->hw_clks;
|
||||
struct device_node *np = dev_of_node(dev);
|
||||
struct clk_hw **hws;
|
||||
int n, max_binding;
|
||||
|
||||
max_binding = data->maxbinding;
|
||||
|
||||
clk_data = devm_kzalloc(dev, struct_size(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_clocks; n++) {
|
||||
const struct clock_config *cfg_clock = &data->tab_clocks[n];
|
||||
struct clk_hw *hw = ERR_PTR(-ENOENT);
|
||||
|
||||
if (cfg_clock->func)
|
||||
hw = (*cfg_clock->func)(dev, data, base, &rlock,
|
||||
cfg_clock);
|
||||
|
||||
if (IS_ERR(hw)) {
|
||||
dev_err(dev, "Can't register clk %d: %ld\n", n,
|
||||
PTR_ERR(hw));
|
||||
return PTR_ERR(hw);
|
||||
}
|
||||
|
||||
if (cfg_clock->id != NO_ID)
|
||||
hws[cfg_clock->id] = hw;
|
||||
}
|
||||
|
||||
return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
|
||||
}
|
||||
|
||||
int stm32_rcc_init(struct device *dev, const struct of_device_id *match_data,
|
||||
void __iomem *base)
|
||||
{
|
||||
const struct of_device_id *match;
|
||||
int err;
|
||||
|
||||
match = of_match_node(match_data, dev_of_node(dev));
|
||||
if (!match) {
|
||||
dev_err(dev, "match data not found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* RCC Reset Configuration */
|
||||
err = stm32_rcc_reset_init(dev, match, base);
|
||||
if (err) {
|
||||
pr_err("stm32 reset failed to initialize\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* RCC Clock Configuration */
|
||||
err = stm32_rcc_clock_init(dev, match, base);
|
||||
if (err) {
|
||||
pr_err("stm32 clock failed to initialize\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
92
drivers/clk/stm32/clk-stm32-core.h
Normal file
92
drivers/clk/stm32/clk-stm32-core.h
Normal file
@ -0,0 +1,92 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) STMicroelectronics 2022 - All Rights Reserved
|
||||
* Author: Gabriel Fernandez <gabriel.fernandez@foss.st.com> for STMicroelectronics.
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
|
||||
struct stm32_rcc_match_data;
|
||||
|
||||
struct stm32_mux_cfg {
|
||||
u16 offset;
|
||||
u8 shift;
|
||||
u8 width;
|
||||
u8 flags;
|
||||
u32 *table;
|
||||
u8 ready;
|
||||
};
|
||||
|
||||
struct stm32_gate_cfg {
|
||||
u16 offset;
|
||||
u8 bit_idx;
|
||||
u8 set_clr;
|
||||
};
|
||||
|
||||
struct stm32_div_cfg {
|
||||
u16 offset;
|
||||
u8 shift;
|
||||
u8 width;
|
||||
u8 flags;
|
||||
u8 ready;
|
||||
const struct clk_div_table *table;
|
||||
};
|
||||
|
||||
struct stm32_composite_cfg {
|
||||
int mux;
|
||||
int gate;
|
||||
int div;
|
||||
};
|
||||
|
||||
#define NO_ID 0xFFFFFFFF
|
||||
|
||||
#define NO_STM32_MUX 0xFFFF
|
||||
#define NO_STM32_DIV 0xFFFF
|
||||
#define NO_STM32_GATE 0xFFFF
|
||||
|
||||
struct clock_config {
|
||||
unsigned long id;
|
||||
void *clock_cfg;
|
||||
|
||||
struct clk_hw *(*func)(struct device *dev,
|
||||
const struct stm32_rcc_match_data *data,
|
||||
void __iomem *base,
|
||||
spinlock_t *lock,
|
||||
const struct clock_config *cfg);
|
||||
};
|
||||
|
||||
struct clk_stm32_clock_data {
|
||||
u16 *gate_cpt;
|
||||
const struct stm32_gate_cfg *gates;
|
||||
const struct stm32_mux_cfg *muxes;
|
||||
const struct stm32_div_cfg *dividers;
|
||||
};
|
||||
|
||||
struct stm32_rcc_match_data {
|
||||
struct clk_hw_onecell_data *hw_clks;
|
||||
unsigned int num_clocks;
|
||||
const struct clock_config *tab_clocks;
|
||||
unsigned int maxbinding;
|
||||
struct clk_stm32_clock_data *clock_data;
|
||||
u32 clear_offset;
|
||||
};
|
||||
|
||||
int stm32_rcc_reset_init(struct device *dev, const struct of_device_id *match,
|
||||
void __iomem *base);
|
||||
|
||||
int stm32_rcc_init(struct device *dev, const struct of_device_id *match_data,
|
||||
void __iomem *base);
|
||||
|
||||
/* MUX define */
|
||||
#define MUX_NO_RDY 0xFF
|
||||
|
||||
/* DIV define */
|
||||
#define DIV_NO_RDY 0xFF
|
||||
|
||||
/* Clock registering */
|
||||
#define STM32_CLOCK_CFG(_binding, _clk, _struct, _register)\
|
||||
{\
|
||||
.id = (_binding),\
|
||||
.clock_cfg = (_struct) {_clk},\
|
||||
.func = (_register),\
|
||||
}
|
520
drivers/clk/stm32/clk-stm32mp13.c
Normal file
520
drivers/clk/stm32/clk-stm32mp13.c
Normal file
@ -0,0 +1,520 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) STMicroelectronics 2022 - All Rights Reserved
|
||||
* Author: Gabriel Fernandez <gabriel.fernandez@foss.st.com> for STMicroelectronics.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <dt-bindings/clock/stm32mp13-clks.h>
|
||||
#include "clk-stm32-core.h"
|
||||
#include "stm32mp13_rcc.h"
|
||||
|
||||
#define RCC_CLR_OFFSET 0x4
|
||||
|
||||
/* STM32 Gates definition */
|
||||
enum enum_gate_cfg {
|
||||
GATE_MCO1,
|
||||
GATE_MCO2,
|
||||
GATE_DBGCK,
|
||||
GATE_TRACECK,
|
||||
GATE_DDRC1,
|
||||
GATE_DDRC1LP,
|
||||
GATE_DDRPHYC,
|
||||
GATE_DDRPHYCLP,
|
||||
GATE_DDRCAPB,
|
||||
GATE_DDRCAPBLP,
|
||||
GATE_AXIDCG,
|
||||
GATE_DDRPHYCAPB,
|
||||
GATE_DDRPHYCAPBLP,
|
||||
GATE_TIM2,
|
||||
GATE_TIM3,
|
||||
GATE_TIM4,
|
||||
GATE_TIM5,
|
||||
GATE_TIM6,
|
||||
GATE_TIM7,
|
||||
GATE_LPTIM1,
|
||||
GATE_SPI2,
|
||||
GATE_SPI3,
|
||||
GATE_USART3,
|
||||
GATE_UART4,
|
||||
GATE_UART5,
|
||||
GATE_UART7,
|
||||
GATE_UART8,
|
||||
GATE_I2C1,
|
||||
GATE_I2C2,
|
||||
GATE_SPDIF,
|
||||
GATE_TIM1,
|
||||
GATE_TIM8,
|
||||
GATE_SPI1,
|
||||
GATE_USART6,
|
||||
GATE_SAI1,
|
||||
GATE_SAI2,
|
||||
GATE_DFSDM,
|
||||
GATE_ADFSDM,
|
||||
GATE_FDCAN,
|
||||
GATE_LPTIM2,
|
||||
GATE_LPTIM3,
|
||||
GATE_LPTIM4,
|
||||
GATE_LPTIM5,
|
||||
GATE_VREF,
|
||||
GATE_DTS,
|
||||
GATE_PMBCTRL,
|
||||
GATE_HDP,
|
||||
GATE_SYSCFG,
|
||||
GATE_DCMIPP,
|
||||
GATE_DDRPERFM,
|
||||
GATE_IWDG2APB,
|
||||
GATE_USBPHY,
|
||||
GATE_STGENRO,
|
||||
GATE_LTDC,
|
||||
GATE_RTCAPB,
|
||||
GATE_TZC,
|
||||
GATE_ETZPC,
|
||||
GATE_IWDG1APB,
|
||||
GATE_BSEC,
|
||||
GATE_STGENC,
|
||||
GATE_USART1,
|
||||
GATE_USART2,
|
||||
GATE_SPI4,
|
||||
GATE_SPI5,
|
||||
GATE_I2C3,
|
||||
GATE_I2C4,
|
||||
GATE_I2C5,
|
||||
GATE_TIM12,
|
||||
GATE_TIM13,
|
||||
GATE_TIM14,
|
||||
GATE_TIM15,
|
||||
GATE_TIM16,
|
||||
GATE_TIM17,
|
||||
GATE_DMA1,
|
||||
GATE_DMA2,
|
||||
GATE_DMAMUX1,
|
||||
GATE_DMA3,
|
||||
GATE_DMAMUX2,
|
||||
GATE_ADC1,
|
||||
GATE_ADC2,
|
||||
GATE_USBO,
|
||||
GATE_TSC,
|
||||
GATE_GPIOA,
|
||||
GATE_GPIOB,
|
||||
GATE_GPIOC,
|
||||
GATE_GPIOD,
|
||||
GATE_GPIOE,
|
||||
GATE_GPIOF,
|
||||
GATE_GPIOG,
|
||||
GATE_GPIOH,
|
||||
GATE_GPIOI,
|
||||
GATE_PKA,
|
||||
GATE_SAES,
|
||||
GATE_CRYP1,
|
||||
GATE_HASH1,
|
||||
GATE_RNG1,
|
||||
GATE_BKPSRAM,
|
||||
GATE_AXIMC,
|
||||
GATE_MCE,
|
||||
GATE_ETH1CK,
|
||||
GATE_ETH1TX,
|
||||
GATE_ETH1RX,
|
||||
GATE_ETH1MAC,
|
||||
GATE_FMC,
|
||||
GATE_QSPI,
|
||||
GATE_SDMMC1,
|
||||
GATE_SDMMC2,
|
||||
GATE_CRC1,
|
||||
GATE_USBH,
|
||||
GATE_ETH2CK,
|
||||
GATE_ETH2TX,
|
||||
GATE_ETH2RX,
|
||||
GATE_ETH2MAC,
|
||||
GATE_ETH1STP,
|
||||
GATE_ETH2STP,
|
||||
GATE_MDMA,
|
||||
GATE_NB
|
||||
};
|
||||
|
||||
#define _CFG_GATE(_id, _offset, _bit_idx, _offset_clr)\
|
||||
[(_id)] = {\
|
||||
.offset = (_offset),\
|
||||
.bit_idx = (_bit_idx),\
|
||||
.set_clr = (_offset_clr),\
|
||||
}
|
||||
|
||||
#define CFG_GATE(_id, _offset, _bit_idx)\
|
||||
_CFG_GATE(_id, _offset, _bit_idx, 0)
|
||||
|
||||
#define CFG_GATE_SETCLR(_id, _offset, _bit_idx)\
|
||||
_CFG_GATE(_id, _offset, _bit_idx, RCC_CLR_OFFSET)
|
||||
|
||||
static struct stm32_gate_cfg stm32mp13_gates[] = {
|
||||
CFG_GATE(GATE_MCO1, RCC_MCO1CFGR, 12),
|
||||
CFG_GATE(GATE_MCO2, RCC_MCO2CFGR, 12),
|
||||
CFG_GATE(GATE_DBGCK, RCC_DBGCFGR, 8),
|
||||
CFG_GATE(GATE_TRACECK, RCC_DBGCFGR, 9),
|
||||
CFG_GATE(GATE_DDRC1, RCC_DDRITFCR, 0),
|
||||
CFG_GATE(GATE_DDRC1LP, RCC_DDRITFCR, 1),
|
||||
CFG_GATE(GATE_DDRPHYC, RCC_DDRITFCR, 4),
|
||||
CFG_GATE(GATE_DDRPHYCLP, RCC_DDRITFCR, 5),
|
||||
CFG_GATE(GATE_DDRCAPB, RCC_DDRITFCR, 6),
|
||||
CFG_GATE(GATE_DDRCAPBLP, RCC_DDRITFCR, 7),
|
||||
CFG_GATE(GATE_AXIDCG, RCC_DDRITFCR, 8),
|
||||
CFG_GATE(GATE_DDRPHYCAPB, RCC_DDRITFCR, 9),
|
||||
CFG_GATE(GATE_DDRPHYCAPBLP, RCC_DDRITFCR, 10),
|
||||
CFG_GATE_SETCLR(GATE_TIM2, RCC_MP_APB1ENSETR, 0),
|
||||
CFG_GATE_SETCLR(GATE_TIM3, RCC_MP_APB1ENSETR, 1),
|
||||
CFG_GATE_SETCLR(GATE_TIM4, RCC_MP_APB1ENSETR, 2),
|
||||
CFG_GATE_SETCLR(GATE_TIM5, RCC_MP_APB1ENSETR, 3),
|
||||
CFG_GATE_SETCLR(GATE_TIM6, RCC_MP_APB1ENSETR, 4),
|
||||
CFG_GATE_SETCLR(GATE_TIM7, RCC_MP_APB1ENSETR, 5),
|
||||
CFG_GATE_SETCLR(GATE_LPTIM1, RCC_MP_APB1ENSETR, 9),
|
||||
CFG_GATE_SETCLR(GATE_SPI2, RCC_MP_APB1ENSETR, 11),
|
||||
CFG_GATE_SETCLR(GATE_SPI3, RCC_MP_APB1ENSETR, 12),
|
||||
CFG_GATE_SETCLR(GATE_USART3, RCC_MP_APB1ENSETR, 15),
|
||||
CFG_GATE_SETCLR(GATE_UART4, RCC_MP_APB1ENSETR, 16),
|
||||
CFG_GATE_SETCLR(GATE_UART5, RCC_MP_APB1ENSETR, 17),
|
||||
CFG_GATE_SETCLR(GATE_UART7, RCC_MP_APB1ENSETR, 18),
|
||||
CFG_GATE_SETCLR(GATE_UART8, RCC_MP_APB1ENSETR, 19),
|
||||
CFG_GATE_SETCLR(GATE_I2C1, RCC_MP_APB1ENSETR, 21),
|
||||
CFG_GATE_SETCLR(GATE_I2C2, RCC_MP_APB1ENSETR, 22),
|
||||
CFG_GATE_SETCLR(GATE_SPDIF, RCC_MP_APB1ENSETR, 26),
|
||||
CFG_GATE_SETCLR(GATE_TIM1, RCC_MP_APB2ENSETR, 0),
|
||||
CFG_GATE_SETCLR(GATE_TIM8, RCC_MP_APB2ENSETR, 1),
|
||||
CFG_GATE_SETCLR(GATE_SPI1, RCC_MP_APB2ENSETR, 8),
|
||||
CFG_GATE_SETCLR(GATE_USART6, RCC_MP_APB2ENSETR, 13),
|
||||
CFG_GATE_SETCLR(GATE_SAI1, RCC_MP_APB2ENSETR, 16),
|
||||
CFG_GATE_SETCLR(GATE_SAI2, RCC_MP_APB2ENSETR, 17),
|
||||
CFG_GATE_SETCLR(GATE_DFSDM, RCC_MP_APB2ENSETR, 20),
|
||||
CFG_GATE_SETCLR(GATE_ADFSDM, RCC_MP_APB2ENSETR, 21),
|
||||
CFG_GATE_SETCLR(GATE_FDCAN, RCC_MP_APB2ENSETR, 24),
|
||||
CFG_GATE_SETCLR(GATE_LPTIM2, RCC_MP_APB3ENSETR, 0),
|
||||
CFG_GATE_SETCLR(GATE_LPTIM3, RCC_MP_APB3ENSETR, 1),
|
||||
CFG_GATE_SETCLR(GATE_LPTIM4, RCC_MP_APB3ENSETR, 2),
|
||||
CFG_GATE_SETCLR(GATE_LPTIM5, RCC_MP_APB3ENSETR, 3),
|
||||
CFG_GATE_SETCLR(GATE_VREF, RCC_MP_APB3ENSETR, 13),
|
||||
CFG_GATE_SETCLR(GATE_DTS, RCC_MP_APB3ENSETR, 16),
|
||||
CFG_GATE_SETCLR(GATE_PMBCTRL, RCC_MP_APB3ENSETR, 17),
|
||||
CFG_GATE_SETCLR(GATE_HDP, RCC_MP_APB3ENSETR, 20),
|
||||
CFG_GATE_SETCLR(GATE_SYSCFG, RCC_MP_NS_APB3ENSETR, 0),
|
||||
CFG_GATE_SETCLR(GATE_DCMIPP, RCC_MP_APB4ENSETR, 1),
|
||||
CFG_GATE_SETCLR(GATE_DDRPERFM, RCC_MP_APB4ENSETR, 8),
|
||||
CFG_GATE_SETCLR(GATE_IWDG2APB, RCC_MP_APB4ENSETR, 15),
|
||||
CFG_GATE_SETCLR(GATE_USBPHY, RCC_MP_APB4ENSETR, 16),
|
||||
CFG_GATE_SETCLR(GATE_STGENRO, RCC_MP_APB4ENSETR, 20),
|
||||
CFG_GATE_SETCLR(GATE_LTDC, RCC_MP_NS_APB4ENSETR, 0),
|
||||
CFG_GATE_SETCLR(GATE_RTCAPB, RCC_MP_APB5ENSETR, 8),
|
||||
CFG_GATE_SETCLR(GATE_TZC, RCC_MP_APB5ENSETR, 11),
|
||||
CFG_GATE_SETCLR(GATE_ETZPC, RCC_MP_APB5ENSETR, 13),
|
||||
CFG_GATE_SETCLR(GATE_IWDG1APB, RCC_MP_APB5ENSETR, 15),
|
||||
CFG_GATE_SETCLR(GATE_BSEC, RCC_MP_APB5ENSETR, 16),
|
||||
CFG_GATE_SETCLR(GATE_STGENC, RCC_MP_APB5ENSETR, 20),
|
||||
CFG_GATE_SETCLR(GATE_USART1, RCC_MP_APB6ENSETR, 0),
|
||||
CFG_GATE_SETCLR(GATE_USART2, RCC_MP_APB6ENSETR, 1),
|
||||
CFG_GATE_SETCLR(GATE_SPI4, RCC_MP_APB6ENSETR, 2),
|
||||
CFG_GATE_SETCLR(GATE_SPI5, RCC_MP_APB6ENSETR, 3),
|
||||
CFG_GATE_SETCLR(GATE_I2C3, RCC_MP_APB6ENSETR, 4),
|
||||
CFG_GATE_SETCLR(GATE_I2C4, RCC_MP_APB6ENSETR, 5),
|
||||
CFG_GATE_SETCLR(GATE_I2C5, RCC_MP_APB6ENSETR, 6),
|
||||
CFG_GATE_SETCLR(GATE_TIM12, RCC_MP_APB6ENSETR, 7),
|
||||
CFG_GATE_SETCLR(GATE_TIM13, RCC_MP_APB6ENSETR, 8),
|
||||
CFG_GATE_SETCLR(GATE_TIM14, RCC_MP_APB6ENSETR, 9),
|
||||
CFG_GATE_SETCLR(GATE_TIM15, RCC_MP_APB6ENSETR, 10),
|
||||
CFG_GATE_SETCLR(GATE_TIM16, RCC_MP_APB6ENSETR, 11),
|
||||
CFG_GATE_SETCLR(GATE_TIM17, RCC_MP_APB6ENSETR, 12),
|
||||
CFG_GATE_SETCLR(GATE_DMA1, RCC_MP_AHB2ENSETR, 0),
|
||||
CFG_GATE_SETCLR(GATE_DMA2, RCC_MP_AHB2ENSETR, 1),
|
||||
CFG_GATE_SETCLR(GATE_DMAMUX1, RCC_MP_AHB2ENSETR, 2),
|
||||
CFG_GATE_SETCLR(GATE_DMA3, RCC_MP_AHB2ENSETR, 3),
|
||||
CFG_GATE_SETCLR(GATE_DMAMUX2, RCC_MP_AHB2ENSETR, 4),
|
||||
CFG_GATE_SETCLR(GATE_ADC1, RCC_MP_AHB2ENSETR, 5),
|
||||
CFG_GATE_SETCLR(GATE_ADC2, RCC_MP_AHB2ENSETR, 6),
|
||||
CFG_GATE_SETCLR(GATE_USBO, RCC_MP_AHB2ENSETR, 8),
|
||||
CFG_GATE_SETCLR(GATE_TSC, RCC_MP_AHB4ENSETR, 15),
|
||||
CFG_GATE_SETCLR(GATE_GPIOA, RCC_MP_NS_AHB4ENSETR, 0),
|
||||
CFG_GATE_SETCLR(GATE_GPIOB, RCC_MP_NS_AHB4ENSETR, 1),
|
||||
CFG_GATE_SETCLR(GATE_GPIOC, RCC_MP_NS_AHB4ENSETR, 2),
|
||||
CFG_GATE_SETCLR(GATE_GPIOD, RCC_MP_NS_AHB4ENSETR, 3),
|
||||
CFG_GATE_SETCLR(GATE_GPIOE, RCC_MP_NS_AHB4ENSETR, 4),
|
||||
CFG_GATE_SETCLR(GATE_GPIOF, RCC_MP_NS_AHB4ENSETR, 5),
|
||||
CFG_GATE_SETCLR(GATE_GPIOG, RCC_MP_NS_AHB4ENSETR, 6),
|
||||
CFG_GATE_SETCLR(GATE_GPIOH, RCC_MP_NS_AHB4ENSETR, 7),
|
||||
CFG_GATE_SETCLR(GATE_GPIOI, RCC_MP_NS_AHB4ENSETR, 8),
|
||||
CFG_GATE_SETCLR(GATE_PKA, RCC_MP_AHB5ENSETR, 2),
|
||||
CFG_GATE_SETCLR(GATE_SAES, RCC_MP_AHB5ENSETR, 3),
|
||||
CFG_GATE_SETCLR(GATE_CRYP1, RCC_MP_AHB5ENSETR, 4),
|
||||
CFG_GATE_SETCLR(GATE_HASH1, RCC_MP_AHB5ENSETR, 5),
|
||||
CFG_GATE_SETCLR(GATE_RNG1, RCC_MP_AHB5ENSETR, 6),
|
||||
CFG_GATE_SETCLR(GATE_BKPSRAM, RCC_MP_AHB5ENSETR, 8),
|
||||
CFG_GATE_SETCLR(GATE_AXIMC, RCC_MP_AHB5ENSETR, 16),
|
||||
CFG_GATE_SETCLR(GATE_MCE, RCC_MP_AHB6ENSETR, 1),
|
||||
CFG_GATE_SETCLR(GATE_ETH1CK, RCC_MP_AHB6ENSETR, 7),
|
||||
CFG_GATE_SETCLR(GATE_ETH1TX, RCC_MP_AHB6ENSETR, 8),
|
||||
CFG_GATE_SETCLR(GATE_ETH1RX, RCC_MP_AHB6ENSETR, 9),
|
||||
CFG_GATE_SETCLR(GATE_ETH1MAC, RCC_MP_AHB6ENSETR, 10),
|
||||
CFG_GATE_SETCLR(GATE_FMC, RCC_MP_AHB6ENSETR, 12),
|
||||
CFG_GATE_SETCLR(GATE_QSPI, RCC_MP_AHB6ENSETR, 14),
|
||||
CFG_GATE_SETCLR(GATE_SDMMC1, RCC_MP_AHB6ENSETR, 16),
|
||||
CFG_GATE_SETCLR(GATE_SDMMC2, RCC_MP_AHB6ENSETR, 17),
|
||||
CFG_GATE_SETCLR(GATE_CRC1, RCC_MP_AHB6ENSETR, 20),
|
||||
CFG_GATE_SETCLR(GATE_USBH, RCC_MP_AHB6ENSETR, 24),
|
||||
CFG_GATE_SETCLR(GATE_ETH2CK, RCC_MP_AHB6ENSETR, 27),
|
||||
CFG_GATE_SETCLR(GATE_ETH2TX, RCC_MP_AHB6ENSETR, 28),
|
||||
CFG_GATE_SETCLR(GATE_ETH2RX, RCC_MP_AHB6ENSETR, 29),
|
||||
CFG_GATE_SETCLR(GATE_ETH2MAC, RCC_MP_AHB6ENSETR, 30),
|
||||
CFG_GATE_SETCLR(GATE_ETH1STP, RCC_MP_AHB6LPENSETR, 11),
|
||||
CFG_GATE_SETCLR(GATE_ETH2STP, RCC_MP_AHB6LPENSETR, 31),
|
||||
CFG_GATE_SETCLR(GATE_MDMA, RCC_MP_NS_AHB6ENSETR, 0),
|
||||
};
|
||||
|
||||
/* STM32 Divivers definition */
|
||||
enum enum_div_cfg {
|
||||
DIV_RTC,
|
||||
DIV_HSI,
|
||||
DIV_MCO1,
|
||||
DIV_MCO2,
|
||||
DIV_TRACE,
|
||||
DIV_ETH1PTP,
|
||||
DIV_ETH2PTP,
|
||||
DIV_NB
|
||||
};
|
||||
|
||||
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 },
|
||||
};
|
||||
|
||||
#define CFG_DIV(_id, _offset, _shift, _width, _flags, _table, _ready)\
|
||||
[(_id)] = {\
|
||||
.offset = (_offset),\
|
||||
.shift = (_shift),\
|
||||
.width = (_width),\
|
||||
.flags = (_flags),\
|
||||
.table = (_table),\
|
||||
.ready = (_ready),\
|
||||
}
|
||||
|
||||
static const struct stm32_div_cfg stm32mp13_dividers[DIV_NB] = {
|
||||
CFG_DIV(DIV_RTC, RCC_RTCDIVR, 0, 6, 0, NULL, DIV_NO_RDY),
|
||||
CFG_DIV(DIV_MCO1, RCC_MCO1CFGR, 4, 4, 0, NULL, DIV_NO_RDY),
|
||||
CFG_DIV(DIV_MCO2, RCC_MCO2CFGR, 4, 4, 0, NULL, DIV_NO_RDY),
|
||||
CFG_DIV(DIV_TRACE, RCC_DBGCFGR, 0, 3, 0, ck_trace_div_table, DIV_NO_RDY),
|
||||
CFG_DIV(DIV_ETH1PTP, RCC_ETH12CKSELR, 4, 4, 0, NULL, DIV_NO_RDY),
|
||||
CFG_DIV(DIV_ETH2PTP, RCC_ETH12CKSELR, 12, 4, 0, NULL, DIV_NO_RDY),
|
||||
};
|
||||
|
||||
/* STM32 Muxes definition */
|
||||
enum enum_mux_cfg {
|
||||
MUX_ADC1,
|
||||
MUX_ADC2,
|
||||
MUX_DCMIPP,
|
||||
MUX_ETH1,
|
||||
MUX_ETH2,
|
||||
MUX_FDCAN,
|
||||
MUX_FMC,
|
||||
MUX_I2C12,
|
||||
MUX_I2C3,
|
||||
MUX_I2C4,
|
||||
MUX_I2C5,
|
||||
MUX_LPTIM1,
|
||||
MUX_LPTIM2,
|
||||
MUX_LPTIM3,
|
||||
MUX_LPTIM45,
|
||||
MUX_MCO1,
|
||||
MUX_MCO2,
|
||||
MUX_QSPI,
|
||||
MUX_RNG1,
|
||||
MUX_SAES,
|
||||
MUX_SAI1,
|
||||
MUX_SAI2,
|
||||
MUX_SDMMC1,
|
||||
MUX_SDMMC2,
|
||||
MUX_SPDIF,
|
||||
MUX_SPI1,
|
||||
MUX_SPI23,
|
||||
MUX_SPI4,
|
||||
MUX_SPI5,
|
||||
MUX_STGEN,
|
||||
MUX_UART1,
|
||||
MUX_UART2,
|
||||
MUX_UART4,
|
||||
MUX_UART6,
|
||||
MUX_UART35,
|
||||
MUX_UART78,
|
||||
MUX_USBO,
|
||||
MUX_USBPHY,
|
||||
MUX_NB
|
||||
};
|
||||
|
||||
#define _CFG_MUX(_id, _offset, _shift, _witdh, _ready, _flags)\
|
||||
[_id] = {\
|
||||
.offset = (_offset),\
|
||||
.shift = (_shift),\
|
||||
.width = (_witdh),\
|
||||
.ready = (_ready),\
|
||||
.flags = (_flags),\
|
||||
}
|
||||
|
||||
#define CFG_MUX(_id, _offset, _shift, _witdh)\
|
||||
_CFG_MUX(_id, _offset, _shift, _witdh, MUX_NO_RDY, 0)
|
||||
|
||||
static const struct stm32_mux_cfg stm32mp13_muxes[] = {
|
||||
CFG_MUX(MUX_I2C12, RCC_I2C12CKSELR, 0, 3),
|
||||
CFG_MUX(MUX_LPTIM45, RCC_LPTIM45CKSELR, 0, 3),
|
||||
CFG_MUX(MUX_SPI23, RCC_SPI2S23CKSELR, 0, 3),
|
||||
CFG_MUX(MUX_UART35, RCC_UART35CKSELR, 0, 3),
|
||||
CFG_MUX(MUX_UART78, RCC_UART78CKSELR, 0, 3),
|
||||
CFG_MUX(MUX_ADC1, RCC_ADC12CKSELR, 0, 2),
|
||||
CFG_MUX(MUX_ADC2, RCC_ADC12CKSELR, 2, 2),
|
||||
CFG_MUX(MUX_DCMIPP, RCC_DCMIPPCKSELR, 0, 2),
|
||||
CFG_MUX(MUX_ETH1, RCC_ETH12CKSELR, 0, 2),
|
||||
CFG_MUX(MUX_ETH2, RCC_ETH12CKSELR, 8, 2),
|
||||
CFG_MUX(MUX_FDCAN, RCC_FDCANCKSELR, 0, 2),
|
||||
CFG_MUX(MUX_I2C3, RCC_I2C345CKSELR, 0, 3),
|
||||
CFG_MUX(MUX_I2C4, RCC_I2C345CKSELR, 3, 3),
|
||||
CFG_MUX(MUX_I2C5, RCC_I2C345CKSELR, 6, 3),
|
||||
CFG_MUX(MUX_LPTIM1, RCC_LPTIM1CKSELR, 0, 3),
|
||||
CFG_MUX(MUX_LPTIM2, RCC_LPTIM23CKSELR, 0, 3),
|
||||
CFG_MUX(MUX_LPTIM3, RCC_LPTIM23CKSELR, 3, 3),
|
||||
CFG_MUX(MUX_MCO1, RCC_MCO1CFGR, 0, 3),
|
||||
CFG_MUX(MUX_MCO2, RCC_MCO2CFGR, 0, 3),
|
||||
CFG_MUX(MUX_RNG1, RCC_RNG1CKSELR, 0, 2),
|
||||
CFG_MUX(MUX_SAES, RCC_SAESCKSELR, 0, 2),
|
||||
CFG_MUX(MUX_SAI1, RCC_SAI1CKSELR, 0, 3),
|
||||
CFG_MUX(MUX_SAI2, RCC_SAI2CKSELR, 0, 3),
|
||||
CFG_MUX(MUX_SPDIF, RCC_SPDIFCKSELR, 0, 2),
|
||||
CFG_MUX(MUX_SPI1, RCC_SPI2S1CKSELR, 0, 3),
|
||||
CFG_MUX(MUX_SPI4, RCC_SPI45CKSELR, 0, 3),
|
||||
CFG_MUX(MUX_SPI5, RCC_SPI45CKSELR, 3, 3),
|
||||
CFG_MUX(MUX_STGEN, RCC_STGENCKSELR, 0, 2),
|
||||
CFG_MUX(MUX_UART1, RCC_UART12CKSELR, 0, 3),
|
||||
CFG_MUX(MUX_UART2, RCC_UART12CKSELR, 3, 3),
|
||||
CFG_MUX(MUX_UART4, RCC_UART4CKSELR, 0, 3),
|
||||
CFG_MUX(MUX_UART6, RCC_UART6CKSELR, 0, 3),
|
||||
CFG_MUX(MUX_USBO, RCC_USBCKSELR, 4, 1),
|
||||
CFG_MUX(MUX_USBPHY, RCC_USBCKSELR, 0, 2),
|
||||
CFG_MUX(MUX_FMC, RCC_FMCCKSELR, 0, 2),
|
||||
CFG_MUX(MUX_QSPI, RCC_QSPICKSELR, 0, 2),
|
||||
CFG_MUX(MUX_SDMMC1, RCC_SDMMC12CKSELR, 0, 3),
|
||||
CFG_MUX(MUX_SDMMC2, RCC_SDMMC12CKSELR, 3, 3),
|
||||
};
|
||||
|
||||
static const struct clock_config stm32mp13_clock_cfg[] = {
|
||||
};
|
||||
|
||||
static u16 stm32mp13_cpt_gate[GATE_NB];
|
||||
|
||||
static struct clk_stm32_clock_data stm32mp13_clock_data = {
|
||||
.gate_cpt = stm32mp13_cpt_gate,
|
||||
.gates = stm32mp13_gates,
|
||||
.muxes = stm32mp13_muxes,
|
||||
.dividers = stm32mp13_dividers,
|
||||
};
|
||||
|
||||
static const struct stm32_rcc_match_data stm32mp13_data = {
|
||||
.tab_clocks = stm32mp13_clock_cfg,
|
||||
.num_clocks = ARRAY_SIZE(stm32mp13_clock_cfg),
|
||||
.clock_data = &stm32mp13_clock_data,
|
||||
.maxbinding = STM32MP1_LAST_CLK,
|
||||
.clear_offset = RCC_CLR_OFFSET,
|
||||
};
|
||||
|
||||
static const struct of_device_id stm32mp13_match_data[] = {
|
||||
{
|
||||
.compatible = "st,stm32mp13-rcc",
|
||||
.data = &stm32mp13_data,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, stm32mp13_match_data);
|
||||
|
||||
static int stm32mp1_rcc_init(struct device *dev)
|
||||
{
|
||||
void __iomem *rcc_base;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
rcc_base = of_iomap(dev_of_node(dev), 0);
|
||||
if (!rcc_base) {
|
||||
dev_err(dev, "%pOFn: unable to map resource", dev_of_node(dev));
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = stm32_rcc_init(dev, stm32mp13_match_data, rcc_base);
|
||||
out:
|
||||
if (ret) {
|
||||
if (rcc_base)
|
||||
iounmap(rcc_base);
|
||||
|
||||
of_node_put(dev_of_node(dev));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int get_clock_deps(struct device *dev)
|
||||
{
|
||||
static const char * const clock_deps_name[] = {
|
||||
"hsi", "hse", "csi", "lsi", "lse",
|
||||
};
|
||||
size_t deps_size = sizeof(struct clk *) * ARRAY_SIZE(clock_deps_name);
|
||||
struct clk **clk_deps;
|
||||
int i;
|
||||
|
||||
clk_deps = devm_kzalloc(dev, deps_size, GFP_KERNEL);
|
||||
if (!clk_deps)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(clock_deps_name); i++) {
|
||||
struct clk *clk = of_clk_get_by_name(dev_of_node(dev),
|
||||
clock_deps_name[i]);
|
||||
|
||||
if (IS_ERR(clk)) {
|
||||
if (PTR_ERR(clk) != -EINVAL && PTR_ERR(clk) != -ENOENT)
|
||||
return PTR_ERR(clk);
|
||||
} else {
|
||||
/* Device gets a reference count on the clock */
|
||||
clk_deps[i] = devm_clk_get(dev, __clk_get_name(clk));
|
||||
clk_put(clk);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32mp1_rcc_clocks_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret = get_clock_deps(dev);
|
||||
|
||||
if (!ret)
|
||||
ret = stm32mp1_rcc_init(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stm32mp1_rcc_clocks_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *child, *np = dev_of_node(dev);
|
||||
|
||||
for_each_available_child_of_node(np, child)
|
||||
of_clk_del_provider(child);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver stm32mp13_rcc_clocks_driver = {
|
||||
.driver = {
|
||||
.name = "stm32mp13_rcc",
|
||||
.of_match_table = stm32mp13_match_data,
|
||||
},
|
||||
.probe = stm32mp1_rcc_clocks_probe,
|
||||
.remove = stm32mp1_rcc_clocks_remove,
|
||||
};
|
||||
|
||||
static int __init stm32mp13_clocks_init(void)
|
||||
{
|
||||
return platform_driver_register(&stm32mp13_rcc_clocks_driver);
|
||||
}
|
||||
core_initcall(stm32mp13_clocks_init);
|
122
drivers/clk/stm32/reset-stm32.c
Normal file
122
drivers/clk/stm32/reset-stm32.c
Normal file
@ -0,0 +1,122 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) STMicroelectronics 2022 - All Rights Reserved
|
||||
* Author: Gabriel Fernandez <gabriel.fernandez@foss.st.com> for STMicroelectronics.
|
||||
*/
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include "clk-stm32-core.h"
|
||||
|
||||
#define STM32_RESET_ID_MASK GENMASK(15, 0)
|
||||
|
||||
struct stm32_reset_data {
|
||||
/* reset lock */
|
||||
spinlock_t lock;
|
||||
struct reset_controller_dev rcdev;
|
||||
void __iomem *membase;
|
||||
u32 clear_offset;
|
||||
};
|
||||
|
||||
static inline struct stm32_reset_data *
|
||||
to_stm32_reset_data(struct reset_controller_dev *rcdev)
|
||||
{
|
||||
return container_of(rcdev, struct stm32_reset_data, rcdev);
|
||||
}
|
||||
|
||||
static int stm32_reset_update(struct reset_controller_dev *rcdev,
|
||||
unsigned long id, bool assert)
|
||||
{
|
||||
struct stm32_reset_data *data = to_stm32_reset_data(rcdev);
|
||||
int reg_width = sizeof(u32);
|
||||
int bank = id / (reg_width * BITS_PER_BYTE);
|
||||
int offset = id % (reg_width * BITS_PER_BYTE);
|
||||
|
||||
if (data->clear_offset) {
|
||||
void __iomem *addr;
|
||||
|
||||
addr = data->membase + (bank * reg_width);
|
||||
if (!assert)
|
||||
addr += data->clear_offset;
|
||||
|
||||
writel(BIT(offset), addr);
|
||||
|
||||
} else {
|
||||
unsigned long flags;
|
||||
u32 reg;
|
||||
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
|
||||
reg = readl(data->membase + (bank * reg_width));
|
||||
|
||||
if (assert)
|
||||
reg |= BIT(offset);
|
||||
else
|
||||
reg &= ~BIT(offset);
|
||||
|
||||
writel(reg, data->membase + (bank * reg_width));
|
||||
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_reset_assert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
return stm32_reset_update(rcdev, id, true);
|
||||
}
|
||||
|
||||
static int stm32_reset_deassert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
return stm32_reset_update(rcdev, id, false);
|
||||
}
|
||||
|
||||
static int stm32_reset_status(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct stm32_reset_data *data = to_stm32_reset_data(rcdev);
|
||||
int reg_width = sizeof(u32);
|
||||
int bank = id / (reg_width * BITS_PER_BYTE);
|
||||
int offset = id % (reg_width * BITS_PER_BYTE);
|
||||
u32 reg;
|
||||
|
||||
reg = readl(data->membase + (bank * reg_width));
|
||||
|
||||
return !!(reg & BIT(offset));
|
||||
}
|
||||
|
||||
static const struct reset_control_ops stm32_reset_ops = {
|
||||
.assert = stm32_reset_assert,
|
||||
.deassert = stm32_reset_deassert,
|
||||
.status = stm32_reset_status,
|
||||
};
|
||||
|
||||
int stm32_rcc_reset_init(struct device *dev, const struct of_device_id *match,
|
||||
void __iomem *base)
|
||||
{
|
||||
const struct stm32_rcc_match_data *data = match->data;
|
||||
struct stm32_reset_data *reset_data = NULL;
|
||||
|
||||
data = match->data;
|
||||
|
||||
reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
|
||||
if (!reset_data)
|
||||
return -ENOMEM;
|
||||
|
||||
reset_data->membase = base;
|
||||
reset_data->rcdev.owner = THIS_MODULE;
|
||||
reset_data->rcdev.ops = &stm32_reset_ops;
|
||||
reset_data->rcdev.of_node = dev_of_node(dev);
|
||||
reset_data->rcdev.nr_resets = STM32_RESET_ID_MASK;
|
||||
reset_data->clear_offset = data->clear_offset;
|
||||
|
||||
return reset_controller_register(&reset_data->rcdev);
|
||||
}
|
8
drivers/clk/stm32/reset-stm32.h
Normal file
8
drivers/clk/stm32/reset-stm32.h
Normal file
@ -0,0 +1,8 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) STMicroelectronics 2022 - All Rights Reserved
|
||||
* Author: Gabriel Fernandez <gabriel.fernandez@foss.st.com> for STMicroelectronics.
|
||||
*/
|
||||
|
||||
int stm32_rcc_reset_init(struct device *dev, const struct of_device_id *match,
|
||||
void __iomem *base);
|
1748
drivers/clk/stm32/stm32mp13_rcc.h
Normal file
1748
drivers/clk/stm32/stm32mp13_rcc.h
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user