diff options
Diffstat (limited to 'drivers/clk')
67 files changed, 6366 insertions, 3038 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 98ce9fc6e6c0..ede9cb0b79d6 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -55,8 +55,10 @@ config COMMON_CLK_RK808 by control register. config COMMON_CLK_HI655X - tristate "Clock driver for Hi655x" - depends on MFD_HI655X_PMIC || COMPILE_TEST + tristate "Clock driver for Hi655x" if EXPERT + depends on (MFD_HI655X_PMIC || COMPILE_TEST) + depends on REGMAP + default MFD_HI655X_PMIC ---help--- This driver supports the hi655x PMIC clock. This multi-function device has one fixed-rate oscillator, clocked @@ -238,6 +240,26 @@ 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 + +config COMMON_CLK_STM32F + bool "Clock driver for stm32f4 and stm32f7 SoC families" + depends on MACH_STM32F429 || MACH_STM32F469 || MACH_STM32F746 + help + ---help--- + Support for stm32f4 and stm32f7 SoC families clocks + +config COMMON_CLK_STM32H7 + bool "Clock driver for stm32h7 SoC family" + depends on MACH_STM32H743 + help + ---help--- + Support for stm32h7 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 71ec41e6364f..e0c106ed9407 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -45,8 +45,9 @@ obj-$(CONFIG_COMMON_CLK_SCPI) += clk-scpi.o obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o 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_STM32F) += clk-stm32f4.o +obj-$(CONFIG_COMMON_CLK_STM32H7) += 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-divider.c b/drivers/clk/clk-divider.c index b49942b9fe50..b6234a5da12d 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -28,12 +28,10 @@ * parent - fixed parent. No clk_set_parent support */ -#define div_mask(width) ((1 << (width)) - 1) - static unsigned int _get_table_maxdiv(const struct clk_div_table *table, u8 width) { - unsigned int maxdiv = 0, mask = div_mask(width); + unsigned int maxdiv = 0, mask = clk_div_mask(width); const struct clk_div_table *clkt; for (clkt = table; clkt->div; clkt++) @@ -57,12 +55,12 @@ static unsigned int _get_maxdiv(const struct clk_div_table *table, u8 width, unsigned long flags) { if (flags & CLK_DIVIDER_ONE_BASED) - return div_mask(width); + return clk_div_mask(width); if (flags & CLK_DIVIDER_POWER_OF_TWO) - return 1 << div_mask(width); + return 1 << clk_div_mask(width); if (table) return _get_table_maxdiv(table, width); - return div_mask(width) + 1; + return clk_div_mask(width) + 1; } static unsigned int _get_table_div(const struct clk_div_table *table, @@ -84,7 +82,7 @@ static unsigned int _get_div(const struct clk_div_table *table, if (flags & CLK_DIVIDER_POWER_OF_TWO) return 1 << val; if (flags & CLK_DIVIDER_MAX_AT_ZERO) - return val ? val : div_mask(width) + 1; + return val ? val : clk_div_mask(width) + 1; if (table) return _get_table_div(table, val); return val + 1; @@ -109,7 +107,7 @@ static unsigned int _get_val(const struct clk_div_table *table, if (flags & CLK_DIVIDER_POWER_OF_TWO) return __ffs(div); if (flags & CLK_DIVIDER_MAX_AT_ZERO) - return (div == div_mask(width) + 1) ? 0 : div; + return (div == clk_div_mask(width) + 1) ? 0 : div; if (table) return _get_table_val(table, div); return div - 1; @@ -141,7 +139,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, unsigned int val; val = clk_readl(divider->reg) >> divider->shift; - val &= div_mask(divider->width); + val &= clk_div_mask(divider->width); return divider_recalc_rate(hw, parent_rate, val, divider->table, divider->flags, divider->width); @@ -344,19 +342,43 @@ long divider_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent, } EXPORT_SYMBOL_GPL(divider_round_rate_parent); +long divider_ro_round_rate_parent(struct clk_hw *hw, struct clk_hw *parent, + unsigned long rate, unsigned long *prate, + const struct clk_div_table *table, u8 width, + unsigned long flags, unsigned int val) +{ + int div; + + div = _get_div(table, val, flags, width); + + /* Even a read-only clock can propagate a rate change */ + if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) { + if (!parent) + return -EINVAL; + + *prate = clk_hw_round_rate(parent, rate * div); + } + + return DIV_ROUND_UP_ULL((u64)*prate, div); +} +EXPORT_SYMBOL_GPL(divider_ro_round_rate_parent); + + static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) { struct clk_divider *divider = to_clk_divider(hw); - int bestdiv; /* if read only, just return current value */ if (divider->flags & CLK_DIVIDER_READ_ONLY) { - bestdiv = clk_readl(divider->reg) >> divider->shift; - bestdiv &= div_mask(divider->width); - bestdiv = _get_div(divider->table, bestdiv, divider->flags, - divider->width); - return DIV_ROUND_UP_ULL((u64)*prate, bestdiv); + u32 val; + + val = clk_readl(divider->reg) >> divider->shift; + val &= clk_div_mask(divider->width); + + return divider_ro_round_rate(hw, rate, prate, divider->table, + divider->width, divider->flags, + val); } return divider_round_rate(hw, rate, prate, divider->table, @@ -376,7 +398,7 @@ int divider_get_val(unsigned long rate, unsigned long parent_rate, value = _get_val(table, div, flags, width); - return min_t(unsigned int, value, div_mask(width)); + return min_t(unsigned int, value, clk_div_mask(width)); } EXPORT_SYMBOL_GPL(divider_get_val); @@ -399,10 +421,10 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, __acquire(divider->lock); if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { - val = div_mask(divider->width) << (divider->shift + 16); + val = clk_div_mask(divider->width) << (divider->shift + 16); } else { val = clk_readl(divider->reg); - val &= ~(div_mask(divider->width) << divider->shift); + val &= ~(clk_div_mask(divider->width) << divider->shift); } val |= (u32)value << divider->shift; clk_writel(val, divider->reg); diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index 151513c655c3..40af4fbab4d2 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -73,14 +73,14 @@ static u8 clk_gpio_mux_get_parent(struct clk_hw *hw) { struct clk_gpio *clk = to_clk_gpio(hw); - return gpiod_get_value(clk->gpiod); + return gpiod_get_value_cansleep(clk->gpiod); } static int clk_gpio_mux_set_parent(struct clk_hw *hw, u8 index) { struct clk_gpio *clk = to_clk_gpio(hw); - gpiod_set_value(clk->gpiod, index); + gpiod_set_value_cansleep(clk->gpiod, index); return 0; } diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c index 39cabe157163..ac4a042f8658 100644 --- a/drivers/clk/clk-mux.c +++ b/drivers/clk/clk-mux.c @@ -26,35 +26,24 @@ * parent - parent is adjustable through clk_set_parent */ -static u8 clk_mux_get_parent(struct clk_hw *hw) +int clk_mux_val_to_index(struct clk_hw *hw, u32 *table, unsigned int flags, + unsigned int val) { - struct clk_mux *mux = to_clk_mux(hw); int num_parents = clk_hw_get_num_parents(hw); - u32 val; - /* - * FIXME need a mux-specific flag to determine if val is bitwise or numeric - * e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges from 0x1 - * to 0x7 (index starts at one) - * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so - * val = 0x4 really means "bit 2, index starts at bit 0" - */ - val = clk_readl(mux->reg) >> mux->shift; - val &= mux->mask; - - if (mux->table) { + if (table) { int i; for (i = 0; i < num_parents; i++) - if (mux->table[i] == val) + if (table[i] == val) return i; return -EINVAL; } - if (val && (mux->flags & CLK_MUX_INDEX_BIT)) + if (val && (flags & CLK_MUX_INDEX_BIT)) val = ffs(val) - 1; - if (val && (mux->flags & CLK_MUX_INDEX_ONE)) + if (val && (flags & CLK_MUX_INDEX_ONE)) val--; if (val >= num_parents) @@ -62,36 +51,58 @@ static u8 clk_mux_get_parent(struct clk_hw *hw) return val; } +EXPORT_SYMBOL_GPL(clk_mux_val_to_index); -static int clk_mux_set_parent(struct clk_hw *hw, u8 index) +unsigned int clk_mux_index_to_val(u32 *table, unsigned int flags, u8 index) { - struct clk_mux *mux = to_clk_mux(hw); - u32 val; - unsigned long flags = 0; + unsigned int val = index; - if (mux->table) { - index = mux->table[index]; + if (table) { + val = table[index]; } else { - if (mux->flags & CLK_MUX_INDEX_BIT) - index = 1 << index; + if (flags & CLK_MUX_INDEX_BIT) + val = 1 << index; - if (mux->flags & CLK_MUX_INDEX_ONE) - index++; + if (flags & CLK_MUX_INDEX_ONE) + val++; } + return val; +} +EXPORT_SYMBOL_GPL(clk_mux_index_to_val); + +static u8 clk_mux_get_parent(struct clk_hw *hw) +{ + struct clk_mux *mux = to_clk_mux(hw); + u32 val; + + val = clk_readl(mux->reg) >> mux->shift; + val &= mux->mask; + + return clk_mux_val_to_index(hw, mux->table, mux->flags, val); +} + +static int clk_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_mux *mux = to_clk_mux(hw); + u32 val = clk_mux_index_to_val(mux->table, mux->flags, index); + unsigned long flags = 0; + u32 reg; + if (mux->lock) spin_lock_irqsave(mux->lock, flags); else __acquire(mux->lock); if (mux->flags & CLK_MUX_HIWORD_MASK) { - val = mux->mask << (mux->shift + 16); + reg = mux->mask << (mux->shift + 16); } else { - val = clk_readl(mux->reg); - val &= ~(mux->mask << mux->shift); + reg = clk_readl(mux->reg); + reg &= ~(mux->mask << mux->shift); } - val |= index << mux->shift; - clk_writel(val, mux->reg); + val = val << mux->shift; + reg |= val; + clk_writel(reg, mux->reg); if (mux->lock) spin_unlock_irqrestore(mux->lock, flags); diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c index da44f8dc1d29..294850bdc195 100644 --- a/drivers/clk/clk-stm32f4.c +++ b/drivers/clk/clk-stm32f4.c @@ -282,6 +282,7 @@ static const struct stm32f4_gate_data stm32f746_gates[] __initconst = { { STM32F4_RCC_APB2ENR, 0, "tim1", "apb2_mul" }, { STM32F4_RCC_APB2ENR, 1, "tim8", "apb2_mul" }, + { STM32F4_RCC_APB2ENR, 7, "sdmmc2", "sdmux" }, { STM32F4_RCC_APB2ENR, 8, "adc1", "apb2_div" }, { STM32F4_RCC_APB2ENR, 9, "adc2", "apb2_div" }, { STM32F4_RCC_APB2ENR, 10, "adc3", "apb2_div" }, @@ -315,7 +316,7 @@ static const u64 stm32f46xx_gate_map[MAX_GATE_MAP] = { 0x000000f17ef417ffull, static const u64 stm32f746_gate_map[MAX_GATE_MAP] = { 0x000000f17ef417ffull, 0x0000000000000003ull, - 0x04f77f033e01c9ffull }; + 0x04f77f833e01c9ffull }; static const u64 *stm32f4_gate_map; @@ -521,7 +522,7 @@ static const struct stm32f4_pll_data stm32f429_pll[MAX_PLL_DIV] = { }; static const struct stm32f4_pll_data stm32f469_pll[MAX_PLL_DIV] = { - { PLL, 50, { "pll", "pll-q", NULL } }, + { PLL, 50, { "pll", "pll-q", "pll-r" } }, { PLL_I2S, 50, { "plli2s-p", "plli2s-q", "plli2s-r" } }, { PLL_SAI, 50, { "pllsai-p", "pllsai-q", "pllsai-r" } }, }; @@ -1047,6 +1048,8 @@ static const char *rtc_parents[4] = { "no-clock", "lse", "lsi", "hse-rtc" }; +static const char *dsi_parent[2] = { NULL, "pll-r" }; + static const char *lcd_parent[1] = { "pllsai-r-div" }; static const char *i2s_parents[2] = { "plli2s-r", NULL }; @@ -1156,6 +1159,12 @@ static const struct stm32_aux_clk stm32f469_aux_clk[] = { NO_GATE, 0, 0 }, + { + CLK_F469_DSI, "dsi", dsi_parent, ARRAY_SIZE(dsi_parent), + STM32F4_RCC_DCKCFGR, 29, 1, + STM32F4_RCC_APB2ENR, 27, + CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT + }, }; static const struct stm32_aux_clk stm32f746_aux_clk[] = { @@ -1450,6 +1459,7 @@ static void __init stm32f4_rcc_init(struct device_node *np) stm32f4_gate_map = data->gates_map; hse_clk = of_clk_get_parent_name(np, 0); + dsi_parent[0] = hse_clk; i2s_in_clk = of_clk_get_parent_name(np, 1); diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c new file mode 100644 index 000000000000..f1d5967b4b39 --- /dev/null +++ b/drivers/clk/clk-stm32mp1.c @@ -0,0 +1,2117 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + * Author: Olivier Bideau <olivier.bideau@st.com> for STMicroelectronics. + * Author: Gabriel Fernandez <gabriel.fernandez@st.com> for STMicroelectronics. + */ + +#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> +#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_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_I2C46CKSELR 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_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_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 sdmmc12_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 spi123_src[] = { + "pll4_p", "pll3_q", "i2s_ckin", "ck_per", "pll3_r" +}; + +static const char * const spi45_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 i2c12_src[] = { + "pclk1", "pll4_r", "ck_hsi", "ck_csi" +}; + +static const char * const i2c35_src[] = { + "pclk1", "pll4_r", "ck_hsi", "ck_csi" +}; + +static const char * const i2c46_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 lptim23_src[] = { + "pclk3", "pll4_q", "ck_per", "ck_lse", "ck_lsi" +}; + +static const char * const lptim45_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 usart234578_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 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 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" +}; + +static const char * const ck_trace_src[] = { + "ck_axi" +}; + +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 }, +}; + +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 MAX_MUX_CLK 2 + +struct stm32_mmux { + u8 nbr_clk; + struct clk_hw *hws[MAX_MUX_CLK]; +}; + +struct stm32_clk_mmux { + struct clk_mux mux; + struct stm32_mmux *mmux; +}; + +struct stm32_mgate { + u8 nbr_clk; + u32 flag; +}; + +struct stm32_clk_mgate { + struct clk_gate gate; + struct stm32_mgate *mgate; + u32 mask; +}; + +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; +}; + +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; +}; + +struct mux_cfg { + u32 reg_off; + u8 shift; + u8 width; + u8 mux_flags; + u32 *table; +}; + +struct stm32_gate_cfg { + struct gate_cfg *gate; + struct stm32_mgate *mgate; + const struct clk_ops *ops; +}; + +struct stm32_div_cfg { + struct div_cfg *div; + const struct clk_ops *ops; +}; + +struct stm32_mux_cfg { + struct mux_cfg *mux; + struct stm32_mmux *mmux; + const struct clk_ops *ops; +}; + +/* STM32 Composite clock */ +struct stm32_composite_cfg { + const struct stm32_gate_cfg *gate; + const struct stm32_div_cfg *div; + const struct stm32_mux_cfg *mux; +}; + +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); +} + +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); +} + +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) +{ + 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 *_get_stm32_mux(void __iomem *base, + const struct stm32_mux_cfg *cfg, + spinlock_t *lock) +{ + struct stm32_clk_mmux *mmux; + struct clk_mux *mux; + struct clk_hw *mux_hw; + + if (cfg->mmux) { + mmux = kzalloc(sizeof(*mmux), GFP_KERNEL); + if (!mmux) + return ERR_PTR(-ENOMEM); + + mmux->mux.reg = cfg->mux->reg_off + base; + mmux->mux.shift = cfg->mux->shift; + mmux->mux.mask = (1 << cfg->mux->width) - 1; + mmux->mux.flags = cfg->mux->mux_flags; + mmux->mux.table = cfg->mux->table; + mmux->mux.lock = lock; + mmux->mmux = cfg->mmux; + mux_hw = &mmux->mux.hw; + cfg->mmux->hws[cfg->mmux->nbr_clk++] = mux_hw; + + } else { + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) + return ERR_PTR(-ENOMEM); + + mux->reg = cfg->mux->reg_off + base; + mux->shift = cfg->mux->shift; + mux->mask = (1 << cfg->mux->width) - 1; + mux->flags = cfg->mux->mux_flags; + mux->table = cfg->mux->table; + mux->lock = lock; + mux_hw = &mux->hw; + } + + return mux_hw; +} + +static struct clk_hw *_get_stm32_div(void __iomem *base, + const struct stm32_div_cfg *cfg, + spinlock_t *lock) +{ + struct clk_divider *div; + + div = kzalloc(sizeof(*div), GFP_KERNEL); + + if (!div) + return ERR_PTR(-ENOMEM); + + div->reg = cfg->div->reg_off + base; + div->shift = cfg->div->shift; + div->width = cfg->div->width; + div->flags = cfg->div->div_flags; + div->table = cfg->div->table; + div->lock = lock; + + return &div->hw; +} + +static struct clk_hw * +_get_stm32_gate(void __iomem *base, + const struct stm32_gate_cfg *cfg, spinlock_t *lock) +{ + struct stm32_clk_mgate *mgate; + struct clk_gate *gate; + struct clk_hw *gate_hw; + + if (cfg->mgate) { + mgate = kzalloc(sizeof(*mgate), GFP_KERNEL); + if (!mgate) + return ERR_PTR(-ENOMEM); + + mgate->gate.reg = cfg->gate->reg_off + base; + mgate->gate.bit_idx = cfg->gate->bit_idx; + mgate->gate.flags = cfg->gate->gate_flags; + mgate->gate.lock = lock; + mgate->mask = BIT(cfg->mgate->nbr_clk++); + + mgate->mgate = cfg->mgate; + + gate_hw = &mgate->gate.hw; + + } else { + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) + return ERR_PTR(-ENOMEM); + + gate->reg = cfg->gate->reg_off + base; + gate->bit_idx = cfg->gate->bit_idx; + gate->flags = cfg->gate->gate_flags; + gate->lock = lock; + + gate_hw = &gate->hw; + } + + return gate_hw; +} + +static struct clk_hw * +clk_stm32_register_gate_ops(struct device *dev, + const char *name, + const char *parent_name, + unsigned long flags, + void __iomem *base, + const struct stm32_gate_cfg *cfg, + spinlock_t *lock) +{ + struct clk_init_data init = { NULL }; + struct clk_gate *gate; + struct clk_hw *hw; + int ret; + + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.parent_names = &parent_name; + init.num_parents = 1; + init.flags = flags; + + init.ops = &clk_gate_ops; + + if (cfg->ops) + init.ops = cfg->ops; + + hw = _get_stm32_gate(base, cfg, lock); + if (IS_ERR(hw)) + return ERR_PTR(-ENOMEM); + + hw->init = &init; + + ret = clk_hw_register(dev, hw); + if (ret) { + kfree(gate); + hw = ERR_PTR(ret); + } + + return hw; +} + +static struct clk_hw * +clk_stm32_register_composite(struct device *dev, + const char *name, const char * const *parent_names, + int num_parents, void __iomem *base, + const struct stm32_composite_cfg *cfg, + unsigned long flags, spinlock_t *lock) +{ + const struct clk_ops *mux_ops, *div_ops, *gate_ops; + struct clk_hw *mux_hw, *div_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_hw = _get_stm32_mux(base, cfg->mux, lock); + + if (!IS_ERR(mux_hw)) { + mux_ops = &clk_mux_ops; + + if (cfg->mux->ops) + mux_ops = cfg->mux->ops; + } + } + + if (cfg->div) { + div_hw = _get_stm32_div(base, cfg->div, lock); + + if (!IS_ERR(div_hw)) { + div_ops = &clk_divider_ops; + + if (cfg->div->ops) + div_ops = cfg->div->ops; + } + } + + if (cfg->gate) { + gate_hw = _get_stm32_gate(base, cfg->gate, lock); + + if (!IS_ERR(gate_hw)) { + gate_ops = &clk_gate_ops; + + if (cfg->gate->ops) + gate_ops = cfg->gate->ops; + } + } + + return clk_hw_register_composite(dev, name, parent_names, num_parents, + mux_hw, mux_ops, div_hw, div_ops, + gate_hw, gate_ops, flags); +} + +#define to_clk_mgate(_gate) container_of(_gate, struct stm32_clk_mgate, gate) + +static int mp1_mgate_clk_enable(struct clk_hw *hw) +{ + struct clk_gate *gate = to_clk_gate(hw); + struct stm32_clk_mgate *clk_mgate = to_clk_mgate(gate); + + clk_mgate->mgate->flag |= clk_mgate->mask; + + mp1_gate_clk_enable(hw); + + return 0; +} + +static void mp1_mgate_clk_disable(struct clk_hw *hw) +{ + struct clk_gate *gate = to_clk_gate(hw); + struct stm32_clk_mgate *clk_mgate = to_clk_mgate(gate); + + clk_mgate->mgate->flag &= ~clk_mgate->mask; + + if (clk_mgate->mgate->flag == 0) + mp1_gate_clk_disable(hw); +} + +const struct clk_ops mp1_mgate_clk_ops = { + .enable = mp1_mgate_clk_enable, + .disable = mp1_mgate_clk_disable, + .is_enabled = clk_gate_is_enabled, + +}; + +#define to_clk_mmux(_mux) container_of(_mux, struct stm32_clk_mmux, mux) + +static u8 clk_mmux_get_parent(struct clk_hw *hw) +{ + return clk_mux_ops.get_parent(hw); +} + +static int clk_mmux_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_mux *mux = to_clk_mux(hw); + struct stm32_clk_mmux *clk_mmux = to_clk_mmux(mux); + struct clk_hw *hwp; + int ret, n; + + ret = clk_mux_ops.set_parent(hw, index); + if (ret) + return ret; + + hwp = clk_hw_get_parent(hw); + + for (n = 0; n < clk_mmux->mmux->nbr_clk; n++) + if (clk_mmux->mmux->hws[n] != hw) + clk_hw_reparent(clk_mmux->mmux->hws[n], hwp); + + return 0; +} + +const struct clk_ops clk_mmux_ops = { + .get_parent = clk_mmux_get_parent, + .set_parent = clk_mmux_set_parent, + .determine_rate = __clk_mux_determine_rate, +}; + +/* 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; +} + +/* 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; +} + +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); +} + +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); +} + +static struct clk_hw * +_clk_stm32_register_gate(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg) +{ + return clk_stm32_register_gate_ops(dev, + cfg->name, + cfg->parent_name, + cfg->flags, + base, + cfg->cfg, + lock); +} + +static struct clk_hw * +_clk_stm32_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_stm32_register_composite(dev, cfg->name, cfg->parent_names, + cfg->num_parents, base, cfg->cfg, + cfg->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,\ +} + +#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 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 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,\ +} + +#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)\ + GATE_MP1(_id, _name, _parent, CLK_SET_RATE_PARENT,\ + _offset_set, _bit_idx, 0) + +/* STM32 GATE */ +#define STM32_GATE(_id, _name, _parent, _flags, _gate)\ +{\ + .id = _id,\ + .name = _name,\ + .parent_name = _parent,\ + .flags = _flags,\ + .cfg = (struct stm32_gate_cfg *) {_gate},\ + .func = _clk_stm32_register_gate,\ +} + +#define _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags, _mgate, _ops)\ + (&(struct stm32_gate_cfg) {\ + &(struct gate_cfg) {\ + .reg_off = _gate_offset,\ + .bit_idx = _gate_bit_idx,\ + .gate_flags = _gate_flags,\ + },\ + .mgate = _mgate,\ + .ops = _ops,\ + }) + +#define _STM32_MGATE(_mgate)\ + (&per_gate_cfg[_mgate]) + +#define _GATE(_gate_offset, _gate_bit_idx, _gate_flags)\ + _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags,\ + NULL, NULL)\ + +#define _GATE_MP1(_gate_offset, _gate_bit_idx, _gate_flags)\ + _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags,\ + NULL, &mp1_gate_clk_ops)\ + +#define _MGATE_MP1(_mgate)\ + .gate = &per_gate_cfg[_mgate] + +#define GATE_MP1(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\ + STM32_GATE(_id, _name, _parent, _flags,\ + _GATE_MP1(_offset, _bit_idx, _gate_flags)) + +#define MGATE_MP1(_id, _name, _parent, _flags, _mgate)\ + STM32_GATE(_id, _name, _parent, _flags,\ + _STM32_MGATE(_mgate)) + +#define _STM32_DIV(_div_offset, _div_shift, _div_width,\ + _div_flags, _div_table, _ops)\ + .div = &(struct stm32_div_cfg) {\ + &(struct div_cfg) {\ + .reg_off = _div_offset,\ + .shift = _div_shift,\ + .width = _div_width,\ + .div_flags = _div_flags,\ + .table = _div_table,\ + },\ + .ops = _ops,\ + } + +#define _DIV(_div_offset, _div_shift, _div_width, _div_flags, _div_table)\ + _STM32_DIV(_div_offset, _div_shift, _div_width,\ + _div_flags, _div_table, NULL)\ + +#define _STM32_MUX(_offset, _shift, _width, _mux_flags, _mmux, _ops)\ + .mux = &(struct stm32_mux_cfg) {\ + &(struct mux_cfg) {\ + .reg_off = _offset,\ + .shift = _shift,\ + .width = _width,\ + .mux_flags = _mux_flags,\ + .table = NULL,\ + },\ + .mmux = _mmux,\ + .ops = _ops,\ + } + +#define _MUX(_offset, _shift, _width, _mux_flags)\ + _STM32_MUX(_offset, _shift, _width, _mux_flags, NULL, NULL)\ + +#define _MMUX(_mmux) .mux = &ker_mux_cfg[_mmux] + +#define PARENT(_parent) ((const char *[]) { _parent}) + +#define _NO_MUX .mux = NULL +#define _NO_DIV .div = NULL +#define _NO_GATE .gate = NULL + +#define COMPOSITE(_id, _name, _parents, _flags, _gate, _mux, _div)\ +{\ + .id = _id,\ + .name = _name,\ + .parent_names = _parents,\ + .num_parents = ARRAY_SIZE(_parents),\ + .flags = _flags,\ + .cfg = &(struct stm32_composite_cfg) {\ + _gate,\ + _mux,\ + _div,\ + },\ + .func = _clk_stm32_register_composite,\ +} + +#define PCLK(_id, _name, _parent, _flags, _mgate)\ + MGATE_MP1(_id, _name, _parent, _flags, _mgate) + +#define KCLK(_id, _name, _parents, _flags, _mgate, _mmux)\ + COMPOSITE(_id, _name, _parents, CLK_OPS_PARENT_ENABLE | _flags,\ + _MGATE_MP1(_mgate),\ + _MMUX(_mmux),\ + _NO_DIV) + +enum { + G_SAI1, + G_SAI2, + G_SAI3, + G_SAI4, + G_SPI1, + G_SPI2, + G_SPI3, + G_SPI4, + G_SPI5, + G_SPI6, + G_SPDIF, + G_I2C1, + G_I2C2, + G_I2C3, + G_I2C4, + G_I2C5, + G_I2C6, + G_USART2, + G_UART4, + G_USART3, + G_UART5, + G_USART1, + G_USART6, + G_UART7, + G_UART8, + G_LPTIM1, + G_LPTIM2, + G_LPTIM3, + G_LPTIM4, + G_LPTIM5, + G_LTDC, + G_DSI, + G_QSPI, + G_FMC, + G_SDMMC1, + G_SDMMC2, + G_SDMMC3, + G_USBO, + G_USBPHY, + G_RNG1, + G_RNG2, + G_FDCAN, + G_DAC12, + G_CEC, + G_ADC12, + G_GPU, + G_STGEN, + G_DFSDM, + G_ADFSDM, + G_TIM2, + G_TIM3, + G_TIM4, + G_TIM5, + G_TIM6, + G_TIM7, + G_TIM12, + G_TIM13, + G_TIM14, + G_MDIO, + G_TIM1, + G_TIM8, + G_TIM15, + G_TIM16, + G_TIM17, + G_SYSCFG, + G_VREF, + G_TMPSENS, + G_PMBCTRL, + G_HDP, + G_IWDG2, + G_STGENRO, + G_DMA1, + G_DMA2, + G_DMAMUX, + G_DCMI, + G_CRYP2, + G_HASH2, + G_CRC2, + G_HSEM, + G_IPCC, + G_GPIOA, + G_GPIOB, + G_GPIOC, + G_GPIOD, + G_GPIOE, + G_GPIOF, + G_GPIOG, + G_GPIOH, + G_GPIOI, + G_GPIOJ, + G_GPIOK, + G_MDMA, + G_ETHCK, + G_ETHTX, + G_ETHRX, + G_ETHMAC, + G_CRC1, + G_USBH, + G_ETHSTP, + G_RTCAPB, + G_TZC, + G_TZPC, + G_IWDG1, + G_BSEC, + G_GPIOZ, + G_CRYP1, + G_HASH1, + G_BKPSRAM, + + G_LAST +}; + +struct stm32_mgate mp1_mgate[G_LAST]; + +#define _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ + _mgate, _ops)\ + [_id] = {\ + &(struct gate_cfg) {\ + .reg_off = _gate_offset,\ + .bit_idx = _gate_bit_idx,\ + .gate_flags = _gate_flags,\ + },\ + .mgate = _mgate,\ + .ops = _ops,\ + } + +#define K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags)\ + _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ + NULL, &mp1_gate_clk_ops) + +#define K_MGATE(_id, _gate_offset, _gate_bit_idx, _gate_flags)\ + _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ + &mp1_mgate[_id], &mp1_mgate_clk_ops) + +/* Peripheral gates */ +struct stm32_gate_cfg per_gate_cfg[G_LAST] = { + /* Multi gates */ + K_GATE(G_MDIO, RCC_APB1ENSETR, 31, 0), + K_MGATE(G_DAC12, RCC_APB1ENSETR, 29, 0), + K_MGATE(G_CEC, RCC_APB1ENSETR, 27, 0), + K_MGATE(G_SPDIF, RCC_APB1ENSETR, 26, 0), + K_MGATE(G_I2C5, RCC_APB1ENSETR, 24, 0), + K_MGATE(G_I2C3, RCC_APB1ENSETR, 23, 0), + K_MGATE(G_I2C2, RCC_APB1ENSETR, 22, 0), + K_MGATE(G_I2C1, RCC_APB1ENSETR, 21, 0), + K_MGATE(G_UART8, RCC_APB1ENSETR, 19, 0), + K_MGATE(G_UART7, RCC_APB1ENSETR, 18, 0), + K_MGATE(G_UART5, RCC_APB1ENSETR, 17, 0), + K_MGATE(G_UART4, RCC_APB1ENSETR, 16, 0), + K_MGATE(G_USART3, RCC_APB1ENSETR, 15, 0), + K_MGATE(G_USART2, RCC_APB1ENSETR, 14, 0), + K_MGATE(G_SPI3, RCC_APB1ENSETR, 12, 0), + K_MGATE(G_SPI2, RCC_APB1ENSETR, 11, 0), + K_MGATE(G_LPTIM1, RCC_APB1ENSETR, 9, 0), + K_GATE(G_TIM14, RCC_APB1ENSETR, 8, 0), + K_GATE(G_TIM13, RCC_APB1ENSETR, 7, 0), + K_GATE(G_TIM12, RCC_APB1ENSETR, 6, 0), + K_GATE(G_TIM7, RCC_APB1ENSETR, 5, 0), + K_GATE(G_TIM6, RCC_APB1ENSETR, 4, 0), + K_GATE(G_TIM5, RCC_APB1ENSETR, 3, 0), + K_GATE(G_TIM4, RCC_APB1ENSETR, 2, 0), + K_GATE(G_TIM3, RCC_APB1ENSETR, 1, 0), + K_GATE(G_TIM2, RCC_APB1ENSETR, 0, 0), + + K_MGATE(G_FDCAN, RCC_APB2ENSETR, 24, 0), + K_GATE(G_ADFSDM, RCC_APB2ENSETR, 21, 0), + K_GATE(G_DFSDM, RCC_APB2ENSETR, 20, 0), + K_MGATE(G_SAI3, RCC_APB2ENSETR, 18, 0), + K_MGATE(G_SAI2, RCC_APB2ENSETR, 17, 0), + K_MGATE(G_SAI1, RCC_APB2ENSETR, 16, 0), + K_MGATE(G_USART6, RCC_APB2ENSETR, 13, 0), + K_MGATE(G_SPI5, RCC_APB2ENSETR, 10, 0), + K_MGATE(G_SPI4, RCC_APB2ENSETR, 9, 0), + K_MGATE(G_SPI1, RCC_APB2ENSETR, 8, 0), + K_GATE(G_TIM17, RCC_APB2ENSETR, 4, 0), + K_GATE(G_TIM16, RCC_APB2ENSETR, 3, 0), + K_GATE(G_TIM15, RCC_APB2ENSETR, 2, 0), + K_GATE(G_TIM8, RCC_APB2ENSETR, 1, 0), + K_GATE(G_TIM1, RCC_APB2ENSETR, 0, 0), + + K_GATE(G_HDP, RCC_APB3ENSETR, 20, 0), + K_GATE(G_PMBCTRL, RCC_APB3ENSETR, 17, 0), + K_GATE(G_TMPSENS, RCC_APB3ENSETR, 16, 0), + K_GATE(G_VREF, RCC_APB3ENSETR, 13, 0), + K_GATE(G_SYSCFG, RCC_APB3ENSETR, 11, 0), + K_MGATE(G_SAI4, RCC_APB3ENSETR, 8, 0), + K_MGATE(G_LPTIM5, RCC_APB3ENSETR, 3, 0), + K_MGATE(G_LPTIM4, RCC_APB3ENSETR, 2, 0), + K_MGATE(G_LPTIM3, RCC_APB3ENSETR, 1, 0), + K_MGATE(G_LPTIM2, RCC_APB3ENSETR, 0, 0), + + K_GATE(G_STGENRO, RCC_APB4ENSETR, 20, 0), + K_MGATE(G_USBPHY, RCC_APB4ENSETR, 16, 0), + K_GATE(G_IWDG2, RCC_APB4ENSETR, 15, 0), + K_MGATE(G_DSI, RCC_APB4ENSETR, 4, 0), + K_MGATE(G_LTDC, RCC_APB4ENSETR, 0, 0), + + K_GATE(G_STGEN, RCC_APB5ENSETR, 20, 0), + K_GATE(G_BSEC, RCC_APB5ENSETR, 16, 0), + K_GATE(G_IWDG1, RCC_APB5ENSETR, 15, 0), + K_GATE(G_TZPC, RCC_APB5ENSETR, 13, 0), + K_GATE(G_TZC, RCC_APB5ENSETR, 12, 0), + K_GATE(G_RTCAPB, RCC_APB5ENSETR, 8, 0), + K_MGATE(G_USART1, RCC_APB5ENSETR, 4, 0), + K_MGATE(G_I2C6, RCC_APB5ENSETR, 3, 0), + K_MGATE(G_I2C4, RCC_APB5ENSETR, 2, 0), + K_MGATE(G_SPI6, RCC_APB5ENSETR, 0, 0), + + K_MGATE(G_SDMMC3, RCC_AHB2ENSETR, 16, 0), + K_MGATE(G_USBO, RCC_AHB2ENSETR, 8, 0), + K_MGATE(G_ADC12, RCC_AHB2ENSETR, 5, 0), + K_GATE(G_DMAMUX, RCC_AHB2ENSETR, 2, 0), + K_GATE(G_DMA2, RCC_AHB2ENSETR, 1, 0), + K_GATE(G_DMA1, RCC_AHB2ENSETR, 0, 0), + + K_GATE(G_IPCC, RCC_AHB3ENSETR, 12, 0), + K_GATE(G_HSEM, RCC_AHB3ENSETR, 11, 0), + K_GATE(G_CRC2, RCC_AHB3ENSETR, 7, 0), + K_MGATE(G_RNG2, RCC_AHB3ENSETR, 6, 0), + K_GATE(G_HASH2, RCC_AHB3ENSETR, 5, 0), + K_GATE(G_CRYP2, RCC_AHB3ENSETR, 4, 0), + K_GATE(G_DCMI, RCC_AHB3ENSETR, 0, 0), + + K_GATE(G_GPIOK, RCC_AHB4ENSETR, 10, 0), + K_GATE(G_GPIOJ, RCC_AHB4ENSETR, 9, 0), + K_GATE(G_GPIOI, RCC_AHB4ENSETR, 8, 0), + K_GATE(G_GPIOH, RCC_AHB4ENSETR, 7, 0), + K_GATE(G_GPIOG, RCC_AHB4ENSETR, 6, 0), + K_GATE(G_GPIOF, RCC_AHB4ENSETR, 5, 0), + K_GATE(G_GPIOE, RCC_AHB4ENSETR, 4, 0), + K_GATE(G_GPIOD, RCC_AHB4ENSETR, 3, 0), + K_GATE(G_GPIOC, RCC_AHB4ENSETR, 2, 0), + K_GATE(G_GPIOB, RCC_AHB4ENSETR, 1, 0), + K_GATE(G_GPIOA, RCC_AHB4ENSETR, 0, 0), + + K_GATE(G_BKPSRAM, RCC_AHB5ENSETR, 8, 0), + K_MGATE(G_RNG1, RCC_AHB5ENSETR, 6, 0), + K_GATE(G_HASH1, RCC_AHB5ENSETR, 5, 0), + K_GATE(G_CRYP1, RCC_AHB5ENSETR, 4, 0), + K_GATE(G_GPIOZ, RCC_AHB5ENSETR, 0, 0), + + K_GATE(G_USBH, RCC_AHB6ENSETR, 24, 0), + K_GATE(G_CRC1, RCC_AHB6ENSETR, 20, 0), + K_MGATE(G_SDMMC2, RCC_AHB6ENSETR, 17, 0), + K_MGATE(G_SDMMC1, RCC_AHB6ENSETR, 16, 0), + K_MGATE(G_QSPI, RCC_AHB6ENSETR, 14, 0), + K_MGATE(G_FMC, RCC_AHB6ENSETR, 12, 0), + K_GATE(G_ETHMAC, RCC_AHB6ENSETR, 10, 0), + K_GATE(G_ETHRX, RCC_AHB6ENSETR, 9, 0), + K_GATE(G_ETHTX, RCC_AHB6ENSETR, 8, 0), + K_GATE(G_ETHCK, RCC_AHB6ENSETR, 7, 0), + K_MGATE(G_GPU, RCC_AHB6ENSETR, 5, 0), + K_GATE(G_MDMA, RCC_AHB6ENSETR, 0, 0), + K_GATE(G_ETHSTP, RCC_AHB6LPENSETR, 11, 0), +}; + +enum { + M_SDMMC12, + M_SDMMC3, + M_FMC, + M_QSPI, + M_RNG1, + M_RNG2, + M_USBPHY, + M_USBO, + M_STGEN, + M_SPDIF, + M_SPI1, + M_SPI23, + M_SPI45, + M_SPI6, + M_CEC, + M_I2C12, + M_I2C35, + M_I2C46, + M_LPTIM1, + M_LPTIM23, + M_LPTIM45, + M_USART1, + M_UART24, + M_UART35, + M_USART6, + M_UART78, + M_SAI1, + M_SAI2, + M_SAI3, + M_SAI4, + M_DSI, + M_FDCAN, + M_ADC12, + M_ETHCK, + M_CKPER, + M_LAST +}; + +struct stm32_mmux ker_mux[M_LAST]; + +#define _K_MUX(_id, _offset, _shift, _width, _mux_flags, _mmux, _ops)\ + [_id] = {\ + &(struct mux_cfg) {\ + .reg_off = _offset,\ + .shift = _shift,\ + .width = _width,\ + .mux_flags = _mux_flags,\ + .table = NULL,\ + },\ + .mmux = _mmux,\ + .ops = _ops,\ + } + +#define K_MUX(_id, _offset, _shift, _width, _mux_flags)\ + _K_MUX(_id, _offset, _shift, _width, _mux_flags,\ + NULL, NULL) + +#define K_MMUX(_id, _offset, _shift, _width, _mux_flags)\ + _K_MUX(_id, _offset, _shift, _width, _mux_flags,\ + &ker_mux[_id], &clk_mmux_ops) + +const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { + /* Kernel multi mux */ + K_MMUX(M_SDMMC12, RCC_SDMMC12CKSELR, 0, 3, 0), + K_MMUX(M_SPI23, RCC_SPI2S23CKSELR, 0, 3, 0), + K_MMUX(M_SPI45, RCC_SPI2S45CKSELR, 0, 3, 0), + K_MMUX(M_I2C12, RCC_I2C12CKSELR, 0, 3, 0), + K_MMUX(M_I2C35, RCC_I2C35CKSELR, 0, 3, 0), + K_MMUX(M_LPTIM23, RCC_LPTIM23CKSELR, 0, 3, 0), + K_MMUX(M_LPTIM45, RCC_LPTIM45CKSELR, 0, 3, 0), + K_MMUX(M_UART24, RCC_UART24CKSELR, 0, 3, 0), + K_MMUX(M_UART35, RCC_UART35CKSELR, 0, 3, 0), + K_MMUX(M_UART78, RCC_UART78CKSELR, 0, 3, 0), + K_MMUX(M_SAI1, RCC_SAI1CKSELR, 0, 3, 0), + K_MMUX(M_ETHCK, RCC_ETHCKSELR, 0, 2, 0), + K_MMUX(M_I2C46, RCC_I2C46CKSELR, 0, 3, 0), + + /* Kernel simple mux */ + K_MUX(M_RNG2, RCC_RNG2CKSELR, 0, 2, 0), + K_MUX(M_SDMMC3, RCC_SDMMC3CKSELR, 0, 3, 0), + K_MUX(M_FMC, RCC_FMCCKSELR, 0, 2, 0), + K_MUX(M_QSPI, RCC_QSPICKSELR, 0, 2, 0), + K_MUX(M_USBPHY, RCC_USBCKSELR, 0, 2, 0), + K_MUX(M_USBO, RCC_USBCKSELR, 4, 1, 0), + K_MUX(M_SPDIF, RCC_SPDIFCKSELR, 0, 2, 0), + K_MUX(M_SPI1, RCC_SPI2S1CKSELR, 0, 3, 0), + K_MUX(M_CEC, RCC_CECCKSELR, 0, 2, 0), + K_MUX(M_LPTIM1, RCC_LPTIM1CKSELR, 0, 3, 0), + K_MUX(M_USART6, RCC_UART6CKSELR, 0, 3, 0), + K_MUX(M_FDCAN, RCC_FDCANCKSELR, 0, 2, 0), + K_MUX(M_SAI2, RCC_SAI2CKSELR, 0, 3, 0), + K_MUX(M_SAI3, RCC_SAI3CKSELR, 0, 3, 0), + K_MUX(M_SAI4, RCC_SAI4CKSELR, 0, 3, 0), + K_MUX(M_ADC12, RCC_ADCCKSELR, 0, 2, 0), + K_MUX(M_DSI, RCC_DSICKSELR, 0, 1, 0), + K_MUX(M_CKPER, RCC_CPERCKSELR, 0, 2, 0), + K_MUX(M_RNG1, RCC_RNG1CKSELR, 0, 2, 0), + K_MUX(M_STGEN, RCC_STGENCKSELR, 0, 2, 0), + K_MUX(M_USART1, RCC_UART1CKSELR, 0, 3, 0), + K_MUX(M_SPI6, RCC_SPI6CKSELR, 0, 3, 0), +}; + +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 */ + GATE_MP1(CK_HSE, "ck_hse", "clk-hse", 0, RCC_OCENSETR, 8, 0), + GATE_MP1(CK_CSI, "ck_csi", "clk-csi", 0, RCC_OCENSETR, 4, 0), + GATE_MP1(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), + + /* 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), + + /* 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), + + /* ODF */ + COMPOSITE(PLL1_P, "pll1_p", PARENT("pll1"), 0, + _GATE(RCC_PLL1CR, 4, 0), + _NO_MUX, + _DIV(RCC_PLL1CFGR2, 0, 7, 0, NULL)), + + COMPOSITE(PLL2_P, "pll2_p", PARENT("pll2"), 0, + _GATE(RCC_PLL2CR, 4, 0), + _NO_MUX, + _DIV(RCC_PLL2CFGR2, 0, 7, 0, NULL)), + + COMPOSITE(PLL2_Q, "pll2_q", PARENT("pll2"), 0, + _GATE(RCC_PLL2CR, 5, 0), + _NO_MUX, + _DIV(RCC_PLL2CFGR2, 8, 7, 0, NULL)), + + COMPOSITE(PLL2_R, "pll2_r", PARENT("pll2"), CLK_IS_CRITICAL, + _GATE(RCC_PLL2CR, 6, 0), + _NO_MUX, + _DIV(RCC_PLL2CFGR2, 16, 7, 0, NULL)), + + COMPOSITE(PLL3_P, "pll3_p", PARENT("pll3"), 0, + _GATE(RCC_PLL3CR, 4, 0), + _NO_MUX, + _DIV(RCC_PLL3CFGR2, 0, 7, 0, NULL)), + + COMPOSITE(PLL3_Q, "pll3_q", PARENT("pll3"), 0, + _GATE(RCC_PLL3CR, 5, 0), + _NO_MUX, + _DIV(RCC_PLL3CFGR2, 8, 7, 0, NULL)), + + COMPOSITE(PLL3_R, "pll3_r", PARENT("pll3"), 0, + _GATE(RCC_PLL3CR, 6, 0), + _NO_MUX, + _DIV(RCC_PLL3CFGR2, 16, 7, 0, NULL)), + + COMPOSITE(PLL4_P, "pll4_p", PARENT("pll4"), 0, + _GATE(RCC_PLL4CR, 4, 0), + _NO_MUX, + _DIV(RCC_PLL4CFGR2, 0, 7, 0, NULL)), + + COMPOSITE(PLL4_Q, "pll4_q", PARENT("pll4"), 0, + _GATE(RCC_PLL4CR, 5, 0), + _NO_MUX, + _DIV(RCC_PLL4CFGR2, 8, 7, 0, NULL)), + + COMPOSITE(PLL4_R, "pll4_r", PARENT("pll4"), 0, + _GATE(RCC_PLL4CR, 6, 0), + _NO_MUX, + _DIV(RCC_PLL4CFGR2, 16, 7, 0, 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, + _NO_GATE, + _MUX(RCC_ASSCKSELR, 0, 2, 0), + _DIV(RCC_AXIDIVR, 0, 3, 0, axi_div_table)), + + COMPOSITE(CK_MCU, "ck_mcu", mcu_src, CLK_IS_CRITICAL | + CLK_OPS_PARENT_ENABLE, + _NO_GATE, + _MUX(RCC_MSSCKSELR, 0, 2, 0), + _DIV(RCC_MCUDIVR, 0, 4, 0, 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), + + /* 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), + + /* Peripheral clocks */ + PCLK(TIM2, "tim2", "pclk1", CLK_IGNORE_UNUSED, G_TIM2), + PCLK(TIM3, "tim3", "pclk1", CLK_IGNORE_UNUSED, G_TIM3), + PCLK(TIM4, "tim4", "pclk1", CLK_IGNORE_UNUSED, G_TIM4), + PCLK(TIM5, "tim5", "pclk1", CLK_IGNORE_UNUSED, G_TIM5), + PCLK(TIM6, "tim6", "pclk1", CLK_IGNORE_UNUSED, G_TIM6), + PCLK(TIM7, "tim7", "pclk1", CLK_IGNORE_UNUSED, G_TIM7), + PCLK(TIM12, "tim12", "pclk1", CLK_IGNORE_UNUSED, G_TIM12), + PCLK(TIM13, "tim13", "pclk1", CLK_IGNORE_UNUSED, G_TIM13), + PCLK(TIM14, "tim14", "pclk1", CLK_IGNORE_UNUSED, G_TIM14), + PCLK(LPTIM1, "lptim1", "pclk1", 0, G_LPTIM1), + PCLK(SPI2, "spi2", "pclk1", 0, G_SPI2), + PCLK(SPI3, "spi3", "pclk1", 0, G_SPI3), + PCLK(USART2, "usart2", "pclk1", 0, G_USART2), + PCLK(USART3, "usart3", "pclk1", 0, G_USART3), + PCLK(UART4, "uart4", "pclk1", 0, G_UART4), + PCLK(UART5, "uart5", "pclk1", 0, G_UART5), + PCLK(UART7, "uart7", "pclk1", 0, G_UART7), + PCLK(UART8, "uart8", "pclk1", 0, G_UART8), + PCLK(I2C1, "i2c1", "pclk1", 0, G_I2C1), + PCLK(I2C2, "i2c2", "pclk1", 0, G_I2C2), + PCLK(I2C3, "i2c3", "pclk1", 0, G_I2C3), + PCLK(I2C5, "i2c5", "pclk1", 0, G_I2C5), + PCLK(SPDIF, "spdif", "pclk1", 0, G_SPDIF), + PCLK(CEC, "cec", "pclk1", 0, G_CEC), + PCLK(DAC12, "dac12", "pclk1", 0, G_DAC12), + PCLK(MDIO, "mdio", "pclk1", 0, G_MDIO), + PCLK(TIM1, "tim1", "pclk2", CLK_IGNORE_UNUSED, G_TIM1), + PCLK(TIM8, "tim8", "pclk2", CLK_IGNORE_UNUSED, G_TIM8), + PCLK(TIM15, "tim15", "pclk2", CLK_IGNORE_UNUSED, G_TIM15), + PCLK(TIM16, "tim16", "pclk2", CLK_IGNORE_UNUSED, G_TIM16), + PCLK(TIM17, "tim17", "pclk2", CLK_IGNORE_UNUSED, G_TIM17), + PCLK(SPI1, "spi1", "pclk2", 0, G_SPI1), + PCLK(SPI4, "spi4", "pclk2", 0, G_SPI4), + PCLK(SPI5, "spi5", "pclk2", 0, G_SPI5), + PCLK(USART6, "usart6", "pclk2", 0, G_USART6), + PCLK(SAI1, "sai1", "pclk2", 0, G_SAI1), + PCLK(SAI2, "sai2", "pclk2", 0, G_SAI2), + PCLK(SAI3, "sai3", "pclk2", 0, G_SAI3), + PCLK(DFSDM, "dfsdm", "pclk2", 0, G_DFSDM), + PCLK(FDCAN, "fdcan", "pclk2", 0, G_FDCAN), + PCLK(LPTIM2, "lptim2", "pclk3", 0, G_LPTIM2), + PCLK(LPTIM3, "lptim3", "pclk3", 0, G_LPTIM3), + PCLK(LPTIM4, "lptim4", "pclk3", 0, G_LPTIM4), + PCLK(LPTIM5, "lptim5", "pclk3", 0, G_LPTIM5), + PCLK(SAI4, "sai4", "pclk3", 0, G_SAI4), + PCLK(SYSCFG, "syscfg", "pclk3", 0, G_SYSCFG), + PCLK(VREF, "vref", "pclk3", 13, G_VREF), + PCLK(TMPSENS, "tmpsens", "pclk3", 0, G_TMPSENS), + PCLK(PMBCTRL, "pmbctrl", "pclk3", 0, G_PMBCTRL), + PCLK(HDP, "hdp", "pclk3", 0, G_HDP), + PCLK(LTDC, "ltdc", "pclk4", 0, G_LTDC), + PCLK(DSI, "dsi", "pclk4", 0, G_DSI), + PCLK(IWDG2, "iwdg2", "pclk4", 0, G_IWDG2), + PCLK(USBPHY, "usbphy", "pclk4", 0, G_USBPHY), + PCLK(STGENRO, "stgenro", "pclk4", 0, G_STGENRO), + PCLK(SPI6, "spi6", "pclk5", 0, G_SPI6), + PCLK(I2C4, "i2c4", "pclk5", 0, G_I2C4), + PCLK(I2C6, "i2c6", "pclk5", 0, G_I2C6), + PCLK(USART1, "usart1", "pclk5", 0, G_USART1), + PCLK(RTCAPB, "rtcapb", "pclk5", CLK_IGNORE_UNUSED | + CLK_IS_CRITICAL, G_RTCAPB), + PCLK(TZC, "tzc", "pclk5", CLK_IGNORE_UNUSED, G_TZC), + PCLK(TZPC, "tzpc", "pclk5", CLK_IGNORE_UNUSED, G_TZPC), + PCLK(IWDG1, "iwdg1", "pclk5", 0, G_IWDG1), + PCLK(BSEC, "bsec", "pclk5", CLK_IGNORE_UNUSED, G_BSEC), + PCLK(STGEN, "stgen", "pclk5", CLK_IGNORE_UNUSED, G_STGEN), + PCLK(DMA1, "dma1", "ck_mcu", 0, G_DMA1), + PCLK(DMA2, "dma2", "ck_mcu", 0, G_DMA2), + PCLK(DMAMUX, "dmamux", "ck_mcu", 0, G_DMAMUX), + PCLK(ADC12, "adc12", "ck_mcu", 0, G_ADC12), + PCLK(USBO, "usbo", "ck_mcu", 0, G_USBO), + PCLK(SDMMC3, "sdmmc3", "ck_mcu", 0, G_SDMMC3), + PCLK(DCMI, "dcmi", "ck_mcu", 0, G_DCMI), + PCLK(CRYP2, "cryp2", "ck_mcu", 0, G_CRYP2), + PCLK(HASH2, "hash2", "ck_mcu", 0, G_HASH2), + PCLK(RNG2, "rng2", "ck_mcu", 0, G_RNG2), + PCLK(CRC2, "crc2", "ck_mcu", 0, G_CRC2), + PCLK(HSEM, "hsem", "ck_mcu", 0, G_HSEM), + PCLK(IPCC, "ipcc", "ck_mcu", 0, G_IPCC), + PCLK(GPIOA, "gpioa", "ck_mcu", 0, G_GPIOA), + PCLK(GPIOB, "gpiob", "ck_mcu", 0, G_GPIOB), + PCLK(GPIOC, "gpioc", "ck_mcu", 0, G_GPIOC), + PCLK(GPIOD, "gpiod", "ck_mcu", 0, G_GPIOD), + PCLK(GPIOE, "gpioe", "ck_mcu", 0, G_GPIOE), + PCLK(GPIOF, "gpiof", "ck_mcu", 0, G_GPIOF), + PCLK(GPIOG, "gpiog", "ck_mcu", 0, G_GPIOG), + PCLK(GPIOH, "gpioh", "ck_mcu", 0, G_GPIOH), + PCLK(GPIOI, "gpioi", "ck_mcu", 0, G_GPIOI), + PCLK(GPIOJ, "gpioj", "ck_mcu", 0, G_GPIOJ), + PCLK(GPIOK, "gpiok", "ck_mcu", 0, G_GPIOK), + PCLK(GPIOZ, "gpioz", "ck_axi", CLK_IGNORE_UNUSED, G_GPIOZ), + PCLK(CRYP1, "cryp1", "ck_axi", CLK_IGNORE_UNUSED, G_CRYP1), + PCLK(HASH1, "hash1", "ck_axi", CLK_IGNORE_UNUSED, G_HASH1), + PCLK(RNG1, "rng1", "ck_axi", 0, G_RNG1), + PCLK(BKPSRAM, "bkpsram", "ck_axi", CLK_IGNORE_UNUSED, G_BKPSRAM), + PCLK(MDMA, "mdma", "ck_axi", 0, G_MDMA), + PCLK(GPU, "gpu", "ck_axi", 0, G_GPU), + PCLK(ETHTX, "ethtx", "ck_axi", 0, G_ETHTX), + PCLK(ETHRX, "ethrx", "ck_axi", 0, G_ETHRX), + PCLK(ETHMAC, "ethmac", "ck_axi", 0, G_ETHMAC), + PCLK(FMC, "fmc", "ck_axi", CLK_IGNORE_UNUSED, G_FMC), + PCLK(QSPI, "qspi", "ck_axi", CLK_IGNORE_UNUSED, G_QSPI), + PCLK(SDMMC1, "sdmmc1", "ck_axi", 0, G_SDMMC1), + PCLK(SDMMC2, "sdmmc2", "ck_axi", 0, G_SDMMC2), + PCLK(CRC1, "crc1", "ck_axi", 0, G_CRC1), + PCLK(USBH, "usbh", "ck_axi", 0, G_USBH), + PCLK(ETHSTP, "ethstp", "ck_axi", 0, G_ETHSTP), + + /* Kernel clocks */ + KCLK(SDMMC1_K, "sdmmc1_k", sdmmc12_src, 0, G_SDMMC1, M_SDMMC12), + KCLK(SDMMC2_K, "sdmmc2_k", sdmmc12_src, 0, G_SDMMC2, M_SDMMC12), + KCLK(SDMMC3_K, "sdmmc3_k", sdmmc3_src, 0, G_SDMMC3, M_SDMMC3), + KCLK(FMC_K, "fmc_k", fmc_src, 0, G_FMC, M_FMC), + KCLK(QSPI_K, "qspi_k", qspi_src, 0, G_QSPI, M_QSPI), + KCLK(RNG1_K, "rng1_k", rng_src, 0, G_RNG1, M_RNG1), + KCLK(RNG2_K, "rng2_k", rng_src, 0, G_RNG2, M_RNG2), + KCLK(USBPHY_K, "usbphy_k", usbphy_src, 0, G_USBPHY, M_USBPHY), + KCLK(STGEN_K, "stgen_k", stgen_src, CLK_IGNORE_UNUSED, + G_STGEN, M_STGEN), + KCLK(SPDIF_K, "spdif_k", spdif_src, 0, G_SPDIF, M_SPDIF), + KCLK(SPI1_K, "spi1_k", spi123_src, 0, G_SPI1, M_SPI1), + KCLK(SPI2_K, "spi2_k", spi123_src, 0, G_SPI2, M_SPI23), + KCLK(SPI3_K, "spi3_k", spi123_src, 0, G_SPI3, M_SPI23), + KCLK(SPI4_K, "spi4_k", spi45_src, 0, G_SPI4, M_SPI45), + KCLK(SPI5_K, "spi5_k", spi45_src, 0, G_SPI5, M_SPI45), + KCLK(SPI6_K, "spi6_k", spi6_src, 0, G_SPI6, M_SPI6), + KCLK(CEC_K, "cec_k", cec_src, 0, G_CEC, M_CEC), + KCLK(I2C1_K, "i2c1_k", i2c12_src, 0, G_I2C1, M_I2C12), + KCLK(I2C2_K, "i2c2_k", i2c12_src, 0, G_I2C2, M_I2C12), + KCLK(I2C3_K, "i2c3_k", i2c35_src, 0, G_I2C3, M_I2C35), + KCLK(I2C5_K, "i2c5_k", i2c35_src, 0, G_I2C5, M_I2C35), + KCLK(I2C4_K, "i2c4_k", i2c46_src, 0, G_I2C4, M_I2C46), + KCLK(I2C6_K, "i2c6_k", i2c46_src, 0, G_I2C6, M_I2C46), + KCLK(LPTIM1_K, "lptim1_k", lptim1_src, 0, G_LPTIM1, M_LPTIM1), + KCLK(LPTIM2_K, "lptim2_k", lptim23_src, 0, G_LPTIM2, M_LPTIM23), + KCLK(LPTIM3_K, "lptim3_k", lptim23_src, 0, G_LPTIM3, M_LPTIM23), + KCLK(LPTIM4_K, "lptim4_k", lptim45_src, 0, G_LPTIM4, M_LPTIM45), + KCLK(LPTIM5_K, "lptim5_k", lptim45_src, 0, G_LPTIM5, M_LPTIM45), + KCLK(USART1_K, "usart1_k", usart1_src, 0, G_USART1, M_USART1), + KCLK(USART2_K, "usart2_k", usart234578_src, 0, G_USART2, M_UART24), + KCLK(USART3_K, "usart3_k", usart234578_src, 0, G_USART3, M_UART35), + KCLK(UART4_K, "uart4_k", usart234578_src, 0, G_UART4, M_UART24), + KCLK(UART5_K, "uart5_k", usart234578_src, 0, G_UART5, M_UART35), + KCLK(USART6_K, "uart6_k", usart6_src, 0, G_USART6, M_USART6), + KCLK(UART7_K, "uart7_k", usart234578_src, 0, G_UART7, M_UART78), + KCLK(UART8_K, "uart8_k", usart234578_src, 0, G_UART8, M_UART78), + KCLK(FDCAN_K, "fdcan_k", fdcan_src, 0, G_FDCAN, M_FDCAN), + KCLK(SAI1_K, "sai1_k", sai_src, 0, G_SAI1, M_SAI1), + KCLK(SAI2_K, "sai2_k", sai2_src, 0, G_SAI2, M_SAI2), + KCLK(SAI3_K, "sai3_k", sai_src, 0, G_SAI2, M_SAI3), + KCLK(SAI4_K, "sai4_k", sai_src, 0, G_SAI2, M_SAI4), + KCLK(ADC12_K, "adc12_k", adc12_src, 0, G_ADC12, M_ADC12), + KCLK(DSI_K, "dsi_k", dsi_src, 0, G_DSI, M_DSI), + KCLK(ADFSDM_K, "adfsdm_k", sai_src, 0, G_ADFSDM, M_SAI1), + KCLK(USBO_K, "usbo_k", usbo_src, 0, G_USBO, M_USBO), + KCLK(ETHCK_K, "ethck_k", eth_src, 0, G_ETHCK, M_ETHCK), + + /* Particulary Kernel Clocks (no mux or no gate) */ + MGATE_MP1(DFSDM_K, "dfsdm_k", "ck_mcu", 0, G_DFSDM), + MGATE_MP1(DSI_PX, "dsi_px", "pll4_q", CLK_SET_RATE_PARENT, G_DSI), + MGATE_MP1(LTDC_PX, "ltdc_px", "pll4_q", CLK_SET_RATE_PARENT, G_LTDC), + MGATE_MP1(GPU_K, "gpu_k", "pll2_q", 0, G_GPU), + MGATE_MP1(DAC12_K, "dac12_k", "ck_lsi", 0, G_DAC12), + + COMPOSITE(ETHPTP_K, "ethptp_k", eth_src, CLK_OPS_PARENT_ENABLE, + _NO_GATE, + _MMUX(M_ETHCK), + _DIV(RCC_ETHCKSELR, 4, 4, CLK_DIVIDER_ALLOW_ZERO, NULL)), + + /* 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, + _GATE(RCC_BDCR, 20, 0), + _MUX(RCC_BDCR, 16, 2, 0), + _NO_DIV), + + /* MCO clocks */ + COMPOSITE(CK_MCO1, "ck_mco1", mco1_src, CLK_OPS_PARENT_ENABLE | + CLK_SET_RATE_NO_REPARENT, + _GATE(RCC_MCO1CFGR, 12, 0), + _MUX(RCC_MCO1CFGR, 0, 3, 0), + _DIV(RCC_MCO1CFGR, 4, 4, 0, NULL)), + + COMPOSITE(CK_MCO2, "ck_mco2", mco2_src, CLK_OPS_PARENT_ENABLE | + CLK_SET_RATE_NO_REPARENT, + _GATE(RCC_MCO2CFGR, 12, 0), + _MUX(RCC_MCO2CFGR, 0, 3, 0), + _DIV(RCC_MCO2CFGR, 4, 4, 0, NULL)), + + /* 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, + _GATE(RCC_DBGCFGR, 9, 0), + _NO_MUX, + _DIV(RCC_DBGCFGR, 0, 3, 0, ck_trace_div_table)), +}; + +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", + .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) +{ + void __iomem *base; + + base = of_iomap(np, 0); + if (!base) { + pr_err("%s: unable to map resource", np->name); + of_node_put(np); + return; + } + + if (stm32_rcc_init(np, base, stm32mp1_match_data)) { + iounmap(base); + of_node_put(np); + } +} + +CLK_OF_DECLARE_DRIVER(stm32mp1_rcc, "st,stm32mp1-rcc", stm32mp1_rcc_init); diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 0f686a9dac3e..ea67ac81c6f9 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1125,8 +1125,10 @@ static int clk_core_round_rate_nolock(struct clk_core *core, { lockdep_assert_held(&prepare_lock); - if (!core) + if (!core) { + req->rate = 0; return 0; + } clk_core_init_rate_req(core, req); @@ -2309,8 +2311,11 @@ static int clk_core_set_phase_nolock(struct clk_core *core, int degrees) trace_clk_set_phase(core, degrees); - if (core->ops->set_phase) + if (core->ops->set_phase) { ret = core->ops->set_phase(core->hw, degrees); + if (!ret) + core->phase = degrees; + } trace_clk_set_phase_complete(core, degrees); @@ -2370,6 +2375,9 @@ static int clk_core_get_phase(struct clk_core *core) int ret; clk_prepare_lock(); + /* Always try to update cached phase if possible */ + if (core->ops->get_phase) + core->phase = core->ops->get_phase(core->hw); ret = core->phase; clk_prepare_unlock(); @@ -2486,19 +2494,7 @@ static int clk_summary_show(struct seq_file *s, void *data) return 0; } - - -static int clk_summary_open(struct inode *inode, struct file *file) -{ - return single_open(file, clk_summary_show, inode->i_private); -} - -static const struct file_operations clk_summary_fops = { - .open = clk_summary_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(clk_summary); static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level) { @@ -2532,7 +2528,7 @@ static void clk_dump_subtree(struct seq_file *s, struct clk_core *c, int level) seq_putc(s, '}'); } -static int clk_dump(struct seq_file *s, void *data) +static int clk_dump_show(struct seq_file *s, void *data) { struct clk_core *c; bool first_node = true; @@ -2555,19 +2551,7 @@ static int clk_dump(struct seq_file *s, void *data) seq_puts(s, "}\n"); return 0; } - - -static int clk_dump_open(struct inode *inode, struct file *file) -{ - return single_open(file, clk_dump, inode->i_private); -} - -static const struct file_operations clk_dump_fops = { - .open = clk_dump_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(clk_dump); static const struct { unsigned long flag; @@ -2589,7 +2573,7 @@ static const struct { #undef ENTRY }; -static int clk_flags_dump(struct seq_file *s, void *data) +static int clk_flags_show(struct seq_file *s, void *data) { struct clk_core *core = s->private; unsigned long flags = core->flags; @@ -2608,20 +2592,9 @@ static int clk_flags_dump(struct seq_file *s, void *data) return 0; } +DEFINE_SHOW_ATTRIBUTE(clk_flags); -static int clk_flags_open(struct inode *inode, struct file *file) -{ - return single_open(file, clk_flags_dump, inode->i_private); -} - -static const struct file_operations clk_flags_fops = { - .open = clk_flags_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int possible_parents_dump(struct seq_file *s, void *data) +static int possible_parents_show(struct seq_file *s, void *data) { struct clk_core *core = s->private; int i; @@ -2633,18 +2606,7 @@ static int possible_parents_dump(struct seq_file *s, void *data) return 0; } - -static int possible_parents_open(struct inode *inode, struct file *file) -{ - return single_open(file, possible_parents_dump, inode->i_private); -} - -static const struct file_operations possible_parents_fops = { - .open = possible_parents_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(possible_parents); static int clk_debug_create_one(struct clk_core *core, struct dentry *pdentry) { @@ -2928,6 +2890,17 @@ static int __clk_core_init(struct clk_core *core) } /* + * optional platform-specific magic + * + * The .init callback is not used by any of the basic clock types, but + * exists for weird hardware that must perform initialization magic. + * Please consider other ways of solving initialization problems before + * using this callback, as its use is discouraged. + */ + if (core->ops->init) + core->ops->init(core->hw); + + /* * Set clk's accuracy. The preferred method is to use * .recalc_accuracy. For simple clocks and lazy developers the default * fallback is to use the parent's accuracy. If a clock doesn't have a @@ -2968,48 +2941,42 @@ static int __clk_core_init(struct clk_core *core) core->rate = core->req_rate = rate; /* + * Enable CLK_IS_CRITICAL clocks so newly added critical clocks + * don't get accidentally disabled when walking the orphan tree and + * reparenting clocks + */ + if (core->flags & CLK_IS_CRITICAL) { + unsigned long flags; + + clk_core_prepare(core); + + flags = clk_enable_lock(); + clk_core_enable(core); + clk_enable_unlock(flags); + } + + /* * walk the list of orphan clocks and reparent any that newly finds a * parent. */ hlist_for_each_entry_safe(orphan, tmp2, &clk_orphan_list, child_node) { struct clk_core *parent = __clk_init_parent(orphan); - unsigned long flags; /* - * we could call __clk_set_parent, but that would result in a - * redundant call to the .set_rate op, if it exists + * We need to use __clk_set_parent_before() and _after() to + * to properly migrate any prepare/enable count of the orphan + * clock. This is important for CLK_IS_CRITICAL clocks, which + * are enabled during init but might not have a parent yet. */ if (parent) { /* update the clk tree topology */ - flags = clk_enable_lock(); - clk_reparent(orphan, parent); - clk_enable_unlock(flags); + __clk_set_parent_before(orphan, parent); + __clk_set_parent_after(orphan, parent, NULL); __clk_recalc_accuracies(orphan); __clk_recalc_rates(orphan, 0); } } - /* - * optional platform-specific magic - * - * The .init callback is not used by any of the basic clock types, but - * exists for weird hardware that must perform initialization magic. - * Please consider other ways of solving initialization problems before - * using this callback, as its use is discouraged. - */ - if (core->ops->init) - core->ops->init(core->hw); - - if (core->flags & CLK_IS_CRITICAL) { - unsigned long flags; - - clk_core_prepare(core); - - flags = clk_enable_lock(); - clk_core_enable(core); - clk_enable_unlock(flags); - } - kref_init(&core->ref); out: clk_pm_runtime_put(core); diff --git a/drivers/clk/keystone/sci-clk.c b/drivers/clk/keystone/sci-clk.c index 9cdf9d5050ac..4cb70bed89a9 100644 --- a/drivers/clk/keystone/sci-clk.c +++ b/drivers/clk/keystone/sci-clk.c @@ -29,21 +29,10 @@ #define SCI_CLK_INPUT_TERMINATION BIT(2) /** - * struct sci_clk_data - TI SCI clock data - * @dev: device index - * @num_clks: number of clocks for this device - */ -struct sci_clk_data { - u16 dev; - u16 num_clks; -}; - -/** * struct sci_clk_provider - TI SCI clock provider representation * @sci: Handle to the System Control Interface protocol handler * @ops: Pointer to the SCI ops to be used by the clocks * @dev: Device pointer for the clock provider - * @clk_data: Clock data * @clocks: Clocks array for this device * @num_clocks: Total number of clocks for this provider */ @@ -51,8 +40,7 @@ struct sci_clk_provider { const struct ti_sci_handle *sci; const struct ti_sci_clk_ops *ops; struct device *dev; - const struct sci_clk_data *clk_data; - struct clk_hw **clocks; + struct sci_clk **clocks; int num_clocks; }; @@ -61,6 +49,7 @@ struct sci_clk_provider { * @hw: Hardware clock cookie for common clock framework * @dev_id: Device index * @clk_id: Clock index + * @num_parents: Number of parents for this clock * @provider: Master clock provider * @flags: Flags for the clock */ @@ -68,6 +57,7 @@ struct sci_clk { struct clk_hw hw; u16 dev_id; u8 clk_id; + u8 num_parents; struct sci_clk_provider *provider; u8 flags; }; @@ -273,38 +263,22 @@ static const struct clk_ops sci_clk_ops = { /** * _sci_clk_get - Gets a handle for an SCI clock * @provider: Handle to SCI clock provider - * @dev_id: device ID for the clock to register - * @clk_id: clock ID for the clock to register + * @sci_clk: Handle to the SCI clock to populate * * Gets a handle to an existing TI SCI hw clock, or builds a new clock * entry and registers it with the common clock framework. Called from * the common clock framework, when a corresponding of_clk_get call is * executed, or recursively from itself when parsing parent clocks. - * Returns a pointer to the hw clock struct, or ERR_PTR value in failure. + * Returns 0 on success, negative error code on failure. */ -static struct clk_hw *_sci_clk_build(struct sci_clk_provider *provider, - u16 dev_id, u8 clk_id) +static int _sci_clk_build(struct sci_clk_provider *provider, + struct sci_clk *sci_clk) { struct clk_init_data init = { NULL }; - struct sci_clk *sci_clk = NULL; char *name = NULL; char **parent_names = NULL; int i; - int ret; - - sci_clk = devm_kzalloc(provider->dev, sizeof(*sci_clk), GFP_KERNEL); - if (!sci_clk) - return ERR_PTR(-ENOMEM); - - sci_clk->dev_id = dev_id; - sci_clk->clk_id = clk_id; - sci_clk->provider = provider; - - ret = provider->ops->get_num_parents(provider->sci, dev_id, - clk_id, - &init.num_parents); - if (ret) - goto err; + int ret = 0; name = kasprintf(GFP_KERNEL, "%s:%d:%d", dev_name(provider->dev), sci_clk->dev_id, sci_clk->clk_id); @@ -317,11 +291,11 @@ static struct clk_hw *_sci_clk_build(struct sci_clk_provider *provider, * to have mux functionality. Otherwise it is going to act as a root * clock. */ - if (init.num_parents < 2) - init.num_parents = 0; + if (sci_clk->num_parents < 2) + sci_clk->num_parents = 0; - if (init.num_parents) { - parent_names = kcalloc(init.num_parents, sizeof(char *), + if (sci_clk->num_parents) { + parent_names = kcalloc(sci_clk->num_parents, sizeof(char *), GFP_KERNEL); if (!parent_names) { @@ -329,7 +303,7 @@ static struct clk_hw *_sci_clk_build(struct sci_clk_provider *provider, goto err; } - for (i = 0; i < init.num_parents; i++) { + for (i = 0; i < sci_clk->num_parents; i++) { char *parent_name; parent_name = kasprintf(GFP_KERNEL, "%s:%d:%d", @@ -346,6 +320,7 @@ static struct clk_hw *_sci_clk_build(struct sci_clk_provider *provider, } init.ops = &sci_clk_ops; + init.num_parents = sci_clk->num_parents; sci_clk->hw.init = &init; ret = devm_clk_hw_register(provider->dev, &sci_clk->hw); @@ -354,7 +329,7 @@ static struct clk_hw *_sci_clk_build(struct sci_clk_provider *provider, err: if (parent_names) { - for (i = 0; i < init.num_parents; i++) + for (i = 0; i < sci_clk->num_parents; i++) kfree(parent_names[i]); kfree(parent_names); @@ -362,10 +337,7 @@ err: kfree(name); - if (ret) - return ERR_PTR(ret); - - return &sci_clk->hw; + return ret; } static int _cmp_sci_clk(const void *a, const void *b) @@ -414,253 +386,20 @@ static struct clk_hw *sci_clk_get(struct of_phandle_args *clkspec, void *data) static int ti_sci_init_clocks(struct sci_clk_provider *p) { - const struct sci_clk_data *data = p->clk_data; - struct clk_hw *hw; int i; - int num_clks = 0; - - while (data->num_clks) { - num_clks += data->num_clks; - data++; - } - - p->num_clocks = num_clks; - - p->clocks = devm_kcalloc(p->dev, num_clks, sizeof(struct sci_clk), - GFP_KERNEL); - if (!p->clocks) - return -ENOMEM; - - num_clks = 0; - - data = p->clk_data; - - while (data->num_clks) { - for (i = 0; i < data->num_clks; i++) { - hw = _sci_clk_build(p, data->dev, i); - if (!IS_ERR(hw)) { - p->clocks[num_clks++] = hw; - continue; - } - - /* Skip any holes in the clock lists */ - if (PTR_ERR(hw) == -ENODEV) - continue; + int ret; - return PTR_ERR(hw); - } - data++; + for (i = 0; i < p->num_clocks; i++) { + ret = _sci_clk_build(p, p->clocks[i]); + if (ret) + return ret; } return 0; } -static const struct sci_clk_data k2g_clk_data[] = { - /* pmmc */ - { .dev = 0x0, .num_clks = 4 }, - - /* mlb0 */ - { .dev = 0x1, .num_clks = 5 }, - - /* dss0 */ - { .dev = 0x2, .num_clks = 2 }, - - /* mcbsp0 */ - { .dev = 0x3, .num_clks = 8 }, - - /* mcasp0 */ - { .dev = 0x4, .num_clks = 8 }, - - /* mcasp1 */ - { .dev = 0x5, .num_clks = 8 }, - - /* mcasp2 */ - { .dev = 0x6, .num_clks = 8 }, - - /* dcan0 */ - { .dev = 0x8, .num_clks = 2 }, - - /* dcan1 */ - { .dev = 0x9, .num_clks = 2 }, - - /* emif0 */ - { .dev = 0xa, .num_clks = 6 }, - - /* mmchs0 */ - { .dev = 0xb, .num_clks = 3 }, - - /* mmchs1 */ - { .dev = 0xc, .num_clks = 3 }, - - /* gpmc0 */ - { .dev = 0xd, .num_clks = 1 }, - - /* elm0 */ - { .dev = 0xe, .num_clks = 1 }, - - /* spi0 */ - { .dev = 0x10, .num_clks = 1 }, - - /* spi1 */ - { .dev = 0x11, .num_clks = 1 }, - - /* spi2 */ - { .dev = 0x12, .num_clks = 1 }, - - /* spi3 */ - { .dev = 0x13, .num_clks = 1 }, - - /* icss0 */ - { .dev = 0x14, .num_clks = 6 }, - - /* icss1 */ - { .dev = 0x15, .num_clks = 6 }, - - /* usb0 */ - { .dev = 0x16, .num_clks = 7 }, - - /* usb1 */ - { .dev = 0x17, .num_clks = 7 }, - - /* nss0 */ - { .dev = 0x18, .num_clks = 14 }, - - /* pcie0 */ - { .dev = 0x19, .num_clks = 1 }, - - /* gpio0 */ - { .dev = 0x1b, .num_clks = 1 }, - - /* gpio1 */ - { .dev = 0x1c, .num_clks = 1 }, - - /* timer64_0 */ - { .dev = 0x1d, .num_clks = 9 }, - - /* timer64_1 */ - { .dev = 0x1e, .num_clks = 9 }, - - /* timer64_2 */ - { .dev = 0x1f, .num_clks = 9 }, - - /* timer64_3 */ - { .dev = 0x20, .num_clks = 9 }, - - /* timer64_4 */ - { .dev = 0x21, .num_clks = 9 }, - - /* timer64_5 */ - { .dev = 0x22, .num_clks = 9 }, - - /* timer64_6 */ - { .dev = 0x23, .num_clks = 9 }, - - /* msgmgr0 */ - { .dev = 0x25, .num_clks = 1 }, - - /* bootcfg0 */ - { .dev = 0x26, .num_clks = 1 }, - - /* arm_bootrom0 */ - { .dev = 0x27, .num_clks = 1 }, - - /* dsp_bootrom0 */ - { .dev = 0x29, .num_clks = 1 }, - - /* debugss0 */ - { .dev = 0x2b, .num_clks = 8 }, - - /* uart0 */ - { .dev = 0x2c, .num_clks = 1 }, - - /* uart1 */ - { .dev = 0x2d, .num_clks = 1 }, - - /* uart2 */ - { .dev = 0x2e, .num_clks = 1 }, - - /* ehrpwm0 */ - { .dev = 0x2f, .num_clks = 1 }, - - /* ehrpwm1 */ - { .dev = 0x30, .num_clks = 1 }, - - /* ehrpwm2 */ - { .dev = 0x31, .num_clks = 1 }, - - /* ehrpwm3 */ - { .dev = 0x32, .num_clks = 1 }, - - /* ehrpwm4 */ - { .dev = 0x33, .num_clks = 1 }, - - /* ehrpwm5 */ - { .dev = 0x34, .num_clks = 1 }, - - /* eqep0 */ - { .dev = 0x35, .num_clks = 1 }, - - /* eqep1 */ - { .dev = 0x36, .num_clks = 1 }, - - /* eqep2 */ - { .dev = 0x37, .num_clks = 1 }, - - /* ecap0 */ - { .dev = 0x38, .num_clks = 1 }, - - /* ecap1 */ - { .dev = 0x39, .num_clks = 1 }, - - /* i2c0 */ - { .dev = 0x3a, .num_clks = 1 }, - - /* i2c1 */ - { .dev = 0x3b, .num_clks = 1 }, - - /* i2c2 */ - { .dev = 0x3c, .num_clks = 1 }, - - /* edma0 */ - { .dev = 0x3f, .num_clks = 2 }, - - /* semaphore0 */ - { .dev = 0x40, .num_clks = 1 }, - - /* intc0 */ - { .dev = 0x41, .num_clks = 1 }, - - /* gic0 */ - { .dev = 0x42, .num_clks = 1 }, - - /* qspi0 */ - { .dev = 0x43, .num_clks = 5 }, - - /* arm_64b_counter0 */ - { .dev = 0x44, .num_clks = 2 }, - - /* tetris0 */ - { .dev = 0x45, .num_clks = 2 }, - - /* cgem0 */ - { .dev = 0x46, .num_clks = 2 }, - - /* msmc0 */ - { .dev = 0x47, .num_clks = 1 }, - - /* cbass0 */ - { .dev = 0x49, .num_clks = 1 }, - - /* board0 */ - { .dev = 0x4c, .num_clks = 36 }, - - /* edma1 */ - { .dev = 0x4f, .num_clks = 2 }, - { .num_clks = 0 }, -}; - static const struct of_device_id ti_sci_clk_of_match[] = { - { .compatible = "ti,k2g-sci-clk", .data = &k2g_clk_data }, + { .compatible = "ti,k2g-sci-clk" }, { /* Sentinel */ }, }; MODULE_DEVICE_TABLE(of, ti_sci_clk_of_match); @@ -681,12 +420,16 @@ static int ti_sci_clk_probe(struct platform_device *pdev) struct device_node *np = dev->of_node; struct sci_clk_provider *provider; const struct ti_sci_handle *handle; - const struct sci_clk_data *data; int ret; - - data = of_device_get_match_data(dev); - if (!data) - return -EINVAL; + int num_clks = 0; + struct sci_clk **clks = NULL; + struct sci_clk **tmp_clks; + struct sci_clk *sci_clk; + int max_clks = 0; + int clk_id = 0; + int dev_id = 0; + u8 num_parents; + int gap_size = 0; handle = devm_ti_sci_get_handle(dev); if (IS_ERR(handle)) @@ -696,12 +439,69 @@ static int ti_sci_clk_probe(struct platform_device *pdev) if (!provider) return -ENOMEM; - provider->clk_data = data; - provider->sci = handle; provider->ops = &handle->ops.clk_ops; provider->dev = dev; + while (1) { + ret = provider->ops->get_num_parents(provider->sci, dev_id, + clk_id, &num_parents); + if (ret) { + gap_size++; + if (!clk_id) { + if (gap_size >= 5) + break; + dev_id++; + } else { + if (gap_size >= 2) { + dev_id++; + clk_id = 0; + gap_size = 0; + } else { + clk_id++; + } + } + continue; + } + + gap_size = 0; + + if (num_clks == max_clks) { + tmp_clks = devm_kmalloc_array(dev, max_clks + 64, + sizeof(sci_clk), + GFP_KERNEL); + memcpy(tmp_clks, clks, max_clks * sizeof(sci_clk)); + if (max_clks) + devm_kfree(dev, clks); + max_clks += 64; + clks = tmp_clks; + } + + sci_clk = devm_kzalloc(dev, sizeof(*sci_clk), GFP_KERNEL); + if (!sci_clk) + return -ENOMEM; + sci_clk->dev_id = dev_id; + sci_clk->clk_id = clk_id; + sci_clk->provider = provider; + sci_clk->num_parents = num_parents; + + clks[num_clks] = sci_clk; + + clk_id++; + num_clks++; + } + + provider->clocks = devm_kmalloc_array(dev, num_clks, sizeof(sci_clk), + GFP_KERNEL); + if (!provider->clocks) + return -ENOMEM; + + memcpy(provider->clocks, clks, num_clks * sizeof(sci_clk)); + + provider->num_clocks = num_clks; + + devm_kfree(dev, clks); + ret = ti_sci_init_clocks(provider); if (ret) { pr_err("ti-sci-init-clocks failed.\n"); diff --git a/drivers/clk/mediatek/clk-mt2712.c b/drivers/clk/mediatek/clk-mt2712.c index 498d13799388..991d4093726e 100644 --- a/drivers/clk/mediatek/clk-mt2712.c +++ b/drivers/clk/mediatek/clk-mt2712.c @@ -221,6 +221,8 @@ static const struct mtk_fixed_factor top_divs[] = { 4), FACTOR(CLK_TOP_D2A_ULCLK_6P5M, "d2a_ulclk_6p5m", "clk26m", 1, 4), + FACTOR(CLK_TOP_APLL1_D3, "apll1_d3", "apll1_ck", 1, + 3), }; static const char * const axi_parents[] = { @@ -625,7 +627,7 @@ static const char * const ether_125m_parents[] = { static const char * const ether_50m_parents[] = { "clk26m", "etherpll_50m", - "univpll_d26", + "apll1_d3", "univpll3_d4" }; @@ -686,7 +688,7 @@ static const char * const i2c_parents[] = { static const char * const msdc0p_aes_parents[] = { "clk26m", - "msdcpll_ck", + "syspll_d2", "univpll_d3", "vcodecpll_ck" }; @@ -719,6 +721,17 @@ static const char * const aud_apll2_parents[] = { "clkaud_ext_i_2" }; +static const char * const apll1_ref_parents[] = { + "clkaud_ext_i_2", + "clkaud_ext_i_1", + "clki2si0_mck_i", + "clki2si1_mck_i", + "clki2si2_mck_i", + "clktdmin_mclk_i", + "clki2si2_mck_i", + "clktdmin_mclk_i" +}; + static const char * const audull_vtx_parents[] = { "d2a_ulclk_6p5m", "clkaud_ext_i_0" @@ -886,6 +899,10 @@ static struct mtk_composite top_muxes[] = { aud_apll2_parents, 0x134, 1, 1), MUX(CLK_TOP_DA_AUDULL_VTX_6P5M_SEL, "audull_vtx_sel", audull_vtx_parents, 0x134, 31, 1), + MUX(CLK_TOP_APLL1_REF_SEL, "apll1_ref_sel", + apll1_ref_parents, 0x134, 4, 3), + MUX(CLK_TOP_APLL2_REF_SEL, "apll2_ref_sel", + apll1_ref_parents, 0x134, 7, 3), }; static const char * const mcu_mp0_parents[] = { @@ -932,36 +949,56 @@ static const struct mtk_clk_divider top_adj_divs[] = { DIV_ADJ(CLK_TOP_APLL_DIV7, "apll_div7", "i2si3_sel", 0x128, 24, 8), }; -static const struct mtk_gate_regs top_cg_regs = { +static const struct mtk_gate_regs top0_cg_regs = { .set_ofs = 0x120, .clr_ofs = 0x120, .sta_ofs = 0x120, }; -#define GATE_TOP(_id, _name, _parent, _shift) { \ +static const struct mtk_gate_regs top1_cg_regs = { + .set_ofs = 0x424, + .clr_ofs = 0x424, + .sta_ofs = 0x424, +}; + +#define GATE_TOP0(_id, _name, _parent, _shift) { \ .id = _id, \ .name = _name, \ .parent_name = _parent, \ - .regs = &top_cg_regs, \ + .regs = &top0_cg_regs, \ .shift = _shift, \ .ops = &mtk_clk_gate_ops_no_setclr, \ } +#define GATE_TOP1(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &top1_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr_inv, \ + } + static const struct mtk_gate top_clks[] = { - GATE_TOP(CLK_TOP_APLL_DIV_PDN0, "apll_div_pdn0", "i2so1_sel", 0), - GATE_TOP(CLK_TOP_APLL_DIV_PDN1, "apll_div_pdn1", "i2so2_sel", 1), - GATE_TOP(CLK_TOP_APLL_DIV_PDN2, "apll_div_pdn2", "i2so3_sel", 2), - GATE_TOP(CLK_TOP_APLL_DIV_PDN3, "apll_div_pdn3", "tdmo0_sel", 3), - GATE_TOP(CLK_TOP_APLL_DIV_PDN4, "apll_div_pdn4", "tdmo1_sel", 4), - GATE_TOP(CLK_TOP_APLL_DIV_PDN5, "apll_div_pdn5", "i2si1_sel", 5), - GATE_TOP(CLK_TOP_APLL_DIV_PDN6, "apll_div_pdn6", "i2si2_sel", 6), - GATE_TOP(CLK_TOP_APLL_DIV_PDN7, "apll_div_pdn7", "i2si3_sel", 7), + /* TOP0 */ + GATE_TOP0(CLK_TOP_APLL_DIV_PDN0, "apll_div_pdn0", "i2so1_sel", 0), + GATE_TOP0(CLK_TOP_APLL_DIV_PDN1, "apll_div_pdn1", "i2so2_sel", 1), + GATE_TOP0(CLK_TOP_APLL_DIV_PDN2, "apll_div_pdn2", "i2so3_sel", 2), + GATE_TOP0(CLK_TOP_APLL_DIV_PDN3, "apll_div_pdn3", "tdmo0_sel", 3), + GATE_TOP0(CLK_TOP_APLL_DIV_PDN4, "apll_div_pdn4", "tdmo1_sel", 4), + GATE_TOP0(CLK_TOP_APLL_DIV_PDN5, "apll_div_pdn5", "i2si1_sel", 5), + GATE_TOP0(CLK_TOP_APLL_DIV_PDN6, "apll_div_pdn6", "i2si2_sel", 6), + GATE_TOP0(CLK_TOP_APLL_DIV_PDN7, "apll_div_pdn7", "i2si3_sel", 7), + /* TOP1 */ + GATE_TOP1(CLK_TOP_NFI2X_EN, "nfi2x_en", "nfi2x_sel", 0), + GATE_TOP1(CLK_TOP_NFIECC_EN, "nfiecc_en", "nfiecc_sel", 1), + GATE_TOP1(CLK_TOP_NFI1X_CK_EN, "nfi1x_ck_en", "nfi2x_sel", 2), }; static const struct mtk_gate_regs infra_cg_regs = { .set_ofs = 0x40, .clr_ofs = 0x44, - .sta_ofs = 0x40, + .sta_ofs = 0x48, }; #define GATE_INFRA(_id, _name, _parent, _shift) { \ @@ -1120,6 +1157,10 @@ static const struct mtk_gate peri_clks[] = { "msdc50_0_h_sel", 4), GATE_PERI2(CLK_PERI_MSDC50_3_HCLK_EN, "per_msdc50_3_h", "msdc50_3_h_sel", 5), + GATE_PERI2(CLK_PERI_MSDC30_0_QTR_EN, "per_msdc30_0_q", + "axi_sel", 6), + GATE_PERI2(CLK_PERI_MSDC30_3_QTR_EN, "per_msdc30_3_q", + "mem_sel", 7), }; #define MT2712_PLL_FMAX (3000UL * MHZ) diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index 7694302c70a4..d5cbec522aec 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -3,10 +3,15 @@ config COMMON_CLK_AMLOGIC depends on OF depends on ARCH_MESON || COMPILE_TEST +config COMMON_CLK_REGMAP_MESON + bool + select REGMAP + config COMMON_CLK_MESON8B bool depends on COMMON_CLK_AMLOGIC select RESET_CONTROLLER + select COMMON_CLK_REGMAP_MESON help Support for the clock controller on AmLogic S802 (Meson8), S805 (Meson8b) and S812 (Meson8m2) devices. Say Y if you @@ -16,6 +21,8 @@ config COMMON_CLK_GXBB bool depends on COMMON_CLK_AMLOGIC select RESET_CONTROLLER + select COMMON_CLK_REGMAP_MESON + select MFD_SYSCON help Support for the clock controller on AmLogic S905 devices, aka gxbb. Say Y if you want peripherals and CPU frequency scaling to work. @@ -24,6 +31,8 @@ config COMMON_CLK_AXG bool depends on COMMON_CLK_AMLOGIC select RESET_CONTROLLER + select COMMON_CLK_REGMAP_MESON + select MFD_SYSCON help Support for the clock controller on AmLogic A113D devices, aka axg. Say Y if you want peripherals and CPU frequency scaling to work. diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index 3c03ce583798..ffee82e60b7a 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -2,7 +2,8 @@ # Makefile for Meson specific clk # -obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-cpu.o clk-mpll.o clk-audio-divider.o +obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-audio-divider.o obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o -obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-regmap.o gxbb-aoclk-32k.o +obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o obj-$(CONFIG_COMMON_CLK_AXG) += axg.o +obj-$(CONFIG_COMMON_CLK_REGMAP_MESON) += clk-regmap.o diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 1294f3ad7cd5..5f5d468c1efe 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -11,125 +11,51 @@ #include <linux/clk.h> #include <linux/clk-provider.h> +#include <linux/init.h> #include <linux/of_address.h> #include <linux/of_device.h> +#include <linux/mfd/syscon.h> #include <linux/platform_device.h> -#include <linux/init.h> +#include <linux/regmap.h> #include "clkc.h" #include "axg.h" static DEFINE_SPINLOCK(meson_clk_lock); -static const struct pll_rate_table sys_pll_rate_table[] = { - PLL_RATE(24000000, 56, 1, 2), - PLL_RATE(48000000, 64, 1, 2), - PLL_RATE(72000000, 72, 1, 2), - PLL_RATE(96000000, 64, 1, 2), - PLL_RATE(120000000, 80, 1, 2), - PLL_RATE(144000000, 96, 1, 2), - PLL_RATE(168000000, 56, 1, 1), - PLL_RATE(192000000, 64, 1, 1), - PLL_RATE(216000000, 72, 1, 1), - PLL_RATE(240000000, 80, 1, 1), - PLL_RATE(264000000, 88, 1, 1), - PLL_RATE(288000000, 96, 1, 1), - PLL_RATE(312000000, 52, 1, 2), - PLL_RATE(336000000, 56, 1, 2), - PLL_RATE(360000000, 60, 1, 2), - PLL_RATE(384000000, 64, 1, 2), - PLL_RATE(408000000, 68, 1, 2), - PLL_RATE(432000000, 72, 1, 2), - PLL_RATE(456000000, 76, 1, 2), - PLL_RATE(480000000, 80, 1, 2), - PLL_RATE(504000000, 84, 1, 2), - PLL_RATE(528000000, 88, 1, 2), - PLL_RATE(552000000, 92, 1, 2), - PLL_RATE(576000000, 96, 1, 2), - PLL_RATE(600000000, 50, 1, 1), - PLL_RATE(624000000, 52, 1, 1), - PLL_RATE(648000000, 54, 1, 1), - PLL_RATE(672000000, 56, 1, 1), - PLL_RATE(696000000, 58, 1, 1), - PLL_RATE(720000000, 60, 1, 1), - PLL_RATE(744000000, 62, 1, 1), - PLL_RATE(768000000, 64, 1, 1), - PLL_RATE(792000000, 66, 1, 1), - PLL_RATE(816000000, 68, 1, 1), - PLL_RATE(840000000, 70, 1, 1), - PLL_RATE(864000000, 72, 1, 1), - PLL_RATE(888000000, 74, 1, 1), - PLL_RATE(912000000, 76, 1, 1), - PLL_RATE(936000000, 78, 1, 1), - PLL_RATE(960000000, 80, 1, 1), - PLL_RATE(984000000, 82, 1, 1), - PLL_RATE(1008000000, 84, 1, 1), - PLL_RATE(1032000000, 86, 1, 1), - PLL_RATE(1056000000, 88, 1, 1), - PLL_RATE(1080000000, 90, 1, 1), - PLL_RATE(1104000000, 92, 1, 1), - PLL_RATE(1128000000, 94, 1, 1), - PLL_RATE(1152000000, 96, 1, 1), - PLL_RATE(1176000000, 98, 1, 1), - PLL_RATE(1200000000, 50, 1, 0), - PLL_RATE(1224000000, 51, 1, 0), - PLL_RATE(1248000000, 52, 1, 0), - PLL_RATE(1272000000, 53, 1, 0), - PLL_RATE(1296000000, 54, 1, 0), - PLL_RATE(1320000000, 55, 1, 0), - PLL_RATE(1344000000, 56, 1, 0), - PLL_RATE(1368000000, 57, 1, 0), - PLL_RATE(1392000000, 58, 1, 0), - PLL_RATE(1416000000, 59, 1, 0), - PLL_RATE(1440000000, 60, 1, 0), - PLL_RATE(1464000000, 61, 1, 0), - PLL_RATE(1488000000, 62, 1, 0), - PLL_RATE(1512000000, 63, 1, 0), - PLL_RATE(1536000000, 64, 1, 0), - PLL_RATE(1560000000, 65, 1, 0), - PLL_RATE(1584000000, 66, 1, 0), - PLL_RATE(1608000000, 67, 1, 0), - PLL_RATE(1632000000, 68, 1, 0), - PLL_RATE(1656000000, 68, 1, 0), - PLL_RATE(1680000000, 68, 1, 0), - PLL_RATE(1704000000, 68, 1, 0), - PLL_RATE(1728000000, 69, 1, 0), - PLL_RATE(1752000000, 69, 1, 0), - PLL_RATE(1776000000, 69, 1, 0), - PLL_RATE(1800000000, 69, 1, 0), - PLL_RATE(1824000000, 70, 1, 0), - PLL_RATE(1848000000, 70, 1, 0), - PLL_RATE(1872000000, 70, 1, 0), - PLL_RATE(1896000000, 70, 1, 0), - PLL_RATE(1920000000, 71, 1, 0), - PLL_RATE(1944000000, 71, 1, 0), - PLL_RATE(1968000000, 71, 1, 0), - PLL_RATE(1992000000, 71, 1, 0), - PLL_RATE(2016000000, 72, 1, 0), - PLL_RATE(2040000000, 72, 1, 0), - PLL_RATE(2064000000, 72, 1, 0), - PLL_RATE(2088000000, 72, 1, 0), - PLL_RATE(2112000000, 73, 1, 0), - { /* sentinel */ }, -}; - -static struct meson_clk_pll axg_fixed_pll = { - .m = { - .reg_off = HHI_MPLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_MPLL_CNTL, - .shift = 9, - .width = 5, - }, - .od = { - .reg_off = HHI_MPLL_CNTL, - .shift = 16, - .width = 2, +static struct clk_regmap axg_fixed_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_MPLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_MPLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_MPLL_CNTL, + .shift = 16, + .width = 2, + }, + .frac = { + .reg_off = HHI_MPLL_CNTL2, + .shift = 0, + .width = 12, + }, + .l = { + .reg_off = HHI_MPLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_MPLL_CNTL, + .shift = 29, + .width = 1, + }, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "fixed_pll", .ops = &meson_clk_pll_ro_ops, @@ -138,25 +64,34 @@ static struct meson_clk_pll axg_fixed_pll = { }, }; -static struct meson_clk_pll axg_sys_pll = { - .m = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 0, - .width = 9, +static struct clk_regmap axg_sys_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 16, + .width = 2, + }, + .l = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 29, + .width = 1, + }, }, - .n = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 9, - .width = 5, - }, - .od = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 10, - .width = 2, - }, - .rate_table = sys_pll_rate_table, - .rate_count = ARRAY_SIZE(sys_pll_rate_table), - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "sys_pll", .ops = &meson_clk_pll_ro_ops, @@ -257,40 +192,51 @@ static const struct pll_rate_table axg_gp0_pll_rate_table[] = { { /* sentinel */ }, }; -static struct pll_params_table axg_gp0_params_table[] = { - PLL_PARAM(HHI_GP0_PLL_CNTL, 0x40010250), - PLL_PARAM(HHI_GP0_PLL_CNTL1, 0xc084a000), - PLL_PARAM(HHI_GP0_PLL_CNTL2, 0xb75020be), - PLL_PARAM(HHI_GP0_PLL_CNTL3, 0x0a59a288), - PLL_PARAM(HHI_GP0_PLL_CNTL4, 0xc000004d), - PLL_PARAM(HHI_GP0_PLL_CNTL5, 0x00078000), -}; - -static struct meson_clk_pll axg_gp0_pll = { - .m = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 9, - .width = 5, - }, - .od = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 16, - .width = 2, - }, - .params = { - .params_table = axg_gp0_params_table, - .params_count = ARRAY_SIZE(axg_gp0_params_table), - .no_init_reset = true, - .reset_lock_loop = true, - }, - .rate_table = axg_gp0_pll_rate_table, - .rate_count = ARRAY_SIZE(axg_gp0_pll_rate_table), - .lock = &meson_clk_lock, +static const struct reg_sequence axg_gp0_init_regs[] = { + { .reg = HHI_GP0_PLL_CNTL1, .def = 0xc084b000 }, + { .reg = HHI_GP0_PLL_CNTL2, .def = 0xb75020be }, + { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a59a288 }, + { .reg = HHI_GP0_PLL_CNTL4, .def = 0xc000004d }, + { .reg = HHI_GP0_PLL_CNTL5, .def = 0x00078000 }, + { .reg = HHI_GP0_PLL_CNTL, .def = 0x40010250 }, +}; + +static struct clk_regmap axg_gp0_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 16, + .width = 2, + }, + .frac = { + .reg_off = HHI_GP0_PLL_CNTL1, + .shift = 0, + .width = 10, + }, + .l = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 29, + .width = 1, + }, + .table = axg_gp0_pll_rate_table, + .init_regs = axg_gp0_init_regs, + .init_count = ARRAY_SIZE(axg_gp0_init_regs), + }, .hw.init = &(struct clk_init_data){ .name = "gp0_pll", .ops = &meson_clk_pll_ops, @@ -299,234 +245,427 @@ static struct meson_clk_pll axg_gp0_pll = { }, }; +static const struct reg_sequence axg_hifi_init_regs[] = { + { .reg = HHI_HIFI_PLL_CNTL1, .def = 0xc084b000 }, + { .reg = HHI_HIFI_PLL_CNTL2, .def = 0xb75020be }, + { .reg = HHI_HIFI_PLL_CNTL3, .def = 0x0a6a3a88 }, + { .reg = HHI_HIFI_PLL_CNTL4, .def = 0xc000004d }, + { .reg = HHI_HIFI_PLL_CNTL5, .def = 0x00058000 }, + { .reg = HHI_HIFI_PLL_CNTL, .def = 0x40010250 }, +}; + +static struct clk_regmap axg_hifi_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_HIFI_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_HIFI_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_HIFI_PLL_CNTL, + .shift = 16, + .width = 2, + }, + .frac = { + .reg_off = HHI_HIFI_PLL_CNTL5, + .shift = 0, + .width = 13, + }, + .l = { + .reg_off = HHI_HIFI_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_HIFI_PLL_CNTL, + .shift = 29, + .width = 1, + }, + .table = axg_gp0_pll_rate_table, + .init_regs = axg_hifi_init_regs, + .init_count = ARRAY_SIZE(axg_hifi_init_regs), + .flags = CLK_MESON_PLL_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "hifi_pll", + .ops = &meson_clk_pll_ops, + .parent_names = (const char *[]){ "xtal" }, + .num_parents = 1, + }, +}; -static struct clk_fixed_factor axg_fclk_div2 = { +static struct clk_fixed_factor axg_fclk_div2_div = { .mult = 1, .div = 2, .hw.init = &(struct clk_init_data){ - .name = "fclk_div2", + .name = "fclk_div2_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_fixed_factor axg_fclk_div3 = { +static struct clk_regmap axg_fclk_div2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 27, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div2_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor axg_fclk_div3_div = { .mult = 1, .div = 3, .hw.init = &(struct clk_init_data){ - .name = "fclk_div3", + .name = "fclk_div3_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_fixed_factor axg_fclk_div4 = { +static struct clk_regmap axg_fclk_div3 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 28, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div3_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor axg_fclk_div4_div = { .mult = 1, .div = 4, .hw.init = &(struct clk_init_data){ - .name = "fclk_div4", + .name = "fclk_div4_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_fixed_factor axg_fclk_div5 = { +static struct clk_regmap axg_fclk_div4 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 29, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div4_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor axg_fclk_div5_div = { .mult = 1, .div = 5, .hw.init = &(struct clk_init_data){ - .name = "fclk_div5", + .name = "fclk_div5_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_fixed_factor axg_fclk_div7 = { +static struct clk_regmap axg_fclk_div5 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div5_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor axg_fclk_div7_div = { .mult = 1, .div = 7, .hw.init = &(struct clk_init_data){ - .name = "fclk_div7", + .name = "fclk_div7_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct meson_clk_mpll axg_mpll0 = { - .sdm = { - .reg_off = HHI_MPLL_CNTL7, - .shift = 0, - .width = 14, +static struct clk_regmap axg_fclk_div7 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 31, }, - .sdm_en = { - .reg_off = HHI_MPLL_CNTL7, - .shift = 15, - .width = 1, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div7_div" }, + .num_parents = 1, }, - .n2 = { - .reg_off = HHI_MPLL_CNTL7, - .shift = 16, - .width = 9, +}; + +static struct clk_regmap axg_mpll_prediv = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPLL_CNTL5, + .shift = 12, + .width = 1, }, - .en = { - .reg_off = HHI_MPLL_CNTL7, - .shift = 14, - .width = 1, + .hw.init = &(struct clk_init_data){ + .name = "mpll_prediv", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, }, - .ssen = { - .reg_off = HHI_MPLL_CNTL, - .shift = 25, - .width = 1, +}; + +static struct clk_regmap axg_mpll0_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 16, + .width = 9, + }, + .ssen = { + .reg_off = HHI_MPLL_CNTL, + .shift = 25, + .width = 1, + }, + .misc = { + .reg_off = HHI_PLL_TOP_MISC, + .shift = 0, + .width = 1, + }, + .lock = &meson_clk_lock, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ - .name = "mpll0", + .name = "mpll0_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_names = (const char *[]){ "mpll_prediv" }, .num_parents = 1, }, }; -static struct meson_clk_mpll axg_mpll1 = { - .sdm = { - .reg_off = HHI_MPLL_CNTL8, - .shift = 0, - .width = 14, +static struct clk_regmap axg_mpll0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL7, + .bit_idx = 14, }, - .sdm_en = { - .reg_off = HHI_MPLL_CNTL8, - .shift = 15, - .width = 1, - }, - .n2 = { - .reg_off = HHI_MPLL_CNTL8, - .shift = 16, - .width = 9, + .hw.init = &(struct clk_init_data){ + .name = "mpll0", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mpll0_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, }, - .en = { - .reg_off = HHI_MPLL_CNTL8, - .shift = 14, - .width = 1, +}; + +static struct clk_regmap axg_mpll1_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 16, + .width = 9, + }, + .misc = { + .reg_off = HHI_PLL_TOP_MISC, + .shift = 1, + .width = 1, + }, + .lock = &meson_clk_lock, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ - .name = "mpll1", + .name = "mpll1_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_names = (const char *[]){ "mpll_prediv" }, .num_parents = 1, }, }; -static struct meson_clk_mpll axg_mpll2 = { - .sdm = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 0, - .width = 14, +static struct clk_regmap axg_mpll1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL8, + .bit_idx = 14, }, - .sdm_en = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 15, - .width = 1, - }, - .n2 = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 16, - .width = 9, + .hw.init = &(struct clk_init_data){ + .name = "mpll1", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mpll1_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, }, - .en = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 14, - .width = 1, +}; + +static struct clk_regmap axg_mpll2_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 16, + .width = 9, + }, + .misc = { + .reg_off = HHI_PLL_TOP_MISC, + .shift = 2, + .width = 1, + }, + .lock = &meson_clk_lock, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ - .name = "mpll2", + .name = "mpll2_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_names = (const char *[]){ "mpll_prediv" }, .num_parents = 1, }, }; -static struct meson_clk_mpll axg_mpll3 = { - .sdm = { - .reg_off = HHI_MPLL3_CNTL0, - .shift = 12, - .width = 14, +static struct clk_regmap axg_mpll2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL9, + .bit_idx = 14, }, - .sdm_en = { - .reg_off = HHI_MPLL3_CNTL0, - .shift = 11, - .width = 1, + .hw.init = &(struct clk_init_data){ + .name = "mpll2", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mpll2_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap axg_mpll3_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL3_CNTL0, + .shift = 12, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL3_CNTL0, + .shift = 11, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL3_CNTL0, + .shift = 2, + .width = 9, + }, + .misc = { + .reg_off = HHI_PLL_TOP_MISC, + .shift = 3, + .width = 1, + }, + .lock = &meson_clk_lock, }, - .n2 = { - .reg_off = HHI_MPLL3_CNTL0, - .shift = 2, - .width = 9, + .hw.init = &(struct clk_init_data){ + .name = "mpll3_div", + .ops = &meson_clk_mpll_ops, + .parent_names = (const char *[]){ "mpll_prediv" }, + .num_parents = 1, }, - .en = { - .reg_off = HHI_MPLL3_CNTL0, - .shift = 0, - .width = 1, +}; + +static struct clk_regmap axg_mpll3 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL3_CNTL0, + .bit_idx = 0, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "mpll3", - .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mpll3_div" }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, }, }; -/* - * FIXME The legacy composite clocks (e.g. clk81) are both PLL post-dividers - * and should be modeled with their respective PLLs via the forthcoming - * coordinated clock rates feature - */ static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 }; static const char * const clk81_parent_names[] = { "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4", "fclk_div3", "fclk_div5" }; -static struct clk_mux axg_mpeg_clk_sel = { - .reg = (void *)HHI_MPEG_CLK_CNTL, - .mask = 0x7, - .shift = 12, - .flags = CLK_MUX_READ_ONLY, - .table = mux_table_clk81, - .lock = &meson_clk_lock, +static struct clk_regmap axg_mpeg_clk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MPEG_CLK_CNTL, + .mask = 0x7, + .shift = 12, + .table = mux_table_clk81, + }, .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_sel", - .ops = &clk_mux_ro_ops, + .ops = &clk_regmap_mux_ro_ops, .parent_names = clk81_parent_names, .num_parents = ARRAY_SIZE(clk81_parent_names), }, }; -static struct clk_divider axg_mpeg_clk_div = { - .reg = (void *)HHI_MPEG_CLK_CNTL, - .shift = 0, - .width = 7, - .lock = &meson_clk_lock, +static struct clk_regmap axg_mpeg_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPEG_CLK_CNTL, + .shift = 0, + .width = 7, + }, .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "mpeg_clk_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_gate axg_clk81 = { - .reg = (void *)HHI_MPEG_CLK_CNTL, - .bit_idx = 7, - .lock = &meson_clk_lock, +static struct clk_regmap axg_clk81 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPEG_CLK_CNTL, + .bit_idx = 7, + }, .hw.init = &(struct clk_init_data){ .name = "clk81", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "mpeg_clk_div" }, .num_parents = 1, .flags = (CLK_SET_RATE_PARENT | CLK_IS_CRITICAL), @@ -545,42 +684,45 @@ static const char * const axg_sd_emmc_clk0_parent_names[] = { }; /* SDcard clock */ -static struct clk_mux axg_sd_emmc_b_clk0_sel = { - .reg = (void *)HHI_SD_EMMC_CLK_CNTL, - .mask = 0x7, - .shift = 25, - .lock = &meson_clk_lock, +static struct clk_regmap axg_sd_emmc_b_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .mask = 0x7, + .shift = 25, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_b_clk0_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = axg_sd_emmc_clk0_parent_names, .num_parents = ARRAY_SIZE(axg_sd_emmc_clk0_parent_names), .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_divider axg_sd_emmc_b_clk0_div = { - .reg = (void *)HHI_SD_EMMC_CLK_CNTL, - .shift = 16, - .width = 7, - .lock = &meson_clk_lock, - .flags = CLK_DIVIDER_ROUND_CLOSEST, +static struct clk_regmap axg_sd_emmc_b_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .shift = 16, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_b_clk0_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "sd_emmc_b_clk0_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_gate axg_sd_emmc_b_clk0 = { - .reg = (void *)HHI_SD_EMMC_CLK_CNTL, - .bit_idx = 23, - .lock = &meson_clk_lock, +static struct clk_regmap axg_sd_emmc_b_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .bit_idx = 23, + }, .hw.init = &(struct clk_init_data){ .name = "sd_emmc_b_clk0", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "sd_emmc_b_clk0_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -588,42 +730,45 @@ static struct clk_gate axg_sd_emmc_b_clk0 = { }; /* EMMC/NAND clock */ -static struct clk_mux axg_sd_emmc_c_clk0_sel = { - .reg = (void *)HHI_NAND_CLK_CNTL, - .mask = 0x7, - .shift = 9, - .lock = &meson_clk_lock, +static struct clk_regmap axg_sd_emmc_c_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_NAND_CLK_CNTL, + .mask = 0x7, + .shift = 9, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_c_clk0_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = axg_sd_emmc_clk0_parent_names, .num_parents = ARRAY_SIZE(axg_sd_emmc_clk0_parent_names), .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_divider axg_sd_emmc_c_clk0_div = { - .reg = (void *)HHI_NAND_CLK_CNTL, - .shift = 0, - .width = 7, - .lock = &meson_clk_lock, - .flags = CLK_DIVIDER_ROUND_CLOSEST, +static struct clk_regmap axg_sd_emmc_c_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_NAND_CLK_CNTL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_c_clk0_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "sd_emmc_c_clk0_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_gate axg_sd_emmc_c_clk0 = { - .reg = (void *)HHI_NAND_CLK_CNTL, - .bit_idx = 7, - .lock = &meson_clk_lock, +static struct clk_regmap axg_sd_emmc_c_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_NAND_CLK_CNTL, + .bit_idx = 7, + }, .hw.init = &(struct clk_init_data){ .name = "sd_emmc_c_clk0", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "sd_emmc_c_clk0_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -750,27 +895,24 @@ static struct clk_hw_onecell_data axg_hw_onecell_data = { [CLKID_SD_EMMC_C_CLK0_SEL] = &axg_sd_emmc_c_clk0_sel.hw, [CLKID_SD_EMMC_C_CLK0_DIV] = &axg_sd_emmc_c_clk0_div.hw, [CLKID_SD_EMMC_C_CLK0] = &axg_sd_emmc_c_clk0.hw, + [CLKID_MPLL0_DIV] = &axg_mpll0_div.hw, + [CLKID_MPLL1_DIV] = &axg_mpll1_div.hw, + [CLKID_MPLL2_DIV] = &axg_mpll2_div.hw, + [CLKID_MPLL3_DIV] = &axg_mpll3_div.hw, + [CLKID_HIFI_PLL] = &axg_hifi_pll.hw, + [CLKID_MPLL_PREDIV] = &axg_mpll_prediv.hw, + [CLKID_FCLK_DIV2_DIV] = &axg_fclk_div2_div.hw, + [CLKID_FCLK_DIV3_DIV] = &axg_fclk_div3_div.hw, + [CLKID_FCLK_DIV4_DIV] = &axg_fclk_div4_div.hw, + [CLKID_FCLK_DIV5_DIV] = &axg_fclk_div5_div.hw, + [CLKID_FCLK_DIV7_DIV] = &axg_fclk_div7_div.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, }; -/* Convenience tables to populate base addresses in .probe */ - -static struct meson_clk_pll *const axg_clk_plls[] = { - &axg_fixed_pll, - &axg_sys_pll, - &axg_gp0_pll, -}; - -static struct meson_clk_mpll *const axg_clk_mplls[] = { - &axg_mpll0, - &axg_mpll1, - &axg_mpll2, - &axg_mpll3, -}; - -static struct clk_gate *const axg_clk_gates[] = { +/* Convenience table to populate regmap in .probe */ +static struct clk_regmap *const axg_clk_regmaps[] = { &axg_clk81, &axg_ddr, &axg_audio_locker, @@ -818,113 +960,100 @@ static struct clk_gate *const axg_clk_gates[] = { &axg_ao_i2c, &axg_sd_emmc_b_clk0, &axg_sd_emmc_c_clk0, -}; - -static struct clk_mux *const axg_clk_muxes[] = { - &axg_mpeg_clk_sel, - &axg_sd_emmc_b_clk0_sel, - &axg_sd_emmc_c_clk0_sel, -}; - -static struct clk_divider *const axg_clk_dividers[] = { &axg_mpeg_clk_div, &axg_sd_emmc_b_clk0_div, &axg_sd_emmc_c_clk0_div, -}; - -struct clkc_data { - struct clk_gate *const *clk_gates; - unsigned int clk_gates_count; - struct meson_clk_mpll *const *clk_mplls; - unsigned int clk_mplls_count; - struct meson_clk_pll *const *clk_plls; - unsigned int clk_plls_count; - struct clk_mux *const *clk_muxes; - unsigned int clk_muxes_count; - struct clk_divider *const *clk_dividers; - unsigned int clk_dividers_count; - struct clk_hw_onecell_data *hw_onecell_data; -}; - -static const struct clkc_data axg_clkc_data = { - .clk_gates = axg_clk_gates, - .clk_gates_count = ARRAY_SIZE(axg_clk_gates), - .clk_mplls = axg_clk_mplls, - .clk_mplls_count = ARRAY_SIZE(axg_clk_mplls), - .clk_plls = axg_clk_plls, - .clk_plls_count = ARRAY_SIZE(axg_clk_plls), - .clk_muxes = axg_clk_muxes, - .clk_muxes_count = ARRAY_SIZE(axg_clk_muxes), - .clk_dividers = axg_clk_dividers, - .clk_dividers_count = ARRAY_SIZE(axg_clk_dividers), - .hw_onecell_data = &axg_hw_onecell_data, + &axg_mpeg_clk_sel, + &axg_sd_emmc_b_clk0_sel, + &axg_sd_emmc_c_clk0_sel, + &axg_mpll0, + &axg_mpll1, + &axg_mpll2, + &axg_mpll3, + &axg_mpll0_div, + &axg_mpll1_div, + &axg_mpll2_div, + &axg_mpll3_div, + &axg_fixed_pll, + &axg_sys_pll, + &axg_gp0_pll, + &axg_hifi_pll, + &axg_mpll_prediv, + &axg_fclk_div2, + &axg_fclk_div3, + &axg_fclk_div4, + &axg_fclk_div5, + &axg_fclk_div7, }; static const struct of_device_id clkc_match_table[] = { - { .compatible = "amlogic,axg-clkc", .data = &axg_clkc_data }, + { .compatible = "amlogic,axg-clkc" }, {} }; +static const struct regmap_config clkc_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + static int axg_clkc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - const struct clkc_data *clkc_data; struct resource *res; - void __iomem *clk_base; - int ret, clkid, i; - - clkc_data = of_device_get_match_data(&pdev->dev); - if (!clkc_data) - return -EINVAL; - - /* Generic clocks and PLLs */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -EINVAL; - clk_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - if (!clk_base) { - dev_err(&pdev->dev, "Unable to map clk base\n"); - return -ENXIO; - } + void __iomem *clk_base = NULL; + struct regmap *map; + int ret, i; - /* Populate base address for PLLs */ - for (i = 0; i < clkc_data->clk_plls_count; i++) - clkc_data->clk_plls[i]->base = clk_base; + /* Get the hhi system controller node if available */ + map = syscon_node_to_regmap(of_get_parent(dev->of_node)); + if (IS_ERR(map)) { + dev_err(dev, + "failed to get HHI regmap - Trying obsolete regs\n"); - /* Populate base address for MPLLs */ - for (i = 0; i < clkc_data->clk_mplls_count; i++) - clkc_data->clk_mplls[i]->base = clk_base; + /* + * FIXME: HHI registers should be accessed through + * the appropriate system controller. This is required because + * there is more than just clocks in this register space + * + * This fallback method is only provided temporarily until + * all the platform DTs are properly using the syscon node + */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; - /* Populate base address for gates */ - for (i = 0; i < clkc_data->clk_gates_count; i++) - clkc_data->clk_gates[i]->reg = clk_base + - (u64)clkc_data->clk_gates[i]->reg; - /* Populate base address for muxes */ - for (i = 0; i < clkc_data->clk_muxes_count; i++) - clkc_data->clk_muxes[i]->reg = clk_base + - (u64)clkc_data->clk_muxes[i]->reg; + clk_base = devm_ioremap(dev, res->start, resource_size(res)); + if (!clk_base) { + dev_err(dev, "Unable to map clk base\n"); + return -ENXIO; + } + + map = devm_regmap_init_mmio(dev, clk_base, + &clkc_regmap_config); + if (IS_ERR(map)) + return PTR_ERR(map); + } - /* Populate base address for dividers */ - for (i = 0; i < clkc_data->clk_dividers_count; i++) - clkc_data->clk_dividers[i]->reg = clk_base + - (u64)clkc_data->clk_dividers[i]->reg; + /* Populate regmap for the regmap backed clocks */ + for (i = 0; i < ARRAY_SIZE(axg_clk_regmaps); i++) + axg_clk_regmaps[i]->map = map; - for (clkid = 0; clkid < clkc_data->hw_onecell_data->num; clkid++) { + for (i = 0; i < axg_hw_onecell_data.num; i++) { /* array might be sparse */ - if (!clkc_data->hw_onecell_data->hws[clkid]) + if (!axg_hw_onecell_data.hws[i]) continue; - ret = devm_clk_hw_register(dev, - clkc_data->hw_onecell_data->hws[clkid]); + ret = devm_clk_hw_register(dev, axg_hw_onecell_data.hws[i]); if (ret) { - dev_err(&pdev->dev, "Clock registration failed\n"); + dev_err(dev, "Clock registration failed\n"); return ret; } } - return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, - clkc_data->hw_onecell_data); + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, + &axg_hw_onecell_data); } static struct platform_driver axg_driver = { diff --git a/drivers/clk/meson/axg.h b/drivers/clk/meson/axg.h index ce0bafdb6b28..b421df6a7ea0 100644 --- a/drivers/clk/meson/axg.h +++ b/drivers/clk/meson/axg.h @@ -117,8 +117,18 @@ #define CLKID_SD_EMMC_B_CLK0_DIV 62 #define CLKID_SD_EMMC_C_CLK0_SEL 63 #define CLKID_SD_EMMC_C_CLK0_DIV 64 +#define CLKID_MPLL0_DIV 65 +#define CLKID_MPLL1_DIV 66 +#define CLKID_MPLL2_DIV 67 +#define CLKID_MPLL3_DIV 68 +#define CLKID_MPLL_PREDIV 70 +#define CLKID_FCLK_DIV2_DIV 71 +#define CLKID_FCLK_DIV3_DIV 72 +#define CLKID_FCLK_DIV4_DIV 73 +#define CLKID_FCLK_DIV5_DIV 74 +#define CLKID_FCLK_DIV7_DIV 75 -#define NR_CLKS 65 +#define NR_CLKS 76 /* include the CLKIDs that have been made part of the DT binding */ #include <dt-bindings/clock/axg-clkc.h> diff --git a/drivers/clk/meson/clk-audio-divider.c b/drivers/clk/meson/clk-audio-divider.c index 6c07db06642d..f7ab5b1db342 100644 --- a/drivers/clk/meson/clk-audio-divider.c +++ b/drivers/clk/meson/clk-audio-divider.c @@ -28,8 +28,11 @@ #include <linux/clk-provider.h> #include "clkc.h" -#define to_meson_clk_audio_divider(_hw) container_of(_hw, \ - struct meson_clk_audio_divider, hw) +static inline struct meson_clk_audio_div_data * +meson_clk_audio_div_data(struct clk_regmap *clk) +{ + return (struct meson_clk_audio_div_data *)clk->data; +} static int _div_round(unsigned long parent_rate, unsigned long rate, unsigned long flags) @@ -45,15 +48,9 @@ static int _get_val(unsigned long parent_rate, unsigned long rate) return DIV_ROUND_UP_ULL((u64)parent_rate, rate) - 1; } -static int _valid_divider(struct clk_hw *hw, int divider) +static int _valid_divider(unsigned int width, int divider) { - struct meson_clk_audio_divider *adiv = - to_meson_clk_audio_divider(hw); - int max_divider; - u8 width; - - width = adiv->div.width; - max_divider = 1 << width; + int max_divider = 1 << width; return clamp(divider, 1, max_divider); } @@ -61,14 +58,11 @@ static int _valid_divider(struct clk_hw *hw, int divider) static unsigned long audio_divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { - struct meson_clk_audio_divider *adiv = - to_meson_clk_audio_divider(hw); - struct parm *p; - unsigned long reg, divider; + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_audio_div_data *adiv = meson_clk_audio_div_data(clk); + unsigned long divider; - p = &adiv->div; - reg = readl(adiv->base + p->reg_off); - divider = PARM_GET(p->width, p->shift, reg) + 1; + divider = meson_parm_read(clk->map, &adiv->div); return DIV_ROUND_UP_ULL((u64)parent_rate, divider); } @@ -77,14 +71,14 @@ static long audio_divider_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) { - struct meson_clk_audio_divider *adiv = - to_meson_clk_audio_divider(hw); + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_audio_div_data *adiv = meson_clk_audio_div_data(clk); unsigned long max_prate; int divider; if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) { divider = _div_round(*parent_rate, rate, adiv->flags); - divider = _valid_divider(hw, divider); + divider = _valid_divider(adiv->div.width, divider); return DIV_ROUND_UP_ULL((u64)*parent_rate, divider); } @@ -93,7 +87,7 @@ static long audio_divider_round_rate(struct clk_hw *hw, /* Get the corresponding rounded down divider */ divider = max_prate / rate; - divider = _valid_divider(hw, divider); + divider = _valid_divider(adiv->div.width, divider); /* Get actual rate of the parent */ *parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), @@ -106,28 +100,11 @@ static int audio_divider_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { - struct meson_clk_audio_divider *adiv = - to_meson_clk_audio_divider(hw); - struct parm *p; - unsigned long reg, flags = 0; - int val; - - val = _get_val(parent_rate, rate); - - if (adiv->lock) - spin_lock_irqsave(adiv->lock, flags); - else - __acquire(adiv->lock); - - p = &adiv->div; - reg = readl(adiv->base + p->reg_off); - reg = PARM_SET(p->width, p->shift, reg, val); - writel(reg, adiv->base + p->reg_off); - - if (adiv->lock) - spin_unlock_irqrestore(adiv->lock, flags); - else - __release(adiv->lock); + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_audio_div_data *adiv = meson_clk_audio_div_data(clk); + int val = _get_val(parent_rate, rate); + + meson_parm_write(clk->map, &adiv->div, val); return 0; } diff --git a/drivers/clk/meson/clk-cpu.c b/drivers/clk/meson/clk-cpu.c deleted file mode 100644 index f8b2b7efd016..000000000000 --- a/drivers/clk/meson/clk-cpu.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2015 Endless Mobile, Inc. - * Author: Carlo Caione <carlo@endlessm.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. - */ - -/* - * CPU clock path: - * - * +-[/N]-----|3| - * MUX2 +--[/3]-+----------|2| MUX1 - * [sys_pll]---|1| |--[/2]------------|1|-|1| - * | |---+------------------|0| | |----- [a5_clk] - * +--|0| | | - * [xtal]---+-------------------------------|0| - * - * - * - */ - -#include <linux/delay.h> -#include <linux/err.h> -#include <linux/io.h> -#include <linux/module.h> -#include <linux/of_address.h> -#include <linux/slab.h> -#include <linux/clk.h> -#include <linux/clk-provider.h> - -#define MESON_CPU_CLK_CNTL1 0x00 -#define MESON_CPU_CLK_CNTL 0x40 - -#define MESON_CPU_CLK_MUX1 BIT(7) -#define MESON_CPU_CLK_MUX2 BIT(0) - -#define MESON_N_WIDTH 9 -#define MESON_N_SHIFT 20 -#define MESON_SEL_WIDTH 2 -#define MESON_SEL_SHIFT 2 - -#include "clkc.h" - -#define to_meson_clk_cpu_hw(_hw) container_of(_hw, struct meson_clk_cpu, hw) -#define to_meson_clk_cpu_nb(_nb) container_of(_nb, struct meson_clk_cpu, clk_nb) - -static long meson_clk_cpu_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - struct meson_clk_cpu *clk_cpu = to_meson_clk_cpu_hw(hw); - - return divider_round_rate(hw, rate, prate, clk_cpu->div_table, - MESON_N_WIDTH, CLK_DIVIDER_ROUND_CLOSEST); -} - -static int meson_clk_cpu_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct meson_clk_cpu *clk_cpu = to_meson_clk_cpu_hw(hw); - unsigned int div, sel, N = 0; - u32 reg; - - div = DIV_ROUND_UP(parent_rate, rate); - - if (div <= 3) { - sel = div - 1; - } else { - sel = 3; - N = div / 2; - } - - reg = readl(clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL1); - reg = PARM_SET(MESON_N_WIDTH, MESON_N_SHIFT, reg, N); - writel(reg, clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL1); - - reg = readl(clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL); - reg = PARM_SET(MESON_SEL_WIDTH, MESON_SEL_SHIFT, reg, sel); - writel(reg, clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL); - - return 0; -} - -static unsigned long meson_clk_cpu_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct meson_clk_cpu *clk_cpu = to_meson_clk_cpu_hw(hw); - unsigned int N, sel; - unsigned int div = 1; - u32 reg; - - reg = readl(clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL1); - N = PARM_GET(MESON_N_WIDTH, MESON_N_SHIFT, reg); - - reg = readl(clk_cpu->base + clk_cpu->reg_off + MESON_CPU_CLK_CNTL); - sel = PARM_GET(MESON_SEL_WIDTH, MESON_SEL_SHIFT, reg); - - if (sel < 3) - div = sel + 1; - else - div = 2 * N; - - return parent_rate / div; -} - -/* FIXME MUX1 & MUX2 should be struct clk_hw objects */ -static int meson_clk_cpu_pre_rate_change(struct meson_clk_cpu *clk_cpu, - struct clk_notifier_data *ndata) -{ - u32 cpu_clk_cntl; - - /* switch MUX1 to xtal */ - cpu_clk_cntl = readl(clk_cpu->base + clk_cpu->reg_off - + MESON_CPU_CLK_CNTL); - cpu_clk_cntl &= ~MESON_CPU_CLK_MUX1; - writel(cpu_clk_cntl, clk_cpu->base + clk_cpu->reg_off - + MESON_CPU_CLK_CNTL); - udelay(100); - - /* switch MUX2 to sys-pll */ - cpu_clk_cntl |= MESON_CPU_CLK_MUX2; - writel(cpu_clk_cntl, clk_cpu->base + clk_cpu->reg_off - + MESON_CPU_CLK_CNTL); - - return 0; -} - -/* FIXME MUX1 & MUX2 should be struct clk_hw objects */ -static int meson_clk_cpu_post_rate_change(struct meson_clk_cpu *clk_cpu, - struct clk_notifier_data *ndata) -{ - u32 cpu_clk_cntl; - - /* switch MUX1 to divisors' output */ - cpu_clk_cntl = readl(clk_cpu->base + clk_cpu->reg_off - + MESON_CPU_CLK_CNTL); - cpu_clk_cntl |= MESON_CPU_CLK_MUX1; - writel(cpu_clk_cntl, clk_cpu->base + clk_cpu->reg_off - + MESON_CPU_CLK_CNTL); - udelay(100); - - return 0; -} - -/* - * This clock notifier is called when the frequency of the of the parent - * PLL clock is to be changed. We use the xtal input as temporary parent - * while the PLL frequency is stabilized. - */ -int meson_clk_cpu_notifier_cb(struct notifier_block *nb, - unsigned long event, void *data) -{ - struct clk_notifier_data *ndata = data; - struct meson_clk_cpu *clk_cpu = to_meson_clk_cpu_nb(nb); - int ret = 0; - - if (event == PRE_RATE_CHANGE) - ret = meson_clk_cpu_pre_rate_change(clk_cpu, ndata); - else if (event == POST_RATE_CHANGE) - ret = meson_clk_cpu_post_rate_change(clk_cpu, ndata); - - return notifier_from_errno(ret); -} - -const struct clk_ops meson_clk_cpu_ops = { - .recalc_rate = meson_clk_cpu_recalc_rate, - .round_rate = meson_clk_cpu_round_rate, - .set_rate = meson_clk_cpu_set_rate, -}; diff --git a/drivers/clk/meson/clk-mpll.c b/drivers/clk/meson/clk-mpll.c index 5144360e2c80..0df1227b65b3 100644 --- a/drivers/clk/meson/clk-mpll.c +++ b/drivers/clk/meson/clk-mpll.c @@ -68,11 +68,15 @@ #define N2_MIN 4 #define N2_MAX 511 -#define to_meson_clk_mpll(_hw) container_of(_hw, struct meson_clk_mpll, hw) +static inline struct meson_clk_mpll_data * +meson_clk_mpll_data(struct clk_regmap *clk) +{ + return (struct meson_clk_mpll_data *)clk->data; +} static long rate_from_params(unsigned long parent_rate, - unsigned long sdm, - unsigned long n2) + unsigned int sdm, + unsigned int n2) { unsigned long divisor = (SDM_DEN * n2) + sdm; @@ -84,8 +88,8 @@ static long rate_from_params(unsigned long parent_rate, static void params_from_rate(unsigned long requested_rate, unsigned long parent_rate, - unsigned long *sdm, - unsigned long *n2) + unsigned int *sdm, + unsigned int *n2) { uint64_t div = parent_rate; unsigned long rem = do_div(div, requested_rate); @@ -105,31 +109,23 @@ static void params_from_rate(unsigned long requested_rate, static unsigned long mpll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { - struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw); - struct parm *p; - unsigned long reg, sdm, n2; + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk); + unsigned int sdm, n2; long rate; - p = &mpll->sdm; - reg = readl(mpll->base + p->reg_off); - sdm = PARM_GET(p->width, p->shift, reg); - - p = &mpll->n2; - reg = readl(mpll->base + p->reg_off); - n2 = PARM_GET(p->width, p->shift, reg); + sdm = meson_parm_read(clk->map, &mpll->sdm); + n2 = meson_parm_read(clk->map, &mpll->n2); rate = rate_from_params(parent_rate, sdm, n2); - if (rate < 0) - return 0; - - return rate; + return rate < 0 ? 0 : rate; } static long mpll_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) { - unsigned long sdm, n2; + unsigned int sdm, n2; params_from_rate(rate, *parent_rate, &sdm, &n2); return rate_from_params(*parent_rate, sdm, n2); @@ -139,9 +135,9 @@ static int mpll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { - struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw); - struct parm *p; - unsigned long reg, sdm, n2; + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk); + unsigned int sdm, n2; unsigned long flags = 0; params_from_rate(rate, parent_rate, &sdm, &n2); @@ -151,97 +147,36 @@ static int mpll_set_rate(struct clk_hw *hw, else __acquire(mpll->lock); - p = &mpll->sdm; - reg = readl(mpll->base + p->reg_off); - reg = PARM_SET(p->width, p->shift, reg, sdm); - writel(reg, mpll->base + p->reg_off); - - p = &mpll->sdm_en; - reg = readl(mpll->base + p->reg_off); - reg = PARM_SET(p->width, p->shift, reg, 1); - writel(reg, mpll->base + p->reg_off); - - p = &mpll->ssen; - if (p->width != 0) { - reg = readl(mpll->base + p->reg_off); - reg = PARM_SET(p->width, p->shift, reg, 1); - writel(reg, mpll->base + p->reg_off); - } - - p = &mpll->n2; - reg = readl(mpll->base + p->reg_off); - reg = PARM_SET(p->width, p->shift, reg, n2); - writel(reg, mpll->base + p->reg_off); - - if (mpll->lock) - spin_unlock_irqrestore(mpll->lock, flags); - else - __release(mpll->lock); - - return 0; -} + /* Enable and set the fractional part */ + meson_parm_write(clk->map, &mpll->sdm, sdm); + meson_parm_write(clk->map, &mpll->sdm_en, 1); -static void mpll_enable_core(struct clk_hw *hw, int enable) -{ - struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw); - struct parm *p; - unsigned long reg; - unsigned long flags = 0; + /* Set additional fractional part enable if required */ + if (MESON_PARM_APPLICABLE(&mpll->ssen)) + meson_parm_write(clk->map, &mpll->ssen, 1); - if (mpll->lock) - spin_lock_irqsave(mpll->lock, flags); - else - __acquire(mpll->lock); + /* Set the integer divider part */ + meson_parm_write(clk->map, &mpll->n2, n2); - p = &mpll->en; - reg = readl(mpll->base + p->reg_off); - reg = PARM_SET(p->width, p->shift, reg, enable ? 1 : 0); - writel(reg, mpll->base + p->reg_off); + /* Set the magic misc bit if required */ + if (MESON_PARM_APPLICABLE(&mpll->misc)) + meson_parm_write(clk->map, &mpll->misc, 1); if (mpll->lock) spin_unlock_irqrestore(mpll->lock, flags); else __release(mpll->lock); -} - - -static int mpll_enable(struct clk_hw *hw) -{ - mpll_enable_core(hw, 1); return 0; } -static void mpll_disable(struct clk_hw *hw) -{ - mpll_enable_core(hw, 0); -} - -static int mpll_is_enabled(struct clk_hw *hw) -{ - struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw); - struct parm *p; - unsigned long reg; - int en; - - p = &mpll->en; - reg = readl(mpll->base + p->reg_off); - en = PARM_GET(p->width, p->shift, reg); - - return en; -} - const struct clk_ops meson_clk_mpll_ro_ops = { .recalc_rate = mpll_recalc_rate, .round_rate = mpll_round_rate, - .is_enabled = mpll_is_enabled, }; const struct clk_ops meson_clk_mpll_ops = { .recalc_rate = mpll_recalc_rate, .round_rate = mpll_round_rate, .set_rate = mpll_set_rate, - .enable = mpll_enable, - .disable = mpll_disable, - .is_enabled = mpll_is_enabled, }; diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c index 01341553f50b..65a7bd903551 100644 --- a/drivers/clk/meson/clk-pll.c +++ b/drivers/clk/meson/clk-pll.c @@ -2,6 +2,9 @@ * Copyright (c) 2015 Endless Mobile, Inc. * Author: Carlo Caione <carlo@endlessm.com> * + * Copyright (c) 2018 Baylibre, SAS. + * Author: Jerome Brunet <jbrunet@baylibre.com> + * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. @@ -27,13 +30,14 @@ * | | * FREF VCO * - * out = (in * M / N) >> OD + * out = in * (m + frac / frac_max) / (n << sum(ods)) */ #include <linux/clk-provider.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/io.h> +#include <linux/math64.h> #include <linux/module.h> #include <linux/of_address.h> #include <linux/slab.h> @@ -41,209 +45,213 @@ #include "clkc.h" -#define MESON_PLL_RESET BIT(29) -#define MESON_PLL_LOCK BIT(31) - -#define to_meson_clk_pll(_hw) container_of(_hw, struct meson_clk_pll, hw) - -static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) +static inline struct meson_clk_pll_data * +meson_clk_pll_data(struct clk_regmap *clk) { - struct meson_clk_pll *pll = to_meson_clk_pll(hw); - struct parm *p; - unsigned long parent_rate_mhz = parent_rate / 1000000; - unsigned long rate_mhz; - u16 n, m, frac = 0, od, od2 = 0; - u32 reg; - - p = &pll->n; - reg = readl(pll->base + p->reg_off); - n = PARM_GET(p->width, p->shift, reg); - - p = &pll->m; - reg = readl(pll->base + p->reg_off); - m = PARM_GET(p->width, p->shift, reg); - - p = &pll->od; - reg = readl(pll->base + p->reg_off); - od = PARM_GET(p->width, p->shift, reg); - - p = &pll->od2; - if (p->width) { - reg = readl(pll->base + p->reg_off); - od2 = PARM_GET(p->width, p->shift, reg); - } - - p = &pll->frac; - if (p->width) { - reg = readl(pll->base + p->reg_off); - frac = PARM_GET(p->width, p->shift, reg); - rate_mhz = (parent_rate_mhz * m + \ - (parent_rate_mhz * frac >> 12)) * 2 / n; - rate_mhz = rate_mhz >> od >> od2; - } else - rate_mhz = (parent_rate_mhz * m / n) >> od >> od2; - - return rate_mhz * 1000000; + return (struct meson_clk_pll_data *)clk->data; } -static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static unsigned long __pll_params_to_rate(unsigned long parent_rate, + const struct pll_rate_table *pllt, + u16 frac, + struct meson_clk_pll_data *pll) { - struct meson_clk_pll *pll = to_meson_clk_pll(hw); - const struct pll_rate_table *rate_table = pll->rate_table; - int i; + u64 rate = (u64)parent_rate * pllt->m; + unsigned int od = pllt->od + pllt->od2 + pllt->od3; - for (i = 0; i < pll->rate_count; i++) { - if (rate <= rate_table[i].rate) - return rate_table[i].rate; + if (frac && MESON_PARM_APPLICABLE(&pll->frac)) { + u64 frac_rate = (u64)parent_rate * frac; + + rate += DIV_ROUND_UP_ULL(frac_rate, + (1 << pll->frac.width)); } - /* else return the smallest value */ - return rate_table[0].rate; + return DIV_ROUND_UP_ULL(rate, pllt->n << od); } -static const struct pll_rate_table *meson_clk_get_pll_settings(struct meson_clk_pll *pll, - unsigned long rate) +static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) { - const struct pll_rate_table *rate_table = pll->rate_table; - int i; + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); + struct pll_rate_table pllt; + u16 frac; - for (i = 0; i < pll->rate_count; i++) { - if (rate == rate_table[i].rate) - return &rate_table[i]; - } - return NULL; + pllt.n = meson_parm_read(clk->map, &pll->n); + pllt.m = meson_parm_read(clk->map, &pll->m); + pllt.od = meson_parm_read(clk->map, &pll->od); + + pllt.od2 = MESON_PARM_APPLICABLE(&pll->od2) ? + meson_parm_read(clk->map, &pll->od2) : + 0; + + pllt.od3 = MESON_PARM_APPLICABLE(&pll->od3) ? + meson_parm_read(clk->map, &pll->od3) : + 0; + + frac = MESON_PARM_APPLICABLE(&pll->frac) ? + meson_parm_read(clk->map, &pll->frac) : + 0; + + return __pll_params_to_rate(parent_rate, &pllt, frac, pll); } -/* Specific wait loop for GXL/GXM GP0 PLL */ -static int meson_clk_pll_wait_lock_reset(struct meson_clk_pll *pll, - struct parm *p_n) +static u16 __pll_params_with_frac(unsigned long rate, + unsigned long parent_rate, + const struct pll_rate_table *pllt, + struct meson_clk_pll_data *pll) { - int delay = 100; - u32 reg; + u16 frac_max = (1 << pll->frac.width); + u64 val = (u64)rate * pllt->n; - while (delay > 0) { - reg = readl(pll->base + p_n->reg_off); - writel(reg | MESON_PLL_RESET, pll->base + p_n->reg_off); - udelay(10); - writel(reg & ~MESON_PLL_RESET, pll->base + p_n->reg_off); + val <<= pllt->od + pllt->od2 + pllt->od3; - /* This delay comes from AMLogic tree clk-gp0-gxl driver */ - mdelay(1); + if (pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) + val = DIV_ROUND_CLOSEST_ULL(val * frac_max, parent_rate); + else + val = div_u64(val * frac_max, parent_rate); - reg = readl(pll->base + p_n->reg_off); - if (reg & MESON_PLL_LOCK) - return 0; - delay--; + val -= pllt->m * frac_max; + + return min((u16)val, (u16)(frac_max - 1)); +} + +static const struct pll_rate_table * +meson_clk_get_pll_settings(unsigned long rate, + struct meson_clk_pll_data *pll) +{ + const struct pll_rate_table *table = pll->table; + unsigned int i = 0; + + if (!table) + return NULL; + + /* Find the first table element exceeding rate */ + while (table[i].rate && table[i].rate <= rate) + i++; + + if (i != 0) { + if (MESON_PARM_APPLICABLE(&pll->frac) || + !(pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) || + (abs(rate - table[i - 1].rate) < + abs(rate - table[i].rate))) + i--; } - return -ETIMEDOUT; + + return (struct pll_rate_table *)&table[i]; } -static int meson_clk_pll_wait_lock(struct meson_clk_pll *pll, - struct parm *p_n) +static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) { - int delay = 24000000; - u32 reg; + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); + const struct pll_rate_table *pllt = + meson_clk_get_pll_settings(rate, pll); + u16 frac; + + if (!pllt) + return meson_clk_pll_recalc_rate(hw, *parent_rate); + + if (!MESON_PARM_APPLICABLE(&pll->frac) + || rate == pllt->rate) + return pllt->rate; + + /* + * The rate provided by the setting is not an exact match, let's + * try to improve the result using the fractional parameter + */ + frac = __pll_params_with_frac(rate, *parent_rate, pllt, pll); + + return __pll_params_to_rate(*parent_rate, pllt, frac, pll); +} - while (delay > 0) { - reg = readl(pll->base + p_n->reg_off); +static int meson_clk_pll_wait_lock(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); + int delay = 24000000; - if (reg & MESON_PLL_LOCK) + do { + /* Is the clock locked now ? */ + if (meson_parm_read(clk->map, &pll->l)) return 0; + delay--; - } + } while (delay > 0); + return -ETIMEDOUT; } -static void meson_clk_pll_init_params(struct meson_clk_pll *pll) +static void meson_clk_pll_init(struct clk_hw *hw) { - int i; - - for (i = 0 ; i < pll->params.params_count ; ++i) - writel(pll->params.params_table[i].value, - pll->base + pll->params.params_table[i].reg_off); + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); + + if (pll->init_count) { + meson_parm_write(clk->map, &pll->rst, 1); + regmap_multi_reg_write(clk->map, pll->init_regs, + pll->init_count); + meson_parm_write(clk->map, &pll->rst, 0); + } } static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { - struct meson_clk_pll *pll = to_meson_clk_pll(hw); - struct parm *p; - const struct pll_rate_table *rate_set; + struct clk_regmap *clk = to_clk_regmap(hw); + struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); + const struct pll_rate_table *pllt; unsigned long old_rate; - int ret = 0; - u32 reg; + u16 frac = 0; if (parent_rate == 0 || rate == 0) return -EINVAL; old_rate = rate; - rate_set = meson_clk_get_pll_settings(pll, rate); - if (!rate_set) + pllt = meson_clk_get_pll_settings(rate, pll); + if (!pllt) return -EINVAL; - /* Initialize the PLL in a clean state if specified */ - if (pll->params.params_count) - meson_clk_pll_init_params(pll); - - /* PLL reset */ - p = &pll->n; - reg = readl(pll->base + p->reg_off); - /* If no_init_reset is provided, avoid resetting at this point */ - if (!pll->params.no_init_reset) - writel(reg | MESON_PLL_RESET, pll->base + p->reg_off); - - reg = PARM_SET(p->width, p->shift, reg, rate_set->n); - writel(reg, pll->base + p->reg_off); - - p = &pll->m; - reg = readl(pll->base + p->reg_off); - reg = PARM_SET(p->width, p->shift, reg, rate_set->m); - writel(reg, pll->base + p->reg_off); - - p = &pll->od; - reg = readl(pll->base + p->reg_off); - reg = PARM_SET(p->width, p->shift, reg, rate_set->od); - writel(reg, pll->base + p->reg_off); - - p = &pll->od2; - if (p->width) { - reg = readl(pll->base + p->reg_off); - reg = PARM_SET(p->width, p->shift, reg, rate_set->od2); - writel(reg, pll->base + p->reg_off); - } + /* Put the pll in reset to write the params */ + meson_parm_write(clk->map, &pll->rst, 1); - p = &pll->frac; - if (p->width) { - reg = readl(pll->base + p->reg_off); - reg = PARM_SET(p->width, p->shift, reg, rate_set->frac); - writel(reg, pll->base + p->reg_off); - } + meson_parm_write(clk->map, &pll->n, pllt->n); + meson_parm_write(clk->map, &pll->m, pllt->m); + meson_parm_write(clk->map, &pll->od, pllt->od); + + if (MESON_PARM_APPLICABLE(&pll->od2)) + meson_parm_write(clk->map, &pll->od2, pllt->od2); + + if (MESON_PARM_APPLICABLE(&pll->od3)) + meson_parm_write(clk->map, &pll->od3, pllt->od3); - p = &pll->n; - /* If clear_reset_for_lock is provided, remove the reset bit here */ - if (pll->params.clear_reset_for_lock) { - reg = readl(pll->base + p->reg_off); - writel(reg & ~MESON_PLL_RESET, pll->base + p->reg_off); + if (MESON_PARM_APPLICABLE(&pll->frac)) { + frac = __pll_params_with_frac(rate, parent_rate, pllt, pll); + meson_parm_write(clk->map, &pll->frac, frac); } - /* If reset_lock_loop, use a special loop including resetting */ - if (pll->params.reset_lock_loop) - ret = meson_clk_pll_wait_lock_reset(pll, p); - else - ret = meson_clk_pll_wait_lock(pll, p); - if (ret) { + /* make sure the reset is cleared at this point */ + meson_parm_write(clk->map, &pll->rst, 0); + + if (meson_clk_pll_wait_lock(hw)) { pr_warn("%s: pll did not lock, trying to restore old rate %lu\n", __func__, old_rate); + /* + * FIXME: Do we really need/want this HACK ? + * It looks unsafe. what happens if the clock gets into a + * broken state and we can't lock back on the old_rate ? Looks + * like an infinite recursion is possible + */ meson_clk_pll_set_rate(hw, old_rate, parent_rate); } - return ret; + return 0; } const struct clk_ops meson_clk_pll_ops = { + .init = meson_clk_pll_init, .recalc_rate = meson_clk_pll_recalc_rate, .round_rate = meson_clk_pll_round_rate, .set_rate = meson_clk_pll_set_rate, diff --git a/drivers/clk/meson/clk-regmap.c b/drivers/clk/meson/clk-regmap.c new file mode 100644 index 000000000000..3645fdb62343 --- /dev/null +++ b/drivers/clk/meson/clk-regmap.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 BayLibre, SAS. +// Author: Jerome Brunet <jbrunet@baylibre.com> + +#include "clk-regmap.h" + +static int clk_regmap_gate_endisable(struct clk_hw *hw, int enable) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct clk_regmap_gate_data *gate = clk_get_regmap_gate_data(clk); + int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0; + + set ^= enable; + + return regmap_update_bits(clk->map, gate->offset, BIT(gate->bit_idx), + set ? BIT(gate->bit_idx) : 0); +} + +static int clk_regmap_gate_enable(struct clk_hw *hw) +{ + return clk_regmap_gate_endisable(hw, 1); +} + +static void clk_regmap_gate_disable(struct clk_hw *hw) +{ + clk_regmap_gate_endisable(hw, 0); +} + +static int clk_regmap_gate_is_enabled(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct clk_regmap_gate_data *gate = clk_get_regmap_gate_data(clk); + unsigned int val; + + regmap_read(clk->map, gate->offset, &val); + if (gate->flags & CLK_GATE_SET_TO_DISABLE) + val ^= BIT(gate->bit_idx); + + val &= BIT(gate->bit_idx); + + return val ? 1 : 0; +} + +const struct clk_ops clk_regmap_gate_ops = { + .enable = clk_regmap_gate_enable, + .disable = clk_regmap_gate_disable, + .is_enabled = clk_regmap_gate_is_enabled, +}; +EXPORT_SYMBOL_GPL(clk_regmap_gate_ops); + +static unsigned long clk_regmap_div_recalc_rate(struct clk_hw *hw, + unsigned long prate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct clk_regmap_div_data *div = clk_get_regmap_div_data(clk); + unsigned int val; + int ret; + + ret = regmap_read(clk->map, div->offset, &val); + if (ret) + /* Gives a hint that something is wrong */ + return 0; + + val >>= div->shift; + val &= clk_div_mask(div->width); + return divider_recalc_rate(hw, prate, val, div->table, div->flags, + div->width); +} + +static long clk_regmap_div_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct clk_regmap_div_data *div = clk_get_regmap_div_data(clk); + unsigned int val; + int ret; + + /* if read only, just return current value */ + if (div->flags & CLK_DIVIDER_READ_ONLY) { + ret = regmap_read(clk->map, div->offset, &val); + if (ret) + /* Gives a hint that something is wrong */ + return 0; + + val >>= div->shift; + val &= clk_div_mask(div->width); + + return divider_ro_round_rate(hw, rate, prate, div->table, + div->width, div->flags, val); + } + + return divider_round_rate(hw, rate, prate, div->table, div->width, + div->flags); +} + +static int clk_regmap_div_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct clk_regmap_div_data *div = clk_get_regmap_div_data(clk); + unsigned int val; + int ret; + + ret = divider_get_val(rate, parent_rate, div->table, div->width, + div->flags); + if (ret < 0) + return ret; + + val = (unsigned int)ret << div->shift; + return regmap_update_bits(clk->map, div->offset, + clk_div_mask(div->width) << div->shift, val); +}; + +/* Would prefer clk_regmap_div_ro_ops but clashes with qcom */ + +const struct clk_ops clk_regmap_divider_ops = { + .recalc_rate = clk_regmap_div_recalc_rate, + .round_rate = clk_regmap_div_round_rate, + .set_rate = clk_regmap_div_set_rate, +}; +EXPORT_SYMBOL_GPL(clk_regmap_divider_ops); + +const struct clk_ops clk_regmap_divider_ro_ops = { + .recalc_rate = clk_regmap_div_recalc_rate, + .round_rate = clk_regmap_div_round_rate, +}; +EXPORT_SYMBOL_GPL(clk_regmap_divider_ro_ops); + +static u8 clk_regmap_mux_get_parent(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct clk_regmap_mux_data *mux = clk_get_regmap_mux_data(clk); + unsigned int val; + int ret; + + ret = regmap_read(clk->map, mux->offset, &val); + if (ret) + return ret; + + val >>= mux->shift; + val &= mux->mask; + return clk_mux_val_to_index(hw, mux->table, mux->flags, val); +} + +static int clk_regmap_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct clk_regmap_mux_data *mux = clk_get_regmap_mux_data(clk); + unsigned int val = clk_mux_index_to_val(mux->table, mux->flags, index); + + return regmap_update_bits(clk->map, mux->offset, + mux->mask << mux->shift, + val << mux->shift); +} + +const struct clk_ops clk_regmap_mux_ops = { + .get_parent = clk_regmap_mux_get_parent, + .set_parent = clk_regmap_mux_set_parent, + .determine_rate = __clk_mux_determine_rate, +}; +EXPORT_SYMBOL_GPL(clk_regmap_mux_ops); + +const struct clk_ops clk_regmap_mux_ro_ops = { + .get_parent = clk_regmap_mux_get_parent, +}; +EXPORT_SYMBOL_GPL(clk_regmap_mux_ro_ops); diff --git a/drivers/clk/meson/clk-regmap.h b/drivers/clk/meson/clk-regmap.h new file mode 100644 index 000000000000..627c888026d7 --- /dev/null +++ b/drivers/clk/meson/clk-regmap.h @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 BayLibre, SAS. +// Author: Jerome Brunet <jbrunet@baylibre.com> + +#ifndef __CLK_REGMAP_H +#define __CLK_REGMAP_H + +#include <linux/clk-provider.h> +#include <linux/regmap.h> + +/** + * struct clk_regmap - regmap backed clock + * + * @hw: handle between common and hardware-specific interfaces + * @map: pointer to the regmap structure controlling the clock + * @data: data specific to the clock type + * + * Clock which is controlled by regmap backed registers. The actual type of + * of the clock is controlled by the clock_ops and data. + */ +struct clk_regmap { + struct clk_hw hw; + struct regmap *map; + void *data; +}; + +#define to_clk_regmap(_hw) container_of(_hw, struct clk_regmap, hw) + +/** + * struct clk_regmap_gate_data - regmap backed gate specific data + * + * @offset: offset of the register controlling gate + * @bit_idx: single bit controlling gate + * @flags: hardware-specific flags + * + * Flags: + * Same as clk_gate except CLK_GATE_HIWORD_MASK which is ignored + */ +struct clk_regmap_gate_data { + unsigned int offset; + u8 bit_idx; + u8 flags; +}; + +static inline struct clk_regmap_gate_data * +clk_get_regmap_gate_data(struct clk_regmap *clk) +{ + return (struct clk_regmap_gate_data *)clk->data; +} + +extern const struct clk_ops clk_regmap_gate_ops; + +/** + * struct clk_regmap_div_data - regmap backed adjustable divider specific data + * + * @offset: offset of the register controlling the divider + * @shift: shift to the divider bit field + * @width: width of the divider bit field + * @table: array of value/divider pairs, last entry should have div = 0 + * + * Flags: + * Same as clk_divider except CLK_DIVIDER_HIWORD_MASK which is ignored + */ +struct clk_regmap_div_data { + unsigned int offset; + u8 shift; + u8 width; + u8 flags; + const struct clk_div_table *table; +}; + +static inline struct clk_regmap_div_data * +clk_get_regmap_div_data(struct clk_regmap *clk) +{ + return (struct clk_regmap_div_data *)clk->data; +} + +extern const struct clk_ops clk_regmap_divider_ops; +extern const struct clk_ops clk_regmap_divider_ro_ops; + +/** + * struct clk_regmap_mux_data - regmap backed multiplexer clock specific data + * + * @hw: handle between common and hardware-specific interfaces + * @offset: offset of theregister controlling multiplexer + * @table: array of parent indexed register values + * @shift: shift to multiplexer bit field + * @mask: mask of mutliplexer bit field + * @flags: hardware-specific flags + * + * Flags: + * Same as clk_divider except CLK_MUX_HIWORD_MASK which is ignored + */ +struct clk_regmap_mux_data { + unsigned int offset; + u32 *table; + u32 mask; + u8 shift; + u8 flags; +}; + +static inline struct clk_regmap_mux_data * +clk_get_regmap_mux_data(struct clk_regmap *clk) +{ + return (struct clk_regmap_mux_data *)clk->data; +} + +extern const struct clk_ops clk_regmap_mux_ops; +extern const struct clk_ops clk_regmap_mux_ro_ops; + +#endif /* __CLK_REGMAP_H */ diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index c2ff0520ce53..8fe73c4edca8 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h @@ -18,6 +18,9 @@ #ifndef __CLKC_H #define __CLKC_H +#include <linux/clk-provider.h> +#include "clk-regmap.h" + #define PMASK(width) GENMASK(width - 1, 0) #define SETPMASK(width, shift) GENMASK(shift + width - 1, shift) #define CLRPMASK(width, shift) (~SETPMASK(width, shift)) @@ -35,13 +38,29 @@ struct parm { u8 width; }; +static inline unsigned int meson_parm_read(struct regmap *map, struct parm *p) +{ + unsigned int val; + + regmap_read(map, p->reg_off, &val); + return PARM_GET(p->width, p->shift, val); +} + +static inline void meson_parm_write(struct regmap *map, struct parm *p, + unsigned int val) +{ + regmap_update_bits(map, p->reg_off, SETPMASK(p->width, p->shift), + val << p->shift); +} + + struct pll_rate_table { unsigned long rate; u16 m; u16 n; u16 od; u16 od2; - u16 frac; + u16 od3; }; #define PLL_RATE(_r, _m, _n, _od) \ @@ -50,97 +69,53 @@ struct pll_rate_table { .m = (_m), \ .n = (_n), \ .od = (_od), \ - } \ - -#define PLL_FRAC_RATE(_r, _m, _n, _od, _od2, _frac) \ - { \ - .rate = (_r), \ - .m = (_m), \ - .n = (_n), \ - .od = (_od), \ - .od2 = (_od2), \ - .frac = (_frac), \ - } \ - -struct pll_params_table { - unsigned int reg_off; - unsigned int value; -}; - -#define PLL_PARAM(_reg, _val) \ - { \ - .reg_off = (_reg), \ - .value = (_val), \ } -struct pll_setup_params { - struct pll_params_table *params_table; - unsigned int params_count; - /* Workaround for GP0, do not reset before configuring */ - bool no_init_reset; - /* Workaround for GP0, unreset right before checking for lock */ - bool clear_reset_for_lock; - /* Workaround for GXL GP0, reset in the lock checking loop */ - bool reset_lock_loop; -}; +#define CLK_MESON_PLL_ROUND_CLOSEST BIT(0) -struct meson_clk_pll { - struct clk_hw hw; - void __iomem *base; +struct meson_clk_pll_data { struct parm m; struct parm n; struct parm frac; struct parm od; struct parm od2; - const struct pll_setup_params params; - const struct pll_rate_table *rate_table; - unsigned int rate_count; - spinlock_t *lock; + struct parm od3; + struct parm l; + struct parm rst; + const struct reg_sequence *init_regs; + unsigned int init_count; + const struct pll_rate_table *table; + u8 flags; }; #define to_meson_clk_pll(_hw) container_of(_hw, struct meson_clk_pll, hw) -struct meson_clk_cpu { - struct clk_hw hw; - void __iomem *base; - u16 reg_off; - struct notifier_block clk_nb; - const struct clk_div_table *div_table; -}; - -int meson_clk_cpu_notifier_cb(struct notifier_block *nb, unsigned long event, - void *data); - -struct meson_clk_mpll { - struct clk_hw hw; - void __iomem *base; +struct meson_clk_mpll_data { struct parm sdm; struct parm sdm_en; struct parm n2; - struct parm en; struct parm ssen; + struct parm misc; spinlock_t *lock; }; -struct meson_clk_audio_divider { - struct clk_hw hw; - void __iomem *base; +struct meson_clk_audio_div_data { struct parm div; u8 flags; - spinlock_t *lock; }; #define MESON_GATE(_name, _reg, _bit) \ -struct clk_gate _name = { \ - .reg = (void __iomem *) _reg, \ - .bit_idx = (_bit), \ - .lock = &meson_clk_lock, \ - .hw.init = &(struct clk_init_data) { \ - .name = #_name, \ - .ops = &clk_gate_ops, \ +struct clk_regmap _name = { \ + .data = &(struct clk_regmap_gate_data){ \ + .offset = (_reg), \ + .bit_idx = (_bit), \ + }, \ + .hw.init = &(struct clk_init_data) { \ + .name = #_name, \ + .ops = &clk_regmap_gate_ops, \ .parent_names = (const char *[]){ "clk81" }, \ .num_parents = 1, \ - .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \ + .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \ }, \ }; diff --git a/drivers/clk/meson/gxbb-aoclk-regmap.c b/drivers/clk/meson/gxbb-aoclk-regmap.c deleted file mode 100644 index 2515fbfa0467..000000000000 --- a/drivers/clk/meson/gxbb-aoclk-regmap.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2017 BayLibre, SAS. - * Author: Neil Armstrong <narmstrong@baylibre.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <linux/clk-provider.h> -#include <linux/bitfield.h> -#include <linux/regmap.h> -#include "gxbb-aoclk.h" - -static int aoclk_gate_regmap_enable(struct clk_hw *hw) -{ - struct aoclk_gate_regmap *gate = to_aoclk_gate_regmap(hw); - - return regmap_update_bits(gate->regmap, AO_RTI_GEN_CNTL_REG0, - BIT(gate->bit_idx), BIT(gate->bit_idx)); -} - -static void aoclk_gate_regmap_disable(struct clk_hw *hw) -{ - struct aoclk_gate_regmap *gate = to_aoclk_gate_regmap(hw); - - regmap_update_bits(gate->regmap, AO_RTI_GEN_CNTL_REG0, - BIT(gate->bit_idx), 0); -} - -static int aoclk_gate_regmap_is_enabled(struct clk_hw *hw) -{ - struct aoclk_gate_regmap *gate = to_aoclk_gate_regmap(hw); - unsigned int val; - int ret; - - ret = regmap_read(gate->regmap, AO_RTI_GEN_CNTL_REG0, &val); - if (ret) - return ret; - - return (val & BIT(gate->bit_idx)) != 0; -} - -const struct clk_ops meson_aoclk_gate_regmap_ops = { - .enable = aoclk_gate_regmap_enable, - .disable = aoclk_gate_regmap_disable, - .is_enabled = aoclk_gate_regmap_is_enabled, -}; diff --git a/drivers/clk/meson/gxbb-aoclk.c b/drivers/clk/meson/gxbb-aoclk.c index 6c161e0a8e59..9ec23ae9a219 100644 --- a/drivers/clk/meson/gxbb-aoclk.c +++ b/drivers/clk/meson/gxbb-aoclk.c @@ -62,10 +62,9 @@ #include <linux/delay.h> #include <dt-bindings/clock/gxbb-aoclkc.h> #include <dt-bindings/reset/gxbb-aoclkc.h> +#include "clk-regmap.h" #include "gxbb-aoclk.h" -static DEFINE_SPINLOCK(gxbb_aoclk_lock); - struct gxbb_aoclk_reset_controller { struct reset_controller_dev reset; unsigned int *data; @@ -87,12 +86,14 @@ static const struct reset_control_ops gxbb_aoclk_reset_ops = { }; #define GXBB_AO_GATE(_name, _bit) \ -static struct aoclk_gate_regmap _name##_ao = { \ - .bit_idx = (_bit), \ - .lock = &gxbb_aoclk_lock, \ +static struct clk_regmap _name##_ao = { \ + .data = &(struct clk_regmap_gate_data) { \ + .offset = AO_RTI_GEN_CNTL_REG0, \ + .bit_idx = (_bit), \ + }, \ .hw.init = &(struct clk_init_data) { \ .name = #_name "_ao", \ - .ops = &meson_aoclk_gate_regmap_ops, \ + .ops = &clk_regmap_gate_ops, \ .parent_names = (const char *[]){ "clk81" }, \ .num_parents = 1, \ .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \ @@ -107,7 +108,6 @@ GXBB_AO_GATE(uart2, 5); GXBB_AO_GATE(ir_blaster, 6); static struct aoclk_cec_32k cec_32k_ao = { - .lock = &gxbb_aoclk_lock, .hw.init = &(struct clk_init_data) { .name = "cec_32k_ao", .ops = &meson_aoclk_cec_32k_ops, @@ -126,7 +126,7 @@ static unsigned int gxbb_aoclk_reset[] = { [RESET_AO_IR_BLASTER] = 23, }; -static struct aoclk_gate_regmap *gxbb_aoclk_gate[] = { +static struct clk_regmap *gxbb_aoclk_gate[] = { [CLKID_AO_REMOTE] = &remote_ao, [CLKID_AO_I2C_MASTER] = &i2c_master_ao, [CLKID_AO_I2C_SLAVE] = &i2c_slave_ao, @@ -177,10 +177,10 @@ static int gxbb_aoclkc_probe(struct platform_device *pdev) * Populate regmap and register all clks */ for (clkid = 0; clkid < ARRAY_SIZE(gxbb_aoclk_gate); clkid++) { - gxbb_aoclk_gate[clkid]->regmap = regmap; + gxbb_aoclk_gate[clkid]->map = regmap; ret = devm_clk_hw_register(dev, - gxbb_aoclk_onecell_data.hws[clkid]); + gxbb_aoclk_onecell_data.hws[clkid]); if (ret) return ret; } diff --git a/drivers/clk/meson/gxbb-aoclk.h b/drivers/clk/meson/gxbb-aoclk.h index e8604c8f7eee..0be78383f257 100644 --- a/drivers/clk/meson/gxbb-aoclk.h +++ b/drivers/clk/meson/gxbb-aoclk.h @@ -17,22 +17,11 @@ #define AO_RTC_ALT_CLK_CNTL0 0x94 #define AO_RTC_ALT_CLK_CNTL1 0x98 -struct aoclk_gate_regmap { - struct clk_hw hw; - unsigned bit_idx; - struct regmap *regmap; - spinlock_t *lock; -}; - -#define to_aoclk_gate_regmap(_hw) \ - container_of(_hw, struct aoclk_gate_regmap, hw) - extern const struct clk_ops meson_aoclk_gate_regmap_ops; struct aoclk_cec_32k { struct clk_hw hw; struct regmap *regmap; - spinlock_t *lock; }; #define to_aoclk_cec_32k(_hw) container_of(_hw, struct aoclk_cec_32k, hw) diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index af24455af5b4..b1e4d9557610 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -19,108 +19,19 @@ #include <linux/clk.h> #include <linux/clk-provider.h> +#include <linux/init.h> #include <linux/of_address.h> #include <linux/of_device.h> +#include <linux/mfd/syscon.h> #include <linux/platform_device.h> -#include <linux/init.h> +#include <linux/regmap.h> #include "clkc.h" #include "gxbb.h" +#include "clk-regmap.h" static DEFINE_SPINLOCK(meson_clk_lock); -static const struct pll_rate_table sys_pll_rate_table[] = { - PLL_RATE(24000000, 56, 1, 2), - PLL_RATE(48000000, 64, 1, 2), - PLL_RATE(72000000, 72, 1, 2), - PLL_RATE(96000000, 64, 1, 2), - PLL_RATE(120000000, 80, 1, 2), - PLL_RATE(144000000, 96, 1, 2), - PLL_RATE(168000000, 56, 1, 1), - PLL_RATE(192000000, 64, 1, 1), - PLL_RATE(216000000, 72, 1, 1), - PLL_RATE(240000000, 80, 1, 1), - PLL_RATE(264000000, 88, 1, 1), - PLL_RATE(288000000, 96, 1, 1), - PLL_RATE(312000000, 52, 1, 2), - PLL_RATE(336000000, 56, 1, 2), - PLL_RATE(360000000, 60, 1, 2), - PLL_RATE(384000000, 64, 1, 2), - PLL_RATE(408000000, 68, 1, 2), - PLL_RATE(432000000, 72, 1, 2), - PLL_RATE(456000000, 76, 1, 2), - PLL_RATE(480000000, 80, 1, 2), - PLL_RATE(504000000, 84, 1, 2), - PLL_RATE(528000000, 88, 1, 2), - PLL_RATE(552000000, 92, 1, 2), - PLL_RATE(576000000, 96, 1, 2), - PLL_RATE(600000000, 50, 1, 1), - PLL_RATE(624000000, 52, 1, 1), - PLL_RATE(648000000, 54, 1, 1), - PLL_RATE(672000000, 56, 1, 1), - PLL_RATE(696000000, 58, 1, 1), - PLL_RATE(720000000, 60, 1, 1), - PLL_RATE(744000000, 62, 1, 1), - PLL_RATE(768000000, 64, 1, 1), - PLL_RATE(792000000, 66, 1, 1), - PLL_RATE(816000000, 68, 1, 1), - PLL_RATE(840000000, 70, 1, 1), - PLL_RATE(864000000, 72, 1, 1), - PLL_RATE(888000000, 74, 1, 1), - PLL_RATE(912000000, 76, 1, 1), - PLL_RATE(936000000, 78, 1, 1), - PLL_RATE(960000000, 80, 1, 1), - PLL_RATE(984000000, 82, 1, 1), - PLL_RATE(1008000000, 84, 1, 1), - PLL_RATE(1032000000, 86, 1, 1), - PLL_RATE(1056000000, 88, 1, 1), - PLL_RATE(1080000000, 90, 1, 1), - PLL_RATE(1104000000, 92, 1, 1), - PLL_RATE(1128000000, 94, 1, 1), - PLL_RATE(1152000000, 96, 1, 1), - PLL_RATE(1176000000, 98, 1, 1), - PLL_RATE(1200000000, 50, 1, 0), - PLL_RATE(1224000000, 51, 1, 0), - PLL_RATE(1248000000, 52, 1, 0), - PLL_RATE(1272000000, 53, 1, 0), - PLL_RATE(1296000000, 54, 1, 0), - PLL_RATE(1320000000, 55, 1, 0), - PLL_RATE(1344000000, 56, 1, 0), - PLL_RATE(1368000000, 57, 1, 0), - PLL_RATE(1392000000, 58, 1, 0), - PLL_RATE(1416000000, 59, 1, 0), - PLL_RATE(1440000000, 60, 1, 0), - PLL_RATE(1464000000, 61, 1, 0), - PLL_RATE(1488000000, 62, 1, 0), - PLL_RATE(1512000000, 63, 1, 0), - PLL_RATE(1536000000, 64, 1, 0), - PLL_RATE(1560000000, 65, 1, 0), - PLL_RATE(1584000000, 66, 1, 0), - PLL_RATE(1608000000, 67, 1, 0), - PLL_RATE(1632000000, 68, 1, 0), - PLL_RATE(1656000000, 68, 1, 0), - PLL_RATE(1680000000, 68, 1, 0), - PLL_RATE(1704000000, 68, 1, 0), - PLL_RATE(1728000000, 69, 1, 0), - PLL_RATE(1752000000, 69, 1, 0), - PLL_RATE(1776000000, 69, 1, 0), - PLL_RATE(1800000000, 69, 1, 0), - PLL_RATE(1824000000, 70, 1, 0), - PLL_RATE(1848000000, 70, 1, 0), - PLL_RATE(1872000000, 70, 1, 0), - PLL_RATE(1896000000, 70, 1, 0), - PLL_RATE(1920000000, 71, 1, 0), - PLL_RATE(1944000000, 71, 1, 0), - PLL_RATE(1968000000, 71, 1, 0), - PLL_RATE(1992000000, 71, 1, 0), - PLL_RATE(2016000000, 72, 1, 0), - PLL_RATE(2040000000, 72, 1, 0), - PLL_RATE(2064000000, 72, 1, 0), - PLL_RATE(2088000000, 72, 1, 0), - PLL_RATE(2112000000, 73, 1, 0), - { /* sentinel */ }, -}; - static const struct pll_rate_table gxbb_gp0_pll_rate_table[] = { PLL_RATE(96000000, 32, 1, 3), PLL_RATE(99000000, 33, 1, 3), @@ -278,23 +189,39 @@ static const struct pll_rate_table gxl_gp0_pll_rate_table[] = { { /* sentinel */ }, }; -static struct meson_clk_pll gxbb_fixed_pll = { - .m = { - .reg_off = HHI_MPLL_CNTL, - .shift = 0, - .width = 9, +static struct clk_regmap gxbb_fixed_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_MPLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_MPLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_MPLL_CNTL, + .shift = 16, + .width = 2, + }, + .frac = { + .reg_off = HHI_MPLL_CNTL2, + .shift = 0, + .width = 12, + }, + .l = { + .reg_off = HHI_MPLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_MPLL_CNTL, + .shift = 29, + .width = 1, + }, }, - .n = { - .reg_off = HHI_MPLL_CNTL, - .shift = 9, - .width = 5, - }, - .od = { - .reg_off = HHI_MPLL_CNTL, - .shift = 16, - .width = 2, - }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "fixed_pll", .ops = &meson_clk_pll_ro_ops, @@ -304,33 +231,118 @@ static struct meson_clk_pll gxbb_fixed_pll = { }, }; -static struct meson_clk_pll gxbb_hdmi_pll = { - .m = { - .reg_off = HHI_HDMI_PLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_HDMI_PLL_CNTL, - .shift = 9, - .width = 5, +static struct clk_fixed_factor gxbb_hdmi_pll_pre_mult = { + .mult = 2, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_pre_mult", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "xtal" }, + .num_parents = 1, }, - .frac = { - .reg_off = HHI_HDMI_PLL_CNTL2, - .shift = 0, - .width = 12, +}; + +static struct clk_regmap gxbb_hdmi_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .frac = { + .reg_off = HHI_HDMI_PLL_CNTL2, + .shift = 0, + .width = 12, + }, + .od = { + .reg_off = HHI_HDMI_PLL_CNTL2, + .shift = 16, + .width = 2, + }, + .od2 = { + .reg_off = HHI_HDMI_PLL_CNTL2, + .shift = 22, + .width = 2, + }, + .od3 = { + .reg_off = HHI_HDMI_PLL_CNTL2, + .shift = 18, + .width = 2, + }, + .l = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 28, + .width = 1, + }, }, - .od = { - .reg_off = HHI_HDMI_PLL_CNTL2, - .shift = 16, - .width = 2, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll", + .ops = &meson_clk_pll_ro_ops, + .parent_names = (const char *[]){ "hdmi_pll_pre_mult" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, }, - .od2 = { - .reg_off = HHI_HDMI_PLL_CNTL2, - .shift = 22, - .width = 2, +}; + +static struct clk_regmap gxl_hdmi_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .frac = { + /* + * On gxl, there is a register shift due to + * HHI_HDMI_PLL_CNTL1 which does not exist on gxbb, + * so we compute the register offset based on the PLL + * base to get it right + */ + .reg_off = HHI_HDMI_PLL_CNTL + 4, + .shift = 0, + .width = 12, + }, + .od = { + .reg_off = HHI_HDMI_PLL_CNTL + 8, + .shift = 21, + .width = 2, + }, + .od2 = { + .reg_off = HHI_HDMI_PLL_CNTL + 8, + .shift = 23, + .width = 2, + }, + .od3 = { + .reg_off = HHI_HDMI_PLL_CNTL + 8, + .shift = 19, + .width = 2, + }, + .l = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_HDMI_PLL_CNTL, + .shift = 29, + .width = 1, + }, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "hdmi_pll", .ops = &meson_clk_pll_ro_ops, @@ -340,25 +352,34 @@ static struct meson_clk_pll gxbb_hdmi_pll = { }, }; -static struct meson_clk_pll gxbb_sys_pll = { - .m = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 9, - .width = 5, +static struct clk_regmap gxbb_sys_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 10, + .width = 2, + }, + .l = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 29, + .width = 1, + }, }, - .od = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 10, - .width = 2, - }, - .rate_table = sys_pll_rate_table, - .rate_count = ARRAY_SIZE(sys_pll_rate_table), - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "sys_pll", .ops = &meson_clk_pll_ro_ops, @@ -368,38 +389,44 @@ static struct meson_clk_pll gxbb_sys_pll = { }, }; -struct pll_params_table gxbb_gp0_params_table[] = { - PLL_PARAM(HHI_GP0_PLL_CNTL, 0x6a000228), - PLL_PARAM(HHI_GP0_PLL_CNTL2, 0x69c80000), - PLL_PARAM(HHI_GP0_PLL_CNTL3, 0x0a5590c4), - PLL_PARAM(HHI_GP0_PLL_CNTL4, 0x0000500d), -}; - -static struct meson_clk_pll gxbb_gp0_pll = { - .m = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 9, - .width = 5, - }, - .od = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 16, - .width = 2, - }, - .params = { - .params_table = gxbb_gp0_params_table, - .params_count = ARRAY_SIZE(gxbb_gp0_params_table), - .no_init_reset = true, - .clear_reset_for_lock = true, +static const struct reg_sequence gxbb_gp0_init_regs[] = { + { .reg = HHI_GP0_PLL_CNTL2, .def = 0x69c80000 }, + { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a5590c4 }, + { .reg = HHI_GP0_PLL_CNTL4, .def = 0x0000500d }, + { .reg = HHI_GP0_PLL_CNTL, .def = 0x4a000228 }, +}; + +static struct clk_regmap gxbb_gp0_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 16, + .width = 2, + }, + .l = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 29, + .width = 1, + }, + .table = gxbb_gp0_pll_rate_table, + .init_regs = gxbb_gp0_init_regs, + .init_count = ARRAY_SIZE(gxbb_gp0_init_regs), }, - .rate_table = gxbb_gp0_pll_rate_table, - .rate_count = ARRAY_SIZE(gxbb_gp0_pll_rate_table), - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "gp0_pll", .ops = &meson_clk_pll_ops, @@ -409,40 +436,51 @@ static struct meson_clk_pll gxbb_gp0_pll = { }, }; -struct pll_params_table gxl_gp0_params_table[] = { - PLL_PARAM(HHI_GP0_PLL_CNTL, 0x40010250), - PLL_PARAM(HHI_GP0_PLL_CNTL1, 0xc084a000), - PLL_PARAM(HHI_GP0_PLL_CNTL2, 0xb75020be), - PLL_PARAM(HHI_GP0_PLL_CNTL3, 0x0a59a288), - PLL_PARAM(HHI_GP0_PLL_CNTL4, 0xc000004d), - PLL_PARAM(HHI_GP0_PLL_CNTL5, 0x00078000), -}; - -static struct meson_clk_pll gxl_gp0_pll = { - .m = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 9, - .width = 5, - }, - .od = { - .reg_off = HHI_GP0_PLL_CNTL, - .shift = 16, - .width = 2, +static const struct reg_sequence gxl_gp0_init_regs[] = { + { .reg = HHI_GP0_PLL_CNTL1, .def = 0xc084b000 }, + { .reg = HHI_GP0_PLL_CNTL2, .def = 0xb75020be }, + { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a59a288 }, + { .reg = HHI_GP0_PLL_CNTL4, .def = 0xc000004d }, + { .reg = HHI_GP0_PLL_CNTL5, .def = 0x00078000 }, + { .reg = HHI_GP0_PLL_CNTL, .def = 0x40010250 }, +}; + +static struct clk_regmap gxl_gp0_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 16, + .width = 2, + }, + .frac = { + .reg_off = HHI_GP0_PLL_CNTL1, + .shift = 0, + .width = 10, + }, + .l = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_GP0_PLL_CNTL, + .shift = 29, + .width = 1, + }, + .table = gxl_gp0_pll_rate_table, + .init_regs = gxl_gp0_init_regs, + .init_count = ARRAY_SIZE(gxl_gp0_init_regs), }, - .params = { - .params_table = gxl_gp0_params_table, - .params_count = ARRAY_SIZE(gxl_gp0_params_table), - .no_init_reset = true, - .reset_lock_loop = true, - }, - .rate_table = gxl_gp0_pll_rate_table, - .rate_count = ARRAY_SIZE(gxl_gp0_pll_rate_table), - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "gp0_pll", .ops = &meson_clk_pll_ops, @@ -452,161 +490,267 @@ static struct meson_clk_pll gxl_gp0_pll = { }, }; -static struct clk_fixed_factor gxbb_fclk_div2 = { +static struct clk_fixed_factor gxbb_fclk_div2_div = { .mult = 1, .div = 2, .hw.init = &(struct clk_init_data){ - .name = "fclk_div2", + .name = "fclk_div2_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_fixed_factor gxbb_fclk_div3 = { +static struct clk_regmap gxbb_fclk_div2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 27, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div2_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor gxbb_fclk_div3_div = { .mult = 1, .div = 3, .hw.init = &(struct clk_init_data){ - .name = "fclk_div3", + .name = "fclk_div3_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_fixed_factor gxbb_fclk_div4 = { +static struct clk_regmap gxbb_fclk_div3 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 28, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div3_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor gxbb_fclk_div4_div = { .mult = 1, .div = 4, .hw.init = &(struct clk_init_data){ - .name = "fclk_div4", + .name = "fclk_div4_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_fixed_factor gxbb_fclk_div5 = { +static struct clk_regmap gxbb_fclk_div4 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 29, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div4_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor gxbb_fclk_div5_div = { .mult = 1, .div = 5, .hw.init = &(struct clk_init_data){ - .name = "fclk_div5", + .name = "fclk_div5_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_fixed_factor gxbb_fclk_div7 = { +static struct clk_regmap gxbb_fclk_div5 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div5_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor gxbb_fclk_div7_div = { .mult = 1, .div = 7, .hw.init = &(struct clk_init_data){ - .name = "fclk_div7", + .name = "fclk_div7_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct meson_clk_mpll gxbb_mpll0 = { - .sdm = { - .reg_off = HHI_MPLL_CNTL7, - .shift = 0, - .width = 14, +static struct clk_regmap gxbb_fclk_div7 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 31, }, - .sdm_en = { - .reg_off = HHI_MPLL_CNTL7, - .shift = 15, - .width = 1, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div7_div" }, + .num_parents = 1, }, - .n2 = { - .reg_off = HHI_MPLL_CNTL7, - .shift = 16, - .width = 9, +}; + +static struct clk_regmap gxbb_mpll_prediv = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPLL_CNTL5, + .shift = 12, + .width = 1, }, - .en = { - .reg_off = HHI_MPLL_CNTL7, - .shift = 14, - .width = 1, + .hw.init = &(struct clk_init_data){ + .name = "mpll_prediv", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, }, - .ssen = { - .reg_off = HHI_MPLL_CNTL, - .shift = 25, - .width = 1, +}; + +static struct clk_regmap gxbb_mpll0_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 16, + .width = 9, + }, + .ssen = { + .reg_off = HHI_MPLL_CNTL, + .shift = 25, + .width = 1, + }, + .lock = &meson_clk_lock, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ - .name = "mpll0", + .name = "mpll0_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_names = (const char *[]){ "mpll_prediv" }, .num_parents = 1, }, }; -static struct meson_clk_mpll gxbb_mpll1 = { - .sdm = { - .reg_off = HHI_MPLL_CNTL8, - .shift = 0, - .width = 14, - }, - .sdm_en = { - .reg_off = HHI_MPLL_CNTL8, - .shift = 15, - .width = 1, +static struct clk_regmap gxbb_mpll0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL7, + .bit_idx = 14, }, - .n2 = { - .reg_off = HHI_MPLL_CNTL8, - .shift = 16, - .width = 9, + .hw.init = &(struct clk_init_data){ + .name = "mpll0", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mpll0_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, }, - .en = { - .reg_off = HHI_MPLL_CNTL8, - .shift = 14, - .width = 1, +}; + +static struct clk_regmap gxbb_mpll1_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 16, + .width = 9, + }, + .lock = &meson_clk_lock, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ - .name = "mpll1", + .name = "mpll1_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_names = (const char *[]){ "mpll_prediv" }, .num_parents = 1, }, }; -static struct meson_clk_mpll gxbb_mpll2 = { - .sdm = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 0, - .width = 14, - }, - .sdm_en = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 15, - .width = 1, +static struct clk_regmap gxbb_mpll1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL8, + .bit_idx = 14, }, - .n2 = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 16, - .width = 9, + .hw.init = &(struct clk_init_data){ + .name = "mpll1", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mpll1_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, }, - .en = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 14, - .width = 1, +}; + +static struct clk_regmap gxbb_mpll2_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 16, + .width = 9, + }, + .lock = &meson_clk_lock, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ - .name = "mpll2", + .name = "mpll2_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_names = (const char *[]){ "mpll_prediv" }, .num_parents = 1, }, }; -/* - * FIXME The legacy composite clocks (e.g. clk81) are both PLL post-dividers - * and should be modeled with their respective PLLs via the forthcoming - * coordinated clock rates feature - */ +static struct clk_regmap gxbb_mpll2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL9, + .bit_idx = 14, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll2", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mpll2_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; static u32 mux_table_clk81[] = { 0, 2, 3, 4, 5, 6, 7 }; static const char * const clk81_parent_names[] = { @@ -614,16 +758,16 @@ static const char * const clk81_parent_names[] = { "fclk_div3", "fclk_div5" }; -static struct clk_mux gxbb_mpeg_clk_sel = { - .reg = (void *)HHI_MPEG_CLK_CNTL, - .mask = 0x7, - .shift = 12, - .flags = CLK_MUX_READ_ONLY, - .table = mux_table_clk81, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_mpeg_clk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MPEG_CLK_CNTL, + .mask = 0x7, + .shift = 12, + .table = mux_table_clk81, + }, .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_sel", - .ops = &clk_mux_ro_ops, + .ops = &clk_regmap_mux_ro_ops, /* * bits 14:12 selects from 8 possible parents: * xtal, 1'b0 (wtf), fclk_div7, mpll_clkout1, mpll_clkout2, @@ -631,72 +775,75 @@ static struct clk_mux gxbb_mpeg_clk_sel = { */ .parent_names = clk81_parent_names, .num_parents = ARRAY_SIZE(clk81_parent_names), - .flags = (CLK_SET_RATE_NO_REPARENT | CLK_IGNORE_UNUSED), }, }; -static struct clk_divider gxbb_mpeg_clk_div = { - .reg = (void *)HHI_MPEG_CLK_CNTL, - .shift = 0, - .width = 7, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_mpeg_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPEG_CLK_CNTL, + .shift = 0, + .width = 7, + }, .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ro_ops, .parent_names = (const char *[]){ "mpeg_clk_sel" }, .num_parents = 1, - .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), }, }; -/* the mother of dragons^W gates */ -static struct clk_gate gxbb_clk81 = { - .reg = (void *)HHI_MPEG_CLK_CNTL, - .bit_idx = 7, - .lock = &meson_clk_lock, +/* the mother of dragons gates */ +static struct clk_regmap gxbb_clk81 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPEG_CLK_CNTL, + .bit_idx = 7, + }, .hw.init = &(struct clk_init_data){ .name = "clk81", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "mpeg_clk_div" }, .num_parents = 1, - .flags = (CLK_SET_RATE_PARENT | CLK_IS_CRITICAL), + .flags = CLK_IS_CRITICAL, }, }; -static struct clk_mux gxbb_sar_adc_clk_sel = { - .reg = (void *)HHI_SAR_CLK_CNTL, - .mask = 0x3, - .shift = 9, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_sar_adc_clk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SAR_CLK_CNTL, + .mask = 0x3, + .shift = 9, + }, .hw.init = &(struct clk_init_data){ .name = "sar_adc_clk_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, /* NOTE: The datasheet doesn't list the parents for bit 10 */ .parent_names = (const char *[]){ "xtal", "clk81", }, .num_parents = 2, }, }; -static struct clk_divider gxbb_sar_adc_clk_div = { - .reg = (void *)HHI_SAR_CLK_CNTL, - .shift = 0, - .width = 8, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_sar_adc_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SAR_CLK_CNTL, + .shift = 0, + .width = 8, + }, .hw.init = &(struct clk_init_data){ .name = "sar_adc_clk_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "sar_adc_clk_sel" }, .num_parents = 1, }, }; -static struct clk_gate gxbb_sar_adc_clk = { - .reg = (void *)HHI_SAR_CLK_CNTL, - .bit_idx = 8, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_sar_adc_clk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SAR_CLK_CNTL, + .bit_idx = 8, + }, .hw.init = &(struct clk_init_data){ .name = "sar_adc_clk", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "sar_adc_clk_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -708,21 +855,20 @@ static struct clk_gate gxbb_sar_adc_clk = { * muxed by a glitch-free switch. */ -static u32 mux_table_mali_0_1[] = {0, 1, 2, 3, 4, 5, 6, 7}; static const char * const gxbb_mali_0_1_parent_names[] = { "xtal", "gp0_pll", "mpll2", "mpll1", "fclk_div7", "fclk_div4", "fclk_div3", "fclk_div5" }; -static struct clk_mux gxbb_mali_0_sel = { - .reg = (void *)HHI_MALI_CLK_CNTL, - .mask = 0x7, - .shift = 9, - .table = mux_table_mali_0_1, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_mali_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MALI_CLK_CNTL, + .mask = 0x7, + .shift = 9, + }, .hw.init = &(struct clk_init_data){ .name = "mali_0_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, /* * bits 10:9 selects from 8 possible parents: * xtal, gp0_pll, mpll2, mpll1, fclk_div7, @@ -734,42 +880,44 @@ static struct clk_mux gxbb_mali_0_sel = { }, }; -static struct clk_divider gxbb_mali_0_div = { - .reg = (void *)HHI_MALI_CLK_CNTL, - .shift = 0, - .width = 7, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_mali_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MALI_CLK_CNTL, + .shift = 0, + .width = 7, + }, .hw.init = &(struct clk_init_data){ .name = "mali_0_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "mali_0_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_NO_REPARENT, }, }; -static struct clk_gate gxbb_mali_0 = { - .reg = (void *)HHI_MALI_CLK_CNTL, - .bit_idx = 8, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_mali_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MALI_CLK_CNTL, + .bit_idx = 8, + }, .hw.init = &(struct clk_init_data){ .name = "mali_0", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "mali_0_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_mux gxbb_mali_1_sel = { - .reg = (void *)HHI_MALI_CLK_CNTL, - .mask = 0x7, - .shift = 25, - .table = mux_table_mali_0_1, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_mali_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MALI_CLK_CNTL, + .mask = 0x7, + .shift = 25, + }, .hw.init = &(struct clk_init_data){ .name = "mali_1_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, /* * bits 10:9 selects from 8 possible parents: * xtal, gp0_pll, mpll2, mpll1, fclk_div7, @@ -781,77 +929,79 @@ static struct clk_mux gxbb_mali_1_sel = { }, }; -static struct clk_divider gxbb_mali_1_div = { - .reg = (void *)HHI_MALI_CLK_CNTL, - .shift = 16, - .width = 7, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_mali_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MALI_CLK_CNTL, + .shift = 16, + .width = 7, + }, .hw.init = &(struct clk_init_data){ .name = "mali_1_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "mali_1_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_NO_REPARENT, }, }; -static struct clk_gate gxbb_mali_1 = { - .reg = (void *)HHI_MALI_CLK_CNTL, - .bit_idx = 24, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_mali_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MALI_CLK_CNTL, + .bit_idx = 24, + }, .hw.init = &(struct clk_init_data){ .name = "mali_1", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "mali_1_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static u32 mux_table_mali[] = {0, 1}; static const char * const gxbb_mali_parent_names[] = { "mali_0", "mali_1" }; -static struct clk_mux gxbb_mali = { - .reg = (void *)HHI_MALI_CLK_CNTL, - .mask = 1, - .shift = 31, - .table = mux_table_mali, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_mali = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MALI_CLK_CNTL, + .mask = 1, + .shift = 31, + }, .hw.init = &(struct clk_init_data){ .name = "mali", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = gxbb_mali_parent_names, .num_parents = 2, .flags = CLK_SET_RATE_NO_REPARENT, }, }; -static struct clk_mux gxbb_cts_amclk_sel = { - .reg = (void *) HHI_AUD_CLK_CNTL, - .mask = 0x3, - .shift = 9, - /* Default parent unknown (register reset value: 0) */ - .table = (u32[]){ 1, 2, 3 }, - .lock = &meson_clk_lock, - .hw.init = &(struct clk_init_data){ +static struct clk_regmap gxbb_cts_amclk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_AUD_CLK_CNTL, + .mask = 0x3, + .shift = 9, + .table = (u32[]){ 1, 2, 3 }, + }, + .hw.init = &(struct clk_init_data){ .name = "cts_amclk_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = (const char *[]){ "mpll0", "mpll1", "mpll2" }, .num_parents = 3, .flags = CLK_SET_RATE_PARENT, }, }; -static struct meson_clk_audio_divider gxbb_cts_amclk_div = { - .div = { - .reg_off = HHI_AUD_CLK_CNTL, - .shift = 0, - .width = 8, +static struct clk_regmap gxbb_cts_amclk_div = { + .data = &(struct meson_clk_audio_div_data){ + .div = { + .reg_off = HHI_AUD_CLK_CNTL, + .shift = 0, + .width = 8, + }, + .flags = CLK_DIVIDER_ROUND_CLOSEST, }, - .flags = CLK_DIVIDER_ROUND_CLOSEST, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "cts_amclk_div", .ops = &meson_clk_audio_divider_ops, @@ -861,71 +1011,75 @@ static struct meson_clk_audio_divider gxbb_cts_amclk_div = { }, }; -static struct clk_gate gxbb_cts_amclk = { - .reg = (void *) HHI_AUD_CLK_CNTL, - .bit_idx = 8, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_cts_amclk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_AUD_CLK_CNTL, + .bit_idx = 8, + }, .hw.init = &(struct clk_init_data){ .name = "cts_amclk", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "cts_amclk_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_mux gxbb_cts_mclk_i958_sel = { - .reg = (void *)HHI_AUD_CLK_CNTL2, - .mask = 0x3, - .shift = 25, - /* Default parent unknown (register reset value: 0) */ - .table = (u32[]){ 1, 2, 3 }, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_cts_mclk_i958_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_AUD_CLK_CNTL2, + .mask = 0x3, + .shift = 25, + .table = (u32[]){ 1, 2, 3 }, + }, .hw.init = &(struct clk_init_data) { .name = "cts_mclk_i958_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = (const char *[]){ "mpll0", "mpll1", "mpll2" }, .num_parents = 3, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_divider gxbb_cts_mclk_i958_div = { - .reg = (void *)HHI_AUD_CLK_CNTL2, - .shift = 16, - .width = 8, - .lock = &meson_clk_lock, - .flags = CLK_DIVIDER_ROUND_CLOSEST, +static struct clk_regmap gxbb_cts_mclk_i958_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_AUD_CLK_CNTL2, + .shift = 16, + .width = 8, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, .hw.init = &(struct clk_init_data) { .name = "cts_mclk_i958_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "cts_mclk_i958_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_gate gxbb_cts_mclk_i958 = { - .reg = (void *)HHI_AUD_CLK_CNTL2, - .bit_idx = 24, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_cts_mclk_i958 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_AUD_CLK_CNTL2, + .bit_idx = 24, + }, .hw.init = &(struct clk_init_data){ .name = "cts_mclk_i958", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "cts_mclk_i958_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_mux gxbb_cts_i958 = { - .reg = (void *)HHI_AUD_CLK_CNTL2, - .mask = 0x1, - .shift = 27, - .lock = &meson_clk_lock, - .hw.init = &(struct clk_init_data){ +static struct clk_regmap gxbb_cts_i958 = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_AUD_CLK_CNTL2, + .mask = 0x1, + .shift = 27, + }, + .hw.init = &(struct clk_init_data){ .name = "cts_i958", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = (const char *[]){ "cts_amclk", "cts_mclk_i958" }, .num_parents = 2, /* @@ -936,27 +1090,29 @@ static struct clk_mux gxbb_cts_i958 = { }, }; -static struct clk_divider gxbb_32k_clk_div = { - .reg = (void *)HHI_32K_CLK_CNTL, - .shift = 0, - .width = 14, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_32k_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_32K_CLK_CNTL, + .shift = 0, + .width = 14, + }, .hw.init = &(struct clk_init_data){ .name = "32k_clk_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "32k_clk_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_DIVIDER_ROUND_CLOSEST, }, }; -static struct clk_gate gxbb_32k_clk = { - .reg = (void *)HHI_32K_CLK_CNTL, - .bit_idx = 15, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_32k_clk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_32K_CLK_CNTL, + .bit_idx = 15, + }, .hw.init = &(struct clk_init_data){ .name = "32k_clk", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "32k_clk_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -967,14 +1123,15 @@ static const char * const gxbb_32k_clk_parent_names[] = { "xtal", "cts_slow_oscin", "fclk_div3", "fclk_div5" }; -static struct clk_mux gxbb_32k_clk_sel = { - .reg = (void *)HHI_32K_CLK_CNTL, - .mask = 0x3, - .shift = 16, - .lock = &meson_clk_lock, - .hw.init = &(struct clk_init_data){ +static struct clk_regmap gxbb_32k_clk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_32K_CLK_CNTL, + .mask = 0x3, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ .name = "32k_clk_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = gxbb_32k_clk_parent_names, .num_parents = 4, .flags = CLK_SET_RATE_PARENT, @@ -993,42 +1150,45 @@ static const char * const gxbb_sd_emmc_clk0_parent_names[] = { }; /* SDIO clock */ -static struct clk_mux gxbb_sd_emmc_a_clk0_sel = { - .reg = (void *)HHI_SD_EMMC_CLK_CNTL, - .mask = 0x7, - .shift = 9, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_sd_emmc_a_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .mask = 0x7, + .shift = 9, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_a_clk0_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = gxbb_sd_emmc_clk0_parent_names, .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names), .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_divider gxbb_sd_emmc_a_clk0_div = { - .reg = (void *)HHI_SD_EMMC_CLK_CNTL, - .shift = 0, - .width = 7, - .lock = &meson_clk_lock, - .flags = CLK_DIVIDER_ROUND_CLOSEST, +static struct clk_regmap gxbb_sd_emmc_a_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_a_clk0_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "sd_emmc_a_clk0_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_gate gxbb_sd_emmc_a_clk0 = { - .reg = (void *)HHI_SD_EMMC_CLK_CNTL, - .bit_idx = 7, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_sd_emmc_a_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .bit_idx = 7, + }, .hw.init = &(struct clk_init_data){ .name = "sd_emmc_a_clk0", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "sd_emmc_a_clk0_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -1036,42 +1196,45 @@ static struct clk_gate gxbb_sd_emmc_a_clk0 = { }; /* SDcard clock */ -static struct clk_mux gxbb_sd_emmc_b_clk0_sel = { - .reg = (void *)HHI_SD_EMMC_CLK_CNTL, - .mask = 0x7, - .shift = 25, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_sd_emmc_b_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .mask = 0x7, + .shift = 25, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_b_clk0_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = gxbb_sd_emmc_clk0_parent_names, .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names), .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_divider gxbb_sd_emmc_b_clk0_div = { - .reg = (void *)HHI_SD_EMMC_CLK_CNTL, - .shift = 16, - .width = 7, - .lock = &meson_clk_lock, - .flags = CLK_DIVIDER_ROUND_CLOSEST, +static struct clk_regmap gxbb_sd_emmc_b_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .shift = 16, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_b_clk0_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "sd_emmc_b_clk0_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_gate gxbb_sd_emmc_b_clk0 = { - .reg = (void *)HHI_SD_EMMC_CLK_CNTL, - .bit_idx = 23, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_sd_emmc_b_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SD_EMMC_CLK_CNTL, + .bit_idx = 23, + }, .hw.init = &(struct clk_init_data){ .name = "sd_emmc_b_clk0", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "sd_emmc_b_clk0_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -1079,42 +1242,45 @@ static struct clk_gate gxbb_sd_emmc_b_clk0 = { }; /* EMMC/NAND clock */ -static struct clk_mux gxbb_sd_emmc_c_clk0_sel = { - .reg = (void *)HHI_NAND_CLK_CNTL, - .mask = 0x7, - .shift = 9, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_sd_emmc_c_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_NAND_CLK_CNTL, + .mask = 0x7, + .shift = 9, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_c_clk0_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, .parent_names = gxbb_sd_emmc_clk0_parent_names, .num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names), .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_divider gxbb_sd_emmc_c_clk0_div = { - .reg = (void *)HHI_NAND_CLK_CNTL, - .shift = 0, - .width = 7, - .lock = &meson_clk_lock, - .flags = CLK_DIVIDER_ROUND_CLOSEST, +static struct clk_regmap gxbb_sd_emmc_c_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_NAND_CLK_CNTL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, .hw.init = &(struct clk_init_data) { .name = "sd_emmc_c_clk0_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "sd_emmc_c_clk0_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_gate gxbb_sd_emmc_c_clk0 = { - .reg = (void *)HHI_NAND_CLK_CNTL, - .bit_idx = 7, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_sd_emmc_c_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_NAND_CLK_CNTL, + .bit_idx = 7, + }, .hw.init = &(struct clk_init_data){ .name = "sd_emmc_c_clk0", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "sd_emmc_c_clk0_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, @@ -1123,20 +1289,19 @@ static struct clk_gate gxbb_sd_emmc_c_clk0 = { /* VPU Clock */ -static u32 mux_table_vpu[] = {0, 1, 2, 3}; static const char * const gxbb_vpu_parent_names[] = { "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7" }; -static struct clk_mux gxbb_vpu_0_sel = { - .reg = (void *)HHI_VPU_CLK_CNTL, - .mask = 0x3, - .shift = 9, - .lock = &meson_clk_lock, - .table = mux_table_vpu, +static struct clk_regmap gxbb_vpu_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 0x3, + .shift = 9, + }, .hw.init = &(struct clk_init_data){ .name = "vpu_0_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, /* * bits 9:10 selects from 4 possible parents: * fclk_div4, fclk_div3, fclk_div5, fclk_div7, @@ -1147,42 +1312,44 @@ static struct clk_mux gxbb_vpu_0_sel = { }, }; -static struct clk_divider gxbb_vpu_0_div = { - .reg = (void *)HHI_VPU_CLK_CNTL, - .shift = 0, - .width = 7, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vpu_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VPU_CLK_CNTL, + .shift = 0, + .width = 7, + }, .hw.init = &(struct clk_init_data){ .name = "vpu_0_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "vpu_0_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_gate gxbb_vpu_0 = { - .reg = (void *)HHI_VPU_CLK_CNTL, - .bit_idx = 8, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vpu_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VPU_CLK_CNTL, + .bit_idx = 8, + }, .hw.init = &(struct clk_init_data) { .name = "vpu_0", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "vpu_0_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, }; -static struct clk_mux gxbb_vpu_1_sel = { - .reg = (void *)HHI_VPU_CLK_CNTL, - .mask = 0x3, - .shift = 25, - .lock = &meson_clk_lock, - .table = mux_table_vpu, +static struct clk_regmap gxbb_vpu_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 0x3, + .shift = 25, + }, .hw.init = &(struct clk_init_data){ .name = "vpu_1_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, /* * bits 25:26 selects from 4 possible parents: * fclk_div4, fclk_div3, fclk_div5, fclk_div7, @@ -1193,41 +1360,44 @@ static struct clk_mux gxbb_vpu_1_sel = { }, }; -static struct clk_divider gxbb_vpu_1_div = { - .reg = (void *)HHI_VPU_CLK_CNTL, - .shift = 16, - .width = 7, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vpu_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VPU_CLK_CNTL, + .shift = 16, + .width = 7, + }, .hw.init = &(struct clk_init_data){ .name = "vpu_1_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "vpu_1_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_gate gxbb_vpu_1 = { - .reg = (void *)HHI_VPU_CLK_CNTL, - .bit_idx = 24, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vpu_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VPU_CLK_CNTL, + .bit_idx = 24, + }, .hw.init = &(struct clk_init_data) { .name = "vpu_1", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "vpu_1_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, }; -static struct clk_mux gxbb_vpu = { - .reg = (void *)HHI_VPU_CLK_CNTL, - .mask = 1, - .shift = 31, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vpu = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VPU_CLK_CNTL, + .mask = 1, + .shift = 31, + }, .hw.init = &(struct clk_init_data){ .name = "vpu", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, /* * bit 31 selects from 2 possible parents: * vpu_0 or vpu_1 @@ -1240,20 +1410,19 @@ static struct clk_mux gxbb_vpu = { /* VAPB Clock */ -static u32 mux_table_vapb[] = {0, 1, 2, 3}; static const char * const gxbb_vapb_parent_names[] = { "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7" }; -static struct clk_mux gxbb_vapb_0_sel = { - .reg = (void *)HHI_VAPBCLK_CNTL, - .mask = 0x3, - .shift = 9, - .lock = &meson_clk_lock, - .table = mux_table_vapb, +static struct clk_regmap gxbb_vapb_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VAPBCLK_CNTL, + .mask = 0x3, + .shift = 9, + }, .hw.init = &(struct clk_init_data){ .name = "vapb_0_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, /* * bits 9:10 selects from 4 possible parents: * fclk_div4, fclk_div3, fclk_div5, fclk_div7, @@ -1264,42 +1433,44 @@ static struct clk_mux gxbb_vapb_0_sel = { }, }; -static struct clk_divider gxbb_vapb_0_div = { - .reg = (void *)HHI_VAPBCLK_CNTL, - .shift = 0, - .width = 7, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vapb_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VAPBCLK_CNTL, + .shift = 0, + .width = 7, + }, .hw.init = &(struct clk_init_data){ .name = "vapb_0_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "vapb_0_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_gate gxbb_vapb_0 = { - .reg = (void *)HHI_VAPBCLK_CNTL, - .bit_idx = 8, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vapb_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VAPBCLK_CNTL, + .bit_idx = 8, + }, .hw.init = &(struct clk_init_data) { .name = "vapb_0", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "vapb_0_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, }; -static struct clk_mux gxbb_vapb_1_sel = { - .reg = (void *)HHI_VAPBCLK_CNTL, - .mask = 0x3, - .shift = 25, - .lock = &meson_clk_lock, - .table = mux_table_vapb, +static struct clk_regmap gxbb_vapb_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VAPBCLK_CNTL, + .mask = 0x3, + .shift = 25, + }, .hw.init = &(struct clk_init_data){ .name = "vapb_1_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, /* * bits 25:26 selects from 4 possible parents: * fclk_div4, fclk_div3, fclk_div5, fclk_div7, @@ -1310,41 +1481,44 @@ static struct clk_mux gxbb_vapb_1_sel = { }, }; -static struct clk_divider gxbb_vapb_1_div = { - .reg = (void *)HHI_VAPBCLK_CNTL, - .shift = 16, - .width = 7, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vapb_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_VAPBCLK_CNTL, + .shift = 16, + .width = 7, + }, .hw.init = &(struct clk_init_data){ .name = "vapb_1_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ops, .parent_names = (const char *[]){ "vapb_1_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, }; -static struct clk_gate gxbb_vapb_1 = { - .reg = (void *)HHI_VAPBCLK_CNTL, - .bit_idx = 24, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vapb_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VAPBCLK_CNTL, + .bit_idx = 24, + }, .hw.init = &(struct clk_init_data) { .name = "vapb_1", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "vapb_1_div" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, }, }; -static struct clk_mux gxbb_vapb_sel = { - .reg = (void *)HHI_VAPBCLK_CNTL, - .mask = 1, - .shift = 31, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vapb_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VAPBCLK_CNTL, + .mask = 1, + .shift = 31, + }, .hw.init = &(struct clk_init_data){ .name = "vapb_sel", - .ops = &clk_mux_ops, + .ops = &clk_regmap_mux_ops, /* * bit 31 selects from 2 possible parents: * vapb_0 or vapb_1 @@ -1355,13 +1529,14 @@ static struct clk_mux gxbb_vapb_sel = { }, }; -static struct clk_gate gxbb_vapb = { - .reg = (void *)HHI_VAPBCLK_CNTL, - .bit_idx = 30, - .lock = &meson_clk_lock, +static struct clk_regmap gxbb_vapb = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VAPBCLK_CNTL, + .bit_idx = 30, + }, .hw.init = &(struct clk_init_data) { .name = "vapb", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "vapb_sel" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, @@ -1601,6 +1776,16 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = { [CLKID_VAPB_1] = &gxbb_vapb_1.hw, [CLKID_VAPB_SEL] = &gxbb_vapb_sel.hw, [CLKID_VAPB] = &gxbb_vapb.hw, + [CLKID_HDMI_PLL_PRE_MULT] = &gxbb_hdmi_pll_pre_mult.hw, + [CLKID_MPLL0_DIV] = &gxbb_mpll0_div.hw, + [CLKID_MPLL1_DIV] = &gxbb_mpll1_div.hw, + [CLKID_MPLL2_DIV] = &gxbb_mpll2_div.hw, + [CLKID_MPLL_PREDIV] = &gxbb_mpll_prediv.hw, + [CLKID_FCLK_DIV2_DIV] = &gxbb_fclk_div2_div.hw, + [CLKID_FCLK_DIV3_DIV] = &gxbb_fclk_div3_div.hw, + [CLKID_FCLK_DIV4_DIV] = &gxbb_fclk_div4_div.hw, + [CLKID_FCLK_DIV5_DIV] = &gxbb_fclk_div5_div.hw, + [CLKID_FCLK_DIV7_DIV] = &gxbb_fclk_div7_div.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -1609,7 +1794,7 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = { static struct clk_hw_onecell_data gxl_hw_onecell_data = { .hws = { [CLKID_SYS_PLL] = &gxbb_sys_pll.hw, - [CLKID_HDMI_PLL] = &gxbb_hdmi_pll.hw, + [CLKID_HDMI_PLL] = &gxl_hdmi_pll.hw, [CLKID_FIXED_PLL] = &gxbb_fixed_pll.hw, [CLKID_FCLK_DIV2] = &gxbb_fclk_div2.hw, [CLKID_FCLK_DIV3] = &gxbb_fclk_div3.hw, @@ -1748,34 +1933,31 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = { [CLKID_VAPB_1] = &gxbb_vapb_1.hw, [CLKID_VAPB_SEL] = &gxbb_vapb_sel.hw, [CLKID_VAPB] = &gxbb_vapb.hw, + [CLKID_MPLL0_DIV] = &gxbb_mpll0_div.hw, + [CLKID_MPLL1_DIV] = &gxbb_mpll1_div.hw, + [CLKID_MPLL2_DIV] = &gxbb_mpll2_div.hw, + [CLKID_MPLL_PREDIV] = &gxbb_mpll_prediv.hw, + [CLKID_FCLK_DIV2_DIV] = &gxbb_fclk_div2_div.hw, + [CLKID_FCLK_DIV3_DIV] = &gxbb_fclk_div3_div.hw, + [CLKID_FCLK_DIV4_DIV] = &gxbb_fclk_div4_div.hw, + [CLKID_FCLK_DIV5_DIV] = &gxbb_fclk_div5_div.hw, + [CLKID_FCLK_DIV7_DIV] = &gxbb_fclk_div7_div.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, }; -/* Convenience tables to populate base addresses in .probe */ - -static struct meson_clk_pll *const gxbb_clk_plls[] = { - &gxbb_fixed_pll, - &gxbb_hdmi_pll, - &gxbb_sys_pll, +static struct clk_regmap *const gxbb_clk_regmaps[] = { &gxbb_gp0_pll, -}; - -static struct meson_clk_pll *const gxl_clk_plls[] = { - &gxbb_fixed_pll, &gxbb_hdmi_pll, - &gxbb_sys_pll, - &gxl_gp0_pll, }; -static struct meson_clk_mpll *const gxbb_clk_mplls[] = { - &gxbb_mpll0, - &gxbb_mpll1, - &gxbb_mpll2, +static struct clk_regmap *const gxl_clk_regmaps[] = { + &gxl_gp0_pll, + &gxl_hdmi_pll, }; -static struct clk_gate *const gxbb_clk_gates[] = { +static struct clk_regmap *const gx_clk_regmaps[] = { &gxbb_clk81, &gxbb_ddr, &gxbb_dos, @@ -1872,9 +2054,19 @@ static struct clk_gate *const gxbb_clk_gates[] = { &gxbb_vapb_0, &gxbb_vapb_1, &gxbb_vapb, -}; - -static struct clk_mux *const gxbb_clk_muxes[] = { + &gxbb_mpeg_clk_div, + &gxbb_sar_adc_clk_div, + &gxbb_mali_0_div, + &gxbb_mali_1_div, + &gxbb_cts_mclk_i958_div, + &gxbb_32k_clk_div, + &gxbb_sd_emmc_a_clk0_div, + &gxbb_sd_emmc_b_clk0_div, + &gxbb_sd_emmc_c_clk0_div, + &gxbb_vpu_0_div, + &gxbb_vpu_1_div, + &gxbb_vapb_0_div, + &gxbb_vapb_1_div, &gxbb_mpeg_clk_sel, &gxbb_sar_adc_clk_sel, &gxbb_mali_0_sel, @@ -1893,73 +2085,38 @@ static struct clk_mux *const gxbb_clk_muxes[] = { &gxbb_vapb_0_sel, &gxbb_vapb_1_sel, &gxbb_vapb_sel, -}; - -static struct clk_divider *const gxbb_clk_dividers[] = { - &gxbb_mpeg_clk_div, - &gxbb_sar_adc_clk_div, - &gxbb_mali_0_div, - &gxbb_mali_1_div, - &gxbb_cts_mclk_i958_div, - &gxbb_32k_clk_div, - &gxbb_sd_emmc_a_clk0_div, - &gxbb_sd_emmc_b_clk0_div, - &gxbb_sd_emmc_c_clk0_div, - &gxbb_vpu_0_div, - &gxbb_vpu_1_div, - &gxbb_vapb_0_div, - &gxbb_vapb_1_div, -}; - -static struct meson_clk_audio_divider *const gxbb_audio_dividers[] = { + &gxbb_mpll0, + &gxbb_mpll1, + &gxbb_mpll2, + &gxbb_mpll0_div, + &gxbb_mpll1_div, + &gxbb_mpll2_div, &gxbb_cts_amclk_div, + &gxbb_fixed_pll, + &gxbb_sys_pll, + &gxbb_mpll_prediv, + &gxbb_fclk_div2, + &gxbb_fclk_div3, + &gxbb_fclk_div4, + &gxbb_fclk_div5, + &gxbb_fclk_div7, }; struct clkc_data { - struct clk_gate *const *clk_gates; - unsigned int clk_gates_count; - struct meson_clk_mpll *const *clk_mplls; - unsigned int clk_mplls_count; - struct meson_clk_pll *const *clk_plls; - unsigned int clk_plls_count; - struct clk_mux *const *clk_muxes; - unsigned int clk_muxes_count; - struct clk_divider *const *clk_dividers; - unsigned int clk_dividers_count; - struct meson_clk_audio_divider *const *clk_audio_dividers; - unsigned int clk_audio_dividers_count; + struct clk_regmap *const *regmap_clks; + unsigned int regmap_clks_count; struct clk_hw_onecell_data *hw_onecell_data; }; static const struct clkc_data gxbb_clkc_data = { - .clk_gates = gxbb_clk_gates, - .clk_gates_count = ARRAY_SIZE(gxbb_clk_gates), - .clk_mplls = gxbb_clk_mplls, - .clk_mplls_count = ARRAY_SIZE(gxbb_clk_mplls), - .clk_plls = gxbb_clk_plls, - .clk_plls_count = ARRAY_SIZE(gxbb_clk_plls), - .clk_muxes = gxbb_clk_muxes, - .clk_muxes_count = ARRAY_SIZE(gxbb_clk_muxes), - .clk_dividers = gxbb_clk_dividers, - .clk_dividers_count = ARRAY_SIZE(gxbb_clk_dividers), - .clk_audio_dividers = gxbb_audio_dividers, - .clk_audio_dividers_count = ARRAY_SIZE(gxbb_audio_dividers), + .regmap_clks = gxbb_clk_regmaps, + .regmap_clks_count = ARRAY_SIZE(gxbb_clk_regmaps), .hw_onecell_data = &gxbb_hw_onecell_data, }; static const struct clkc_data gxl_clkc_data = { - .clk_gates = gxbb_clk_gates, - .clk_gates_count = ARRAY_SIZE(gxbb_clk_gates), - .clk_mplls = gxbb_clk_mplls, - .clk_mplls_count = ARRAY_SIZE(gxbb_clk_mplls), - .clk_plls = gxl_clk_plls, - .clk_plls_count = ARRAY_SIZE(gxl_clk_plls), - .clk_muxes = gxbb_clk_muxes, - .clk_muxes_count = ARRAY_SIZE(gxbb_clk_muxes), - .clk_dividers = gxbb_clk_dividers, - .clk_dividers_count = ARRAY_SIZE(gxbb_clk_dividers), - .clk_audio_dividers = gxbb_audio_dividers, - .clk_audio_dividers_count = ARRAY_SIZE(gxbb_audio_dividers), + .regmap_clks = gxl_clk_regmaps, + .regmap_clks_count = ARRAY_SIZE(gxl_clk_regmaps), .hw_onecell_data = &gxl_hw_onecell_data, }; @@ -1969,71 +2126,79 @@ static const struct of_device_id clkc_match_table[] = { {}, }; +static const struct regmap_config clkc_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + static int gxbb_clkc_probe(struct platform_device *pdev) { const struct clkc_data *clkc_data; + struct resource *res; void __iomem *clk_base; - int ret, clkid, i; + struct regmap *map; + int ret, i; struct device *dev = &pdev->dev; - clkc_data = of_device_get_match_data(&pdev->dev); + clkc_data = of_device_get_match_data(dev); if (!clkc_data) return -EINVAL; - /* Generic clocks and PLLs */ - clk_base = of_iomap(dev->of_node, 0); - if (!clk_base) { - pr_err("%s: Unable to map clk base\n", __func__); - return -ENXIO; - } - - /* Populate base address for PLLs */ - for (i = 0; i < clkc_data->clk_plls_count; i++) - clkc_data->clk_plls[i]->base = clk_base; - - /* Populate base address for MPLLs */ - for (i = 0; i < clkc_data->clk_mplls_count; i++) - clkc_data->clk_mplls[i]->base = clk_base; + /* Get the hhi system controller node if available */ + map = syscon_node_to_regmap(of_get_parent(dev->of_node)); + if (IS_ERR(map)) { + dev_err(dev, + "failed to get HHI regmap - Trying obsolete regs\n"); - /* Populate base address for gates */ - for (i = 0; i < clkc_data->clk_gates_count; i++) - clkc_data->clk_gates[i]->reg = clk_base + - (u64)clkc_data->clk_gates[i]->reg; - - /* Populate base address for muxes */ - for (i = 0; i < clkc_data->clk_muxes_count; i++) - clkc_data->clk_muxes[i]->reg = clk_base + - (u64)clkc_data->clk_muxes[i]->reg; + /* + * FIXME: HHI registers should be accessed through + * the appropriate system controller. This is required because + * there is more than just clocks in this register space + * + * This fallback method is only provided temporarily until + * all the platform DTs are properly using the syscon node + */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; + + clk_base = devm_ioremap(dev, res->start, resource_size(res)); + if (!clk_base) { + dev_err(dev, "Unable to map clk base\n"); + return -ENXIO; + } + + map = devm_regmap_init_mmio(dev, clk_base, + &clkc_regmap_config); + if (IS_ERR(map)) + return PTR_ERR(map); + } - /* Populate base address for dividers */ - for (i = 0; i < clkc_data->clk_dividers_count; i++) - clkc_data->clk_dividers[i]->reg = clk_base + - (u64)clkc_data->clk_dividers[i]->reg; + /* Populate regmap for the common regmap backed clocks */ + for (i = 0; i < ARRAY_SIZE(gx_clk_regmaps); i++) + gx_clk_regmaps[i]->map = map; - /* Populate base address for the audio dividers */ - for (i = 0; i < clkc_data->clk_audio_dividers_count; i++) - clkc_data->clk_audio_dividers[i]->base = clk_base; + /* Populate regmap for soc specific clocks */ + for (i = 0; i < clkc_data->regmap_clks_count; i++) + clkc_data->regmap_clks[i]->map = map; - /* - * register all clks - */ - for (clkid = 0; clkid < clkc_data->hw_onecell_data->num; clkid++) { + /* Register all clks */ + for (i = 0; i < clkc_data->hw_onecell_data->num; i++) { /* array might be sparse */ - if (!clkc_data->hw_onecell_data->hws[clkid]) + if (!clkc_data->hw_onecell_data->hws[i]) continue; ret = devm_clk_hw_register(dev, - clkc_data->hw_onecell_data->hws[clkid]); - if (ret) - goto iounmap; + clkc_data->hw_onecell_data->hws[i]); + if (ret) { + dev_err(dev, "Clock registration failed\n"); + return ret; + } } - return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, - clkc_data->hw_onecell_data); - -iounmap: - iounmap(clk_base); - return ret; + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, + clkc_data->hw_onecell_data); } static struct platform_driver gxbb_driver = { diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h index aee6fbba2004..9febf3f03739 100644 --- a/drivers/clk/meson/gxbb.h +++ b/drivers/clk/meson/gxbb.h @@ -194,8 +194,18 @@ #define CLKID_VPU_1_DIV 130 #define CLKID_VAPB_0_DIV 134 #define CLKID_VAPB_1_DIV 137 - -#define NR_CLKS 141 +#define CLKID_HDMI_PLL_PRE_MULT 141 +#define CLKID_MPLL0_DIV 142 +#define CLKID_MPLL1_DIV 143 +#define CLKID_MPLL2_DIV 144 +#define CLKID_MPLL_PREDIV 145 +#define CLKID_FCLK_DIV2_DIV 146 +#define CLKID_FCLK_DIV3_DIV 147 +#define CLKID_FCLK_DIV4_DIV 148 +#define CLKID_FCLK_DIV5_DIV 149 +#define CLKID_FCLK_DIV7_DIV 150 + +#define NR_CLKS 151 /* include the CLKIDs that have been made part of the DT binding */ #include <dt-bindings/clock/gxbb-clkc.h> diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 3ffea80c1308..cc2992493e0b 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -23,14 +23,16 @@ #include <linux/clk.h> #include <linux/clk-provider.h> +#include <linux/init.h> #include <linux/of_address.h> #include <linux/platform_device.h> #include <linux/reset-controller.h> #include <linux/slab.h> -#include <linux/init.h> +#include <linux/regmap.h> #include "clkc.h" #include "meson8b.h" +#include "clk-regmap.h" static DEFINE_SPINLOCK(meson_clk_lock); @@ -97,20 +99,6 @@ static const struct pll_rate_table sys_pll_rate_table[] = { { /* sentinel */ }, }; -static const struct clk_div_table cpu_div_table[] = { - { .val = 1, .div = 1 }, - { .val = 2, .div = 2 }, - { .val = 3, .div = 3 }, - { .val = 2, .div = 4 }, - { .val = 3, .div = 6 }, - { .val = 4, .div = 8 }, - { .val = 5, .div = 10 }, - { .val = 6, .div = 12 }, - { .val = 7, .div = 14 }, - { .val = 8, .div = 16 }, - { /* sentinel */ }, -}; - static struct clk_fixed_rate meson8b_xtal = { .fixed_rate = 24000000, .hw.init = &(struct clk_init_data){ @@ -120,23 +108,39 @@ static struct clk_fixed_rate meson8b_xtal = { }, }; -static struct meson_clk_pll meson8b_fixed_pll = { - .m = { - .reg_off = HHI_MPLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_MPLL_CNTL, - .shift = 9, - .width = 5, - }, - .od = { - .reg_off = HHI_MPLL_CNTL, - .shift = 16, - .width = 2, +static struct clk_regmap meson8b_fixed_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_MPLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_MPLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_MPLL_CNTL, + .shift = 16, + .width = 2, + }, + .frac = { + .reg_off = HHI_MPLL_CNTL2, + .shift = 0, + .width = 12, + }, + .l = { + .reg_off = HHI_MPLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_MPLL_CNTL, + .shift = 29, + .width = 1, + }, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "fixed_pll", .ops = &meson_clk_pll_ro_ops, @@ -146,23 +150,34 @@ static struct meson_clk_pll meson8b_fixed_pll = { }, }; -static struct meson_clk_pll meson8b_vid_pll = { - .m = { - .reg_off = HHI_VID_PLL_CNTL, - .shift = 0, - .width = 9, +static struct clk_regmap meson8b_vid_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_VID_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_VID_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_VID_PLL_CNTL, + .shift = 16, + .width = 2, + }, + .l = { + .reg_off = HHI_VID_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_VID_PLL_CNTL, + .shift = 29, + .width = 1, + }, }, - .n = { - .reg_off = HHI_VID_PLL_CNTL, - .shift = 9, - .width = 5, - }, - .od = { - .reg_off = HHI_VID_PLL_CNTL, - .shift = 16, - .width = 2, - }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "vid_pll", .ops = &meson_clk_pll_ro_ops, @@ -172,213 +187,317 @@ static struct meson_clk_pll meson8b_vid_pll = { }, }; -static struct meson_clk_pll meson8b_sys_pll = { - .m = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 0, - .width = 9, - }, - .n = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 9, - .width = 5, +static struct clk_regmap meson8b_sys_pll = { + .data = &(struct meson_clk_pll_data){ + .m = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 0, + .width = 9, + }, + .n = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 9, + .width = 5, + }, + .od = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 16, + .width = 2, + }, + .l = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = HHI_SYS_PLL_CNTL, + .shift = 29, + .width = 1, + }, + .table = sys_pll_rate_table, }, - .od = { - .reg_off = HHI_SYS_PLL_CNTL, - .shift = 16, - .width = 2, - }, - .rate_table = sys_pll_rate_table, - .rate_count = ARRAY_SIZE(sys_pll_rate_table), - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ .name = "sys_pll", - .ops = &meson_clk_pll_ops, + .ops = &meson_clk_pll_ro_ops, .parent_names = (const char *[]){ "xtal" }, .num_parents = 1, .flags = CLK_GET_RATE_NOCACHE, }, }; -static struct clk_fixed_factor meson8b_fclk_div2 = { +static struct clk_fixed_factor meson8b_fclk_div2_div = { .mult = 1, .div = 2, .hw.init = &(struct clk_init_data){ - .name = "fclk_div2", + .name = "fclk_div2_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_fixed_factor meson8b_fclk_div3 = { +static struct clk_regmap meson8b_fclk_div2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 27, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div2_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor meson8b_fclk_div3_div = { .mult = 1, .div = 3, .hw.init = &(struct clk_init_data){ - .name = "fclk_div3", + .name = "fclk_div_div3", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_fixed_factor meson8b_fclk_div4 = { +static struct clk_regmap meson8b_fclk_div3 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 28, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div3_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor meson8b_fclk_div4_div = { .mult = 1, .div = 4, .hw.init = &(struct clk_init_data){ - .name = "fclk_div4", + .name = "fclk_div4_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_fixed_factor meson8b_fclk_div5 = { +static struct clk_regmap meson8b_fclk_div4 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 29, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div4_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor meson8b_fclk_div5_div = { .mult = 1, .div = 5, .hw.init = &(struct clk_init_data){ - .name = "fclk_div5", + .name = "fclk_div5_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct clk_fixed_factor meson8b_fclk_div7 = { +static struct clk_regmap meson8b_fclk_div5 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div5_div" }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor meson8b_fclk_div7_div = { .mult = 1, .div = 7, .hw.init = &(struct clk_init_data){ - .name = "fclk_div7", + .name = "fclk_div7_div", .ops = &clk_fixed_factor_ops, .parent_names = (const char *[]){ "fixed_pll" }, .num_parents = 1, }, }; -static struct meson_clk_mpll meson8b_mpll0 = { - .sdm = { - .reg_off = HHI_MPLL_CNTL7, - .shift = 0, - .width = 14, +static struct clk_regmap meson8b_fclk_div7 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL6, + .bit_idx = 31, }, - .sdm_en = { - .reg_off = HHI_MPLL_CNTL7, - .shift = 15, - .width = 1, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div7_div" }, + .num_parents = 1, }, - .n2 = { - .reg_off = HHI_MPLL_CNTL7, - .shift = 16, - .width = 9, +}; + +static struct clk_regmap meson8b_mpll_prediv = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPLL_CNTL5, + .shift = 12, + .width = 1, }, - .en = { - .reg_off = HHI_MPLL_CNTL7, - .shift = 14, - .width = 1, + .hw.init = &(struct clk_init_data){ + .name = "mpll_prediv", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "fixed_pll" }, + .num_parents = 1, }, - .ssen = { - .reg_off = HHI_MPLL_CNTL, - .shift = 25, - .width = 1, +}; + +static struct clk_regmap meson8b_mpll0_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 16, + .width = 9, + }, + .ssen = { + .reg_off = HHI_MPLL_CNTL, + .shift = 25, + .width = 1, + }, + .lock = &meson_clk_lock, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ - .name = "mpll0", + .name = "mpll0_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_names = (const char *[]){ "mpll_prediv" }, .num_parents = 1, }, }; -static struct meson_clk_mpll meson8b_mpll1 = { - .sdm = { - .reg_off = HHI_MPLL_CNTL8, - .shift = 0, - .width = 14, +static struct clk_regmap meson8b_mpll0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL7, + .bit_idx = 14, }, - .sdm_en = { - .reg_off = HHI_MPLL_CNTL8, - .shift = 15, - .width = 1, - }, - .n2 = { - .reg_off = HHI_MPLL_CNTL8, - .shift = 16, - .width = 9, + .hw.init = &(struct clk_init_data){ + .name = "mpll0", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mpll0_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, }, - .en = { - .reg_off = HHI_MPLL_CNTL8, - .shift = 14, - .width = 1, +}; + +static struct clk_regmap meson8b_mpll1_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL8, + .shift = 16, + .width = 9, + }, + .lock = &meson_clk_lock, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ - .name = "mpll1", + .name = "mpll1_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_names = (const char *[]){ "mpll_prediv" }, .num_parents = 1, }, }; -static struct meson_clk_mpll meson8b_mpll2 = { - .sdm = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 0, - .width = 14, - }, - .sdm_en = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 15, - .width = 1, +static struct clk_regmap meson8b_mpll1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL8, + .bit_idx = 14, }, - .n2 = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 16, - .width = 9, + .hw.init = &(struct clk_init_data){ + .name = "mpll1", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mpll1_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, }, - .en = { - .reg_off = HHI_MPLL_CNTL9, - .shift = 14, - .width = 1, +}; + +static struct clk_regmap meson8b_mpll2_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 15, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL9, + .shift = 16, + .width = 9, + }, + .lock = &meson_clk_lock, }, - .lock = &meson_clk_lock, .hw.init = &(struct clk_init_data){ - .name = "mpll2", + .name = "mpll2_div", .ops = &meson_clk_mpll_ops, - .parent_names = (const char *[]){ "fixed_pll" }, + .parent_names = (const char *[]){ "mpll_prediv" }, .num_parents = 1, }, }; -/* - * FIXME cpu clocks and the legacy composite clocks (e.g. clk81) are both PLL - * post-dividers and should be modeled with their respective PLLs via the - * forthcoming coordinated clock rates feature - */ -static struct meson_clk_cpu meson8b_cpu_clk = { - .reg_off = HHI_SYS_CPU_CLK_CNTL1, - .div_table = cpu_div_table, - .clk_nb.notifier_call = meson_clk_cpu_notifier_cb, +static struct clk_regmap meson8b_mpll2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPLL_CNTL9, + .bit_idx = 14, + }, .hw.init = &(struct clk_init_data){ - .name = "cpu_clk", - .ops = &meson_clk_cpu_ops, - .parent_names = (const char *[]){ "sys_pll" }, + .name = "mpll2", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "mpll2_div" }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, }, }; static u32 mux_table_clk81[] = { 6, 5, 7 }; - -struct clk_mux meson8b_mpeg_clk_sel = { - .reg = (void *)HHI_MPEG_CLK_CNTL, - .mask = 0x7, - .shift = 12, - .flags = CLK_MUX_READ_ONLY, - .table = mux_table_clk81, - .lock = &meson_clk_lock, +static struct clk_regmap meson8b_mpeg_clk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MPEG_CLK_CNTL, + .mask = 0x7, + .shift = 12, + .table = mux_table_clk81, + }, .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_sel", - .ops = &clk_mux_ro_ops, + .ops = &clk_regmap_mux_ro_ops, /* * FIXME bits 14:12 selects from 8 possible parents: * xtal, 1'b0 (wtf), fclk_div7, mpll_clkout1, mpll_clkout2, @@ -387,34 +506,136 @@ struct clk_mux meson8b_mpeg_clk_sel = { .parent_names = (const char *[]){ "fclk_div3", "fclk_div4", "fclk_div5" }, .num_parents = 3, - .flags = (CLK_SET_RATE_NO_REPARENT | CLK_IGNORE_UNUSED), }, }; -struct clk_divider meson8b_mpeg_clk_div = { - .reg = (void *)HHI_MPEG_CLK_CNTL, - .shift = 0, - .width = 7, - .lock = &meson_clk_lock, +static struct clk_regmap meson8b_mpeg_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MPEG_CLK_CNTL, + .shift = 0, + .width = 7, + }, .hw.init = &(struct clk_init_data){ .name = "mpeg_clk_div", - .ops = &clk_divider_ops, + .ops = &clk_regmap_divider_ro_ops, .parent_names = (const char *[]){ "mpeg_clk_sel" }, .num_parents = 1, - .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), }, }; -struct clk_gate meson8b_clk81 = { - .reg = (void *)HHI_MPEG_CLK_CNTL, - .bit_idx = 7, - .lock = &meson_clk_lock, +static struct clk_regmap meson8b_clk81 = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MPEG_CLK_CNTL, + .bit_idx = 7, + }, .hw.init = &(struct clk_init_data){ .name = "clk81", - .ops = &clk_gate_ops, + .ops = &clk_regmap_gate_ops, .parent_names = (const char *[]){ "mpeg_clk_div" }, .num_parents = 1, - .flags = (CLK_SET_RATE_PARENT | CLK_IS_CRITICAL), + .flags = CLK_IS_CRITICAL, + }, +}; + +static struct clk_regmap meson8b_cpu_in_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL0, + .mask = 0x1, + .shift = 0, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_in_sel", + .ops = &clk_regmap_mux_ro_ops, + .parent_names = (const char *[]){ "xtal", "sys_pll" }, + .num_parents = 2, + .flags = (CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), + }, +}; + +static struct clk_fixed_factor meson8b_cpu_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "cpu_div2", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "cpu_in_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor meson8b_cpu_div3 = { + .mult = 1, + .div = 3, + .hw.init = &(struct clk_init_data){ + .name = "cpu_div3", + .ops = &clk_fixed_factor_ops, + .parent_names = (const char *[]){ "cpu_in_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_div_table cpu_scale_table[] = { + { .val = 2, .div = 4 }, + { .val = 3, .div = 6 }, + { .val = 4, .div = 8 }, + { .val = 5, .div = 10 }, + { .val = 6, .div = 12 }, + { .val = 7, .div = 14 }, + { .val = 8, .div = 16 }, + { /* sentinel */ }, +}; + +static struct clk_regmap meson8b_cpu_scale_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, + .shift = 20, + .width = 9, + .table = cpu_scale_table, + .flags = CLK_DIVIDER_ALLOW_ZERO, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_scale_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_names = (const char *[]){ "cpu_in_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_cpu_scale_out_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL0, + .mask = 0x3, + .shift = 2, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_scale_out_sel", + .ops = &clk_regmap_mux_ro_ops, + .parent_names = (const char *[]) { "cpu_in_sel", + "cpu_div2", + "cpu_div3", + "cpu_scale_div" }, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap meson8b_cpu_clk = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_SYS_CPU_CLK_CNTL0, + .mask = 0x1, + .shift = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "cpu_clk", + .ops = &clk_regmap_mux_ro_ops, + .parent_names = (const char *[]){ "xtal", "cpu_out_sel" }, + .num_parents = 2, + .flags = (CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), }, }; @@ -599,24 +820,26 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = { [CLKID_MPLL0] = &meson8b_mpll0.hw, [CLKID_MPLL1] = &meson8b_mpll1.hw, [CLKID_MPLL2] = &meson8b_mpll2.hw, + [CLKID_MPLL0_DIV] = &meson8b_mpll0_div.hw, + [CLKID_MPLL1_DIV] = &meson8b_mpll1_div.hw, + [CLKID_MPLL2_DIV] = &meson8b_mpll2_div.hw, + [CLKID_CPU_IN_SEL] = &meson8b_cpu_in_sel.hw, + [CLKID_CPU_DIV2] = &meson8b_cpu_div2.hw, + [CLKID_CPU_DIV3] = &meson8b_cpu_div3.hw, + [CLKID_CPU_SCALE_DIV] = &meson8b_cpu_scale_div.hw, + [CLKID_CPU_SCALE_OUT_SEL] = &meson8b_cpu_scale_out_sel.hw, + [CLKID_MPLL_PREDIV] = &meson8b_mpll_prediv.hw, + [CLKID_FCLK_DIV2_DIV] = &meson8b_fclk_div2_div.hw, + [CLKID_FCLK_DIV3_DIV] = &meson8b_fclk_div3_div.hw, + [CLKID_FCLK_DIV4_DIV] = &meson8b_fclk_div4_div.hw, + [CLKID_FCLK_DIV5_DIV] = &meson8b_fclk_div5_div.hw, + [CLKID_FCLK_DIV7_DIV] = &meson8b_fclk_div7_div.hw, [CLK_NR_CLKS] = NULL, }, .num = CLK_NR_CLKS, }; -static struct meson_clk_pll *const meson8b_clk_plls[] = { - &meson8b_fixed_pll, - &meson8b_vid_pll, - &meson8b_sys_pll, -}; - -static struct meson_clk_mpll *const meson8b_clk_mplls[] = { - &meson8b_mpll0, - &meson8b_mpll1, - &meson8b_mpll2, -}; - -static struct clk_gate *const meson8b_clk_gates[] = { +static struct clk_regmap *const meson8b_clk_regmaps[] = { &meson8b_clk81, &meson8b_ddr, &meson8b_dos, @@ -695,14 +918,27 @@ static struct clk_gate *const meson8b_clk_gates[] = { &meson8b_ao_ahb_sram, &meson8b_ao_ahb_bus, &meson8b_ao_iface, -}; - -static struct clk_mux *const meson8b_clk_muxes[] = { - &meson8b_mpeg_clk_sel, -}; - -static struct clk_divider *const meson8b_clk_dividers[] = { &meson8b_mpeg_clk_div, + &meson8b_mpeg_clk_sel, + &meson8b_mpll0, + &meson8b_mpll1, + &meson8b_mpll2, + &meson8b_mpll0_div, + &meson8b_mpll1_div, + &meson8b_mpll2_div, + &meson8b_fixed_pll, + &meson8b_vid_pll, + &meson8b_sys_pll, + &meson8b_cpu_in_sel, + &meson8b_cpu_scale_div, + &meson8b_cpu_scale_out_sel, + &meson8b_cpu_clk, + &meson8b_mpll_prediv, + &meson8b_fclk_div2, + &meson8b_fclk_div3, + &meson8b_fclk_div4, + &meson8b_fclk_div5, + &meson8b_fclk_div7, }; static const struct meson8b_clk_reset_line { @@ -804,82 +1040,45 @@ static const struct reset_control_ops meson8b_clk_reset_ops = { .deassert = meson8b_clk_reset_deassert, }; +static const struct regmap_config clkc_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + static int meson8b_clkc_probe(struct platform_device *pdev) { - int ret, clkid, i; - struct clk_hw *parent_hw; - struct clk *parent_clk; + int ret, i; struct device *dev = &pdev->dev; + struct regmap *map; if (!clk_base) return -ENXIO; - /* Populate base address for PLLs */ - for (i = 0; i < ARRAY_SIZE(meson8b_clk_plls); i++) - meson8b_clk_plls[i]->base = clk_base; - - /* Populate base address for MPLLs */ - for (i = 0; i < ARRAY_SIZE(meson8b_clk_mplls); i++) - meson8b_clk_mplls[i]->base = clk_base; - - /* Populate the base address for CPU clk */ - meson8b_cpu_clk.base = clk_base; - - /* Populate base address for gates */ - for (i = 0; i < ARRAY_SIZE(meson8b_clk_gates); i++) - meson8b_clk_gates[i]->reg = clk_base + - (u32)meson8b_clk_gates[i]->reg; - - /* Populate base address for muxes */ - for (i = 0; i < ARRAY_SIZE(meson8b_clk_muxes); i++) - meson8b_clk_muxes[i]->reg = clk_base + - (u32)meson8b_clk_muxes[i]->reg; + map = devm_regmap_init_mmio(dev, clk_base, &clkc_regmap_config); + if (IS_ERR(map)) + return PTR_ERR(map); - /* Populate base address for dividers */ - for (i = 0; i < ARRAY_SIZE(meson8b_clk_dividers); i++) - meson8b_clk_dividers[i]->reg = clk_base + - (u32)meson8b_clk_dividers[i]->reg; + /* Populate regmap for the regmap backed clocks */ + for (i = 0; i < ARRAY_SIZE(meson8b_clk_regmaps); i++) + meson8b_clk_regmaps[i]->map = map; /* * register all clks * CLKID_UNUSED = 0, so skip it and start with CLKID_XTAL = 1 */ - for (clkid = CLKID_XTAL; clkid < CLK_NR_CLKS; clkid++) { + for (i = CLKID_XTAL; i < CLK_NR_CLKS; i++) { /* array might be sparse */ - if (!meson8b_hw_onecell_data.hws[clkid]) + if (!meson8b_hw_onecell_data.hws[i]) continue; - /* FIXME convert to devm_clk_register */ - ret = devm_clk_hw_register(dev, meson8b_hw_onecell_data.hws[clkid]); + ret = devm_clk_hw_register(dev, meson8b_hw_onecell_data.hws[i]); if (ret) return ret; } - /* - * Register CPU clk notifier - * - * FIXME this is wrong for a lot of reasons. First, the muxes should be - * struct clk_hw objects. Second, we shouldn't program the muxes in - * notifier handlers. The tricky programming sequence will be handled - * by the forthcoming coordinated clock rates mechanism once that - * feature is released. - * - * Furthermore, looking up the parent this way is terrible. At some - * point we will stop allocating a default struct clk when registering - * a new clk_hw, and this hack will no longer work. Releasing the ccr - * feature before that time solves the problem :-) - */ - parent_hw = clk_hw_get_parent(&meson8b_cpu_clk.hw); - parent_clk = parent_hw->clk; - ret = clk_notifier_register(parent_clk, &meson8b_cpu_clk.clk_nb); - if (ret) { - pr_err("%s: failed to register clock notifier for cpu_clk\n", - __func__); - return ret; - } - - return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, - &meson8b_hw_onecell_data); + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, + &meson8b_hw_onecell_data); } static const struct of_device_id meson8b_clkc_match_table[] = { diff --git a/drivers/clk/meson/meson8b.h b/drivers/clk/meson/meson8b.h index 2eaf8a52e7dd..6e414bd36981 100644 --- a/drivers/clk/meson/meson8b.h +++ b/drivers/clk/meson/meson8b.h @@ -69,7 +69,22 @@ * will remain defined here. */ -#define CLK_NR_CLKS 96 +#define CLKID_MPLL0_DIV 96 +#define CLKID_MPLL1_DIV 97 +#define CLKID_MPLL2_DIV 98 +#define CLKID_CPU_IN_SEL 99 +#define CLKID_CPU_DIV2 100 +#define CLKID_CPU_DIV3 101 +#define CLKID_CPU_SCALE_DIV 102 +#define CLKID_CPU_SCALE_OUT_SEL 103 +#define CLKID_MPLL_PREDIV 104 +#define CLKID_FCLK_DIV2_DIV 105 +#define CLKID_FCLK_DIV3_DIV 106 +#define CLKID_FCLK_DIV4_DIV 107 +#define CLKID_FCLK_DIV5_DIV 108 +#define CLKID_FCLK_DIV7_DIV 109 + +#define CLK_NR_CLKS 110 /* * include the CLKID and RESETID that have diff --git a/drivers/clk/mvebu/armada-38x.c b/drivers/clk/mvebu/armada-38x.c index 394aa6f03f01..9ff4ea63932d 100644 --- a/drivers/clk/mvebu/armada-38x.c +++ b/drivers/clk/mvebu/armada-38x.c @@ -46,11 +46,11 @@ static u32 __init armada_38x_get_tclk_freq(void __iomem *sar) } static const u32 armada_38x_cpu_frequencies[] __initconst = { - 0, 0, 0, 0, - 1066 * 1000 * 1000, 0, 0, 0, + 666 * 1000 * 1000, 0, 800 * 1000 * 1000, 0, + 1066 * 1000 * 1000, 0, 1200 * 1000 * 1000, 0, 1332 * 1000 * 1000, 0, 0, 0, 1600 * 1000 * 1000, 0, 0, 0, - 1866 * 1000 * 1000, + 1866 * 1000 * 1000, 0, 0, 2000 * 1000 * 1000, }; static u32 __init armada_38x_get_cpu_freq(void __iomem *sar) @@ -76,11 +76,11 @@ static const struct coreclk_ratio armada_38x_coreclk_ratios[] __initconst = { }; static const int armada_38x_cpu_l2_ratios[32][2] __initconst = { - {0, 1}, {0, 1}, {0, 1}, {0, 1}, - {1, 2}, {0, 1}, {0, 1}, {0, 1}, - {1, 2}, {0, 1}, {0, 1}, {0, 1}, + {1, 2}, {0, 1}, {1, 2}, {0, 1}, + {1, 2}, {0, 1}, {1, 2}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, + {1, 2}, {0, 1}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, @@ -91,7 +91,7 @@ static const int armada_38x_cpu_ddr_ratios[32][2] __initconst = { {1, 2}, {0, 1}, {0, 1}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, - {1, 2}, {0, 1}, {0, 1}, {0, 1}, + {1, 2}, {0, 1}, {0, 1}, {7, 15}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, diff --git a/drivers/clk/mvebu/cp110-system-controller.c b/drivers/clk/mvebu/cp110-system-controller.c index ca9a0a536174..75bf7b8f282f 100644 --- a/drivers/clk/mvebu/cp110-system-controller.c +++ b/drivers/clk/mvebu/cp110-system-controller.c @@ -13,18 +13,17 @@ /* * CP110 has 6 core clocks: * - * - APLL (1 Ghz) - * - PPv2 core (1/3 APLL) - * - EIP (1/2 APLL) - * - Core (1/2 EIP) - * - SDIO (2/5 APLL) + * - PLL0 (1 Ghz) + * - PPv2 core (1/3 PLL0) + * - x2 Core (1/2 PLL0) + * - Core (1/2 x2 Core) + * - SDIO (2/5 PLL0) * * - NAND clock, which is either: * - Equal to SDIO clock - * - 2/5 APLL + * - 2/5 PLL0 * - * CP110 has 32 gatable clocks, for the various peripherals in the - * IP. They have fairly complicated parent/child relationships. + * CP110 has 32 gatable clocks, for the various peripherals in the IP. */ #define pr_fmt(fmt) "cp110-system-controller: " fmt @@ -53,9 +52,9 @@ enum { #define CP110_CLK_NUM \ (CP110_MAX_CORE_CLOCKS + CP110_MAX_GATABLE_CLOCKS) -#define CP110_CORE_APLL 0 +#define CP110_CORE_PLL0 0 #define CP110_CORE_PPV2 1 -#define CP110_CORE_EIP 2 +#define CP110_CORE_X2CORE 2 #define CP110_CORE_CORE 3 #define CP110_CORE_NAND 4 #define CP110_CORE_SDIO 5 @@ -237,7 +236,7 @@ static int cp110_syscon_common_probe(struct platform_device *pdev, struct regmap *regmap; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - const char *ppv2_name, *apll_name, *core_name, *eip_name, *nand_name, + const char *ppv2_name, *pll0_name, *core_name, *x2core_name, *nand_name, *sdio_name; struct clk_hw_onecell_data *cp110_clk_data; struct clk_hw *hw, **cp110_clks; @@ -263,20 +262,20 @@ static int cp110_syscon_common_probe(struct platform_device *pdev, cp110_clks = cp110_clk_data->hws; cp110_clk_data->num = CP110_CLK_NUM; - /* Register the APLL which is the root of the hw tree */ - apll_name = cp110_unique_name(dev, syscon_node, "apll"); - hw = clk_hw_register_fixed_rate(NULL, apll_name, NULL, 0, + /* Register the PLL0 which is the root of the hw tree */ + pll0_name = cp110_unique_name(dev, syscon_node, "pll0"); + hw = clk_hw_register_fixed_rate(NULL, pll0_name, NULL, 0, 1000 * 1000 * 1000); if (IS_ERR(hw)) { ret = PTR_ERR(hw); - goto fail_apll; + goto fail_pll0; } - cp110_clks[CP110_CORE_APLL] = hw; + cp110_clks[CP110_CORE_PLL0] = hw; - /* PPv2 is APLL/3 */ + /* PPv2 is PLL0/3 */ ppv2_name = cp110_unique_name(dev, syscon_node, "ppv2-core"); - hw = clk_hw_register_fixed_factor(NULL, ppv2_name, apll_name, 0, 1, 3); + hw = clk_hw_register_fixed_factor(NULL, ppv2_name, pll0_name, 0, 1, 3); if (IS_ERR(hw)) { ret = PTR_ERR(hw); goto fail_ppv2; @@ -284,30 +283,32 @@ static int cp110_syscon_common_probe(struct platform_device *pdev, cp110_clks[CP110_CORE_PPV2] = hw; - /* EIP clock is APLL/2 */ - eip_name = cp110_unique_name(dev, syscon_node, "eip"); - hw = clk_hw_register_fixed_factor(NULL, eip_name, apll_name, 0, 1, 2); + /* X2CORE clock is PLL0/2 */ + x2core_name = cp110_unique_name(dev, syscon_node, "x2core"); + hw = clk_hw_register_fixed_factor(NULL, x2core_name, pll0_name, + 0, 1, 2); if (IS_ERR(hw)) { ret = PTR_ERR(hw); goto fail_eip; } - cp110_clks[CP110_CORE_EIP] = hw; + cp110_clks[CP110_CORE_X2CORE] = hw; - /* Core clock is EIP/2 */ + /* Core clock is X2CORE/2 */ core_name = cp110_unique_name(dev, syscon_node, "core"); - hw = clk_hw_register_fixed_factor(NULL, core_name, eip_name, 0, 1, 2); + hw = clk_hw_register_fixed_factor(NULL, core_name, x2core_name, + 0, 1, 2); if (IS_ERR(hw)) { ret = PTR_ERR(hw); goto fail_core; } cp110_clks[CP110_CORE_CORE] = hw; - /* NAND can be either APLL/2.5 or core clock */ + /* NAND can be either PLL0/2.5 or core clock */ nand_name = cp110_unique_name(dev, syscon_node, "nand-core"); if (nand_clk_ctrl & NF_CLOCK_SEL_400_MASK) hw = clk_hw_register_fixed_factor(NULL, nand_name, - apll_name, 0, 2, 5); + pll0_name, 0, 2, 5); else hw = clk_hw_register_fixed_factor(NULL, nand_name, core_name, 0, 1, 1); @@ -318,10 +319,10 @@ static int cp110_syscon_common_probe(struct platform_device *pdev, cp110_clks[CP110_CORE_NAND] = hw; - /* SDIO clock is APLL/2.5 */ + /* SDIO clock is PLL0/2.5 */ sdio_name = cp110_unique_name(dev, syscon_node, "sdio-core"); hw = clk_hw_register_fixed_factor(NULL, sdio_name, - apll_name, 0, 2, 5); + pll0_name, 0, 2, 5); if (IS_ERR(hw)) { ret = PTR_ERR(hw); goto fail_sdio; @@ -341,40 +342,23 @@ static int cp110_syscon_common_probe(struct platform_device *pdev, continue; switch (i) { - case CP110_GATE_AUDIO: - case CP110_GATE_COMM_UNIT: - case CP110_GATE_EIP150: - case CP110_GATE_EIP197: - case CP110_GATE_SLOW_IO: - parent = gate_name[CP110_GATE_MAIN]; - break; - case CP110_GATE_MG: - parent = gate_name[CP110_GATE_MG_CORE]; - break; case CP110_GATE_NAND: parent = nand_name; break; + case CP110_GATE_MG: + case CP110_GATE_GOP_DP: case CP110_GATE_PPV2: parent = ppv2_name; break; case CP110_GATE_SDIO: parent = sdio_name; break; - case CP110_GATE_GOP_DP: - parent = gate_name[CP110_GATE_SDMMC_GOP]; - break; - case CP110_GATE_XOR1: - case CP110_GATE_XOR0: - case CP110_GATE_PCIE_X1_0: - case CP110_GATE_PCIE_X1_1: + case CP110_GATE_MAIN: + case CP110_GATE_PCIE_XOR: case CP110_GATE_PCIE_X4: - parent = gate_name[CP110_GATE_PCIE_XOR]; - break; - case CP110_GATE_SATA: - case CP110_GATE_USB3H0: - case CP110_GATE_USB3H1: - case CP110_GATE_USB3DEV: - parent = gate_name[CP110_GATE_SATA_USB]; + case CP110_GATE_EIP150: + case CP110_GATE_EIP197: + parent = x2core_name; break; default: parent = core_name; @@ -413,12 +397,12 @@ fail_sdio: fail_nand: clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_CORE]); fail_core: - clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_EIP]); + clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_X2CORE]); fail_eip: clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_PPV2]); fail_ppv2: - clk_hw_unregister_fixed_rate(cp110_clks[CP110_CORE_APLL]); -fail_apll: + clk_hw_unregister_fixed_rate(cp110_clks[CP110_CORE_PLL0]); +fail_pll0: return ret; } diff --git a/drivers/clk/qcom/clk-regmap-divider.c b/drivers/clk/qcom/clk-regmap-divider.c index 4e9b8c2c8980..1ee75a5e93f4 100644 --- a/drivers/clk/qcom/clk-regmap-divider.c +++ b/drivers/clk/qcom/clk-regmap-divider.c @@ -28,22 +28,14 @@ static long div_round_ro_rate(struct clk_hw *hw, unsigned long rate, { struct clk_regmap_div *divider = to_clk_regmap_div(hw); struct clk_regmap *clkr = ÷r->clkr; - u32 div; - struct clk_hw *hw_parent = clk_hw_get_parent(hw); - - regmap_read(clkr->regmap, divider->reg, &div); - div >>= divider->shift; - div &= BIT(divider->width) - 1; - div += 1; - - if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) { - if (!hw_parent) - return -EINVAL; + u32 val; - *prate = clk_hw_round_rate(hw_parent, rate * div); - } + regmap_read(clkr->regmap, divider->reg, &val); + val >>= divider->shift; + val &= BIT(divider->width) - 1; - return DIV_ROUND_UP_ULL((u64)*prate, div); + return divider_ro_round_rate(hw, rate, prate, NULL, divider->width, + CLK_DIVIDER_ROUND_CLOSEST, val); } static long div_round_rate(struct clk_hw *hw, unsigned long rate, diff --git a/drivers/clk/qcom/clk-rpm.c b/drivers/clk/qcom/clk-rpm.c index c60f61b10c7f..b94981447664 100644 --- a/drivers/clk/qcom/clk-rpm.c +++ b/drivers/clk/qcom/clk-rpm.c @@ -29,6 +29,7 @@ #define QCOM_RPM_MISC_CLK_TYPE 0x306b6c63 #define QCOM_RPM_SCALING_ENABLE_ID 0x2 +#define QCOM_RPM_XO_MODE_ON 0x2 #define DEFINE_CLK_RPM(_platform, _name, _active, r_id) \ static struct clk_rpm _platform##_##_active; \ @@ -56,6 +57,18 @@ }, \ } +#define DEFINE_CLK_RPM_XO_BUFFER(_platform, _name, _active, offset) \ + static struct clk_rpm _platform##_##_name = { \ + .rpm_clk_id = QCOM_RPM_CXO_BUFFERS, \ + .xo_offset = (offset), \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_rpm_xo_ops, \ + .name = #_name, \ + .parent_names = (const char *[]){ "cxo_board" }, \ + .num_parents = 1, \ + }, \ + } + #define DEFINE_CLK_RPM_FIXED(_platform, _name, _active, r_id, r) \ static struct clk_rpm _platform##_##_name = { \ .rpm_clk_id = (r_id), \ @@ -126,8 +139,11 @@ #define to_clk_rpm(_hw) container_of(_hw, struct clk_rpm, hw) +struct rpm_cc; + struct clk_rpm { const int rpm_clk_id; + const int xo_offset; const bool active_only; unsigned long rate; bool enabled; @@ -135,12 +151,15 @@ struct clk_rpm { struct clk_rpm *peer; struct clk_hw hw; struct qcom_rpm *rpm; + struct rpm_cc *rpm_cc; }; struct rpm_cc { struct qcom_rpm *rpm; struct clk_rpm **clks; size_t num_clks; + u32 xo_buffer_value; + struct mutex xo_lock; }; struct rpm_clk_desc { @@ -159,7 +178,8 @@ static int clk_rpm_handoff(struct clk_rpm *r) * The vendor tree simply reads the status for this * RPM clock. */ - if (r->rpm_clk_id == QCOM_RPM_PLL_4) + if (r->rpm_clk_id == QCOM_RPM_PLL_4 || + r->rpm_clk_id == QCOM_RPM_CXO_BUFFERS) return 0; ret = qcom_rpm_write(r->rpm, QCOM_RPM_ACTIVE_STATE, @@ -288,6 +308,46 @@ out: mutex_unlock(&rpm_clk_lock); } +static int clk_rpm_xo_prepare(struct clk_hw *hw) +{ + struct clk_rpm *r = to_clk_rpm(hw); + struct rpm_cc *rcc = r->rpm_cc; + int ret, clk_id = r->rpm_clk_id; + u32 value; + + mutex_lock(&rcc->xo_lock); + + value = rcc->xo_buffer_value | (QCOM_RPM_XO_MODE_ON << r->xo_offset); + ret = qcom_rpm_write(r->rpm, QCOM_RPM_ACTIVE_STATE, clk_id, &value, 1); + if (!ret) { + r->enabled = true; + rcc->xo_buffer_value = value; + } + + mutex_unlock(&rcc->xo_lock); + + return ret; +} + +static void clk_rpm_xo_unprepare(struct clk_hw *hw) +{ + struct clk_rpm *r = to_clk_rpm(hw); + struct rpm_cc *rcc = r->rpm_cc; + int ret, clk_id = r->rpm_clk_id; + u32 value; + + mutex_lock(&rcc->xo_lock); + + value = rcc->xo_buffer_value & ~(QCOM_RPM_XO_MODE_ON << r->xo_offset); + ret = qcom_rpm_write(r->rpm, QCOM_RPM_ACTIVE_STATE, clk_id, &value, 1); + if (!ret) { + r->enabled = false; + rcc->xo_buffer_value = value; + } + + mutex_unlock(&rcc->xo_lock); +} + static int clk_rpm_fixed_prepare(struct clk_hw *hw) { struct clk_rpm *r = to_clk_rpm(hw); @@ -378,6 +438,11 @@ static unsigned long clk_rpm_recalc_rate(struct clk_hw *hw, return r->rate; } +static const struct clk_ops clk_rpm_xo_ops = { + .prepare = clk_rpm_xo_prepare, + .unprepare = clk_rpm_xo_unprepare, +}; + static const struct clk_ops clk_rpm_fixed_ops = { .prepare = clk_rpm_fixed_prepare, .unprepare = clk_rpm_fixed_unprepare, @@ -449,6 +514,11 @@ DEFINE_CLK_RPM(apq8064, mmfpb_clk, mmfpb_a_clk, QCOM_RPM_MMFPB_CLK); DEFINE_CLK_RPM(apq8064, sfab_clk, sfab_a_clk, QCOM_RPM_SYS_FABRIC_CLK); DEFINE_CLK_RPM(apq8064, sfpb_clk, sfpb_a_clk, QCOM_RPM_SFPB_CLK); DEFINE_CLK_RPM(apq8064, qdss_clk, qdss_a_clk, QCOM_RPM_QDSS_CLK); +DEFINE_CLK_RPM_XO_BUFFER(apq8064, xo_d0_clk, xo_d0_a_clk, 0); +DEFINE_CLK_RPM_XO_BUFFER(apq8064, xo_d1_clk, xo_d1_a_clk, 8); +DEFINE_CLK_RPM_XO_BUFFER(apq8064, xo_a0_clk, xo_a0_a_clk, 16); +DEFINE_CLK_RPM_XO_BUFFER(apq8064, xo_a1_clk, xo_a1_a_clk, 24); +DEFINE_CLK_RPM_XO_BUFFER(apq8064, xo_a2_clk, xo_a2_a_clk, 28); static struct clk_rpm *apq8064_clks[] = { [RPM_APPS_FABRIC_CLK] = &apq8064_afab_clk, @@ -469,6 +539,11 @@ static struct clk_rpm *apq8064_clks[] = { [RPM_SFPB_A_CLK] = &apq8064_sfpb_a_clk, [RPM_QDSS_CLK] = &apq8064_qdss_clk, [RPM_QDSS_A_CLK] = &apq8064_qdss_a_clk, + [RPM_XO_D0] = &apq8064_xo_d0_clk, + [RPM_XO_D1] = &apq8064_xo_d1_clk, + [RPM_XO_A0] = &apq8064_xo_a0_clk, + [RPM_XO_A1] = &apq8064_xo_a1_clk, + [RPM_XO_A2] = &apq8064_xo_a2_clk, }; static const struct rpm_clk_desc rpm_clk_apq8064 = { @@ -526,12 +601,14 @@ static int rpm_clk_probe(struct platform_device *pdev) rcc->clks = rpm_clks; rcc->num_clks = num_clks; + mutex_init(&rcc->xo_lock); for (i = 0; i < num_clks; i++) { if (!rpm_clks[i]) continue; rpm_clks[i]->rpm = rpm; + rpm_clks[i]->rpm_cc = rcc; ret = clk_rpm_handoff(rpm_clks[i]); if (ret) diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c index c26d9007bfc4..850c02a52248 100644 --- a/drivers/clk/qcom/clk-smd-rpm.c +++ b/drivers/clk/qcom/clk-smd-rpm.c @@ -686,7 +686,7 @@ static int rpm_smd_clk_probe(struct platform_device *pdev) goto err; } - ret = of_clk_add_hw_provider(pdev->dev.of_node, qcom_smdrpm_clk_hw_get, + ret = devm_of_clk_add_hw_provider(&pdev->dev, qcom_smdrpm_clk_hw_get, rcc); if (ret) goto err; @@ -697,19 +697,12 @@ err: return ret; } -static int rpm_smd_clk_remove(struct platform_device *pdev) -{ - of_clk_del_provider(pdev->dev.of_node); - return 0; -} - static struct platform_driver rpm_smd_clk_driver = { .driver = { .name = "qcom-clk-smd-rpm", .of_match_table = rpm_smd_clk_match_table, }, .probe = rpm_smd_clk_probe, - .remove = rpm_smd_clk_remove, }; static int __init rpm_smd_clk_init(void) diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c index 5d7451209206..3d6452932797 100644 --- a/drivers/clk/qcom/gcc-msm8996.c +++ b/drivers/clk/qcom/gcc-msm8996.c @@ -2895,7 +2895,7 @@ static struct clk_branch gcc_aggre0_snoc_axi_clk = { .name = "gcc_aggre0_snoc_axi_clk", .parent_names = (const char *[]){ "system_noc_clk_src" }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -2910,7 +2910,7 @@ static struct clk_branch gcc_aggre0_cnoc_ahb_clk = { .name = "gcc_aggre0_cnoc_ahb_clk", .parent_names = (const char *[]){ "config_noc_clk_src" }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -2925,7 +2925,7 @@ static struct clk_branch gcc_smmu_aggre0_axi_clk = { .name = "gcc_smmu_aggre0_axi_clk", .parent_names = (const char *[]){ "system_noc_clk_src" }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -2940,7 +2940,7 @@ static struct clk_branch gcc_smmu_aggre0_ahb_clk = { .name = "gcc_smmu_aggre0_ahb_clk", .parent_names = (const char *[]){ "config_noc_clk_src" }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile index ef8900bc077f..513826393158 100644 --- a/drivers/clk/samsung/Makefile +++ b/drivers/clk/samsung/Makefile @@ -8,9 +8,11 @@ obj-$(CONFIG_SOC_EXYNOS3250) += clk-exynos3250.o obj-$(CONFIG_ARCH_EXYNOS4) += clk-exynos4.o obj-$(CONFIG_ARCH_EXYNOS4) += clk-exynos4412-isp.o obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5250.o +obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5-subcmu.o obj-$(CONFIG_SOC_EXYNOS5260) += clk-exynos5260.o obj-$(CONFIG_SOC_EXYNOS5410) += clk-exynos5410.o obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5420.o +obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5-subcmu.o obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos5433.o obj-$(CONFIG_SOC_EXYNOS5440) += clk-exynos5440.o obj-$(CONFIG_EXYNOS_AUDSS_CLK_CON) += clk-exynos-audss.o diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c index 5bfc92ee3129..b4b057c7301c 100644 --- a/drivers/clk/samsung/clk-exynos-audss.c +++ b/drivers/clk/samsung/clk-exynos-audss.c @@ -143,10 +143,8 @@ static int exynos_audss_clk_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); reg_base = devm_ioremap_resource(dev, res); - if (IS_ERR(reg_base)) { - dev_err(dev, "failed to map audss registers\n"); + if (IS_ERR(reg_base)) return PTR_ERR(reg_base); - } epll = ERR_PTR(-ENODEV); diff --git a/drivers/clk/samsung/clk-exynos3250.c b/drivers/clk/samsung/clk-exynos3250.c index 1b81e283f605..27c9d23657b3 100644 --- a/drivers/clk/samsung/clk-exynos3250.c +++ b/drivers/clk/samsung/clk-exynos3250.c @@ -670,73 +670,73 @@ static const struct samsung_gate_clock gate_clks[] __initconst = { /* APLL & MPLL & BPLL & UPLL */ static const struct samsung_pll_rate_table exynos3250_pll_rates[] __initconst = { - PLL_35XX_RATE(1200000000, 400, 4, 1), - PLL_35XX_RATE(1100000000, 275, 3, 1), - PLL_35XX_RATE(1066000000, 533, 6, 1), - PLL_35XX_RATE(1000000000, 250, 3, 1), - PLL_35XX_RATE( 960000000, 320, 4, 1), - PLL_35XX_RATE( 900000000, 300, 4, 1), - PLL_35XX_RATE( 850000000, 425, 6, 1), - PLL_35XX_RATE( 800000000, 200, 3, 1), - PLL_35XX_RATE( 700000000, 175, 3, 1), - PLL_35XX_RATE( 667000000, 667, 12, 1), - PLL_35XX_RATE( 600000000, 400, 4, 2), - PLL_35XX_RATE( 533000000, 533, 6, 2), - PLL_35XX_RATE( 520000000, 260, 3, 2), - PLL_35XX_RATE( 500000000, 250, 3, 2), - PLL_35XX_RATE( 400000000, 200, 3, 2), - PLL_35XX_RATE( 200000000, 200, 3, 3), - PLL_35XX_RATE( 100000000, 200, 3, 4), + PLL_35XX_RATE(24 * MHZ, 1200000000, 400, 4, 1), + PLL_35XX_RATE(24 * MHZ, 1100000000, 275, 3, 1), + PLL_35XX_RATE(24 * MHZ, 1066000000, 533, 6, 1), + PLL_35XX_RATE(24 * MHZ, 1000000000, 250, 3, 1), + PLL_35XX_RATE(24 * MHZ, 960000000, 320, 4, 1), + PLL_35XX_RATE(24 * MHZ, 900000000, 300, 4, 1), + PLL_35XX_RATE(24 * MHZ, 850000000, 425, 6, 1), + PLL_35XX_RATE(24 * MHZ, 800000000, 200, 3, 1), + PLL_35XX_RATE(24 * MHZ, 700000000, 175, 3, 1), + PLL_35XX_RATE(24 * MHZ, 667000000, 667, 12, 1), + PLL_35XX_RATE(24 * MHZ, 600000000, 400, 4, 2), + PLL_35XX_RATE(24 * MHZ, 533000000, 533, 6, 2), + PLL_35XX_RATE(24 * MHZ, 520000000, 260, 3, 2), + PLL_35XX_RATE(24 * MHZ, 500000000, 250, 3, 2), + PLL_35XX_RATE(24 * MHZ, 400000000, 200, 3, 2), + PLL_35XX_RATE(24 * MHZ, 200000000, 200, 3, 3), + PLL_35XX_RATE(24 * MHZ, 100000000, 200, 3, 4), { /* sentinel */ } }; /* EPLL */ static const struct samsung_pll_rate_table exynos3250_epll_rates[] __initconst = { - PLL_36XX_RATE(800000000, 200, 3, 1, 0), - PLL_36XX_RATE(288000000, 96, 2, 2, 0), - PLL_36XX_RATE(192000000, 128, 2, 3, 0), - PLL_36XX_RATE(144000000, 96, 2, 3, 0), - PLL_36XX_RATE( 96000000, 128, 2, 4, 0), - PLL_36XX_RATE( 84000000, 112, 2, 4, 0), - PLL_36XX_RATE( 80000004, 106, 2, 4, 43691), - PLL_36XX_RATE( 73728000, 98, 2, 4, 19923), - PLL_36XX_RATE( 67737598, 270, 3, 5, 62285), - PLL_36XX_RATE( 65535999, 174, 2, 5, 49982), - PLL_36XX_RATE( 50000000, 200, 3, 5, 0), - PLL_36XX_RATE( 49152002, 131, 2, 5, 4719), - PLL_36XX_RATE( 48000000, 128, 2, 5, 0), - PLL_36XX_RATE( 45158401, 180, 3, 5, 41524), + PLL_36XX_RATE(24 * MHZ, 800000000, 200, 3, 1, 0), + PLL_36XX_RATE(24 * MHZ, 288000000, 96, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 192000000, 128, 2, 3, 0), + PLL_36XX_RATE(24 * MHZ, 144000000, 96, 2, 3, 0), + PLL_36XX_RATE(24 * MHZ, 96000000, 128, 2, 4, 0), + PLL_36XX_RATE(24 * MHZ, 84000000, 112, 2, 4, 0), + PLL_36XX_RATE(24 * MHZ, 80000003, 106, 2, 4, 43691), + PLL_36XX_RATE(24 * MHZ, 73728000, 98, 2, 4, 19923), + PLL_36XX_RATE(24 * MHZ, 67737598, 270, 3, 5, 62285), + PLL_36XX_RATE(24 * MHZ, 65535999, 174, 2, 5, 49982), + PLL_36XX_RATE(24 * MHZ, 50000000, 200, 3, 5, 0), + PLL_36XX_RATE(24 * MHZ, 49152002, 131, 2, 5, 4719), + PLL_36XX_RATE(24 * MHZ, 48000000, 128, 2, 5, 0), + PLL_36XX_RATE(24 * MHZ, 45158401, 180, 3, 5, 41524), { /* sentinel */ } }; /* VPLL */ static const struct samsung_pll_rate_table exynos3250_vpll_rates[] __initconst = { - PLL_36XX_RATE(600000000, 100, 2, 1, 0), - PLL_36XX_RATE(533000000, 266, 3, 2, 32768), - PLL_36XX_RATE(519230987, 173, 2, 2, 5046), - PLL_36XX_RATE(500000000, 250, 3, 2, 0), - PLL_36XX_RATE(445500000, 148, 2, 2, 32768), - PLL_36XX_RATE(445055007, 148, 2, 2, 23047), - PLL_36XX_RATE(400000000, 200, 3, 2, 0), - PLL_36XX_RATE(371250000, 123, 2, 2, 49152), - PLL_36XX_RATE(370878997, 185, 3, 2, 28803), - PLL_36XX_RATE(340000000, 170, 3, 2, 0), - PLL_36XX_RATE(335000015, 111, 2, 2, 43691), - PLL_36XX_RATE(333000000, 111, 2, 2, 0), - PLL_36XX_RATE(330000000, 110, 2, 2, 0), - PLL_36XX_RATE(320000015, 106, 2, 2, 43691), - PLL_36XX_RATE(300000000, 100, 2, 2, 0), - PLL_36XX_RATE(275000000, 275, 3, 3, 0), - PLL_36XX_RATE(222750000, 148, 2, 3, 32768), - PLL_36XX_RATE(222528007, 148, 2, 3, 23069), - PLL_36XX_RATE(160000000, 160, 3, 3, 0), - PLL_36XX_RATE(148500000, 99, 2, 3, 0), - PLL_36XX_RATE(148352005, 98, 2, 3, 59070), - PLL_36XX_RATE(108000000, 144, 2, 4, 0), - PLL_36XX_RATE( 74250000, 99, 2, 4, 0), - PLL_36XX_RATE( 74176002, 98, 3, 4, 59070), - PLL_36XX_RATE( 54054000, 216, 3, 5, 14156), - PLL_36XX_RATE( 54000000, 144, 2, 5, 0), + PLL_36XX_RATE(24 * MHZ, 600000000, 100, 2, 1, 0), + PLL_36XX_RATE(24 * MHZ, 533000000, 266, 3, 2, 32768), + PLL_36XX_RATE(24 * MHZ, 519230987, 173, 2, 2, 5046), + PLL_36XX_RATE(24 * MHZ, 500000000, 250, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 445500000, 148, 2, 2, 32768), + PLL_36XX_RATE(24 * MHZ, 445055007, 148, 2, 2, 23047), + PLL_36XX_RATE(24 * MHZ, 400000000, 200, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 371250000, 123, 2, 2, 49152), + PLL_36XX_RATE(24 * MHZ, 370878997, 185, 3, 2, 28803), + PLL_36XX_RATE(24 * MHZ, 340000000, 170, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 335000015, 111, 2, 2, 43691), + PLL_36XX_RATE(24 * MHZ, 333000000, 111, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 330000000, 110, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 320000015, 106, 2, 2, 43691), + PLL_36XX_RATE(24 * MHZ, 300000000, 100, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 275000000, 275, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 222750000, 148, 2, 3, 32768), + PLL_36XX_RATE(24 * MHZ, 222528007, 148, 2, 3, 23069), + PLL_36XX_RATE(24 * MHZ, 160000000, 160, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 148500000, 99, 2, 3, 0), + PLL_36XX_RATE(24 * MHZ, 148352005, 98, 2, 3, 59070), + PLL_36XX_RATE(24 * MHZ, 108000000, 144, 2, 4, 0), + PLL_36XX_RATE(24 * MHZ, 74250000, 99, 2, 4, 0), + PLL_36XX_RATE(24 * MHZ, 74176002, 98, 2, 4, 59070), + PLL_36XX_RATE(24 * MHZ, 54054000, 216, 3, 5, 14156), + PLL_36XX_RATE(24 * MHZ, 54000000, 144, 2, 5, 0), { /* sentinel */ } }; diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index 134f25f2a913..0421960eb963 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -1266,77 +1266,78 @@ static const struct of_device_id ext_clk_match[] __initconst = { /* PLLs PMS values */ static const struct samsung_pll_rate_table exynos4210_apll_rates[] __initconst = { - PLL_45XX_RATE(1200000000, 150, 3, 1, 28), - PLL_45XX_RATE(1000000000, 250, 6, 1, 28), - PLL_45XX_RATE( 800000000, 200, 6, 1, 28), - PLL_45XX_RATE( 666857142, 389, 14, 1, 13), - PLL_45XX_RATE( 600000000, 100, 4, 1, 13), - PLL_45XX_RATE( 533000000, 533, 24, 1, 5), - PLL_45XX_RATE( 500000000, 250, 6, 2, 28), - PLL_45XX_RATE( 400000000, 200, 6, 2, 28), - PLL_45XX_RATE( 200000000, 200, 6, 3, 28), + PLL_4508_RATE(24 * MHZ, 1200000000, 150, 3, 1, 28), + PLL_4508_RATE(24 * MHZ, 1000000000, 250, 6, 1, 28), + PLL_4508_RATE(24 * MHZ, 800000000, 200, 6, 1, 28), + PLL_4508_RATE(24 * MHZ, 666857142, 389, 14, 1, 13), + PLL_4508_RATE(24 * MHZ, 600000000, 100, 4, 1, 13), + PLL_4508_RATE(24 * MHZ, 533000000, 533, 24, 1, 5), + PLL_4508_RATE(24 * MHZ, 500000000, 250, 6, 2, 28), + PLL_4508_RATE(24 * MHZ, 400000000, 200, 6, 2, 28), + PLL_4508_RATE(24 * MHZ, 200000000, 200, 6, 3, 28), { /* sentinel */ } }; static const struct samsung_pll_rate_table exynos4210_epll_rates[] __initconst = { - PLL_4600_RATE(192000000, 48, 3, 1, 0, 0), - PLL_4600_RATE(180633605, 45, 3, 1, 10381, 0), - PLL_4600_RATE(180000000, 45, 3, 1, 0, 0), - PLL_4600_RATE( 73727996, 73, 3, 3, 47710, 1), - PLL_4600_RATE( 67737602, 90, 4, 3, 20762, 1), - PLL_4600_RATE( 49151992, 49, 3, 3, 9961, 0), - PLL_4600_RATE( 45158401, 45, 3, 3, 10381, 0), + PLL_4600_RATE(24 * MHZ, 192000000, 48, 3, 1, 0, 0), + PLL_4600_RATE(24 * MHZ, 180633605, 45, 3, 1, 10381, 0), + PLL_4600_RATE(24 * MHZ, 180000000, 45, 3, 1, 0, 0), + PLL_4600_RATE(24 * MHZ, 73727996, 73, 3, 3, 47710, 1), + PLL_4600_RATE(24 * MHZ, 67737602, 90, 4, 3, 20762, 1), + PLL_4600_RATE(24 * MHZ, 49151992, 49, 3, 3, 9961, 0), + PLL_4600_RATE(24 * MHZ, 45158401, 45, 3, 3, 10381, 0), { /* sentinel */ } }; static const struct samsung_pll_rate_table exynos4210_vpll_rates[] __initconst = { - PLL_4650_RATE(360000000, 44, 3, 0, 1024, 0, 14, 0), - PLL_4650_RATE(324000000, 53, 2, 1, 1024, 1, 1, 1), - PLL_4650_RATE(259617187, 63, 3, 1, 1950, 0, 20, 1), - PLL_4650_RATE(110000000, 53, 3, 2, 2048, 0, 17, 0), - PLL_4650_RATE( 55360351, 53, 3, 3, 2417, 0, 17, 0), + PLL_4650_RATE(24 * MHZ, 360000000, 44, 3, 0, 1024, 0, 14, 0), + PLL_4650_RATE(24 * MHZ, 324000000, 53, 2, 1, 1024, 1, 1, 1), + PLL_4650_RATE(24 * MHZ, 259617187, 63, 3, 1, 1950, 0, 20, 1), + PLL_4650_RATE(24 * MHZ, 110000000, 53, 3, 2, 2048, 0, 17, 0), + PLL_4650_RATE(24 * MHZ, 55360351, 53, 3, 3, 2417, 0, 17, 0), { /* sentinel */ } }; static const struct samsung_pll_rate_table exynos4x12_apll_rates[] __initconst = { - PLL_35XX_RATE(1704000000, 213, 3, 0), - PLL_35XX_RATE(1600000000, 200, 3, 0), - PLL_35XX_RATE(1500000000, 250, 4, 0), - PLL_35XX_RATE(1400000000, 175, 3, 0), - PLL_35XX_RATE(1300000000, 325, 6, 0), - PLL_35XX_RATE(1200000000, 200, 4, 0), - PLL_35XX_RATE(1100000000, 275, 6, 0), - PLL_35XX_RATE(1000000000, 125, 3, 0), - PLL_35XX_RATE( 900000000, 150, 4, 0), - PLL_35XX_RATE( 800000000, 100, 3, 0), - PLL_35XX_RATE( 700000000, 175, 3, 1), - PLL_35XX_RATE( 600000000, 200, 4, 1), - PLL_35XX_RATE( 500000000, 125, 3, 1), - PLL_35XX_RATE( 400000000, 100, 3, 1), - PLL_35XX_RATE( 300000000, 200, 4, 2), - PLL_35XX_RATE( 200000000, 100, 3, 2), + PLL_35XX_RATE(24 * MHZ, 1704000000, 213, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1600000000, 200, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1500000000, 250, 4, 0), + PLL_35XX_RATE(24 * MHZ, 1400000000, 175, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1300000000, 325, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1200000000, 200, 4, 0), + PLL_35XX_RATE(24 * MHZ, 1100000000, 275, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1000000000, 125, 3, 0), + PLL_35XX_RATE(24 * MHZ, 900000000, 150, 4, 0), + PLL_35XX_RATE(24 * MHZ, 800000000, 100, 3, 0), + PLL_35XX_RATE(24 * MHZ, 700000000, 175, 3, 1), + PLL_35XX_RATE(24 * MHZ, 600000000, 200, 4, 1), + PLL_35XX_RATE(24 * MHZ, 500000000, 125, 3, 1), + PLL_35XX_RATE(24 * MHZ, 400000000, 100, 3, 1), + PLL_35XX_RATE(24 * MHZ, 300000000, 200, 4, 2), + PLL_35XX_RATE(24 * MHZ, 200000000, 100, 3, 2), { /* sentinel */ } }; static const struct samsung_pll_rate_table exynos4x12_epll_rates[] __initconst = { - PLL_36XX_RATE(192000000, 48, 3, 1, 0), - PLL_36XX_RATE(180633605, 45, 3, 1, 10381), - PLL_36XX_RATE(180000000, 45, 3, 1, 0), - PLL_36XX_RATE( 73727996, 73, 3, 3, 47710), - PLL_36XX_RATE( 67737602, 90, 4, 3, 20762), - PLL_36XX_RATE( 49151992, 49, 3, 3, 9961), - PLL_36XX_RATE( 45158401, 45, 3, 3, 10381), + PLL_36XX_RATE(24 * MHZ, 196608001, 197, 3, 3, -25690), + PLL_36XX_RATE(24 * MHZ, 192000000, 48, 3, 1, 0), + PLL_36XX_RATE(24 * MHZ, 180633605, 45, 3, 1, 10381), + PLL_36XX_RATE(24 * MHZ, 180000000, 45, 3, 1, 0), + PLL_36XX_RATE(24 * MHZ, 73727996, 73, 3, 3, 47710), + PLL_36XX_RATE(24 * MHZ, 67737602, 90, 4, 3, 20762), + PLL_36XX_RATE(24 * MHZ, 49151992, 49, 3, 3, 9961), + PLL_36XX_RATE(24 * MHZ, 45158401, 45, 3, 3, 10381), { /* sentinel */ } }; static const struct samsung_pll_rate_table exynos4x12_vpll_rates[] __initconst = { - PLL_36XX_RATE(533000000, 133, 3, 1, 16384), - PLL_36XX_RATE(440000000, 110, 3, 1, 0), - PLL_36XX_RATE(350000000, 175, 3, 2, 0), - PLL_36XX_RATE(266000000, 133, 3, 2, 0), - PLL_36XX_RATE(160000000, 160, 3, 3, 0), - PLL_36XX_RATE(106031250, 53, 3, 2, 1024), - PLL_36XX_RATE( 53015625, 53, 3, 3, 1024), + PLL_36XX_RATE(24 * MHZ, 533000000, 133, 3, 1, 16384), + PLL_36XX_RATE(24 * MHZ, 440000000, 110, 3, 1, 0), + PLL_36XX_RATE(24 * MHZ, 350000000, 175, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 266000000, 133, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 160000000, 160, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 106031250, 53, 3, 2, 1024), + PLL_36XX_RATE(24 * MHZ, 53015625, 53, 3, 3, 1024), { /* sentinel */ } }; diff --git a/drivers/clk/samsung/clk-exynos5-subcmu.c b/drivers/clk/samsung/clk-exynos5-subcmu.c new file mode 100644 index 000000000000..93306283d764 --- /dev/null +++ b/drivers/clk/samsung/clk-exynos5-subcmu.c @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2018 Samsung Electronics Co., Ltd. +// Author: Marek Szyprowski <m.szyprowski@samsung.com> +// Common Clock Framework support for Exynos5 power-domain dependent clocks + +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/pm_domain.h> +#include <linux/pm_runtime.h> + +#include "clk.h" +#include "clk-exynos5-subcmu.h" + +static struct samsung_clk_provider *ctx; +static const struct exynos5_subcmu_info *cmu; +static int nr_cmus; + +static void exynos5_subcmu_clk_save(void __iomem *base, + struct exynos5_subcmu_reg_dump *rd, + unsigned int num_regs) +{ + for (; num_regs > 0; --num_regs, ++rd) { + rd->save = readl(base + rd->offset); + writel((rd->save & ~rd->mask) | rd->value, base + rd->offset); + rd->save &= rd->mask; + } +}; + +static void exynos5_subcmu_clk_restore(void __iomem *base, + struct exynos5_subcmu_reg_dump *rd, + unsigned int num_regs) +{ + for (; num_regs > 0; --num_regs, ++rd) + writel((readl(base + rd->offset) & ~rd->mask) | rd->save, + base + rd->offset); +} + +static void exynos5_subcmu_defer_gate(struct samsung_clk_provider *ctx, + const struct samsung_gate_clock *list, int nr_clk) +{ + while (nr_clk--) + samsung_clk_add_lookup(ctx, ERR_PTR(-EPROBE_DEFER), list++->id); +} + +/* + * Pass the needed clock provider context and register sub-CMU clocks + * + * NOTE: This function has to be called from the main, OF_CLK_DECLARE- + * initialized clock provider driver. This happens very early during boot + * process. Then this driver, during core_initcall registers two platform + * drivers: one which binds to the same device-tree node as OF_CLK_DECLARE + * driver and second, for handling its per-domain child-devices. Those + * platform drivers are bound to their devices a bit later in arch_initcall, + * when OF-core populates all device-tree nodes. + */ +void exynos5_subcmus_init(struct samsung_clk_provider *_ctx, int _nr_cmus, + const struct exynos5_subcmu_info *_cmu) +{ + ctx = _ctx; + cmu = _cmu; + nr_cmus = _nr_cmus; + + for (; _nr_cmus--; _cmu++) { + exynos5_subcmu_defer_gate(ctx, _cmu->gate_clks, + _cmu->nr_gate_clks); + exynos5_subcmu_clk_save(ctx->reg_base, _cmu->suspend_regs, + _cmu->nr_suspend_regs); + } +} + +static int __maybe_unused exynos5_subcmu_suspend(struct device *dev) +{ + struct exynos5_subcmu_info *info = dev_get_drvdata(dev); + unsigned long flags; + + spin_lock_irqsave(&ctx->lock, flags); + exynos5_subcmu_clk_save(ctx->reg_base, info->suspend_regs, + info->nr_suspend_regs); + spin_unlock_irqrestore(&ctx->lock, flags); + + return 0; +} + +static int __maybe_unused exynos5_subcmu_resume(struct device *dev) +{ + struct exynos5_subcmu_info *info = dev_get_drvdata(dev); + unsigned long flags; + + spin_lock_irqsave(&ctx->lock, flags); + exynos5_subcmu_clk_restore(ctx->reg_base, info->suspend_regs, + info->nr_suspend_regs); + spin_unlock_irqrestore(&ctx->lock, flags); + + return 0; +} + +static int __init exynos5_subcmu_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct exynos5_subcmu_info *info = dev_get_drvdata(dev); + + pm_runtime_set_suspended(dev); + pm_runtime_enable(dev); + pm_runtime_get(dev); + + ctx->dev = dev; + samsung_clk_register_div(ctx, info->div_clks, info->nr_div_clks); + samsung_clk_register_gate(ctx, info->gate_clks, info->nr_gate_clks); + ctx->dev = NULL; + + pm_runtime_put_sync(dev); + + return 0; +} + +static const struct dev_pm_ops exynos5_subcmu_pm_ops = { + SET_RUNTIME_PM_OPS(exynos5_subcmu_suspend, + exynos5_subcmu_resume, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static struct platform_driver exynos5_subcmu_driver __refdata = { + .driver = { + .name = "exynos5-subcmu", + .suppress_bind_attrs = true, + .pm = &exynos5_subcmu_pm_ops, + }, + .probe = exynos5_subcmu_probe, +}; + +static int __init exynos5_clk_register_subcmu(struct device *parent, + const struct exynos5_subcmu_info *info, + struct device_node *pd_node) +{ + struct of_phandle_args genpdspec = { .np = pd_node }; + struct platform_device *pdev; + + pdev = platform_device_alloc(info->pd_name, -1); + pdev->dev.parent = parent; + pdev->driver_override = "exynos5-subcmu"; + platform_set_drvdata(pdev, (void *)info); + of_genpd_add_device(&genpdspec, &pdev->dev); + platform_device_add(pdev); + + return 0; +} + +static int __init exynos5_clk_probe(struct platform_device *pdev) +{ + struct device_node *np; + const char *name; + int i; + + for_each_compatible_node(np, NULL, "samsung,exynos4210-pd") { + if (of_property_read_string(np, "label", &name) < 0) + continue; + for (i = 0; i < nr_cmus; i++) + if (strcmp(cmu[i].pd_name, name) == 0) + exynos5_clk_register_subcmu(&pdev->dev, + &cmu[i], np); + } + return 0; +} + +static const struct of_device_id exynos5_clk_of_match[] = { + { .compatible = "samsung,exynos5250-clock", }, + { .compatible = "samsung,exynos5420-clock", }, + { .compatible = "samsung,exynos5800-clock", }, + { }, +}; + +static struct platform_driver exynos5_clk_driver __refdata = { + .driver = { + .name = "exynos5-clock", + .of_match_table = exynos5_clk_of_match, + .suppress_bind_attrs = true, + }, + .probe = exynos5_clk_probe, +}; + +static int __init exynos5_clk_drv_init(void) +{ + platform_driver_register(&exynos5_clk_driver); + platform_driver_register(&exynos5_subcmu_driver); + return 0; +} +core_initcall(exynos5_clk_drv_init); diff --git a/drivers/clk/samsung/clk-exynos5-subcmu.h b/drivers/clk/samsung/clk-exynos5-subcmu.h new file mode 100644 index 000000000000..755ee8aaa3de --- /dev/null +++ b/drivers/clk/samsung/clk-exynos5-subcmu.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __CLK_EXYNOS5_SUBCMU_H +#define __CLK_EXYNOS5_SUBCMU_H + +struct exynos5_subcmu_reg_dump { + u32 offset; + u32 value; + u32 mask; + u32 save; +}; + +struct exynos5_subcmu_info { + const struct samsung_div_clock *div_clks; + unsigned int nr_div_clks; + const struct samsung_gate_clock *gate_clks; + unsigned int nr_gate_clks; + struct exynos5_subcmu_reg_dump *suspend_regs; + unsigned int nr_suspend_regs; + const char *pd_name; +}; + +void exynos5_subcmus_init(struct samsung_clk_provider *ctx, int nr_cmus, + const struct exynos5_subcmu_info *cmu); + +#endif diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 9b073c98a891..347fd80c351b 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -18,6 +18,7 @@ #include "clk.h" #include "clk-cpu.h" +#include "clk-exynos5-subcmu.h" #define APLL_LOCK 0x0 #define APLL_CON0 0x100 @@ -560,6 +561,8 @@ static const struct samsung_gate_clock exynos5250_gate_clks[] __initconst = { 0), GATE(CLK_GSCL3, "gscl3", "mout_aclk266_gscl_sub", GATE_IP_GSCL, 3, 0, 0), + GATE(CLK_CAMIF_TOP, "camif_top", "mout_aclk266_gscl_sub", + GATE_IP_GSCL, 4, 0, 0), GATE(CLK_GSCL_WA, "gscl_wa", "div_gscl_wa", GATE_IP_GSCL, 5, 0, 0), GATE(CLK_GSCL_WB, "gscl_wb", "div_gscl_wb", GATE_IP_GSCL, 6, 0, 0), GATE(CLK_SMMU_GSCL0, "smmu_gscl0", "mout_aclk266_gscl_sub", @@ -570,18 +573,11 @@ static const struct samsung_gate_clock exynos5250_gate_clks[] __initconst = { GATE_IP_GSCL, 9, 0, 0), GATE(CLK_SMMU_GSCL3, "smmu_gscl3", "mout_aclk266_gscl_sub", GATE_IP_GSCL, 10, 0, 0), + GATE(CLK_SMMU_FIMC_LITE0, "smmu_fimc_lite0", "mout_aclk266_gscl_sub", + GATE_IP_GSCL, 11, 0, 0), + GATE(CLK_SMMU_FIMC_LITE1, "smmu_fimc_lite1", "mout_aclk266_gscl_sub", + GATE_IP_GSCL, 12, 0, 0), - GATE(CLK_FIMD1, "fimd1", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 0, 0, - 0), - GATE(CLK_MIE1, "mie1", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 1, 0, - 0), - GATE(CLK_DSIM0, "dsim0", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 3, 0, - 0), - GATE(CLK_DP, "dp", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 4, 0, 0), - GATE(CLK_MIXER, "mixer", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 5, 0, - 0), - GATE(CLK_HDMI, "hdmi", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 6, 0, - 0), GATE(CLK_MFC, "mfc", "mout_aclk333_sub", GATE_IP_MFC, 0, 0, 0), GATE(CLK_SMMU_MFCR, "smmu_mfcr", "mout_aclk333_sub", GATE_IP_MFC, 1, 0, @@ -671,10 +667,6 @@ static const struct samsung_gate_clock exynos5250_gate_clks[] __initconst = { GATE(CLK_WDT, "wdt", "div_aclk66", GATE_IP_PERIS, 19, 0, 0), GATE(CLK_RTC, "rtc", "div_aclk66", GATE_IP_PERIS, 20, 0, 0), GATE(CLK_TMU, "tmu", "div_aclk66", GATE_IP_PERIS, 21, 0, 0), - GATE(CLK_SMMU_TV, "smmu_tv", "mout_aclk200_disp1_sub", - GATE_IP_DISP1, 9, 0, 0), - GATE(CLK_SMMU_FIMD1, "smmu_fimd1", "mout_aclk200_disp1_sub", - GATE_IP_DISP1, 8, 0, 0), GATE(CLK_SMMU_2D, "smmu_2d", "div_aclk200", GATE_IP_ACP, 7, 0, 0), GATE(CLK_SMMU_FIMC_ISP, "smmu_fimc_isp", "mout_aclk_266_isp_sub", GATE_IP_ISP0, 8, 0, 0), @@ -698,48 +690,80 @@ static const struct samsung_gate_clock exynos5250_gate_clks[] __initconst = { GATE_IP_ISP1, 7, 0, 0), }; +static const struct samsung_gate_clock exynos5250_disp_gate_clks[] __initconst = { + GATE(CLK_FIMD1, "fimd1", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 0, 0, + 0), + GATE(CLK_MIE1, "mie1", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 1, 0, + 0), + GATE(CLK_DSIM0, "dsim0", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 3, 0, + 0), + GATE(CLK_DP, "dp", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 4, 0, 0), + GATE(CLK_MIXER, "mixer", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 5, 0, + 0), + GATE(CLK_HDMI, "hdmi", "mout_aclk200_disp1_sub", GATE_IP_DISP1, 6, 0, + 0), + GATE(CLK_SMMU_TV, "smmu_tv", "mout_aclk200_disp1_sub", + GATE_IP_DISP1, 9, 0, 0), + GATE(CLK_SMMU_FIMD1, "smmu_fimd1", "mout_aclk200_disp1_sub", + GATE_IP_DISP1, 8, 0, 0), +}; + +static struct exynos5_subcmu_reg_dump exynos5250_disp_suspend_regs[] = { + { GATE_IP_DISP1, 0xffffffff, 0xffffffff }, /* DISP1 gates */ + { SRC_TOP3, 0, BIT(4) }, /* MUX mout_aclk200_disp1_sub */ + { SRC_TOP3, 0, BIT(6) }, /* MUX mout_aclk300_disp1_sub */ +}; + +static const struct exynos5_subcmu_info exynos5250_disp_subcmu = { + .gate_clks = exynos5250_disp_gate_clks, + .nr_gate_clks = ARRAY_SIZE(exynos5250_disp_gate_clks), + .suspend_regs = exynos5250_disp_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(exynos5250_disp_suspend_regs), + .pd_name = "DISP1", +}; + static const struct samsung_pll_rate_table vpll_24mhz_tbl[] __initconst = { /* sorted in descending order */ /* PLL_36XX_RATE(rate, m, p, s, k) */ - PLL_36XX_RATE(266000000, 266, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 266000000, 266, 3, 3, 0), /* Not in UM, but need for eDP on snow */ - PLL_36XX_RATE(70500000, 94, 2, 4, 0), + PLL_36XX_RATE(24 * MHZ, 70500000, 94, 2, 4, 0), { }, }; static const struct samsung_pll_rate_table epll_24mhz_tbl[] __initconst = { /* sorted in descending order */ /* PLL_36XX_RATE(rate, m, p, s, k) */ - PLL_36XX_RATE(192000000, 64, 2, 2, 0), - PLL_36XX_RATE(180633600, 90, 3, 2, 20762), - PLL_36XX_RATE(180000000, 90, 3, 2, 0), - PLL_36XX_RATE(73728000, 98, 2, 4, 19923), - PLL_36XX_RATE(67737600, 90, 2, 4, 20762), - PLL_36XX_RATE(49152000, 98, 3, 4, 19923), - PLL_36XX_RATE(45158400, 90, 3, 4, 20762), - PLL_36XX_RATE(32768000, 131, 3, 5, 4719), + PLL_36XX_RATE(24 * MHZ, 192000000, 64, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 180633605, 90, 3, 2, 20762), + PLL_36XX_RATE(24 * MHZ, 180000000, 90, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 73728000, 98, 2, 4, 19923), + PLL_36XX_RATE(24 * MHZ, 67737602, 90, 2, 4, 20762), + PLL_36XX_RATE(24 * MHZ, 49152000, 98, 3, 4, 19923), + PLL_36XX_RATE(24 * MHZ, 45158401, 90, 3, 4, 20762), + PLL_36XX_RATE(24 * MHZ, 32768001, 131, 3, 5, 4719), { }, }; static const struct samsung_pll_rate_table apll_24mhz_tbl[] __initconst = { /* sorted in descending order */ - /* PLL_35XX_RATE(rate, m, p, s) */ - PLL_35XX_RATE(1700000000, 425, 6, 0), - PLL_35XX_RATE(1600000000, 200, 3, 0), - PLL_35XX_RATE(1500000000, 250, 4, 0), - PLL_35XX_RATE(1400000000, 175, 3, 0), - PLL_35XX_RATE(1300000000, 325, 6, 0), - PLL_35XX_RATE(1200000000, 200, 4, 0), - PLL_35XX_RATE(1100000000, 275, 6, 0), - PLL_35XX_RATE(1000000000, 125, 3, 0), - PLL_35XX_RATE(900000000, 150, 4, 0), - PLL_35XX_RATE(800000000, 100, 3, 0), - PLL_35XX_RATE(700000000, 175, 3, 1), - PLL_35XX_RATE(600000000, 200, 4, 1), - PLL_35XX_RATE(500000000, 125, 3, 1), - PLL_35XX_RATE(400000000, 100, 3, 1), - PLL_35XX_RATE(300000000, 200, 4, 2), - PLL_35XX_RATE(200000000, 100, 3, 2), + /* PLL_35XX_RATE(fin, rate, m, p, s) */ + PLL_35XX_RATE(24 * MHZ, 1700000000, 425, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1600000000, 200, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1500000000, 250, 4, 0), + PLL_35XX_RATE(24 * MHZ, 1400000000, 175, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1300000000, 325, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1200000000, 200, 4, 0), + PLL_35XX_RATE(24 * MHZ, 1100000000, 275, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1000000000, 125, 3, 0), + PLL_35XX_RATE(24 * MHZ, 900000000, 150, 4, 0), + PLL_35XX_RATE(24 * MHZ, 800000000, 100, 3, 0), + PLL_35XX_RATE(24 * MHZ, 700000000, 175, 3, 1), + PLL_35XX_RATE(24 * MHZ, 600000000, 200, 4, 1), + PLL_35XX_RATE(24 * MHZ, 500000000, 125, 3, 1), + PLL_35XX_RATE(24 * MHZ, 400000000, 100, 3, 1), + PLL_35XX_RATE(24 * MHZ, 300000000, 200, 4, 2), + PLL_35XX_RATE(24 * MHZ, 200000000, 100, 3, 2), }; static struct samsung_pll_clock exynos5250_plls[nr_plls] __initdata = { @@ -859,10 +883,11 @@ static void __init exynos5250_clk_init(struct device_node *np) __raw_writel(tmp, reg_base + PWR_CTRL2); exynos5250_clk_sleep_init(); + exynos5_subcmus_init(ctx, 1, &exynos5250_disp_subcmu); samsung_clk_of_add_provider(np, ctx); pr_info("Exynos5250: clock setup completed, armclk=%ld\n", _get_rate("div_arm2")); } -CLK_OF_DECLARE(exynos5250_clk, "samsung,exynos5250-clock", exynos5250_clk_init); +CLK_OF_DECLARE_DRIVER(exynos5250_clk, "samsung,exynos5250-clock", exynos5250_clk_init); diff --git a/drivers/clk/samsung/clk-exynos5260.c b/drivers/clk/samsung/clk-exynos5260.c index fd1d9bfc151b..2cc2583abd87 100644 --- a/drivers/clk/samsung/clk-exynos5260.c +++ b/drivers/clk/samsung/clk-exynos5260.c @@ -23,57 +23,57 @@ * DISP_PLL, EGL_PLL, KFC_PLL, MEM_PLL, BUS_PLL, MEDIA_PLL, G3D_PLL. */ static const struct samsung_pll_rate_table pll2550_24mhz_tbl[] __initconst = { - PLL_35XX_RATE(1700000000, 425, 6, 0), - PLL_35XX_RATE(1600000000, 200, 3, 0), - PLL_35XX_RATE(1500000000, 250, 4, 0), - PLL_35XX_RATE(1400000000, 175, 3, 0), - PLL_35XX_RATE(1300000000, 325, 6, 0), - PLL_35XX_RATE(1200000000, 400, 4, 1), - PLL_35XX_RATE(1100000000, 275, 3, 1), - PLL_35XX_RATE(1000000000, 250, 3, 1), - PLL_35XX_RATE(933000000, 311, 4, 1), - PLL_35XX_RATE(900000000, 300, 4, 1), - PLL_35XX_RATE(800000000, 200, 3, 1), - PLL_35XX_RATE(733000000, 733, 12, 1), - PLL_35XX_RATE(700000000, 175, 3, 1), - PLL_35XX_RATE(667000000, 667, 12, 1), - PLL_35XX_RATE(633000000, 211, 4, 1), - PLL_35XX_RATE(620000000, 310, 3, 2), - PLL_35XX_RATE(600000000, 400, 4, 2), - PLL_35XX_RATE(543000000, 362, 4, 2), - PLL_35XX_RATE(533000000, 533, 6, 2), - PLL_35XX_RATE(500000000, 250, 3, 2), - PLL_35XX_RATE(450000000, 300, 4, 2), - PLL_35XX_RATE(400000000, 200, 3, 2), - PLL_35XX_RATE(350000000, 175, 3, 2), - PLL_35XX_RATE(300000000, 400, 4, 3), - PLL_35XX_RATE(266000000, 266, 3, 3), - PLL_35XX_RATE(200000000, 200, 3, 3), - PLL_35XX_RATE(160000000, 160, 3, 3), + PLL_35XX_RATE(24 * MHZ, 1700000000, 425, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1600000000, 200, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1500000000, 250, 4, 0), + PLL_35XX_RATE(24 * MHZ, 1400000000, 175, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1300000000, 325, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1200000000, 400, 4, 1), + PLL_35XX_RATE(24 * MHZ, 1100000000, 275, 3, 1), + PLL_35XX_RATE(24 * MHZ, 1000000000, 250, 3, 1), + PLL_35XX_RATE(24 * MHZ, 933000000, 311, 4, 1), + PLL_35XX_RATE(24 * MHZ, 900000000, 300, 4, 1), + PLL_35XX_RATE(24 * MHZ, 800000000, 200, 3, 1), + PLL_35XX_RATE(24 * MHZ, 733000000, 733, 12, 1), + PLL_35XX_RATE(24 * MHZ, 700000000, 175, 3, 1), + PLL_35XX_RATE(24 * MHZ, 667000000, 667, 12, 1), + PLL_35XX_RATE(24 * MHZ, 633000000, 211, 4, 1), + PLL_35XX_RATE(24 * MHZ, 620000000, 310, 3, 2), + PLL_35XX_RATE(24 * MHZ, 600000000, 400, 4, 2), + PLL_35XX_RATE(24 * MHZ, 543000000, 362, 4, 2), + PLL_35XX_RATE(24 * MHZ, 533000000, 533, 6, 2), + PLL_35XX_RATE(24 * MHZ, 500000000, 250, 3, 2), + PLL_35XX_RATE(24 * MHZ, 450000000, 300, 4, 2), + PLL_35XX_RATE(24 * MHZ, 400000000, 200, 3, 2), + PLL_35XX_RATE(24 * MHZ, 350000000, 175, 3, 2), + PLL_35XX_RATE(24 * MHZ, 300000000, 400, 4, 3), + PLL_35XX_RATE(24 * MHZ, 266000000, 266, 3, 3), + PLL_35XX_RATE(24 * MHZ, 200000000, 200, 3, 3), + PLL_35XX_RATE(24 * MHZ, 160000000, 160, 3, 3), }; /* * Applicable for 2650 Type PLL for AUD_PLL. */ static const struct samsung_pll_rate_table pll2650_24mhz_tbl[] __initconst = { - PLL_36XX_RATE(1600000000, 200, 3, 0, 0), - PLL_36XX_RATE(1200000000, 100, 2, 0, 0), - PLL_36XX_RATE(1000000000, 250, 3, 1, 0), - PLL_36XX_RATE(800000000, 200, 3, 1, 0), - PLL_36XX_RATE(600000000, 100, 2, 1, 0), - PLL_36XX_RATE(532000000, 266, 3, 2, 0), - PLL_36XX_RATE(480000000, 160, 2, 2, 0), - PLL_36XX_RATE(432000000, 144, 2, 2, 0), - PLL_36XX_RATE(400000000, 200, 3, 2, 0), - PLL_36XX_RATE(394073130, 459, 7, 2, 49282), - PLL_36XX_RATE(333000000, 111, 2, 2, 0), - PLL_36XX_RATE(300000000, 100, 2, 2, 0), - PLL_36XX_RATE(266000000, 266, 3, 3, 0), - PLL_36XX_RATE(200000000, 200, 3, 3, 0), - PLL_36XX_RATE(166000000, 166, 3, 3, 0), - PLL_36XX_RATE(133000000, 266, 3, 4, 0), - PLL_36XX_RATE(100000000, 200, 3, 4, 0), - PLL_36XX_RATE(66000000, 176, 2, 5, 0), + PLL_36XX_RATE(24 * MHZ, 1600000000, 200, 3, 0, 0), + PLL_36XX_RATE(24 * MHZ, 1200000000, 100, 2, 0, 0), + PLL_36XX_RATE(24 * MHZ, 1000000000, 250, 3, 1, 0), + PLL_36XX_RATE(24 * MHZ, 800000000, 200, 3, 1, 0), + PLL_36XX_RATE(24 * MHZ, 600000000, 100, 2, 1, 0), + PLL_36XX_RATE(24 * MHZ, 532000000, 266, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 480000000, 160, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 432000000, 144, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 400000000, 200, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 394073128, 459, 7, 2, 49282), + PLL_36XX_RATE(24 * MHZ, 333000000, 111, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 300000000, 100, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 266000000, 266, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 200000000, 200, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 166000000, 166, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 133000000, 266, 3, 4, 0), + PLL_36XX_RATE(24 * MHZ, 100000000, 200, 3, 4, 0), + PLL_36XX_RATE(24 * MHZ, 66000000, 176, 2, 5, 0), }; /* CMU_AUD */ diff --git a/drivers/clk/samsung/clk-exynos5410.c b/drivers/clk/samsung/clk-exynos5410.c index fc471a49e8f4..0a0b09591e6f 100644 --- a/drivers/clk/samsung/clk-exynos5410.c +++ b/drivers/clk/samsung/clk-exynos5410.c @@ -226,16 +226,16 @@ static const struct samsung_gate_clock exynos5410_gate_clks[] __initconst = { }; static const struct samsung_pll_rate_table exynos5410_pll2550x_24mhz_tbl[] __initconst = { - PLL_36XX_RATE(400000000U, 200, 3, 2, 0), - PLL_36XX_RATE(333000000U, 111, 2, 2, 0), - PLL_36XX_RATE(300000000U, 100, 2, 2, 0), - PLL_36XX_RATE(266000000U, 266, 3, 3, 0), - PLL_36XX_RATE(200000000U, 200, 3, 3, 0), - PLL_36XX_RATE(192000000U, 192, 3, 3, 0), - PLL_36XX_RATE(166000000U, 166, 3, 3, 0), - PLL_36XX_RATE(133000000U, 266, 3, 4, 0), - PLL_36XX_RATE(100000000U, 200, 3, 4, 0), - PLL_36XX_RATE(66000000U, 176, 2, 5, 0), + PLL_36XX_RATE(24 * MHZ, 400000000U, 200, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 333000000U, 111, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 300000000U, 100, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 266000000U, 266, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 200000000U, 200, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 192000000U, 192, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 166000000U, 166, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 133000000U, 266, 3, 4, 0), + PLL_36XX_RATE(24 * MHZ, 100000000U, 200, 3, 4, 0), + PLL_36XX_RATE(24 * MHZ, 66000000U, 176, 2, 5, 0), }; static struct samsung_pll_clock exynos5410_plls[nr_plls] __initdata = { diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index 45d34f601e9e..95e1bf69449b 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -19,6 +19,7 @@ #include "clk.h" #include "clk-cpu.h" +#include "clk-exynos5-subcmu.h" #define APLL_LOCK 0x0 #define APLL_CON0 0x100 @@ -620,7 +621,8 @@ static const struct samsung_mux_clock exynos5420_mux_clks[] __initconst = { MUX(CLK_MOUT_MX_MSPLL_CCORE, "mout_mx_mspll_ccore", mout_group5_5800_p, SRC_TOP7, 16, 2), - MUX(0, "mout_mau_epll_clk", mout_mau_epll_clk_p, SRC_TOP7, 20, 2), + MUX_F(0, "mout_mau_epll_clk", mout_mau_epll_clk_p, SRC_TOP7, 20, 2, + CLK_SET_RATE_PARENT, 0), MUX(0, "mout_fimd1", mout_group3_p, SRC_DISP10, 4, 1), }; @@ -863,7 +865,6 @@ static const struct samsung_div_clock exynos5x_div_clks[] __initconst = { DIV(0, "dout_mipi1", "mout_mipi1", DIV_DISP10, 16, 8), DIV(0, "dout_dp1", "mout_dp1", DIV_DISP10, 24, 4), DIV(CLK_DOUT_PIXEL, "dout_hdmi_pixel", "mout_pixel", DIV_DISP10, 28, 4), - DIV(0, "dout_disp1_blk", "aclk200_disp1", DIV2_RATIO0, 16, 2), DIV(CLK_DOUT_ACLK400_DISP1, "dout_aclk400_disp1", "mout_aclk400_disp1", DIV_TOP2, 4, 3), @@ -912,8 +913,6 @@ static const struct samsung_div_clock exynos5x_div_clks[] __initconst = { DIV(0, "dout_spi1", "mout_spi1", DIV_PERIC1, 24, 4), DIV(0, "dout_spi2", "mout_spi2", DIV_PERIC1, 28, 4), - /* Mfc Block */ - DIV(0, "dout_mfc_blk", "mout_user_aclk333", DIV4_RATIO, 0, 2), /* PCM */ DIV(0, "dout_pcm1", "dout_audio1", DIV_PERIC2, 16, 8), @@ -932,8 +931,6 @@ static const struct samsung_div_clock exynos5x_div_clks[] __initconst = { DIV(0, "dout_spi2_pre", "dout_spi2", DIV_PERIC4, 24, 8), /* GSCL Block */ - DIV(0, "dout_gscl_blk_300", "mout_user_aclk300_gscl", - DIV2_RATIO0, 4, 2), DIV(0, "dout_gscl_blk_333", "aclk333_432_gscl", DIV2_RATIO0, 6, 2), /* MSCL Block */ @@ -1190,8 +1187,6 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = { GATE(CLK_SCLK_GSCL_WB, "sclk_gscl_wb", "mout_user_aclk333_432_gscl", GATE_TOP_SCLK_GSCL, 7, 0, 0), - GATE(CLK_GSCL0, "gscl0", "aclk300_gscl", GATE_IP_GSCL0, 0, 0, 0), - GATE(CLK_GSCL1, "gscl1", "aclk300_gscl", GATE_IP_GSCL0, 1, 0, 0), GATE(CLK_FIMC_3AA, "fimc_3aa", "aclk333_432_gscl", GATE_IP_GSCL0, 4, 0, 0), GATE(CLK_FIMC_LITE0, "fimc_lite0", "aclk333_432_gscl", @@ -1205,10 +1200,6 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = { GATE_IP_GSCL1, 3, 0, 0), GATE(CLK_SMMU_FIMCL1, "smmu_fimcl1", "dout_gscl_blk_333", GATE_IP_GSCL1, 4, 0, 0), - GATE(CLK_SMMU_GSCL0, "smmu_gscl0", "dout_gscl_blk_300", - GATE_IP_GSCL1, 6, 0, 0), - GATE(CLK_SMMU_GSCL1, "smmu_gscl1", "dout_gscl_blk_300", - GATE_IP_GSCL1, 7, 0, 0), GATE(CLK_GSCL_WA, "gscl_wa", "sclk_gscl_wa", GATE_IP_GSCL1, 12, 0, 0), GATE(CLK_GSCL_WB, "gscl_wb", "sclk_gscl_wb", GATE_IP_GSCL1, 13, 0, 0), GATE(CLK_SMMU_FIMCL3, "smmu_fimcl3,", "dout_gscl_blk_333", @@ -1227,18 +1218,6 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = { GATE(CLK_SMMU_MSCL2, "smmu_mscl2", "dout_mscl_blk", GATE_IP_MSCL, 10, 0, 0), - GATE(CLK_FIMD1, "fimd1", "aclk300_disp1", GATE_IP_DISP1, 0, 0, 0), - GATE(CLK_DSIM1, "dsim1", "aclk200_disp1", GATE_IP_DISP1, 3, 0, 0), - GATE(CLK_DP1, "dp1", "aclk200_disp1", GATE_IP_DISP1, 4, 0, 0), - GATE(CLK_MIXER, "mixer", "aclk200_disp1", GATE_IP_DISP1, 5, 0, 0), - GATE(CLK_HDMI, "hdmi", "aclk200_disp1", GATE_IP_DISP1, 6, 0, 0), - GATE(CLK_SMMU_FIMD1M0, "smmu_fimd1m0", "dout_disp1_blk", - GATE_IP_DISP1, 7, 0, 0), - GATE(CLK_SMMU_FIMD1M1, "smmu_fimd1m1", "dout_disp1_blk", - GATE_IP_DISP1, 8, 0, 0), - GATE(CLK_SMMU_MIXER, "smmu_mixer", "aclk200_disp1", - GATE_IP_DISP1, 9, 0, 0), - /* ISP */ GATE(CLK_SCLK_UART_ISP, "sclk_uart_isp", "dout_uart_isp", GATE_TOP_SCLK_ISP, 0, CLK_SET_RATE_PARENT, 0), @@ -1255,48 +1234,138 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = { GATE(CLK_SCLK_ISP_SENSOR2, "sclk_isp_sensor2", "dout_isp_sensor2", GATE_TOP_SCLK_ISP, 12, CLK_SET_RATE_PARENT, 0), + GATE(CLK_G3D, "g3d", "mout_user_aclk_g3d", GATE_IP_G3D, 9, 0, 0), +}; + +static const struct samsung_div_clock exynos5x_disp_div_clks[] __initconst = { + DIV(0, "dout_disp1_blk", "aclk200_disp1", DIV2_RATIO0, 16, 2), +}; + +static const struct samsung_gate_clock exynos5x_disp_gate_clks[] __initconst = { + GATE(CLK_FIMD1, "fimd1", "aclk300_disp1", GATE_IP_DISP1, 0, 0, 0), + GATE(CLK_DSIM1, "dsim1", "aclk200_disp1", GATE_IP_DISP1, 3, 0, 0), + GATE(CLK_DP1, "dp1", "aclk200_disp1", GATE_IP_DISP1, 4, 0, 0), + GATE(CLK_MIXER, "mixer", "aclk200_disp1", GATE_IP_DISP1, 5, 0, 0), + GATE(CLK_HDMI, "hdmi", "aclk200_disp1", GATE_IP_DISP1, 6, 0, 0), + GATE(CLK_SMMU_FIMD1M0, "smmu_fimd1m0", "dout_disp1_blk", + GATE_IP_DISP1, 7, 0, 0), + GATE(CLK_SMMU_FIMD1M1, "smmu_fimd1m1", "dout_disp1_blk", + GATE_IP_DISP1, 8, 0, 0), + GATE(CLK_SMMU_MIXER, "smmu_mixer", "aclk200_disp1", + GATE_IP_DISP1, 9, 0, 0), +}; + +static struct exynos5_subcmu_reg_dump exynos5x_disp_suspend_regs[] = { + { GATE_IP_DISP1, 0xffffffff, 0xffffffff }, /* DISP1 gates */ + { SRC_TOP5, 0, BIT(0) }, /* MUX mout_user_aclk400_disp1 */ + { SRC_TOP5, 0, BIT(24) }, /* MUX mout_user_aclk300_disp1 */ + { SRC_TOP3, 0, BIT(8) }, /* MUX mout_user_aclk200_disp1 */ + { DIV2_RATIO0, 0, 0x30000 }, /* DIV dout_disp1_blk */ +}; + +static const struct samsung_div_clock exynos5x_gsc_div_clks[] __initconst = { + DIV(0, "dout_gscl_blk_300", "mout_user_aclk300_gscl", + DIV2_RATIO0, 4, 2), +}; + +static const struct samsung_gate_clock exynos5x_gsc_gate_clks[] __initconst = { + GATE(CLK_GSCL0, "gscl0", "aclk300_gscl", GATE_IP_GSCL0, 0, 0, 0), + GATE(CLK_GSCL1, "gscl1", "aclk300_gscl", GATE_IP_GSCL0, 1, 0, 0), + GATE(CLK_SMMU_GSCL0, "smmu_gscl0", "dout_gscl_blk_300", + GATE_IP_GSCL1, 6, 0, 0), + GATE(CLK_SMMU_GSCL1, "smmu_gscl1", "dout_gscl_blk_300", + GATE_IP_GSCL1, 7, 0, 0), +}; + +static struct exynos5_subcmu_reg_dump exynos5x_gsc_suspend_regs[] = { + { GATE_IP_GSCL0, 0x3, 0x3 }, /* GSC gates */ + { GATE_IP_GSCL1, 0xc0, 0xc0 }, /* GSC gates */ + { SRC_TOP5, 0, BIT(28) }, /* MUX mout_user_aclk300_gscl */ + { DIV2_RATIO0, 0, 0x30 }, /* DIV dout_gscl_blk_300 */ +}; + +static const struct samsung_div_clock exynos5x_mfc_div_clks[] __initconst = { + DIV(0, "dout_mfc_blk", "mout_user_aclk333", DIV4_RATIO, 0, 2), +}; + +static const struct samsung_gate_clock exynos5x_mfc_gate_clks[] __initconst = { GATE(CLK_MFC, "mfc", "aclk333", GATE_IP_MFC, 0, 0, 0), GATE(CLK_SMMU_MFCL, "smmu_mfcl", "dout_mfc_blk", GATE_IP_MFC, 1, 0, 0), GATE(CLK_SMMU_MFCR, "smmu_mfcr", "dout_mfc_blk", GATE_IP_MFC, 2, 0, 0), +}; - GATE(CLK_G3D, "g3d", "mout_user_aclk_g3d", GATE_IP_G3D, 9, 0, 0), +static struct exynos5_subcmu_reg_dump exynos5x_mfc_suspend_regs[] = { + { GATE_IP_MFC, 0xffffffff, 0xffffffff }, /* MFC gates */ + { SRC_TOP4, 0, BIT(28) }, /* MUX mout_user_aclk333 */ + { DIV4_RATIO, 0, 0x3 }, /* DIV dout_mfc_blk */ +}; + +static const struct exynos5_subcmu_info exynos5x_subcmus[] = { + { + .div_clks = exynos5x_disp_div_clks, + .nr_div_clks = ARRAY_SIZE(exynos5x_disp_div_clks), + .gate_clks = exynos5x_disp_gate_clks, + .nr_gate_clks = ARRAY_SIZE(exynos5x_disp_gate_clks), + .suspend_regs = exynos5x_disp_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(exynos5x_disp_suspend_regs), + .pd_name = "DISP", + }, { + .div_clks = exynos5x_gsc_div_clks, + .nr_div_clks = ARRAY_SIZE(exynos5x_gsc_div_clks), + .gate_clks = exynos5x_gsc_gate_clks, + .nr_gate_clks = ARRAY_SIZE(exynos5x_gsc_gate_clks), + .suspend_regs = exynos5x_gsc_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(exynos5x_gsc_suspend_regs), + .pd_name = "GSC", + }, { + .div_clks = exynos5x_mfc_div_clks, + .nr_div_clks = ARRAY_SIZE(exynos5x_mfc_div_clks), + .gate_clks = exynos5x_mfc_gate_clks, + .nr_gate_clks = ARRAY_SIZE(exynos5x_mfc_gate_clks), + .suspend_regs = exynos5x_mfc_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(exynos5x_mfc_suspend_regs), + .pd_name = "MFC", + }, }; static const struct samsung_pll_rate_table exynos5420_pll2550x_24mhz_tbl[] __initconst = { - PLL_35XX_RATE(2000000000, 250, 3, 0), - PLL_35XX_RATE(1900000000, 475, 6, 0), - PLL_35XX_RATE(1800000000, 225, 3, 0), - PLL_35XX_RATE(1700000000, 425, 6, 0), - PLL_35XX_RATE(1600000000, 200, 3, 0), - PLL_35XX_RATE(1500000000, 250, 4, 0), - PLL_35XX_RATE(1400000000, 175, 3, 0), - PLL_35XX_RATE(1300000000, 325, 6, 0), - PLL_35XX_RATE(1200000000, 200, 2, 1), - PLL_35XX_RATE(1100000000, 275, 3, 1), - PLL_35XX_RATE(1000000000, 250, 3, 1), - PLL_35XX_RATE(900000000, 150, 2, 1), - PLL_35XX_RATE(800000000, 200, 3, 1), - PLL_35XX_RATE(700000000, 175, 3, 1), - PLL_35XX_RATE(600000000, 200, 2, 2), - PLL_35XX_RATE(500000000, 250, 3, 2), - PLL_35XX_RATE(400000000, 200, 3, 2), - PLL_35XX_RATE(300000000, 200, 2, 3), - PLL_35XX_RATE(200000000, 200, 3, 3), + PLL_35XX_RATE(24 * MHZ, 2000000000, 250, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1900000000, 475, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1800000000, 225, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1700000000, 425, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1600000000, 200, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1500000000, 250, 4, 0), + PLL_35XX_RATE(24 * MHZ, 1400000000, 175, 3, 0), + PLL_35XX_RATE(24 * MHZ, 1300000000, 325, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1200000000, 200, 2, 1), + PLL_35XX_RATE(24 * MHZ, 1100000000, 275, 3, 1), + PLL_35XX_RATE(24 * MHZ, 1000000000, 250, 3, 1), + PLL_35XX_RATE(24 * MHZ, 900000000, 150, 2, 1), + PLL_35XX_RATE(24 * MHZ, 800000000, 200, 3, 1), + PLL_35XX_RATE(24 * MHZ, 700000000, 175, 3, 1), + PLL_35XX_RATE(24 * MHZ, 600000000, 200, 2, 2), + PLL_35XX_RATE(24 * MHZ, 500000000, 250, 3, 2), + PLL_35XX_RATE(24 * MHZ, 400000000, 200, 3, 2), + PLL_35XX_RATE(24 * MHZ, 300000000, 200, 2, 3), + PLL_35XX_RATE(24 * MHZ, 200000000, 200, 3, 3), }; static const struct samsung_pll_rate_table exynos5420_epll_24mhz_tbl[] = { - PLL_36XX_RATE(600000000U, 100, 2, 1, 0), - PLL_36XX_RATE(400000000U, 200, 3, 2, 0), - PLL_36XX_RATE(393216003U, 197, 3, 2, -25690), - PLL_36XX_RATE(361267218U, 301, 5, 2, 3671), - PLL_36XX_RATE(200000000U, 200, 3, 3, 0), - PLL_36XX_RATE(196608001U, 197, 3, 3, -25690), - PLL_36XX_RATE(180633609U, 301, 5, 3, 3671), - PLL_36XX_RATE(131072006U, 131, 3, 3, 4719), - PLL_36XX_RATE(100000000U, 200, 3, 4, 0), - PLL_36XX_RATE( 65536003U, 131, 3, 4, 4719), - PLL_36XX_RATE( 49152000U, 197, 3, 5, -25690), - PLL_36XX_RATE( 32768001U, 131, 3, 5, 4719), + PLL_36XX_RATE(24 * MHZ, 600000000U, 100, 2, 1, 0), + PLL_36XX_RATE(24 * MHZ, 400000000U, 200, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 393216003U, 197, 3, 2, -25690), + PLL_36XX_RATE(24 * MHZ, 361267218U, 301, 5, 2, 3671), + PLL_36XX_RATE(24 * MHZ, 200000000U, 200, 3, 3, 0), + PLL_36XX_RATE(24 * MHZ, 196608001U, 197, 3, 3, -25690), + PLL_36XX_RATE(24 * MHZ, 180633609U, 301, 5, 3, 3671), + PLL_36XX_RATE(24 * MHZ, 131072006U, 131, 3, 3, 4719), + PLL_36XX_RATE(24 * MHZ, 100000000U, 200, 3, 4, 0), + PLL_36XX_RATE(24 * MHZ, 73728000U, 98, 2, 4, 19923), + PLL_36XX_RATE(24 * MHZ, 67737602U, 90, 2, 4, 20762), + PLL_36XX_RATE(24 * MHZ, 65536003U, 131, 3, 4, 4719), + PLL_36XX_RATE(24 * MHZ, 49152000U, 197, 3, 5, -25690), + PLL_36XX_RATE(24 * MHZ, 45158401U, 90, 3, 4, 20762), + PLL_36XX_RATE(24 * MHZ, 32768001U, 131, 3, 5, 4719), }; static struct samsung_pll_clock exynos5x_plls[nr_plls] __initdata = { @@ -1472,6 +1541,8 @@ static void __init exynos5x_clk_init(struct device_node *np, exynos5420_kfcclk_d, ARRAY_SIZE(exynos5420_kfcclk_d), 0); exynos5420_clk_sleep_init(); + exynos5_subcmus_init(ctx, ARRAY_SIZE(exynos5x_subcmus), + exynos5x_subcmus); samsung_clk_of_add_provider(np, ctx); } @@ -1480,10 +1551,12 @@ static void __init exynos5420_clk_init(struct device_node *np) { exynos5x_clk_init(np, EXYNOS5420); } -CLK_OF_DECLARE(exynos5420_clk, "samsung,exynos5420-clock", exynos5420_clk_init); +CLK_OF_DECLARE_DRIVER(exynos5420_clk, "samsung,exynos5420-clock", + exynos5420_clk_init); static void __init exynos5800_clk_init(struct device_node *np) { exynos5x_clk_init(np, EXYNOS5800); } -CLK_OF_DECLARE(exynos5800_clk, "samsung,exynos5800-clock", exynos5800_clk_init); +CLK_OF_DECLARE_DRIVER(exynos5800_clk, "samsung,exynos5800-clock", + exynos5800_clk_init); diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index db270908037a..5305ace514b2 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -703,68 +703,69 @@ static const struct samsung_gate_clock top_gate_clks[] __initconst = { * & MPHY_PLL & G3D_PLL & DISP_PLL & ISP_PLL */ static const struct samsung_pll_rate_table exynos5433_pll_rates[] __initconst = { - PLL_35XX_RATE(2500000000U, 625, 6, 0), - PLL_35XX_RATE(2400000000U, 500, 5, 0), - PLL_35XX_RATE(2300000000U, 575, 6, 0), - PLL_35XX_RATE(2200000000U, 550, 6, 0), - PLL_35XX_RATE(2100000000U, 350, 4, 0), - PLL_35XX_RATE(2000000000U, 500, 6, 0), - PLL_35XX_RATE(1900000000U, 475, 6, 0), - PLL_35XX_RATE(1800000000U, 375, 5, 0), - PLL_35XX_RATE(1700000000U, 425, 6, 0), - PLL_35XX_RATE(1600000000U, 400, 6, 0), - PLL_35XX_RATE(1500000000U, 250, 4, 0), - PLL_35XX_RATE(1400000000U, 350, 6, 0), - PLL_35XX_RATE(1332000000U, 222, 4, 0), - PLL_35XX_RATE(1300000000U, 325, 6, 0), - PLL_35XX_RATE(1200000000U, 500, 5, 1), - PLL_35XX_RATE(1100000000U, 550, 6, 1), - PLL_35XX_RATE(1086000000U, 362, 4, 1), - PLL_35XX_RATE(1066000000U, 533, 6, 1), - PLL_35XX_RATE(1000000000U, 500, 6, 1), - PLL_35XX_RATE(933000000U, 311, 4, 1), - PLL_35XX_RATE(921000000U, 307, 4, 1), - PLL_35XX_RATE(900000000U, 375, 5, 1), - PLL_35XX_RATE(825000000U, 275, 4, 1), - PLL_35XX_RATE(800000000U, 400, 6, 1), - PLL_35XX_RATE(733000000U, 733, 12, 1), - PLL_35XX_RATE(700000000U, 175, 3, 1), - PLL_35XX_RATE(667000000U, 222, 4, 1), - PLL_35XX_RATE(633000000U, 211, 4, 1), - PLL_35XX_RATE(600000000U, 500, 5, 2), - PLL_35XX_RATE(552000000U, 460, 5, 2), - PLL_35XX_RATE(550000000U, 550, 6, 2), - PLL_35XX_RATE(543000000U, 362, 4, 2), - PLL_35XX_RATE(533000000U, 533, 6, 2), - PLL_35XX_RATE(500000000U, 500, 6, 2), - PLL_35XX_RATE(444000000U, 370, 5, 2), - PLL_35XX_RATE(420000000U, 350, 5, 2), - PLL_35XX_RATE(400000000U, 400, 6, 2), - PLL_35XX_RATE(350000000U, 350, 6, 2), - PLL_35XX_RATE(333000000U, 222, 4, 2), - PLL_35XX_RATE(300000000U, 500, 5, 3), - PLL_35XX_RATE(278000000U, 556, 6, 3), - PLL_35XX_RATE(266000000U, 532, 6, 3), - PLL_35XX_RATE(250000000U, 500, 6, 3), - PLL_35XX_RATE(200000000U, 400, 6, 3), - PLL_35XX_RATE(166000000U, 332, 6, 3), - PLL_35XX_RATE(160000000U, 320, 6, 3), - PLL_35XX_RATE(133000000U, 532, 6, 4), - PLL_35XX_RATE(100000000U, 400, 6, 4), + PLL_35XX_RATE(24 * MHZ, 2500000000U, 625, 6, 0), + PLL_35XX_RATE(24 * MHZ, 2400000000U, 500, 5, 0), + PLL_35XX_RATE(24 * MHZ, 2300000000U, 575, 6, 0), + PLL_35XX_RATE(24 * MHZ, 2200000000U, 550, 6, 0), + PLL_35XX_RATE(24 * MHZ, 2100000000U, 350, 4, 0), + PLL_35XX_RATE(24 * MHZ, 2000000000U, 500, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1900000000U, 475, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1800000000U, 375, 5, 0), + PLL_35XX_RATE(24 * MHZ, 1700000000U, 425, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1600000000U, 400, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1500000000U, 250, 4, 0), + PLL_35XX_RATE(24 * MHZ, 1400000000U, 350, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1332000000U, 222, 4, 0), + PLL_35XX_RATE(24 * MHZ, 1300000000U, 325, 6, 0), + PLL_35XX_RATE(24 * MHZ, 1200000000U, 500, 5, 1), + PLL_35XX_RATE(24 * MHZ, 1100000000U, 550, 6, 1), + PLL_35XX_RATE(24 * MHZ, 1086000000U, 362, 4, 1), + PLL_35XX_RATE(24 * MHZ, 1066000000U, 533, 6, 1), + PLL_35XX_RATE(24 * MHZ, 1000000000U, 500, 6, 1), + PLL_35XX_RATE(24 * MHZ, 933000000U, 311, 4, 1), + PLL_35XX_RATE(24 * MHZ, 921000000U, 307, 4, 1), + PLL_35XX_RATE(24 * MHZ, 900000000U, 375, 5, 1), + PLL_35XX_RATE(24 * MHZ, 825000000U, 275, 4, 1), + PLL_35XX_RATE(24 * MHZ, 800000000U, 400, 6, 1), + PLL_35XX_RATE(24 * MHZ, 733000000U, 733, 12, 1), + PLL_35XX_RATE(24 * MHZ, 700000000U, 175, 3, 1), + PLL_35XX_RATE(24 * MHZ, 666000000U, 222, 4, 1), + PLL_35XX_RATE(24 * MHZ, 633000000U, 211, 4, 1), + PLL_35XX_RATE(24 * MHZ, 600000000U, 500, 5, 2), + PLL_35XX_RATE(24 * MHZ, 552000000U, 460, 5, 2), + PLL_35XX_RATE(24 * MHZ, 550000000U, 550, 6, 2), + PLL_35XX_RATE(24 * MHZ, 543000000U, 362, 4, 2), + PLL_35XX_RATE(24 * MHZ, 533000000U, 533, 6, 2), + PLL_35XX_RATE(24 * MHZ, 500000000U, 500, 6, 2), + PLL_35XX_RATE(24 * MHZ, 444000000U, 370, 5, 2), + PLL_35XX_RATE(24 * MHZ, 420000000U, 350, 5, 2), + PLL_35XX_RATE(24 * MHZ, 400000000U, 400, 6, 2), + PLL_35XX_RATE(24 * MHZ, 350000000U, 350, 6, 2), + PLL_35XX_RATE(24 * MHZ, 333000000U, 222, 4, 2), + PLL_35XX_RATE(24 * MHZ, 300000000U, 500, 5, 3), + PLL_35XX_RATE(24 * MHZ, 278000000U, 556, 6, 3), + PLL_35XX_RATE(24 * MHZ, 266000000U, 532, 6, 3), + PLL_35XX_RATE(24 * MHZ, 250000000U, 500, 6, 3), + PLL_35XX_RATE(24 * MHZ, 200000000U, 400, 6, 3), + PLL_35XX_RATE(24 * MHZ, 166000000U, 332, 6, 3), + PLL_35XX_RATE(24 * MHZ, 160000000U, 320, 6, 3), + PLL_35XX_RATE(24 * MHZ, 133000000U, 532, 6, 4), + PLL_35XX_RATE(24 * MHZ, 100000000U, 400, 6, 4), { /* sentinel */ } }; /* AUD_PLL */ static const struct samsung_pll_rate_table exynos5433_aud_pll_rates[] __initconst = { - PLL_36XX_RATE(400000000U, 200, 3, 2, 0), - PLL_36XX_RATE(393216000U, 197, 3, 2, -25690), - PLL_36XX_RATE(384000000U, 128, 2, 2, 0), - PLL_36XX_RATE(368640000U, 246, 4, 2, -15729), - PLL_36XX_RATE(361507200U, 181, 3, 2, -16148), - PLL_36XX_RATE(338688000U, 113, 2, 2, -6816), - PLL_36XX_RATE(294912000U, 98, 1, 3, 19923), - PLL_36XX_RATE(288000000U, 96, 1, 3, 0), - PLL_36XX_RATE(252000000U, 84, 1, 3, 0), + PLL_36XX_RATE(24 * MHZ, 400000000U, 200, 3, 2, 0), + PLL_36XX_RATE(24 * MHZ, 393216003U, 197, 3, 2, -25690), + PLL_36XX_RATE(24 * MHZ, 384000000U, 128, 2, 2, 0), + PLL_36XX_RATE(24 * MHZ, 368639991U, 246, 4, 2, -15729), + PLL_36XX_RATE(24 * MHZ, 361507202U, 181, 3, 2, -16148), + PLL_36XX_RATE(24 * MHZ, 338687988U, 113, 2, 2, -6816), + PLL_36XX_RATE(24 * MHZ, 294912002U, 98, 1, 3, 19923), + PLL_36XX_RATE(24 * MHZ, 288000000U, 96, 1, 3, 0), + PLL_36XX_RATE(24 * MHZ, 252000000U, 84, 1, 3, 0), + PLL_36XX_RATE(24 * MHZ, 196608001U, 197, 3, 3, -25690), { /* sentinel */ } }; @@ -1672,7 +1673,7 @@ static const struct samsung_gate_clock peric_gate_clks[] __initconst = { ENABLE_SCLK_PERIC, 11, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_IOCLK_I2S1_BCLK, "sclk_ioclk_i2s1_bclk", "ioclk_i2s1_bclk_in", ENABLE_SCLK_PERIC, 10, - CLK_SET_RATE_PARENT, 0), + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0), GATE(CLK_SCLK_SPDIF, "sclk_spdif", "sclk_spdif_peric", ENABLE_SCLK_PERIC, 8, CLK_SET_RATE_PARENT, 0), GATE(CLK_SCLK_PCM1, "sclk_pcm1", "sclk_pcm1_peric", @@ -5513,10 +5514,8 @@ static int __init exynos5433_cmu_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); reg_base = devm_ioremap_resource(dev, res); - if (IS_ERR(reg_base)) { - dev_err(dev, "failed to map registers\n"); + if (IS_ERR(reg_base)) return PTR_ERR(reg_base); - } for (i = 0; i < info->nr_clk_ids; ++i) ctx->clk_data.hws[i] = ERR_PTR(-ENOENT); diff --git a/drivers/clk/samsung/clk-exynos7.c b/drivers/clk/samsung/clk-exynos7.c index 5931a4140c3d..492d51691080 100644 --- a/drivers/clk/samsung/clk-exynos7.c +++ b/drivers/clk/samsung/clk-exynos7.c @@ -140,7 +140,7 @@ static const struct samsung_div_clock topc_div_clks[] __initconst = { }; static const struct samsung_pll_rate_table pll1460x_24mhz_tbl[] __initconst = { - PLL_36XX_RATE(491520000, 20, 1, 0, 31457), + PLL_36XX_RATE(24 * MHZ, 491519897, 20, 1, 0, 31457), {}, }; diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h index 61eb8abbfd9c..ca57b3dfa814 100644 --- a/drivers/clk/samsung/clk-pll.h +++ b/drivers/clk/samsung/clk-pll.h @@ -41,35 +41,62 @@ enum samsung_pll_type { pll_1460x, }; -#define PLL_35XX_RATE(_rate, _m, _p, _s) \ +#define PLL_RATE(_fin, _m, _p, _s, _k, _ks) \ + ((u64)(_fin) * (BIT(_ks) * (_m) + (_k)) / BIT(_ks) / ((_p) << (_s))) +#define PLL_VALID_RATE(_fin, _fout, _m, _p, _s, _k, _ks) ((_fout) + \ + BUILD_BUG_ON_ZERO(PLL_RATE(_fin, _m, _p, _s, _k, _ks) != (_fout))) + +#define PLL_35XX_RATE(_fin, _rate, _m, _p, _s) \ + { \ + .rate = PLL_VALID_RATE(_fin, _rate, \ + _m, _p, _s, 0, 16), \ + .mdiv = (_m), \ + .pdiv = (_p), \ + .sdiv = (_s), \ + } + +#define PLL_S3C2410_MPLL_RATE(_fin, _rate, _m, _p, _s) \ + { \ + .rate = PLL_VALID_RATE(_fin, _rate, \ + _m + 8, _p + 2, _s, 0, 16), \ + .mdiv = (_m), \ + .pdiv = (_p), \ + .sdiv = (_s), \ + } + +#define PLL_S3C2440_MPLL_RATE(_fin, _rate, _m, _p, _s) \ { \ - .rate = (_rate), \ + .rate = PLL_VALID_RATE(_fin, _rate, \ + 2 * (_m + 8), _p + 2, _s, 0, 16), \ .mdiv = (_m), \ .pdiv = (_p), \ .sdiv = (_s), \ } -#define PLL_36XX_RATE(_rate, _m, _p, _s, _k) \ +#define PLL_36XX_RATE(_fin, _rate, _m, _p, _s, _k) \ { \ - .rate = (_rate), \ + .rate = PLL_VALID_RATE(_fin, _rate, \ + _m, _p, _s, _k, 16), \ .mdiv = (_m), \ .pdiv = (_p), \ .sdiv = (_s), \ .kdiv = (_k), \ } -#define PLL_45XX_RATE(_rate, _m, _p, _s, _afc) \ +#define PLL_4508_RATE(_fin, _rate, _m, _p, _s, _afc) \ { \ - .rate = (_rate), \ + .rate = PLL_VALID_RATE(_fin, _rate, \ + _m, _p, _s - 1, 0, 16), \ .mdiv = (_m), \ .pdiv = (_p), \ .sdiv = (_s), \ .afc = (_afc), \ } -#define PLL_4600_RATE(_rate, _m, _p, _s, _k, _vsel) \ +#define PLL_4600_RATE(_fin, _rate, _m, _p, _s, _k, _vsel) \ { \ - .rate = (_rate), \ + .rate = PLL_VALID_RATE(_fin, _rate, \ + _m, _p, _s, _k, 16), \ .mdiv = (_m), \ .pdiv = (_p), \ .sdiv = (_s), \ @@ -77,9 +104,10 @@ enum samsung_pll_type { .vsel = (_vsel), \ } -#define PLL_4650_RATE(_rate, _m, _p, _s, _k, _mfr, _mrr, _vsel) \ +#define PLL_4650_RATE(_fin, _rate, _m, _p, _s, _k, _mfr, _mrr, _vsel) \ { \ - .rate = (_rate), \ + .rate = PLL_VALID_RATE(_fin, _rate, \ + _m, _p, _s, _k, 10), \ .mdiv = (_m), \ .pdiv = (_p), \ .sdiv = (_s), \ diff --git a/drivers/clk/samsung/clk-s3c2410.c b/drivers/clk/samsung/clk-s3c2410.c index e0650c33863b..a9c887475054 100644 --- a/drivers/clk/samsung/clk-s3c2410.c +++ b/drivers/clk/samsung/clk-s3c2410.c @@ -95,7 +95,7 @@ static void __init s3c2410_clk_sleep_init(void) {} PNAME(fclk_p) = { "mpll", "div_slow" }; -struct samsung_mux_clock s3c2410_common_muxes[] __initdata = { +static struct samsung_mux_clock s3c2410_common_muxes[] __initdata = { MUX(FCLK, "fclk", fclk_p, CLKSLOW, 4, 1), }; @@ -111,12 +111,12 @@ static struct clk_div_table divslow_d[] = { { /* sentinel */ }, }; -struct samsung_div_clock s3c2410_common_dividers[] __initdata = { +static struct samsung_div_clock s3c2410_common_dividers[] __initdata = { DIV_T(0, "div_slow", "xti", CLKSLOW, 0, 3, divslow_d), DIV(PCLK, "pclk", "hclk", CLKDIVN, 0, 1), }; -struct samsung_gate_clock s3c2410_common_gates[] __initdata = { +static struct samsung_gate_clock s3c2410_common_gates[] __initdata = { GATE(PCLK_SPI, "spi", "pclk", CLKCON, 18, 0, 0), GATE(PCLK_I2S, "i2s", "pclk", CLKCON, 17, 0, 0), GATE(PCLK_I2C, "i2c", "pclk", CLKCON, 16, 0, 0), @@ -135,7 +135,7 @@ struct samsung_gate_clock s3c2410_common_gates[] __initdata = { }; /* should be added _after_ the soc-specific clocks are created */ -struct samsung_clock_alias s3c2410_common_aliases[] __initdata = { +static struct samsung_clock_alias s3c2410_common_aliases[] __initdata = { ALIAS(PCLK_I2C, "s3c2410-i2c.0", "i2c"), ALIAS(PCLK_ADC, NULL, "adc"), ALIAS(PCLK_RTC, NULL, "rtc"), @@ -162,34 +162,34 @@ struct samsung_clock_alias s3c2410_common_aliases[] __initdata = { static struct samsung_pll_rate_table pll_s3c2410_12mhz_tbl[] __initdata = { /* sorted in descending order */ /* 2410A extras */ - PLL_35XX_RATE(270000000, 127, 1, 1), - PLL_35XX_RATE(268000000, 126, 1, 1), - PLL_35XX_RATE(266000000, 125, 1, 1), - PLL_35XX_RATE(226000000, 105, 1, 1), - PLL_35XX_RATE(210000000, 132, 2, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 270000000, 127, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 268000000, 126, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 266000000, 125, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 226000000, 105, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 210000000, 132, 2, 1), /* 2410 common */ - PLL_35XX_RATE(203000000, 161, 3, 1), - PLL_35XX_RATE(192000000, 88, 1, 1), - PLL_35XX_RATE(186000000, 85, 1, 1), - PLL_35XX_RATE(180000000, 82, 1, 1), - PLL_35XX_RATE(170000000, 77, 1, 1), - PLL_35XX_RATE(158000000, 71, 1, 1), - PLL_35XX_RATE(152000000, 68, 1, 1), - PLL_35XX_RATE(147000000, 90, 2, 1), - PLL_35XX_RATE(135000000, 82, 2, 1), - PLL_35XX_RATE(124000000, 116, 1, 2), - PLL_35XX_RATE(118000000, 150, 2, 2), - PLL_35XX_RATE(113000000, 105, 1, 2), - PLL_35XX_RATE(101000000, 127, 2, 2), - PLL_35XX_RATE(90000000, 112, 2, 2), - PLL_35XX_RATE(85000000, 105, 2, 2), - PLL_35XX_RATE(79000000, 71, 1, 2), - PLL_35XX_RATE(68000000, 82, 2, 2), - PLL_35XX_RATE(56000000, 142, 2, 3), - PLL_35XX_RATE(48000000, 120, 2, 3), - PLL_35XX_RATE(51000000, 161, 3, 3), - PLL_35XX_RATE(45000000, 82, 1, 3), - PLL_35XX_RATE(34000000, 82, 2, 3), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 202800000, 161, 3, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 192000000, 88, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 186000000, 85, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 180000000, 82, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 170000000, 77, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 158000000, 71, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 152000000, 68, 1, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 147000000, 90, 2, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 135000000, 82, 2, 1), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 124000000, 116, 1, 2), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 118500000, 150, 2, 2), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 113000000, 105, 1, 2), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 101250000, 127, 2, 2), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 90000000, 112, 2, 2), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 84750000, 105, 2, 2), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 79000000, 71, 1, 2), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 67500000, 82, 2, 2), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 56250000, 142, 2, 3), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 48000000, 120, 2, 3), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 50700000, 161, 3, 3), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 45000000, 82, 1, 3), + PLL_S3C2410_MPLL_RATE(12 * MHZ, 33750000, 82, 2, 3), { /* sentinel */ }, }; @@ -200,11 +200,11 @@ static struct samsung_pll_clock s3c2410_plls[] __initdata = { LOCKTIME, UPLLCON, NULL), }; -struct samsung_div_clock s3c2410_dividers[] __initdata = { +static struct samsung_div_clock s3c2410_dividers[] __initdata = { DIV(HCLK, "hclk", "mpll", CLKDIVN, 1, 1), }; -struct samsung_fixed_factor_clock s3c2410_ffactor[] __initdata = { +static struct samsung_fixed_factor_clock s3c2410_ffactor[] __initdata = { /* * armclk is directly supplied by the fclk, without * switching possibility like on the s3c244x below. @@ -215,7 +215,7 @@ struct samsung_fixed_factor_clock s3c2410_ffactor[] __initdata = { FFACTOR(UCLK, "uclk", "upll", 1, 1, 0), }; -struct samsung_clock_alias s3c2410_aliases[] __initdata = { +static struct samsung_clock_alias s3c2410_aliases[] __initdata = { ALIAS(PCLK_UART0, "s3c2410-uart.0", "uart"), ALIAS(PCLK_UART1, "s3c2410-uart.1", "uart"), ALIAS(PCLK_UART2, "s3c2410-uart.2", "uart"), @@ -229,33 +229,33 @@ struct samsung_clock_alias s3c2410_aliases[] __initdata = { static struct samsung_pll_rate_table pll_s3c244x_12mhz_tbl[] __initdata = { /* sorted in descending order */ - PLL_35XX_RATE(400000000, 0x5c, 1, 1), - PLL_35XX_RATE(390000000, 0x7a, 2, 1), - PLL_35XX_RATE(380000000, 0x57, 1, 1), - PLL_35XX_RATE(370000000, 0xb1, 4, 1), - PLL_35XX_RATE(360000000, 0x70, 2, 1), - PLL_35XX_RATE(350000000, 0xa7, 4, 1), - PLL_35XX_RATE(340000000, 0x4d, 1, 1), - PLL_35XX_RATE(330000000, 0x66, 2, 1), - PLL_35XX_RATE(320000000, 0x98, 4, 1), - PLL_35XX_RATE(310000000, 0x93, 4, 1), - PLL_35XX_RATE(300000000, 0x75, 3, 1), - PLL_35XX_RATE(240000000, 0x70, 1, 2), - PLL_35XX_RATE(230000000, 0x6b, 1, 2), - PLL_35XX_RATE(220000000, 0x66, 1, 2), - PLL_35XX_RATE(210000000, 0x84, 2, 2), - PLL_35XX_RATE(200000000, 0x5c, 1, 2), - PLL_35XX_RATE(190000000, 0x57, 1, 2), - PLL_35XX_RATE(180000000, 0x70, 2, 2), - PLL_35XX_RATE(170000000, 0x4d, 1, 2), - PLL_35XX_RATE(160000000, 0x98, 4, 2), - PLL_35XX_RATE(150000000, 0x75, 3, 2), - PLL_35XX_RATE(120000000, 0x70, 1, 3), - PLL_35XX_RATE(110000000, 0x66, 1, 3), - PLL_35XX_RATE(100000000, 0x5c, 1, 3), - PLL_35XX_RATE(90000000, 0x70, 2, 3), - PLL_35XX_RATE(80000000, 0x98, 4, 3), - PLL_35XX_RATE(75000000, 0x75, 3, 3), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 400000000, 0x5c, 1, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 390000000, 0x7a, 2, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 380000000, 0x57, 1, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 370000000, 0xb1, 4, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 360000000, 0x70, 2, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 350000000, 0xa7, 4, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 340000000, 0x4d, 1, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 330000000, 0x66, 2, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 320000000, 0x98, 4, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 310000000, 0x93, 4, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 300000000, 0x75, 3, 1), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 240000000, 0x70, 1, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 230000000, 0x6b, 1, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 220000000, 0x66, 1, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 210000000, 0x84, 2, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 200000000, 0x5c, 1, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 190000000, 0x57, 1, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 180000000, 0x70, 2, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 170000000, 0x4d, 1, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 160000000, 0x98, 4, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 150000000, 0x75, 3, 2), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 120000000, 0x70, 1, 3), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 110000000, 0x66, 1, 3), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 100000000, 0x5c, 1, 3), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 90000000, 0x70, 2, 3), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 80000000, 0x98, 4, 3), + PLL_S3C2440_MPLL_RATE(12 * MHZ, 75000000, 0x75, 3, 3), { /* sentinel */ }, }; @@ -269,12 +269,12 @@ static struct samsung_pll_clock s3c244x_common_plls[] __initdata = { PNAME(hclk_p) = { "fclk", "div_hclk_2", "div_hclk_4", "div_hclk_3" }; PNAME(armclk_p) = { "fclk", "hclk" }; -struct samsung_mux_clock s3c244x_common_muxes[] __initdata = { +static struct samsung_mux_clock s3c244x_common_muxes[] __initdata = { MUX(HCLK, "hclk", hclk_p, CLKDIVN, 1, 2), MUX(ARMCLK, "armclk", armclk_p, CAMDIVN, 12, 1), }; -struct samsung_fixed_factor_clock s3c244x_common_ffactor[] __initdata = { +static struct samsung_fixed_factor_clock s3c244x_common_ffactor[] __initdata = { FFACTOR(0, "div_hclk_2", "fclk", 1, 2, 0), FFACTOR(0, "ff_cam", "div_cam", 2, 1, CLK_SET_RATE_PARENT), }; @@ -291,7 +291,7 @@ static struct clk_div_table div_hclk_3_d[] = { { /* sentinel */ }, }; -struct samsung_div_clock s3c244x_common_dividers[] __initdata = { +static struct samsung_div_clock s3c244x_common_dividers[] __initdata = { DIV(UCLK, "uclk", "upll", CLKDIVN, 3, 1), DIV(0, "div_hclk", "fclk", CLKDIVN, 1, 1), DIV_T(0, "div_hclk_4", "fclk", CAMDIVN, 9, 1, div_hclk_4_d), @@ -299,11 +299,11 @@ struct samsung_div_clock s3c244x_common_dividers[] __initdata = { DIV(0, "div_cam", "upll", CAMDIVN, 0, 3), }; -struct samsung_gate_clock s3c244x_common_gates[] __initdata = { +static struct samsung_gate_clock s3c244x_common_gates[] __initdata = { GATE(HCLK_CAM, "cam", "hclk", CLKCON, 19, 0, 0), }; -struct samsung_clock_alias s3c244x_common_aliases[] __initdata = { +static struct samsung_clock_alias s3c244x_common_aliases[] __initdata = { ALIAS(PCLK_UART0, "s3c2440-uart.0", "uart"), ALIAS(PCLK_UART1, "s3c2440-uart.1", "uart"), ALIAS(PCLK_UART2, "s3c2440-uart.2", "uart"), @@ -318,23 +318,23 @@ struct samsung_clock_alias s3c244x_common_aliases[] __initdata = { PNAME(s3c2440_camif_p) = { "upll", "ff_cam" }; -struct samsung_mux_clock s3c2440_muxes[] __initdata = { +static struct samsung_mux_clock s3c2440_muxes[] __initdata = { MUX(CAMIF, "camif", s3c2440_camif_p, CAMDIVN, 4, 1), }; -struct samsung_gate_clock s3c2440_gates[] __initdata = { +static struct samsung_gate_clock s3c2440_gates[] __initdata = { GATE(PCLK_AC97, "ac97", "pclk", CLKCON, 20, 0, 0), }; /* S3C2442 specific clocks */ -struct samsung_fixed_factor_clock s3c2442_ffactor[] __initdata = { +static struct samsung_fixed_factor_clock s3c2442_ffactor[] __initdata = { FFACTOR(0, "upll_3", "upll", 1, 3, 0), }; PNAME(s3c2442_camif_p) = { "upll", "ff_cam", "upll", "upll_3" }; -struct samsung_mux_clock s3c2442_muxes[] __initdata = { +static struct samsung_mux_clock s3c2442_muxes[] __initdata = { MUX(CAMIF, "camif", s3c2442_camif_p, CAMDIVN, 4, 2), }; @@ -343,7 +343,7 @@ struct samsung_mux_clock s3c2442_muxes[] __initdata = { * Only necessary until the devicetree-move is complete */ #define XTI 1 -struct samsung_fixed_rate_clock s3c2410_common_frate_clks[] __initdata = { +static struct samsung_fixed_rate_clock s3c2410_common_frate_clks[] __initdata = { FRATE(XTI, "xti", NULL, 0, 0), }; @@ -468,18 +468,18 @@ void __init s3c2410_common_clk_init(struct device_node *np, unsigned long xti_f, static void __init s3c2410_clk_init(struct device_node *np) { - s3c2410_common_clk_init(np, 0, S3C2410, 0); + s3c2410_common_clk_init(np, 0, S3C2410, NULL); } CLK_OF_DECLARE(s3c2410_clk, "samsung,s3c2410-clock", s3c2410_clk_init); static void __init s3c2440_clk_init(struct device_node *np) { - s3c2410_common_clk_init(np, 0, S3C2440, 0); + s3c2410_common_clk_init(np, 0, S3C2440, NULL); } CLK_OF_DECLARE(s3c2440_clk, "samsung,s3c2440-clock", s3c2440_clk_init); static void __init s3c2442_clk_init(struct device_node *np) { - s3c2410_common_clk_init(np, 0, S3C2442, 0); + s3c2410_common_clk_init(np, 0, S3C2442, NULL); } CLK_OF_DECLARE(s3c2442_clk, "samsung,s3c2442-clock", s3c2442_clk_init); diff --git a/drivers/clk/samsung/clk-s3c2412.c b/drivers/clk/samsung/clk-s3c2412.c index b8340a49921b..6bc94d3aff78 100644 --- a/drivers/clk/samsung/clk-s3c2412.c +++ b/drivers/clk/samsung/clk-s3c2412.c @@ -27,11 +27,6 @@ #define CLKSRC 0x1c #define SWRST 0x30 -/* list of PLLs to be registered */ -enum s3c2412_plls { - mpll, upll, -}; - static void __iomem *reg_base; #ifdef CONFIG_PM_SLEEP @@ -98,7 +93,7 @@ static struct clk_div_table divxti_d[] = { { /* sentinel */ }, }; -struct samsung_div_clock s3c2412_dividers[] __initdata = { +static struct samsung_div_clock s3c2412_dividers[] __initdata = { DIV_T(0, "div_xti", "xti", CLKSRC, 0, 3, divxti_d), DIV(0, "div_cam", "mux_cam", CLKDIVN, 16, 4), DIV(0, "div_i2s", "mux_i2s", CLKDIVN, 12, 4), @@ -110,7 +105,7 @@ struct samsung_div_clock s3c2412_dividers[] __initdata = { DIV(HCLK, "hclk", "armdiv", CLKDIVN, 0, 2), }; -struct samsung_fixed_factor_clock s3c2412_ffactor[] __initdata = { +static struct samsung_fixed_factor_clock s3c2412_ffactor[] __initdata = { FFACTOR(0, "ff_hclk", "hclk", 2, 1, CLK_SET_RATE_PARENT), }; @@ -130,7 +125,7 @@ PNAME(msysclk_p) = { "mdivclk", "mpll" }; PNAME(mdivclk_p) = { "xti", "div_xti" }; PNAME(armclk_p) = { "armdiv", "hclk" }; -struct samsung_mux_clock s3c2412_muxes[] __initdata = { +static struct samsung_mux_clock s3c2412_muxes[] __initdata = { MUX(0, "erefclk", erefclk_p, CLKSRC, 14, 2), MUX(0, "urefclk", urefclk_p, CLKSRC, 12, 2), MUX(0, "mux_cam", camclk_p, CLKSRC, 11, 1), @@ -144,13 +139,11 @@ struct samsung_mux_clock s3c2412_muxes[] __initdata = { }; static struct samsung_pll_clock s3c2412_plls[] __initdata = { - [mpll] = PLL(pll_s3c2440_mpll, MPLL, "mpll", "xti", - LOCKTIME, MPLLCON, NULL), - [upll] = PLL(pll_s3c2410_upll, UPLL, "upll", "urefclk", - LOCKTIME, UPLLCON, NULL), + PLL(pll_s3c2440_mpll, MPLL, "mpll", "xti", LOCKTIME, MPLLCON, NULL), + PLL(pll_s3c2410_upll, UPLL, "upll", "urefclk", LOCKTIME, UPLLCON, NULL), }; -struct samsung_gate_clock s3c2412_gates[] __initdata = { +static struct samsung_gate_clock s3c2412_gates[] __initdata = { GATE(PCLK_WDT, "wdt", "pclk", CLKCON, 28, 0, 0), GATE(PCLK_SPI, "spi", "pclk", CLKCON, 27, 0, 0), GATE(PCLK_I2S, "i2s", "pclk", CLKCON, 26, 0, 0), @@ -181,7 +174,7 @@ struct samsung_gate_clock s3c2412_gates[] __initdata = { GATE(HCLK_DMA0, "dma0", "hclk", CLKCON, 0, CLK_IGNORE_UNUSED, 0), }; -struct samsung_clock_alias s3c2412_aliases[] __initdata = { +static struct samsung_clock_alias s3c2412_aliases[] __initdata = { ALIAS(PCLK_UART0, "s3c2412-uart.0", "uart"), ALIAS(PCLK_UART1, "s3c2412-uart.1", "uart"), ALIAS(PCLK_UART2, "s3c2412-uart.2", "uart"), @@ -231,7 +224,7 @@ static struct notifier_block s3c2412_restart_handler = { * Only necessary until the devicetree-move is complete */ #define XTI 1 -struct samsung_fixed_rate_clock s3c2412_common_frate_clks[] __initdata = { +static struct samsung_fixed_rate_clock s3c2412_common_frate_clks[] __initdata = { FRATE(XTI, "xti", NULL, 0, 0), FRATE(0, "ext", NULL, 0, 0), }; @@ -296,6 +289,6 @@ void __init s3c2412_common_clk_init(struct device_node *np, unsigned long xti_f, static void __init s3c2412_clk_init(struct device_node *np) { - s3c2412_common_clk_init(np, 0, 0, 0); + s3c2412_common_clk_init(np, 0, 0, NULL); } CLK_OF_DECLARE(s3c2412_clk, "samsung,s3c2412-clock", s3c2412_clk_init); diff --git a/drivers/clk/samsung/clk-s3c2443.c b/drivers/clk/samsung/clk-s3c2443.c index d94b85a42356..c46e6d5bc9bc 100644 --- a/drivers/clk/samsung/clk-s3c2443.c +++ b/drivers/clk/samsung/clk-s3c2443.c @@ -41,11 +41,6 @@ enum supported_socs { S3C2450, }; -/* list of PLLs to be registered */ -enum s3c2443_plls { - mpll, epll, -}; - static void __iomem *reg_base; #ifdef CONFIG_PM_SLEEP @@ -113,7 +108,7 @@ PNAME(msysclk_p) = { "mpllref", "mpll" }; PNAME(armclk_p) = { "armdiv" , "hclk" }; PNAME(i2s0_p) = { "div_i2s0", "ext_i2s", "epllref", "epllref" }; -struct samsung_mux_clock s3c2443_common_muxes[] __initdata = { +static struct samsung_mux_clock s3c2443_common_muxes[] __initdata = { MUX(0, "epllref", epllref_p, CLKSRC, 7, 2), MUX(ESYSCLK, "esysclk", esysclk_p, CLKSRC, 6, 1), MUX(0, "mpllref", mpllref_p, CLKSRC, 3, 1), @@ -141,7 +136,7 @@ static struct clk_div_table mdivclk_d[] = { { /* sentinel */ }, }; -struct samsung_div_clock s3c2443_common_dividers[] __initdata = { +static struct samsung_div_clock s3c2443_common_dividers[] __initdata = { DIV_T(0, "mdivclk", "xti", CLKDIV0, 6, 3, mdivclk_d), DIV(0, "prediv", "msysclk", CLKDIV0, 4, 2), DIV_T(HCLK, "hclk", "prediv", CLKDIV0, 0, 2, hclk_d), @@ -154,7 +149,7 @@ struct samsung_div_clock s3c2443_common_dividers[] __initdata = { DIV(0, "div_usbhost", "esysclk", CLKDIV1, 4, 2), }; -struct samsung_gate_clock s3c2443_common_gates[] __initdata = { +static struct samsung_gate_clock s3c2443_common_gates[] __initdata = { GATE(SCLK_HSMMC_EXT, "sclk_hsmmcext", "ext", SCLKCON, 13, 0, 0), GATE(SCLK_HSMMC1, "sclk_hsmmc1", "div_hsmmc1", SCLKCON, 12, 0, 0), GATE(SCLK_FIMD, "sclk_fimd", "div_fimd", SCLKCON, 10, 0, 0), @@ -188,7 +183,7 @@ struct samsung_gate_clock s3c2443_common_gates[] __initdata = { GATE(PCLK_UART0, "uart0", "pclk", PCLKCON, 0, 0, 0), }; -struct samsung_clock_alias s3c2443_common_aliases[] __initdata = { +static struct samsung_clock_alias s3c2443_common_aliases[] __initdata = { ALIAS(MSYSCLK, NULL, "msysclk"), ALIAS(ARMCLK, NULL, "armclk"), ALIAS(MPLL, NULL, "mpll"), @@ -225,10 +220,8 @@ struct samsung_clock_alias s3c2443_common_aliases[] __initdata = { /* S3C2416 specific clocks */ static struct samsung_pll_clock s3c2416_pll_clks[] __initdata = { - [mpll] = PLL(pll_6552_s3c2416, MPLL, "mpll", "mpllref", - LOCKCON0, MPLLCON, NULL), - [epll] = PLL(pll_6553, EPLL, "epll", "epllref", - LOCKCON1, EPLLCON, NULL), + PLL(pll_6552_s3c2416, MPLL, "mpll", "mpllref", LOCKCON0, MPLLCON, NULL), + PLL(pll_6553, EPLL, "epll", "epllref", LOCKCON1, EPLLCON, NULL), }; PNAME(s3c2416_hsmmc0_p) = { "sclk_hsmmc0", "sclk_hsmmcext" }; @@ -245,19 +238,19 @@ static struct clk_div_table armdiv_s3c2416_d[] = { { /* sentinel */ }, }; -struct samsung_div_clock s3c2416_dividers[] __initdata = { +static struct samsung_div_clock s3c2416_dividers[] __initdata = { DIV_T(ARMDIV, "armdiv", "msysclk", CLKDIV0, 9, 3, armdiv_s3c2416_d), DIV(0, "div_hsspi0_mpll", "msysclk", CLKDIV2, 0, 4), DIV(0, "div_hsmmc0", "esysclk", CLKDIV2, 6, 2), }; -struct samsung_mux_clock s3c2416_muxes[] __initdata = { +static struct samsung_mux_clock s3c2416_muxes[] __initdata = { MUX(MUX_HSMMC0, "mux_hsmmc0", s3c2416_hsmmc0_p, CLKSRC, 16, 1), MUX(MUX_HSMMC1, "mux_hsmmc1", s3c2416_hsmmc1_p, CLKSRC, 17, 1), MUX(MUX_HSSPI0, "mux_hsspi0", s3c2416_hsspi0_p, CLKSRC, 18, 1), }; -struct samsung_gate_clock s3c2416_gates[] __initdata = { +static struct samsung_gate_clock s3c2416_gates[] __initdata = { GATE(0, "hsspi0_mpll", "div_hsspi0_mpll", SCLKCON, 19, 0, 0), GATE(0, "hsspi0_epll", "div_hsspi0_epll", SCLKCON, 14, 0, 0), GATE(0, "sclk_hsmmc0", "div_hsmmc0", SCLKCON, 6, 0, 0), @@ -267,7 +260,7 @@ struct samsung_gate_clock s3c2416_gates[] __initdata = { GATE(PCLK_PCM, "pcm", "pclk", PCLKCON, 19, 0, 0), }; -struct samsung_clock_alias s3c2416_aliases[] __initdata = { +static struct samsung_clock_alias s3c2416_aliases[] __initdata = { ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "hsmmc"), ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "mmc_busclk.0"), ALIAS(MUX_HSMMC0, "s3c-sdhci.0", "mmc_busclk.2"), @@ -279,10 +272,8 @@ struct samsung_clock_alias s3c2416_aliases[] __initdata = { /* S3C2443 specific clocks */ static struct samsung_pll_clock s3c2443_pll_clks[] __initdata = { - [mpll] = PLL(pll_3000, MPLL, "mpll", "mpllref", - LOCKCON0, MPLLCON, NULL), - [epll] = PLL(pll_2126, EPLL, "epll", "epllref", - LOCKCON1, EPLLCON, NULL), + PLL(pll_3000, MPLL, "mpll", "mpllref", LOCKCON0, MPLLCON, NULL), + PLL(pll_2126, EPLL, "epll", "epllref", LOCKCON1, EPLLCON, NULL), }; static struct clk_div_table armdiv_s3c2443_d[] = { @@ -297,12 +288,12 @@ static struct clk_div_table armdiv_s3c2443_d[] = { { /* sentinel */ }, }; -struct samsung_div_clock s3c2443_dividers[] __initdata = { +static struct samsung_div_clock s3c2443_dividers[] __initdata = { DIV_T(ARMDIV, "armdiv", "msysclk", CLKDIV0, 9, 4, armdiv_s3c2443_d), DIV(0, "div_cam", "esysclk", CLKDIV1, 26, 4), }; -struct samsung_gate_clock s3c2443_gates[] __initdata = { +static struct samsung_gate_clock s3c2443_gates[] __initdata = { GATE(SCLK_HSSPI0, "sclk_hsspi0", "div_hsspi0_epll", SCLKCON, 14, 0, 0), GATE(SCLK_CAM, "sclk_cam", "div_cam", SCLKCON, 11, 0, 0), GATE(HCLK_CFC, "cfc", "hclk", HCLKCON, 17, CLK_IGNORE_UNUSED, 0), @@ -311,7 +302,7 @@ struct samsung_gate_clock s3c2443_gates[] __initdata = { GATE(PCLK_SDI, "sdi", "pclk", PCLKCON, 5, 0, 0), }; -struct samsung_clock_alias s3c2443_aliases[] __initdata = { +static struct samsung_clock_alias s3c2443_aliases[] __initdata = { ALIAS(SCLK_HSSPI0, "s3c2443-spi.0", "spi_busclk2"), ALIAS(SCLK_HSMMC1, "s3c-sdhci.1", "mmc_busclk.2"), ALIAS(SCLK_CAM, NULL, "camif-upll"), @@ -327,20 +318,20 @@ PNAME(s3c2450_cam_p) = { "div_cam", "hclk" }; PNAME(s3c2450_hsspi1_p) = { "hsspi1_epll", "hsspi1_mpll" }; PNAME(i2s1_p) = { "div_i2s1", "ext_i2s", "epllref", "epllref" }; -struct samsung_div_clock s3c2450_dividers[] __initdata = { +static struct samsung_div_clock s3c2450_dividers[] __initdata = { DIV(0, "div_cam", "esysclk", CLKDIV1, 26, 4), DIV(0, "div_hsspi1_epll", "esysclk", CLKDIV2, 24, 2), DIV(0, "div_hsspi1_mpll", "msysclk", CLKDIV2, 16, 4), DIV(0, "div_i2s1", "esysclk", CLKDIV2, 12, 4), }; -struct samsung_mux_clock s3c2450_muxes[] __initdata = { +static struct samsung_mux_clock s3c2450_muxes[] __initdata = { MUX(0, "mux_cam", s3c2450_cam_p, CLKSRC, 20, 1), MUX(MUX_HSSPI1, "mux_hsspi1", s3c2450_hsspi1_p, CLKSRC, 19, 1), MUX(0, "mux_i2s1", i2s1_p, CLKSRC, 12, 2), }; -struct samsung_gate_clock s3c2450_gates[] __initdata = { +static struct samsung_gate_clock s3c2450_gates[] __initdata = { GATE(SCLK_I2S1, "sclk_i2s1", "div_i2s1", SCLKCON, 5, 0, 0), GATE(HCLK_CFC, "cfc", "hclk", HCLKCON, 17, 0, 0), GATE(HCLK_CAM, "cam", "hclk", HCLKCON, 8, 0, 0), @@ -351,7 +342,7 @@ struct samsung_gate_clock s3c2450_gates[] __initdata = { GATE(PCLK_SPI1, "spi1", "pclk", PCLKCON, 14, 0, 0), }; -struct samsung_clock_alias s3c2450_aliases[] __initdata = { +static struct samsung_clock_alias s3c2450_aliases[] __initdata = { ALIAS(PCLK_SPI1, "s3c2443-spi.1", "spi"), ALIAS(PCLK_SPI1, "s3c2443-spi.1", "spi_busclk0"), ALIAS(MUX_HSSPI1, "s3c2443-spi.1", "spi_busclk2"), @@ -374,7 +365,7 @@ static struct notifier_block s3c2443_restart_handler = { * fixed rate clocks generated outside the soc * Only necessary until the devicetree-move is complete */ -struct samsung_fixed_rate_clock s3c2443_common_frate_clks[] __initdata = { +static struct samsung_fixed_rate_clock s3c2443_common_frate_clks[] __initdata = { FRATE(0, "xti", NULL, 0, 0), FRATE(0, "ext", NULL, 0, 0), FRATE(0, "ext_i2s", NULL, 0, 0), @@ -470,18 +461,18 @@ void __init s3c2443_common_clk_init(struct device_node *np, unsigned long xti_f, static void __init s3c2416_clk_init(struct device_node *np) { - s3c2443_common_clk_init(np, 0, S3C2416, 0); + s3c2443_common_clk_init(np, 0, S3C2416, NULL); } CLK_OF_DECLARE(s3c2416_clk, "samsung,s3c2416-clock", s3c2416_clk_init); static void __init s3c2443_clk_init(struct device_node *np) { - s3c2443_common_clk_init(np, 0, S3C2443, 0); + s3c2443_common_clk_init(np, 0, S3C2443, NULL); } CLK_OF_DECLARE(s3c2443_clk, "samsung,s3c2443-clock", s3c2443_clk_init); static void __init s3c2450_clk_init(struct device_node *np) { - s3c2443_common_clk_init(np, 0, S3C2450, 0); + s3c2443_common_clk_init(np, 0, S3C2450, NULL); } CLK_OF_DECLARE(s3c2450_clk, "samsung,s3c2450-clock", s3c2450_clk_init); diff --git a/drivers/clk/samsung/clk-s3c64xx.c b/drivers/clk/samsung/clk-s3c64xx.c index 7306867a0ab8..6db01cf5ab83 100644 --- a/drivers/clk/samsung/clk-s3c64xx.c +++ b/drivers/clk/samsung/clk-s3c64xx.c @@ -56,11 +56,6 @@ #define GATE_ON(_id, cname, pname, o, b) \ GATE(_id, cname, pname, o, b, CLK_IGNORE_UNUSED, 0) -/* list of PLLs to be registered */ -enum s3c64xx_plls { - apll, mpll, epll, -}; - static void __iomem *reg_base; static bool is_s3c6400; @@ -364,12 +359,12 @@ GATE_CLOCKS(s3c6410_gate_clks) __initdata = { /* List of PLL clocks. */ static struct samsung_pll_clock s3c64xx_pll_clks[] __initdata = { - [apll] = PLL(pll_6552, FOUT_APLL, "fout_apll", "fin_pll", - APLL_LOCK, APLL_CON, NULL), - [mpll] = PLL(pll_6552, FOUT_MPLL, "fout_mpll", "fin_pll", - MPLL_LOCK, MPLL_CON, NULL), - [epll] = PLL(pll_6553, FOUT_EPLL, "fout_epll", "fin_pll", - EPLL_LOCK, EPLL_CON0, NULL), + PLL(pll_6552, FOUT_APLL, "fout_apll", "fin_pll", + APLL_LOCK, APLL_CON, NULL), + PLL(pll_6552, FOUT_MPLL, "fout_mpll", "fin_pll", + MPLL_LOCK, MPLL_CON, NULL), + PLL(pll_6553, FOUT_EPLL, "fout_epll", "fin_pll", + EPLL_LOCK, EPLL_CON0, NULL), }; /* Aliases for common s3c64xx clocks. */ diff --git a/drivers/clk/sprd/sc9860-clk.c b/drivers/clk/sprd/sc9860-clk.c index ed5c027df0f4..9980ab55271b 100644 --- a/drivers/clk/sprd/sc9860-clk.c +++ b/drivers/clk/sprd/sc9860-clk.c @@ -959,6 +959,44 @@ static SPRD_SC_GATE_CLK(sdio2_2x_en, "sdio2-2x-en", "aon-apb", 0x13c, 0x1000, BIT(6), 0, 0); static SPRD_SC_GATE_CLK(emmc_2x_en, "emmc-2x-en", "aon-apb", 0x13c, 0x1000, BIT(9), 0, 0); +static SPRD_SC_GATE_CLK(arch_rtc_eb, "arch-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(0), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(kpb_rtc_eb, "kpb-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(1), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(aon_syst_rtc_eb, "aon-syst-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(2), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(ap_syst_rtc_eb, "ap-syst-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(3), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(aon_tmr_rtc_eb, "aon-tmr-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(4), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(ap_tmr0_rtc_eb, "ap-tmr0-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(5), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(eic_rtc_eb, "eic-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(6), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(eic_rtcdv5_eb, "eic-rtcdv5-eb", "aon-apb", 0x10, + 0x1000, BIT(7), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(ap_wdg_rtc_eb, "ap-wdg-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(9), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(ap_tmr1_rtc_eb, "ap-tmr1-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(15), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(ap_tmr2_rtc_eb, "ap-tmr2-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(16), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(dcxo_tmr_rtc_eb, "dcxo-tmr-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(17), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(bb_cal_rtc_eb, "bb-cal-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(18), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(avs_big_rtc_eb, "avs-big-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(20), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(avs_lit_rtc_eb, "avs-lit-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(21), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(avs_gpu0_rtc_eb, "avs-gpu0-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(22), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(avs_gpu1_rtc_eb, "avs-gpu1-rtc-eb", "aon-apb", 0x10, + 0x1000, BIT(23), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(gpu_ts_eb, "gpu-ts-eb", "aon-apb", 0x10, + 0x1000, BIT(24), CLK_IGNORE_UNUSED, 0); +static SPRD_SC_GATE_CLK(rtcdv10_eb, "rtcdv10-eb", "aon-apb", 0x10, + 0x1000, BIT(27), CLK_IGNORE_UNUSED, 0); static struct sprd_clk_common *sc9860_aon_gate[] = { /* address base is 0x402e0000 */ @@ -1030,6 +1068,25 @@ static struct sprd_clk_common *sc9860_aon_gate[] = { &sdio1_2x_en.common, &sdio2_2x_en.common, &emmc_2x_en.common, + &arch_rtc_eb.common, + &kpb_rtc_eb.common, + &aon_syst_rtc_eb.common, + &ap_syst_rtc_eb.common, + &aon_tmr_rtc_eb.common, + &ap_tmr0_rtc_eb.common, + &eic_rtc_eb.common, + &eic_rtcdv5_eb.common, + &ap_wdg_rtc_eb.common, + &ap_tmr1_rtc_eb.common, + &ap_tmr2_rtc_eb.common, + &dcxo_tmr_rtc_eb.common, + &bb_cal_rtc_eb.common, + &avs_big_rtc_eb.common, + &avs_lit_rtc_eb.common, + &avs_gpu0_rtc_eb.common, + &avs_gpu1_rtc_eb.common, + &gpu_ts_eb.common, + &rtcdv10_eb.common, }; static struct clk_hw_onecell_data sc9860_aon_gate_hws = { @@ -1102,6 +1159,25 @@ static struct clk_hw_onecell_data sc9860_aon_gate_hws = { [CLK_SDIO1_2X_EN] = &sdio1_2x_en.common.hw, [CLK_SDIO2_2X_EN] = &sdio2_2x_en.common.hw, [CLK_EMMC_2X_EN] = &emmc_2x_en.common.hw, + [CLK_ARCH_RTC_EB] = &arch_rtc_eb.common.hw, + [CLK_KPB_RTC_EB] = &kpb_rtc_eb.common.hw, + [CLK_AON_SYST_RTC_EB] = &aon_syst_rtc_eb.common.hw, + [CLK_AP_SYST_RTC_EB] = &ap_syst_rtc_eb.common.hw, + [CLK_AON_TMR_RTC_EB] = &aon_tmr_rtc_eb.common.hw, + [CLK_AP_TMR0_RTC_EB] = &ap_tmr0_rtc_eb.common.hw, + [CLK_EIC_RTC_EB] = &eic_rtc_eb.common.hw, + [CLK_EIC_RTCDV5_EB] = &eic_rtcdv5_eb.common.hw, + [CLK_AP_WDG_RTC_EB] = &ap_wdg_rtc_eb.common.hw, + [CLK_AP_TMR1_RTC_EB] = &ap_tmr1_rtc_eb.common.hw, + [CLK_AP_TMR2_RTC_EB] = &ap_tmr2_rtc_eb.common.hw, + [CLK_DCXO_TMR_RTC_EB] = &dcxo_tmr_rtc_eb.common.hw, + [CLK_BB_CAL_RTC_EB] = &bb_cal_rtc_eb.common.hw, + [CLK_AVS_BIG_RTC_EB] = &avs_big_rtc_eb.common.hw, + [CLK_AVS_LIT_RTC_EB] = &avs_lit_rtc_eb.common.hw, + [CLK_AVS_GPU0_RTC_EB] = &avs_gpu0_rtc_eb.common.hw, + [CLK_AVS_GPU1_RTC_EB] = &avs_gpu1_rtc_eb.common.hw, + [CLK_GPU_TS_EB] = &gpu_ts_eb.common.hw, + [CLK_RTCDV10_EB] = &rtcdv10_eb.common.hw, }, .num = CLK_AON_GATE_NUM, }; diff --git a/drivers/clk/tegra/clk-emc.c b/drivers/clk/tegra/clk-emc.c index 11a5066e5c27..5234acd30e89 100644 --- a/drivers/clk/tegra/clk-emc.c +++ b/drivers/clk/tegra/clk-emc.c @@ -515,7 +515,7 @@ struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np, init.name = "emc"; init.ops = &tegra_clk_emc_ops; - init.flags = 0; + init.flags = CLK_IS_CRITICAL; init.parent_names = emc_parent_clk_names; init.num_parents = ARRAY_SIZE(emc_parent_clk_names); diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index 7c369e21c91c..830d1c87fa7c 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -1151,6 +1151,8 @@ static const struct clk_ops tegra_clk_pllu_ops = { .enable = clk_pllu_enable, .disable = clk_pll_disable, .recalc_rate = clk_pll_recalc_rate, + .round_rate = clk_pll_round_rate, + .set_rate = clk_pll_set_rate, }; static int _pll_fixed_mdiv(struct tegra_clk_pll_params *pll_params, diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c index c02711927d79..2acba2986bc6 100644 --- a/drivers/clk/tegra/clk-tegra-periph.c +++ b/drivers/clk/tegra/clk-tegra-periph.c @@ -830,7 +830,7 @@ static struct tegra_periph_init_data gate_clks[] = { GATE("xusb_host", "xusb_host_src", 89, 0, tegra_clk_xusb_host, 0), GATE("xusb_ss", "xusb_ss_src", 156, 0, tegra_clk_xusb_ss, 0), GATE("xusb_dev", "xusb_dev_src", 95, 0, tegra_clk_xusb_dev, 0), - GATE("emc", "emc_mux", 57, 0, tegra_clk_emc, CLK_IGNORE_UNUSED), + GATE("emc", "emc_mux", 57, 0, tegra_clk_emc, CLK_IS_CRITICAL), GATE("sata_cold", "clk_m", 129, TEGRA_PERIPH_ON_APB, tegra_clk_sata_cold, 0), GATE("ispa", "isp", 23, 0, tegra_clk_ispa, 0), GATE("ispb", "isp", 3, 0, tegra_clk_ispb, 0), diff --git a/drivers/clk/tegra/clk-tegra-super-gen4.c b/drivers/clk/tegra/clk-tegra-super-gen4.c index 10047107c1dc..89d6b47a27a8 100644 --- a/drivers/clk/tegra/clk-tegra-super-gen4.c +++ b/drivers/clk/tegra/clk-tegra-super-gen4.c @@ -125,7 +125,8 @@ static void __init tegra_sclk_init(void __iomem *clk_base, /* SCLK */ dt_clk = tegra_lookup_dt_id(tegra_clk_sclk, tegra_clks); if (dt_clk) { - clk = clk_register_divider(NULL, "sclk", "sclk_mux", 0, + clk = clk_register_divider(NULL, "sclk", "sclk_mux", + CLK_IS_CRITICAL, clk_base + SCLK_DIVIDER, 0, 8, 0, &sysrate_lock); *dt_clk = clk; @@ -137,7 +138,8 @@ static void __init tegra_sclk_init(void __iomem *clk_base, clk = tegra_clk_register_super_mux("sclk", gen_info->sclk_parents, gen_info->num_sclk_parents, - CLK_SET_RATE_PARENT, + CLK_SET_RATE_PARENT | + CLK_IS_CRITICAL, clk_base + SCLK_BURST_POLICY, 0, 4, 0, 0, NULL); *dt_clk = clk; @@ -151,7 +153,7 @@ static void __init tegra_sclk_init(void __iomem *clk_base, clk_base + SYSTEM_CLK_RATE, 4, 2, 0, &sysrate_lock); clk = clk_register_gate(NULL, "hclk", "hclk_div", - CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, clk_base + SYSTEM_CLK_RATE, 7, CLK_GATE_SET_TO_DISABLE, &sysrate_lock); *dt_clk = clk; diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c index 63087d17c3e2..5d5a22d529f5 100644 --- a/drivers/clk/tegra/clk-tegra114.c +++ b/drivers/clk/tegra/clk-tegra114.c @@ -955,8 +955,7 @@ static void __init tegra114_pll_init(void __iomem *clk_base, /* PLLM */ clk = tegra_clk_register_pllm("pll_m", "pll_ref", clk_base, pmc, - CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, - &pll_m_params, NULL); + CLK_SET_RATE_GATE, &pll_m_params, NULL); clks[TEGRA114_CLK_PLL_M] = clk; /* PLLM_OUT1 */ @@ -1190,6 +1189,7 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA114_CLK_XUSB_HS_SRC, TEGRA114_CLK_XUSB_SS_DIV2, 61200000, 0 }, { TEGRA114_CLK_XUSB_FALCON_SRC, TEGRA114_CLK_PLL_P, 204000000, 0 }, { TEGRA114_CLK_XUSB_HOST_SRC, TEGRA114_CLK_PLL_P, 102000000, 0 }, + { TEGRA114_CLK_VDE, TEGRA114_CLK_CLK_MAX, 600000000, 0 }, /* must be the last entry */ { TEGRA114_CLK_CLK_MAX, TEGRA114_CLK_CLK_MAX, 0, 0 }, }; diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index e81ea5b11577..50088e976611 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c @@ -1089,8 +1089,7 @@ static void __init tegra124_pll_init(void __iomem *clk_base, /* PLLM */ clk = tegra_clk_register_pllm("pll_m", "pll_ref", clk_base, pmc, - CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, - &pll_m_params, NULL); + CLK_SET_RATE_GATE, &pll_m_params, NULL); clk_register_clkdev(clk, "pll_m", NULL); clks[TEGRA124_CLK_PLL_M] = clk; @@ -1099,7 +1098,7 @@ static void __init tegra124_pll_init(void __iomem *clk_base, clk_base + PLLM_OUT, 0, TEGRA_DIVIDER_ROUND_UP, 8, 8, 1, NULL); clk = tegra_clk_register_pll_out("pll_m_out1", "pll_m_out1_div", - clk_base + PLLM_OUT, 1, 0, CLK_IGNORE_UNUSED | + clk_base + PLLM_OUT, 1, 0, CLK_SET_RATE_PARENT, 0, NULL); clk_register_clkdev(clk, "pll_m_out1", NULL); clks[TEGRA124_CLK_PLL_M_OUT1] = clk; @@ -1268,11 +1267,11 @@ static struct tegra_clk_init_table common_init_table[] __initdata = { { TEGRA124_CLK_I2S2, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA124_CLK_I2S3, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA124_CLK_I2S4, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 }, - { TEGRA124_CLK_VDE, TEGRA124_CLK_PLL_P, 0, 0 }, + { TEGRA124_CLK_VDE, TEGRA124_CLK_CLK_MAX, 600000000, 0 }, { TEGRA124_CLK_HOST1X, TEGRA124_CLK_PLL_P, 136000000, 1 }, { TEGRA124_CLK_DSIALP, TEGRA124_CLK_PLL_P, 68000000, 0 }, { TEGRA124_CLK_DSIBLP, TEGRA124_CLK_PLL_P, 68000000, 0 }, - { TEGRA124_CLK_SCLK, TEGRA124_CLK_PLL_P_OUT2, 102000000, 1 }, + { TEGRA124_CLK_SCLK, TEGRA124_CLK_PLL_P_OUT2, 102000000, 0 }, { TEGRA124_CLK_DFLL_SOC, TEGRA124_CLK_PLL_P, 51000000, 1 }, { TEGRA124_CLK_DFLL_REF, TEGRA124_CLK_PLL_P, 51000000, 1 }, { TEGRA124_CLK_PLL_C, TEGRA124_CLK_CLK_MAX, 768000000, 0 }, diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index cbd5a2e5c569..0ee56dd04cec 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -576,6 +576,7 @@ static struct tegra_clk tegra20_clks[tegra_clk_max] __initdata = { [tegra_clk_afi] = { .dt_id = TEGRA20_CLK_AFI, .present = true }, [tegra_clk_fuse] = { .dt_id = TEGRA20_CLK_FUSE, .present = true }, [tegra_clk_kfuse] = { .dt_id = TEGRA20_CLK_KFUSE, .present = true }, + [tegra_clk_emc] = { .dt_id = TEGRA20_CLK_EMC, .present = true }, }; static unsigned long tegra20_clk_measure_input_freq(void) @@ -651,8 +652,7 @@ static void tegra20_pll_init(void) /* PLLM */ clk = tegra_clk_register_pll("pll_m", "pll_ref", clk_base, NULL, - CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, - &pll_m_params, NULL); + CLK_SET_RATE_GATE, &pll_m_params, NULL); clks[TEGRA20_CLK_PLL_M] = clk; /* PLLM_OUT1 */ @@ -660,7 +660,7 @@ static void tegra20_pll_init(void) clk_base + PLLM_OUT, 0, TEGRA_DIVIDER_ROUND_UP, 8, 8, 1, NULL); clk = tegra_clk_register_pll_out("pll_m_out1", "pll_m_out1_div", - clk_base + PLLM_OUT, 1, 0, CLK_IGNORE_UNUSED | + clk_base + PLLM_OUT, 1, 0, CLK_SET_RATE_PARENT, 0, NULL); clks[TEGRA20_CLK_PLL_M_OUT1] = clk; @@ -723,7 +723,8 @@ static void tegra20_super_clk_init(void) /* SCLK */ clk = tegra_clk_register_super_mux("sclk", sclk_parents, - ARRAY_SIZE(sclk_parents), CLK_SET_RATE_PARENT, + ARRAY_SIZE(sclk_parents), + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, clk_base + SCLK_BURST_POLICY, 0, 4, 0, 0, NULL); clks[TEGRA20_CLK_SCLK] = clk; @@ -814,9 +815,6 @@ static void __init tegra20_periph_clk_init(void) CLK_SET_RATE_NO_REPARENT, clk_base + CLK_SOURCE_EMC, 30, 2, 0, &emc_lock); - clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, 0, - 57, periph_clk_enb_refcnt); - clks[TEGRA20_CLK_EMC] = clk; clk = tegra_clk_register_mc("mc", "emc_mux", clk_base + CLK_SOURCE_EMC, &emc_lock); @@ -1019,13 +1017,12 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA20_CLK_PLL_P_OUT2, TEGRA20_CLK_CLK_MAX, 48000000, 1 }, { TEGRA20_CLK_PLL_P_OUT3, TEGRA20_CLK_CLK_MAX, 72000000, 1 }, { TEGRA20_CLK_PLL_P_OUT4, TEGRA20_CLK_CLK_MAX, 24000000, 1 }, - { TEGRA20_CLK_PLL_C, TEGRA20_CLK_CLK_MAX, 600000000, 1 }, - { TEGRA20_CLK_PLL_C_OUT1, TEGRA20_CLK_CLK_MAX, 216000000, 1 }, - { TEGRA20_CLK_SCLK, TEGRA20_CLK_PLL_C_OUT1, 0, 1 }, - { TEGRA20_CLK_HCLK, TEGRA20_CLK_CLK_MAX, 0, 1 }, - { TEGRA20_CLK_PCLK, TEGRA20_CLK_CLK_MAX, 60000000, 1 }, + { TEGRA20_CLK_PLL_C, TEGRA20_CLK_CLK_MAX, 600000000, 0 }, + { TEGRA20_CLK_PLL_C_OUT1, TEGRA20_CLK_CLK_MAX, 240000000, 0 }, + { TEGRA20_CLK_SCLK, TEGRA20_CLK_PLL_C_OUT1, 240000000, 0 }, + { TEGRA20_CLK_HCLK, TEGRA20_CLK_CLK_MAX, 240000000, 0 }, + { TEGRA20_CLK_PCLK, TEGRA20_CLK_CLK_MAX, 60000000, 0 }, { TEGRA20_CLK_CSITE, TEGRA20_CLK_CLK_MAX, 0, 1 }, - { TEGRA20_CLK_EMC, TEGRA20_CLK_CLK_MAX, 0, 1 }, { TEGRA20_CLK_CCLK, TEGRA20_CLK_CLK_MAX, 0, 1 }, { TEGRA20_CLK_UARTA, TEGRA20_CLK_PLL_P, 0, 0 }, { TEGRA20_CLK_UARTB, TEGRA20_CLK_PLL_P, 0, 0 }, @@ -1051,6 +1048,7 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA20_CLK_DISP2, TEGRA20_CLK_PLL_P, 600000000, 0 }, { TEGRA20_CLK_GR2D, TEGRA20_CLK_PLL_C, 300000000, 0 }, { TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 }, + { TEGRA20_CLK_VDE, TEGRA20_CLK_CLK_MAX, 300000000, 0 }, /* must be the last entry */ { TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 }, }; diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 9e6260869eb9..9fb5d51ccce4 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -22,10 +22,12 @@ #include <linux/of_address.h> #include <linux/delay.h> #include <linux/export.h> +#include <linux/mutex.h> #include <linux/clk/tegra.h> #include <dt-bindings/clock/tegra210-car.h> #include <dt-bindings/reset/tegra210-car.h> #include <linux/iopoll.h> +#include <soc/tegra/pmc.h> #include "clk.h" #include "clk-id.h" @@ -41,6 +43,7 @@ #define CLK_SOURCE_CSITE 0x1d4 #define CLK_SOURCE_EMC 0x19c #define CLK_SOURCE_SOR1 0x410 +#define CLK_SOURCE_LA 0x1f8 #define PLLC_BASE 0x80 #define PLLC_OUT 0x84 @@ -231,6 +234,30 @@ #define CLK_RST_CONTROLLER_RST_DEV_Y_SET 0x2a8 #define CLK_RST_CONTROLLER_RST_DEV_Y_CLR 0x2ac +#define LVL2_CLK_GATE_OVRA 0xf8 +#define LVL2_CLK_GATE_OVRC 0x3a0 +#define LVL2_CLK_GATE_OVRD 0x3a4 +#define LVL2_CLK_GATE_OVRE 0x554 + +/* I2S registers to handle during APE MBIST WAR */ +#define TEGRA210_I2S_BASE 0x1000 +#define TEGRA210_I2S_SIZE 0x100 +#define TEGRA210_I2S_CTRLS 5 +#define TEGRA210_I2S_CG 0x88 +#define TEGRA210_I2S_CTRL 0xa0 + +/* DISPA registers to handle during MBIST WAR */ +#define DC_CMD_DISPLAY_COMMAND 0xc8 +#define DC_COM_DSC_TOP_CTL 0xcf8 + +/* VIC register to handle during MBIST WAR */ +#define NV_PVIC_THI_SLCG_OVERRIDE_LOW 0x8c + +/* APE, DISPA and VIC base addesses needed for MBIST WAR */ +#define TEGRA210_AHUB_BASE 0x702d0000 +#define TEGRA210_DISPA_BASE 0x54200000 +#define TEGRA210_VIC_BASE 0x54340000 + /* * SDM fractional divisor is 16-bit 2's complement signed number within * (-2^12 ... 2^12-1) range. Represented in PLL data structure as unsigned @@ -255,8 +282,22 @@ static struct cpu_clk_suspend_context { } tegra210_cpu_clk_sctx; #endif +struct tegra210_domain_mbist_war { + void (*handle_lvl2_ovr)(struct tegra210_domain_mbist_war *mbist); + const u32 lvl2_offset; + const u32 lvl2_mask; + const unsigned int num_clks; + const unsigned int *clk_init_data; + struct clk_bulk_data *clks; +}; + +static struct clk **clks; + static void __iomem *clk_base; static void __iomem *pmc_base; +static void __iomem *ahub_base; +static void __iomem *dispa_base; +static void __iomem *vic_base; static unsigned long osc_freq; static unsigned long pll_ref_freq; @@ -267,6 +308,7 @@ static DEFINE_SPINLOCK(pll_re_lock); static DEFINE_SPINLOCK(pll_u_lock); static DEFINE_SPINLOCK(sor1_lock); static DEFINE_SPINLOCK(emc_lock); +static DEFINE_MUTEX(lvl2_ovr_lock); /* possible OSC frequencies in Hz */ static unsigned long tegra210_input_freq[] = { @@ -310,6 +352,8 @@ static const char *mux_pllmcp_clkm[] = { #define PLLA_MISC2_WRITE_MASK 0x06ffffff /* PLLD */ +#define PLLD_BASE_CSI_CLKSOURCE (1 << 23) + #define PLLD_MISC0_EN_SDM (1 << 16) #define PLLD_MISC0_LOCK_OVERRIDE (1 << 17) #define PLLD_MISC0_LOCK_ENABLE (1 << 18) @@ -513,6 +557,115 @@ void tegra210_set_sata_pll_seq_sw(bool state) } EXPORT_SYMBOL_GPL(tegra210_set_sata_pll_seq_sw); +static void tegra210_generic_mbist_war(struct tegra210_domain_mbist_war *mbist) +{ + u32 val; + + val = readl_relaxed(clk_base + mbist->lvl2_offset); + writel_relaxed(val | mbist->lvl2_mask, clk_base + mbist->lvl2_offset); + fence_udelay(1, clk_base); + writel_relaxed(val, clk_base + mbist->lvl2_offset); + fence_udelay(1, clk_base); +} + +static void tegra210_venc_mbist_war(struct tegra210_domain_mbist_war *mbist) +{ + u32 csi_src, ovra, ovre; + unsigned long flags = 0; + + spin_lock_irqsave(&pll_d_lock, flags); + + csi_src = readl_relaxed(clk_base + PLLD_BASE); + writel_relaxed(csi_src | PLLD_BASE_CSI_CLKSOURCE, clk_base + PLLD_BASE); + fence_udelay(1, clk_base); + + ovra = readl_relaxed(clk_base + LVL2_CLK_GATE_OVRA); + writel_relaxed(ovra | BIT(15), clk_base + LVL2_CLK_GATE_OVRA); + ovre = readl_relaxed(clk_base + LVL2_CLK_GATE_OVRE); + writel_relaxed(ovre | BIT(3), clk_base + LVL2_CLK_GATE_OVRE); + fence_udelay(1, clk_base); + + writel_relaxed(ovra, clk_base + LVL2_CLK_GATE_OVRA); + writel_relaxed(ovre, clk_base + LVL2_CLK_GATE_OVRE); + writel_relaxed(csi_src, clk_base + PLLD_BASE); + fence_udelay(1, clk_base); + + spin_unlock_irqrestore(&pll_d_lock, flags); +} + +static void tegra210_disp_mbist_war(struct tegra210_domain_mbist_war *mbist) +{ + u32 ovra, dsc_top_ctrl; + + ovra = readl_relaxed(clk_base + LVL2_CLK_GATE_OVRA); + writel_relaxed(ovra | BIT(1), clk_base + LVL2_CLK_GATE_OVRA); + fence_udelay(1, clk_base); + + dsc_top_ctrl = readl_relaxed(dispa_base + DC_COM_DSC_TOP_CTL); + writel_relaxed(dsc_top_ctrl | BIT(2), dispa_base + DC_COM_DSC_TOP_CTL); + readl_relaxed(dispa_base + DC_CMD_DISPLAY_COMMAND); + writel_relaxed(dsc_top_ctrl, dispa_base + DC_COM_DSC_TOP_CTL); + readl_relaxed(dispa_base + DC_CMD_DISPLAY_COMMAND); + + writel_relaxed(ovra, clk_base + LVL2_CLK_GATE_OVRA); + fence_udelay(1, clk_base); +} + +static void tegra210_vic_mbist_war(struct tegra210_domain_mbist_war *mbist) +{ + u32 ovre, val; + + ovre = readl_relaxed(clk_base + LVL2_CLK_GATE_OVRE); + writel_relaxed(ovre | BIT(5), clk_base + LVL2_CLK_GATE_OVRE); + fence_udelay(1, clk_base); + + val = readl_relaxed(vic_base + NV_PVIC_THI_SLCG_OVERRIDE_LOW); + writel_relaxed(val | BIT(0) | GENMASK(7, 2) | BIT(24), + vic_base + NV_PVIC_THI_SLCG_OVERRIDE_LOW); + fence_udelay(1, vic_base + NV_PVIC_THI_SLCG_OVERRIDE_LOW); + + writel_relaxed(val, vic_base + NV_PVIC_THI_SLCG_OVERRIDE_LOW); + readl(vic_base + NV_PVIC_THI_SLCG_OVERRIDE_LOW); + + writel_relaxed(ovre, clk_base + LVL2_CLK_GATE_OVRE); + fence_udelay(1, clk_base); +} + +static void tegra210_ape_mbist_war(struct tegra210_domain_mbist_war *mbist) +{ + void __iomem *i2s_base; + unsigned int i; + u32 ovrc, ovre; + + ovrc = readl_relaxed(clk_base + LVL2_CLK_GATE_OVRC); + ovre = readl_relaxed(clk_base + LVL2_CLK_GATE_OVRE); + writel_relaxed(ovrc | BIT(1), clk_base + LVL2_CLK_GATE_OVRC); + writel_relaxed(ovre | BIT(10) | BIT(11), + clk_base + LVL2_CLK_GATE_OVRE); + fence_udelay(1, clk_base); + + i2s_base = ahub_base + TEGRA210_I2S_BASE; + + for (i = 0; i < TEGRA210_I2S_CTRLS; i++) { + u32 i2s_ctrl; + + i2s_ctrl = readl_relaxed(i2s_base + TEGRA210_I2S_CTRL); + writel_relaxed(i2s_ctrl | BIT(10), + i2s_base + TEGRA210_I2S_CTRL); + writel_relaxed(0, i2s_base + TEGRA210_I2S_CG); + readl(i2s_base + TEGRA210_I2S_CG); + writel_relaxed(1, i2s_base + TEGRA210_I2S_CG); + writel_relaxed(i2s_ctrl, i2s_base + TEGRA210_I2S_CTRL); + readl(i2s_base + TEGRA210_I2S_CTRL); + + i2s_base += TEGRA210_I2S_SIZE; + } + + writel_relaxed(ovrc, clk_base + LVL2_CLK_GATE_OVRC); + writel_relaxed(ovre, clk_base + LVL2_CLK_GATE_OVRE); + fence_udelay(1, clk_base); +} + static inline void _pll_misc_chk_default(void __iomem *base, struct tegra_clk_pll_params *params, u8 misc_num, u32 default_val, u32 mask) @@ -2411,13 +2564,150 @@ static struct tegra_audio_clk_info tegra210_audio_plls[] = { { "pll_a1", &pll_a1_params, tegra_clk_pll_a1, "pll_ref" }, }; -static struct clk **clks; - static const char * const aclk_parents[] = { "pll_a1", "pll_c", "pll_p", "pll_a_out0", "pll_c2", "pll_c3", "clk_m" }; +static const unsigned int nvjpg_slcg_clkids[] = { TEGRA210_CLK_NVDEC }; +static const unsigned int nvdec_slcg_clkids[] = { TEGRA210_CLK_NVJPG }; +static const unsigned int sor_slcg_clkids[] = { TEGRA210_CLK_HDA2CODEC_2X, + TEGRA210_CLK_HDA2HDMI, TEGRA210_CLK_DISP1, TEGRA210_CLK_DISP2 }; +static const unsigned int disp_slcg_clkids[] = { TEGRA210_CLK_LA, + TEGRA210_CLK_HOST1X}; +static const unsigned int xusba_slcg_clkids[] = { TEGRA210_CLK_XUSB_HOST, + TEGRA210_CLK_XUSB_DEV }; +static const unsigned int xusbb_slcg_clkids[] = { TEGRA210_CLK_XUSB_HOST, + TEGRA210_CLK_XUSB_SS }; +static const unsigned int xusbc_slcg_clkids[] = { TEGRA210_CLK_XUSB_DEV, + TEGRA210_CLK_XUSB_SS }; +static const unsigned int venc_slcg_clkids[] = { TEGRA210_CLK_HOST1X, + TEGRA210_CLK_PLL_D }; +static const unsigned int ape_slcg_clkids[] = { TEGRA210_CLK_ACLK, + TEGRA210_CLK_I2S0, TEGRA210_CLK_I2S1, TEGRA210_CLK_I2S2, + TEGRA210_CLK_I2S3, TEGRA210_CLK_I2S4, TEGRA210_CLK_SPDIF_OUT, + TEGRA210_CLK_D_AUDIO }; +static const unsigned int vic_slcg_clkids[] = { TEGRA210_CLK_HOST1X }; + +static struct tegra210_domain_mbist_war tegra210_pg_mbist_war[] = { + [TEGRA_POWERGATE_VENC] = { + .handle_lvl2_ovr = tegra210_venc_mbist_war, + .num_clks = ARRAY_SIZE(venc_slcg_clkids), + .clk_init_data = venc_slcg_clkids, + }, + [TEGRA_POWERGATE_SATA] = { + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .lvl2_offset = LVL2_CLK_GATE_OVRC, + .lvl2_mask = BIT(0) | BIT(17) | BIT(19), + }, + [TEGRA_POWERGATE_MPE] = { + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .lvl2_offset = LVL2_CLK_GATE_OVRE, + .lvl2_mask = BIT(2), + }, + [TEGRA_POWERGATE_SOR] = { + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .num_clks = ARRAY_SIZE(sor_slcg_clkids), + .clk_init_data = sor_slcg_clkids, + .lvl2_offset = LVL2_CLK_GATE_OVRA, + .lvl2_mask = BIT(1) | BIT(2), + }, + [TEGRA_POWERGATE_DIS] = { + .handle_lvl2_ovr = tegra210_disp_mbist_war, + .num_clks = ARRAY_SIZE(disp_slcg_clkids), + .clk_init_data = disp_slcg_clkids, + }, + [TEGRA_POWERGATE_DISB] = { + .num_clks = ARRAY_SIZE(disp_slcg_clkids), + .clk_init_data = disp_slcg_clkids, + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .lvl2_offset = LVL2_CLK_GATE_OVRA, + .lvl2_mask = BIT(2), + }, + [TEGRA_POWERGATE_XUSBA] = { + .num_clks = ARRAY_SIZE(xusba_slcg_clkids), + .clk_init_data = xusba_slcg_clkids, + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .lvl2_offset = LVL2_CLK_GATE_OVRC, + .lvl2_mask = BIT(30) | BIT(31), + }, + [TEGRA_POWERGATE_XUSBB] = { + .num_clks = ARRAY_SIZE(xusbb_slcg_clkids), + .clk_init_data = xusbb_slcg_clkids, + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .lvl2_offset = LVL2_CLK_GATE_OVRC, + .lvl2_mask = BIT(30) | BIT(31), + }, + [TEGRA_POWERGATE_XUSBC] = { + .num_clks = ARRAY_SIZE(xusbc_slcg_clkids), + .clk_init_data = xusbc_slcg_clkids, + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .lvl2_offset = LVL2_CLK_GATE_OVRC, + .lvl2_mask = BIT(30) | BIT(31), + }, + [TEGRA_POWERGATE_VIC] = { + .num_clks = ARRAY_SIZE(vic_slcg_clkids), + .clk_init_data = vic_slcg_clkids, + .handle_lvl2_ovr = tegra210_vic_mbist_war, + }, + [TEGRA_POWERGATE_NVDEC] = { + .num_clks = ARRAY_SIZE(nvdec_slcg_clkids), + .clk_init_data = nvdec_slcg_clkids, + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .lvl2_offset = LVL2_CLK_GATE_OVRC, + .lvl2_mask = BIT(9) | BIT(31), + }, + [TEGRA_POWERGATE_NVJPG] = { + .num_clks = ARRAY_SIZE(nvjpg_slcg_clkids), + .clk_init_data = nvjpg_slcg_clkids, + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .lvl2_offset = LVL2_CLK_GATE_OVRC, + .lvl2_mask = BIT(9) | BIT(31), + }, + [TEGRA_POWERGATE_AUD] = { + .num_clks = ARRAY_SIZE(ape_slcg_clkids), + .clk_init_data = ape_slcg_clkids, + .handle_lvl2_ovr = tegra210_ape_mbist_war, + }, + [TEGRA_POWERGATE_VE2] = { + .handle_lvl2_ovr = tegra210_generic_mbist_war, + .lvl2_offset = LVL2_CLK_GATE_OVRD, + .lvl2_mask = BIT(22), + }, +}; + +int tegra210_clk_handle_mbist_war(unsigned int id) +{ + int err; + struct tegra210_domain_mbist_war *mbist_war; + + if (id >= ARRAY_SIZE(tegra210_pg_mbist_war)) { + WARN(1, "unknown domain id in MBIST WAR handler\n"); + return -EINVAL; + } + + mbist_war = &tegra210_pg_mbist_war[id]; + if (!mbist_war->handle_lvl2_ovr) + return 0; + + if (mbist_war->num_clks && !mbist_war->clks) + return -ENODEV; + + err = clk_bulk_prepare_enable(mbist_war->num_clks, mbist_war->clks); + if (err < 0) + return err; + + mutex_lock(&lvl2_ovr_lock); + + mbist_war->handle_lvl2_ovr(mbist_war); + + mutex_unlock(&lvl2_ovr_lock); + + clk_bulk_disable_unprepare(mbist_war->num_clks, mbist_war->clks); + + return 0; +} + void tegra210_put_utmipll_in_iddq(void) { u32 reg; @@ -2654,6 +2944,13 @@ static struct tegra_periph_init_data tegra210_periph[] = { sor1_parents_idx, 0, &sor1_lock), }; +static const char * const la_parents[] = { + "pll_p", "pll_c2", "pll_c", "pll_c3", "pll_re_out1", "pll_a1", "clk_m", "pll_c4_out0" +}; + +static struct tegra_clk_periph tegra210_la = + TEGRA_CLK_PERIPH(29, 7, 9, 0, 8, 1, TEGRA_DIVIDER_ROUND_UP, 76, 0, NULL, 0); + static __init void tegra210_periph_clk_init(void __iomem *clk_base, void __iomem *pmc_base) { @@ -2700,6 +2997,12 @@ static __init void tegra210_periph_clk_init(void __iomem *clk_base, periph_clk_enb_refcnt); clks[TEGRA210_CLK_DSIB] = clk; + /* la */ + clk = tegra_clk_register_periph("la", la_parents, + ARRAY_SIZE(la_parents), &tegra210_la, clk_base, + CLK_SOURCE_LA, 0); + clks[TEGRA210_CLK_LA] = clk; + /* emc mux */ clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm, ARRAY_SIZE(mux_pllmcp_clkm), 0, @@ -3025,7 +3328,7 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA210_CLK_I2S4, TEGRA210_CLK_PLL_A_OUT0, 11289600, 0 }, { TEGRA210_CLK_HOST1X, TEGRA210_CLK_PLL_P, 136000000, 1 }, { TEGRA210_CLK_SCLK_MUX, TEGRA210_CLK_PLL_P, 0, 1 }, - { TEGRA210_CLK_SCLK, TEGRA210_CLK_CLK_MAX, 102000000, 1 }, + { TEGRA210_CLK_SCLK, TEGRA210_CLK_CLK_MAX, 102000000, 0 }, { TEGRA210_CLK_DFLL_SOC, TEGRA210_CLK_PLL_P, 51000000, 1 }, { TEGRA210_CLK_DFLL_REF, TEGRA210_CLK_PLL_P, 51000000, 1 }, { TEGRA210_CLK_SBC4, TEGRA210_CLK_PLL_P, 12000000, 1 }, @@ -3040,7 +3343,6 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA210_CLK_XUSB_DEV_SRC, TEGRA210_CLK_PLL_P_OUT_XUSB, 102000000, 0 }, { TEGRA210_CLK_SATA, TEGRA210_CLK_PLL_P, 104000000, 0 }, { TEGRA210_CLK_SATA_OOB, TEGRA210_CLK_PLL_P, 204000000, 0 }, - { TEGRA210_CLK_EMC, TEGRA210_CLK_CLK_MAX, 0, 1 }, { TEGRA210_CLK_MSELECT, TEGRA210_CLK_CLK_MAX, 0, 1 }, { TEGRA210_CLK_CSITE, TEGRA210_CLK_CLK_MAX, 0, 1 }, /* TODO find a way to enable this on-demand */ @@ -3149,6 +3451,37 @@ static int tegra210_reset_deassert(unsigned long id) return 0; } +static void tegra210_mbist_clk_init(void) +{ + unsigned int i, j; + + for (i = 0; i < ARRAY_SIZE(tegra210_pg_mbist_war); i++) { + unsigned int num_clks = tegra210_pg_mbist_war[i].num_clks; + struct clk_bulk_data *clk_data; + + if (!num_clks) + continue; + + clk_data = kmalloc_array(num_clks, sizeof(*clk_data), + GFP_KERNEL); + if (WARN_ON(!clk_data)) + return; + + tegra210_pg_mbist_war[i].clks = clk_data; + for (j = 0; j < num_clks; j++) { + int clk_id = tegra210_pg_mbist_war[i].clk_init_data[j]; + struct clk *clk = clks[clk_id]; + + if (WARN(IS_ERR(clk), "clk_id: %d\n", clk_id)) { + kfree(clk_data); + tegra210_pg_mbist_war[i].clks = NULL; + break; + } + clk_data[j].clk = clk; + } + } +} + /** * tegra210_clock_init - Tegra210-specific clock initialization * @np: struct device_node * of the DT node for the SoC CAR IP block @@ -3183,6 +3516,24 @@ static void __init tegra210_clock_init(struct device_node *np) return; } + ahub_base = ioremap(TEGRA210_AHUB_BASE, SZ_64K); + if (!ahub_base) { + pr_err("ioremap tegra210 APE failed\n"); + return; + } + + dispa_base = ioremap(TEGRA210_DISPA_BASE, SZ_256K); + if (!dispa_base) { + pr_err("ioremap tegra210 DISPA failed\n"); + return; + } + + vic_base = ioremap(TEGRA210_VIC_BASE, SZ_256K); + if (!vic_base) { + pr_err("ioremap tegra210 VIC failed\n"); + return; + } + clks = tegra_clk_init(clk_base, TEGRA210_CLK_CLK_MAX, TEGRA210_CAR_BANK_COUNT); if (!clks) @@ -3219,6 +3570,8 @@ static void __init tegra210_clock_init(struct device_node *np) tegra_add_of_provider(np); tegra_register_devclks(devclks, ARRAY_SIZE(devclks)); + tegra210_mbist_clk_init(); + tegra_cpu_car_ops = &tegra210_cpu_car_ops; } CLK_OF_DECLARE(tegra210, "nvidia,tegra210-car", tegra210_clock_init); diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index bee84c554932..b316dfb6f6c7 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -819,6 +819,7 @@ static struct tegra_clk tegra30_clks[tegra_clk_max] __initdata = { [tegra_clk_pll_a] = { .dt_id = TEGRA30_CLK_PLL_A, .present = true }, [tegra_clk_pll_a_out0] = { .dt_id = TEGRA30_CLK_PLL_A_OUT0, .present = true }, [tegra_clk_cec] = { .dt_id = TEGRA30_CLK_CEC, .present = true }, + [tegra_clk_emc] = { .dt_id = TEGRA30_CLK_EMC, .present = true }, }; static const char *pll_e_parents[] = { "pll_ref", "pll_p" }; @@ -843,8 +844,7 @@ static void __init tegra30_pll_init(void) /* PLLM */ clk = tegra_clk_register_pll("pll_m", "pll_ref", clk_base, pmc_base, - CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, - &pll_m_params, NULL); + CLK_SET_RATE_GATE, &pll_m_params, NULL); clks[TEGRA30_CLK_PLL_M] = clk; /* PLLM_OUT1 */ @@ -852,7 +852,7 @@ static void __init tegra30_pll_init(void) clk_base + PLLM_OUT, 0, TEGRA_DIVIDER_ROUND_UP, 8, 8, 1, NULL); clk = tegra_clk_register_pll_out("pll_m_out1", "pll_m_out1_div", - clk_base + PLLM_OUT, 1, 0, CLK_IGNORE_UNUSED | + clk_base + PLLM_OUT, 1, 0, CLK_SET_RATE_PARENT, 0, NULL); clks[TEGRA30_CLK_PLL_M_OUT1] = clk; @@ -990,7 +990,7 @@ static void __init tegra30_super_clk_init(void) /* SCLK */ clk = tegra_clk_register_super_mux("sclk", sclk_parents, ARRAY_SIZE(sclk_parents), - CLK_SET_RATE_PARENT, + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, clk_base + SCLK_BURST_POLICY, 0, 4, 0, 0, NULL); clks[TEGRA30_CLK_SCLK] = clk; @@ -1060,9 +1060,6 @@ static void __init tegra30_periph_clk_init(void) CLK_SET_RATE_NO_REPARENT, clk_base + CLK_SOURCE_EMC, 30, 2, 0, &emc_lock); - clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, 0, - 57, periph_clk_enb_refcnt); - clks[TEGRA30_CLK_EMC] = clk; clk = tegra_clk_register_mc("mc", "emc_mux", clk_base + CLK_SOURCE_EMC, &emc_lock); @@ -1252,10 +1249,7 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA30_CLK_SDMMC1, TEGRA30_CLK_PLL_P, 48000000, 0 }, { TEGRA30_CLK_SDMMC2, TEGRA30_CLK_PLL_P, 48000000, 0 }, { TEGRA30_CLK_SDMMC3, TEGRA30_CLK_PLL_P, 48000000, 0 }, - { TEGRA30_CLK_PLL_M, TEGRA30_CLK_CLK_MAX, 0, 1 }, - { TEGRA30_CLK_PCLK, TEGRA30_CLK_CLK_MAX, 0, 1 }, { TEGRA30_CLK_CSITE, TEGRA30_CLK_CLK_MAX, 0, 1 }, - { TEGRA30_CLK_EMC, TEGRA30_CLK_CLK_MAX, 0, 1 }, { TEGRA30_CLK_MSELECT, TEGRA30_CLK_CLK_MAX, 0, 1 }, { TEGRA30_CLK_SBC1, TEGRA30_CLK_PLL_P, 100000000, 0 }, { TEGRA30_CLK_SBC2, TEGRA30_CLK_PLL_P, 100000000, 0 }, @@ -1272,6 +1266,7 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA30_CLK_GR3D, TEGRA30_CLK_PLL_C, 300000000, 0 }, { TEGRA30_CLK_GR3D2, TEGRA30_CLK_PLL_C, 300000000, 0 }, { TEGRA30_CLK_PLL_U, TEGRA30_CLK_CLK_MAX, 480000000, 0 }, + { TEGRA30_CLK_VDE, TEGRA30_CLK_CLK_MAX, 600000000, 0 }, /* must be the last entry */ { TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 }, }; diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 3b2763df51c2..ba7e20e6a82b 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -812,4 +812,11 @@ int tegra_pll_wait_for_lock(struct tegra_clk_pll *pll); u16 tegra_pll_get_fixed_mdiv(struct clk_hw *hw, unsigned long input_rate); int tegra_pll_p_div_to_hw(struct tegra_clk_pll *pll, u8 p_div); +/* Combined read fence with delay */ +#define fence_udelay(delay, reg) \ + do { \ + readl(reg); \ + udelay(delay); \ + } while (0) + #endif /* TEGRA_CLK_H */ diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index f4d6802a8544..7d22e1af2247 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -55,6 +55,29 @@ static void clk_memmap_writel(u32 val, const struct clk_omap_reg *reg) writel_relaxed(val, io->mem + reg->offset); } +static void _clk_rmw(u32 val, u32 mask, void __iomem *ptr) +{ + u32 v; + + v = readl_relaxed(ptr); + v &= ~mask; + v |= val; + writel_relaxed(v, ptr); +} + +static void clk_memmap_rmw(u32 val, u32 mask, const struct clk_omap_reg *reg) +{ + struct clk_iomap *io = clk_memmaps[reg->index]; + + if (reg->ptr) { + _clk_rmw(val, mask, reg->ptr); + } else if (io->regmap) { + regmap_update_bits(io->regmap, reg->offset, mask, val); + } else { + _clk_rmw(val, mask, io->mem + reg->offset); + } +} + static u32 clk_memmap_readl(const struct clk_omap_reg *reg) { u32 val; @@ -89,6 +112,7 @@ int ti_clk_setup_ll_ops(struct ti_clk_ll_ops *ops) ti_clk_ll_ops = ops; ops->clk_readl = clk_memmap_readl; ops->clk_writel = clk_memmap_writel; + ops->clk_rmw = clk_memmap_rmw; return 0; } @@ -251,6 +275,20 @@ int ti_clk_get_reg_addr(struct device_node *node, int index, return 0; } +void ti_clk_latch(struct clk_omap_reg *reg, s8 shift) +{ + u32 latch; + + if (shift < 0) + return; + + latch = 1 << shift; + + ti_clk_ll_ops->clk_rmw(latch, latch, reg); + ti_clk_ll_ops->clk_rmw(0, latch, reg); + ti_clk_ll_ops->clk_readl(reg); /* OCP barrier */ +} + /** * omap2_clk_provider_init - init master clock provider * @parent: master node diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index d9b43bfc2532..90b86aadfda7 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -22,6 +22,7 @@ struct clk_omap_divider { u8 shift; u8 width; u8 flags; + s8 latch; const struct clk_div_table *table; }; @@ -33,6 +34,7 @@ struct clk_omap_mux { u32 *table; u32 mask; u8 shift; + s8 latch; u8 flags; }; @@ -194,6 +196,8 @@ struct clk *ti_clk_register(struct device *dev, struct clk_hw *hw, int ti_clk_add_alias(struct device *dev, struct clk *clk, const char *con); void ti_clk_add_aliases(void); +void ti_clk_latch(struct clk_omap_reg *reg, s8 shift); + struct clk_hw *ti_clk_build_component_mux(struct ti_clk_mux *setup); int ti_clk_parse_divider_data(int *div_table, int num_dividers, int max_div, diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c index 77f93f6d2806..aaa277dd6d99 100644 --- a/drivers/clk/ti/divider.c +++ b/drivers/clk/ti/divider.c @@ -263,6 +263,8 @@ static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, val |= value << divider->shift; ti_clk_ll_ops->clk_writel(val, ÷r->reg); + ti_clk_latch(÷r->reg, divider->latch); + return 0; } @@ -276,7 +278,8 @@ static struct clk *_register_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, struct clk_omap_reg *reg, - u8 shift, u8 width, u8 clk_divider_flags, + u8 shift, u8 width, s8 latch, + u8 clk_divider_flags, const struct clk_div_table *table) { struct clk_omap_divider *div; @@ -305,6 +308,7 @@ static struct clk *_register_divider(struct device *dev, const char *name, memcpy(&div->reg, reg, sizeof(*reg)); div->shift = shift; div->width = width; + div->latch = latch; div->flags = clk_divider_flags; div->hw.init = &init; div->table = table; @@ -420,6 +424,7 @@ struct clk_hw *ti_clk_build_component_div(struct ti_clk_divider *setup) div->table = _get_div_table_from_setup(setup, &div->width); div->shift = setup->bit_shift; + div->latch = -EINVAL; return &div->hw; } @@ -452,7 +457,7 @@ struct clk *ti_clk_register_divider(struct ti_clk *setup) clk = _register_divider(NULL, setup->name, div->parent, flags, ®, div->bit_shift, - width, div_flags, table); + width, -EINVAL, div_flags, table); if (IS_ERR(clk)) kfree(table); @@ -556,7 +561,7 @@ static int _get_divider_width(struct device_node *node, static int __init ti_clk_divider_populate(struct device_node *node, struct clk_omap_reg *reg, const struct clk_div_table **table, - u32 *flags, u8 *div_flags, u8 *width, u8 *shift) + u32 *flags, u8 *div_flags, u8 *width, u8 *shift, s8 *latch) { u32 val; int ret; @@ -570,6 +575,13 @@ static int __init ti_clk_divider_populate(struct device_node *node, else *shift = 0; + if (latch) { + if (!of_property_read_u32(node, "ti,latch-bit", &val)) + *latch = val; + else + *latch = -EINVAL; + } + *flags = 0; *div_flags = 0; @@ -606,17 +618,18 @@ static void __init of_ti_divider_clk_setup(struct device_node *node) u8 clk_divider_flags = 0; u8 width = 0; u8 shift = 0; + s8 latch = -EINVAL; const struct clk_div_table *table = NULL; u32 flags = 0; parent_name = of_clk_get_parent_name(node, 0); if (ti_clk_divider_populate(node, ®, &table, &flags, - &clk_divider_flags, &width, &shift)) + &clk_divider_flags, &width, &shift, &latch)) goto cleanup; clk = _register_divider(NULL, node->name, parent_name, flags, ®, - shift, width, clk_divider_flags, table); + shift, width, latch, clk_divider_flags, table); if (!IS_ERR(clk)) { of_clk_add_provider(node, of_clk_src_simple_get, clk); @@ -639,7 +652,8 @@ static void __init of_ti_composite_divider_clk_setup(struct device_node *node) return; if (ti_clk_divider_populate(node, &div->reg, &div->table, &val, - &div->flags, &div->width, &div->shift) < 0) + &div->flags, &div->width, &div->shift, + NULL) < 0) goto cleanup; if (!ti_clk_add_component(node, &div->hw, CLK_COMPONENT_TYPE_DIVIDER)) diff --git a/drivers/clk/ti/mux.c b/drivers/clk/ti/mux.c index d4705803f3d3..69a4308a5a98 100644 --- a/drivers/clk/ti/mux.c +++ b/drivers/clk/ti/mux.c @@ -86,6 +86,7 @@ static int ti_clk_mux_set_parent(struct clk_hw *hw, u8 index) } val |= index << mux->shift; ti_clk_ll_ops->clk_writel(val, &mux->reg); + ti_clk_latch(&mux->reg, mux->latch); return 0; } @@ -100,7 +101,7 @@ static struct clk *_register_mux(struct device *dev, const char *name, const char * const *parent_names, u8 num_parents, unsigned long flags, struct clk_omap_reg *reg, u8 shift, u32 mask, - u8 clk_mux_flags, u32 *table) + s8 latch, u8 clk_mux_flags, u32 *table) { struct clk_omap_mux *mux; struct clk *clk; @@ -121,6 +122,7 @@ static struct clk *_register_mux(struct device *dev, const char *name, memcpy(&mux->reg, reg, sizeof(*reg)); mux->shift = shift; mux->mask = mask; + mux->latch = latch; mux->flags = clk_mux_flags; mux->table = table; mux->hw.init = &init; @@ -160,7 +162,7 @@ struct clk *ti_clk_register_mux(struct ti_clk *setup) flags |= CLK_SET_RATE_PARENT; return _register_mux(NULL, setup->name, mux->parents, mux->num_parents, - flags, ®, mux->bit_shift, mask, + flags, ®, mux->bit_shift, mask, -EINVAL, mux_flags, NULL); } @@ -179,6 +181,7 @@ static void of_mux_clk_setup(struct device_node *node) u8 clk_mux_flags = 0; u32 mask = 0; u32 shift = 0; + s32 latch = -EINVAL; u32 flags = CLK_SET_RATE_NO_REPARENT; num_parents = of_clk_get_parent_count(node); @@ -197,6 +200,8 @@ static void of_mux_clk_setup(struct device_node *node) of_property_read_u32(node, "ti,bit-shift", &shift); + of_property_read_u32(node, "ti,latch-bit", &latch); + if (of_property_read_bool(node, "ti,index-starts-at-one")) clk_mux_flags |= CLK_MUX_INDEX_ONE; @@ -211,7 +216,8 @@ static void of_mux_clk_setup(struct device_node *node) mask = (1 << fls(mask)) - 1; clk = _register_mux(NULL, node->name, parent_names, num_parents, - flags, ®, shift, mask, clk_mux_flags, NULL); + flags, ®, shift, mask, latch, clk_mux_flags, + NULL); if (!IS_ERR(clk)) of_clk_add_provider(node, of_clk_src_simple_get, clk); @@ -234,6 +240,7 @@ struct clk_hw *ti_clk_build_component_mux(struct ti_clk_mux *setup) return ERR_PTR(-ENOMEM); mux->shift = setup->bit_shift; + mux->latch = -EINVAL; mux->reg.index = setup->module; mux->reg.offset = setup->reg; diff --git a/drivers/clk/versatile/clk-vexpress-osc.c b/drivers/clk/versatile/clk-vexpress-osc.c index e7a868b83fe5..dd08ecb498be 100644 --- a/drivers/clk/versatile/clk-vexpress-osc.c +++ b/drivers/clk/versatile/clk-vexpress-osc.c @@ -44,10 +44,10 @@ static long vexpress_osc_round_rate(struct clk_hw *hw, unsigned long rate, { struct vexpress_osc *osc = to_vexpress_osc(hw); - if (WARN_ON(osc->rate_min && rate < osc->rate_min)) + if (osc->rate_min && rate < osc->rate_min) rate = osc->rate_min; - if (WARN_ON(osc->rate_max && rate > osc->rate_max)) + if (osc->rate_max && rate > osc->rate_max) rate = osc->rate_max; return rate; @@ -104,6 +104,7 @@ static int vexpress_osc_probe(struct platform_device *pdev) return PTR_ERR(clk); of_clk_add_provider(pdev->dev.of_node, of_clk_src_simple_get, clk); + clk_hw_set_rate_range(&osc->hw, osc->rate_min, osc->rate_max); dev_dbg(&pdev->dev, "Registered clock '%s'\n", init.name); |