Newer
Older
* Copyright (C) 2017, STMicroelectronics - All Rights Reserved
* Author(s): Vikas Manocha, <vikas.manocha@st.com> for STMicroelectronics.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <clk-uclass.h>
#include <dm.h>
#include <asm/io.h>
#include <asm/arch/rcc.h>
#include <asm/arch/stm32.h>
#include <asm/arch/stm32_periph.h>
#include <asm/arch/stm32_pwr.h>
#include <dt-bindings/mfd/stm32f7-rcc.h>
#define RCC_CR_HSION BIT(0)
#define RCC_CR_HSEON BIT(16)
#define RCC_CR_HSERDY BIT(17)
#define RCC_CR_HSEBYP BIT(18)
#define RCC_CR_CSSON BIT(19)
#define RCC_CR_PLLON BIT(24)
#define RCC_CR_PLLRDY BIT(25)
Toshifumi NISHINAGA
committed
#define RCC_PLLCFGR_PLLM_MASK GENMASK(5, 0)
#define RCC_PLLCFGR_PLLN_MASK GENMASK(14, 6)
#define RCC_PLLCFGR_PLLP_MASK GENMASK(17, 16)
#define RCC_PLLCFGR_PLLQ_MASK GENMASK(27, 24)
#define RCC_PLLCFGR_PLLSRC BIT(22)
#define RCC_PLLCFGR_PLLM_SHIFT 0
#define RCC_PLLCFGR_PLLN_SHIFT 6
#define RCC_PLLCFGR_PLLP_SHIFT 16
#define RCC_PLLCFGR_PLLQ_SHIFT 24
Toshifumi NISHINAGA
committed
#define RCC_CFGR_AHB_PSC_MASK GENMASK(7, 4)
#define RCC_CFGR_APB1_PSC_MASK GENMASK(12, 10)
#define RCC_CFGR_APB2_PSC_MASK GENMASK(15, 13)
#define RCC_CFGR_SW0 BIT(0)
#define RCC_CFGR_SW1 BIT(1)
#define RCC_CFGR_SW_MASK GENMASK(1, 0)
#define RCC_CFGR_SW_HSI 0
#define RCC_CFGR_SW_HSE RCC_CFGR_SW0
#define RCC_CFGR_SW_PLL RCC_CFGR_SW1
#define RCC_CFGR_SWS0 BIT(2)
#define RCC_CFGR_SWS1 BIT(3)
#define RCC_CFGR_SWS_MASK GENMASK(3, 2)
#define RCC_CFGR_SWS_HSI 0
#define RCC_CFGR_SWS_HSE RCC_CFGR_SWS0
#define RCC_CFGR_SWS_PLL RCC_CFGR_SWS1
#define RCC_CFGR_HPRE_SHIFT 4
#define RCC_CFGR_PPRE1_SHIFT 10
#define RCC_CFGR_PPRE2_SHIFT 13
Toshifumi NISHINAGA
committed
struct pll_psc {
u8 pll_m;
u16 pll_n;
u8 pll_p;
u8 pll_q;
u8 ahb_psc;
u8 apb1_psc;
u8 apb2_psc;
};
#define AHB_PSC_1 0
#define AHB_PSC_2 0x8
#define AHB_PSC_4 0x9
#define AHB_PSC_8 0xA
#define AHB_PSC_16 0xB
#define AHB_PSC_64 0xC
#define AHB_PSC_128 0xD
#define AHB_PSC_256 0xE
#define AHB_PSC_512 0xF
Toshifumi NISHINAGA
committed
#define APB_PSC_1 0
#define APB_PSC_2 0x4
#define APB_PSC_4 0x5
#define APB_PSC_8 0x6
#define APB_PSC_16 0x7
Toshifumi NISHINAGA
committed
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
struct stm32_clk_info {
struct pll_psc sys_pll_psc;
bool has_overdrive;
};
struct stm32_clk_info stm32f4_clk_info = {
/* 180 MHz */
.sys_pll_psc = {
.pll_m = 8,
.pll_n = 360,
.pll_p = 2,
.pll_q = 8,
.ahb_psc = AHB_PSC_1,
.apb1_psc = APB_PSC_4,
.apb2_psc = APB_PSC_2,
},
.has_overdrive = false,
};
struct stm32_clk_info stm32f7_clk_info = {
/* 200 MHz */
.sys_pll_psc = {
.pll_m = 25,
.pll_n = 400,
.pll_p = 2,
.pll_q = 8,
.ahb_psc = AHB_PSC_1,
.apb1_psc = APB_PSC_4,
.apb2_psc = APB_PSC_2,
},
.has_overdrive = true,
};
struct stm32_clk {
struct stm32_rcc_regs *base;
struct stm32_pwr_regs *pwr_regs;
};
static int configure_clocks(struct udevice *dev)
Toshifumi NISHINAGA
committed
{
struct stm32_clk *priv = dev_get_priv(dev);
struct stm32_rcc_regs *regs = priv->base;
struct stm32_pwr_regs *pwr = priv->pwr_regs;
struct pll_psc sys_pll_psc = priv->info->sys_pll_psc;
Toshifumi NISHINAGA
committed
/* Reset RCC configuration */
setbits_le32(®s->cr, RCC_CR_HSION);
writel(0, ®s->cfgr); /* Reset CFGR */
clrbits_le32(®s->cr, (RCC_CR_HSEON | RCC_CR_CSSON
Toshifumi NISHINAGA
committed
| RCC_CR_PLLON));
writel(0x24003010, ®s->pllcfgr); /* Reset value from RM */
clrbits_le32(®s->cr, RCC_CR_HSEBYP);
writel(0, ®s->cir); /* Disable all interrupts */
Toshifumi NISHINAGA
committed
/* Configure for HSE+PLL operation */
setbits_le32(®s->cr, RCC_CR_HSEON);
while (!(readl(®s->cr) & RCC_CR_HSERDY))
Toshifumi NISHINAGA
committed
;
setbits_le32(®s->cfgr, ((
Toshifumi NISHINAGA
committed
sys_pll_psc.ahb_psc << RCC_CFGR_HPRE_SHIFT)
| (sys_pll_psc.apb1_psc << RCC_CFGR_PPRE1_SHIFT)
| (sys_pll_psc.apb2_psc << RCC_CFGR_PPRE2_SHIFT)));
/* Configure the main PLL */
setbits_le32(®s->pllcfgr, RCC_PLLCFGR_PLLSRC); /* pll source HSE */
clrsetbits_le32(®s->pllcfgr, RCC_PLLCFGR_PLLM_MASK,
sys_pll_psc.pll_m << RCC_PLLCFGR_PLLM_SHIFT);
clrsetbits_le32(®s->pllcfgr, RCC_PLLCFGR_PLLN_MASK,
sys_pll_psc.pll_n << RCC_PLLCFGR_PLLN_SHIFT);
clrsetbits_le32(®s->pllcfgr, RCC_PLLCFGR_PLLP_MASK,
((sys_pll_psc.pll_p >> 1) - 1) << RCC_PLLCFGR_PLLP_SHIFT);
clrsetbits_le32(®s->pllcfgr, RCC_PLLCFGR_PLLQ_MASK,
sys_pll_psc.pll_q << RCC_PLLCFGR_PLLQ_SHIFT);
Toshifumi NISHINAGA
committed
/* Enable the main PLL */
setbits_le32(®s->cr, RCC_CR_PLLON);
while (!(readl(®s->cr) & RCC_CR_PLLRDY))
Toshifumi NISHINAGA
committed
;
setbits_le32(®s->apb1enr, RCC_APB1ENR_PWREN);
if (priv->info->has_overdrive) {
/*
* Enable high performance mode
* System frequency up to 200 MHz
*/
setbits_le32(&pwr->cr1, PWR_CR1_ODEN);
/* Infinite wait! */
while (!(readl(&pwr->csr1) & PWR_CSR1_ODRDY))
;
/* Enable the Over-drive switch */
setbits_le32(&pwr->cr1, PWR_CR1_ODSWEN);
/* Infinite wait! */
while (!(readl(&pwr->csr1) & PWR_CSR1_ODSWRDY))
;
}
Toshifumi NISHINAGA
committed
stm32_flash_latency_cfg(5);
clrbits_le32(®s->cfgr, (RCC_CFGR_SW0 | RCC_CFGR_SW1));
setbits_le32(®s->cfgr, RCC_CFGR_SW_PLL);
Toshifumi NISHINAGA
committed
while ((readl(®s->cfgr) & RCC_CFGR_SWS_MASK) !=
Toshifumi NISHINAGA
committed
RCC_CFGR_SWS_PLL)
;
return 0;
}
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
static unsigned long stm32_clk_get_rate(struct clk *clk)
{
struct stm32_clk *priv = dev_get_priv(clk->dev);
struct stm32_rcc_regs *regs = priv->base;
u32 sysclk = 0;
u32 shift = 0;
/* Prescaler table lookups for clock computation */
u8 ahb_psc_table[16] = {
0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9
};
u8 apb_psc_table[8] = {
0, 0, 0, 0, 1, 2, 3, 4
};
if ((readl(®s->cfgr) & RCC_CFGR_SWS_MASK) ==
RCC_CFGR_SWS_PLL) {
u16 pllm, plln, pllp;
pllm = (readl(®s->pllcfgr) & RCC_PLLCFGR_PLLM_MASK);
plln = ((readl(®s->pllcfgr) & RCC_PLLCFGR_PLLN_MASK)
>> RCC_PLLCFGR_PLLN_SHIFT);
pllp = ((((readl(®s->pllcfgr) & RCC_PLLCFGR_PLLP_MASK)
>> RCC_PLLCFGR_PLLP_SHIFT) + 1) << 1);
sysclk = ((CONFIG_STM32_HSE_HZ / pllm) * plln) / pllp;
} else {
return -EINVAL;
}
switch (clk->id) {
/*
* AHB CLOCK: 3 x 32 bits consecutive registers are used :
* AHB1, AHB2 and AHB3
*/
case STM32F7_AHB1_CLOCK(GPIOA) ... STM32F7_AHB3_CLOCK(QSPI):
shift = ahb_psc_table[(
(readl(®s->cfgr) & RCC_CFGR_AHB_PSC_MASK)
>> RCC_CFGR_HPRE_SHIFT)];
return sysclk >>= shift;
break;
/* APB1 CLOCK */
case STM32F7_APB1_CLOCK(TIM2) ... STM32F7_APB1_CLOCK(UART8):
shift = apb_psc_table[(
(readl(®s->cfgr) & RCC_CFGR_APB1_PSC_MASK)
>> RCC_CFGR_PPRE1_SHIFT)];
return sysclk >>= shift;
break;
/* APB2 CLOCK */
case STM32F7_APB2_CLOCK(TIM1) ... STM32F7_APB2_CLOCK(LTDC):
shift = apb_psc_table[(
(readl(®s->cfgr) & RCC_CFGR_APB2_PSC_MASK)
>> RCC_CFGR_PPRE2_SHIFT)];
return sysclk >>= shift;
break;
default:
pr_err("clock index %ld out of range\n", clk->id);
return -EINVAL;
break;
}
}
static int stm32_clk_enable(struct clk *clk)
{
struct stm32_clk *priv = dev_get_priv(clk->dev);
struct stm32_rcc_regs *regs = priv->base;
u32 offset = clk->id / 32;
u32 bit_index = clk->id % 32;
debug("%s: clkid = %ld, offset from AHB1ENR is %d, bit_index = %d\n",
__func__, clk->id, offset, bit_index);
setbits_le32(®s->ahb1enr + offset, BIT(bit_index));
Toshifumi NISHINAGA
committed
void clock_setup(int peripheral)
{
switch (peripheral) {
case SYSCFG_CLOCK_CFG:
setbits_le32(&STM32_RCC->apb2enr, RCC_APB2ENR_SYSCFGEN);
break;
case TIMER2_CLOCK_CFG:
setbits_le32(&STM32_RCC->apb1enr, RCC_APB1ENR_TIM2EN);
break;
case STMMAC_CLOCK_CFG:
setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_ETHMAC_EN);
setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_ETHMAC_RX_EN);
setbits_le32(&STM32_RCC->ahb1enr, RCC_AHB1ENR_ETHMAC_TX_EN);
break;
default:
break;
}
}
static int stm32_clk_probe(struct udevice *dev)
{
struct ofnode_phandle_args args;
int err;
debug("%s: stm32_clk_probe\n", __func__);
struct stm32_clk *priv = dev_get_priv(dev);
fdt_addr_t addr;
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
priv->base = (struct stm32_rcc_regs *)addr;
priv->info = (struct stm32_clk_info *)dev_get_driver_data(dev);
if (priv->info->has_overdrive) {
err = dev_read_phandle_with_args(dev, "st,syscfg", NULL, 0, 0,
&args);
if (err) {
debug("%s: can't find syscon device (%d)\n", __func__,
err);
return err;
}
priv->pwr_regs = (struct stm32_pwr_regs *)ofnode_get_addr(args.node);
return 0;
}
static int stm32_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args)
{
debug("%s(clk=%p)\n", __func__, clk);
if (args->args_count != 2) {
debug("Invaild args_count: %d\n", args->args_count);
return -EINVAL;
}
if (args->args_count)
clk->id = args->args[1];
else
clk->id = 0;
return 0;
}
static struct clk_ops stm32_clk_ops = {
.of_xlate = stm32_clk_of_xlate,
.enable = stm32_clk_enable,
.get_rate = stm32_clk_get_rate,
};
static const struct udevice_id stm32_clk_ids[] = {
{ .compatible = "st,stm32f42xx-rcc", .data = (ulong)&stm32f4_clk_info},
{ .compatible = "st,stm32f746-rcc", .data = (ulong)&stm32f7_clk_info},
{}
};
U_BOOT_DRIVER(stm32f7_clk) = {
.name = "stm32f7_clk",
.id = UCLASS_CLK,
.of_match = stm32_clk_ids,
.ops = &stm32_clk_ops,
.probe = stm32_clk_probe,
.priv_auto_alloc_size = sizeof(struct stm32_clk),
.flags = DM_FLAG_PRE_RELOC,