@ -57,8 +57,12 @@
# define RCC_PLLSAICFGR_PLLSAIN_MASK GENMASK(14, 6)
# define RCC_PLLSAICFGR_PLLSAIP_MASK GENMASK(17, 16)
# define RCC_PLLSAICFGR_PLLSAIQ_MASK GENMASK(27, 24)
# define RCC_PLLSAICFGR_PLLSAIR_MASK GENMASK(30, 28)
# define RCC_PLLSAICFGR_PLLSAIN_SHIFT 6
# define RCC_PLLSAICFGR_PLLSAIP_SHIFT 16
# define RCC_PLLSAICFGR_PLLSAIQ_SHIFT 24
# define RCC_PLLSAICFGR_PLLSAIR_SHIFT 28
# define RCC_PLLSAICFGR_PLLSAIP_4 BIT(16)
# define RCC_PLLSAICFGR_PLLSAIQ_4 BIT(26)
# define RCC_PLLSAICFGR_PLLSAIR_2 BIT(29)
@ -87,6 +91,12 @@
# define RCC_APB2ENR_SYSCFGEN BIT(14)
# define RCC_APB2ENR_SAI1EN BIT(22)
enum pllsai_div {
PLLSAIP ,
PLLSAIQ ,
PLLSAIR ,
} ;
static const struct stm32_clk_info stm32f4_clk_info = {
/* 180 MHz */
. sys_pll_psc = {
@ -216,32 +226,57 @@ static int configure_clocks(struct udevice *dev)
return 0 ;
}
static unsigned long stm32_clk_pll48clk_rate ( struct stm32_clk * priv ,
u32 vco )
static bool stm32_clk_get_ck48msel ( struct stm32_clk * priv )
{
struct stm32_rcc_regs * regs = priv - > base ;
u16 pllq , pllm , pllsain , pllsaip ;
bool pllsai ;
pllq = ( readl ( & regs - > pllcfgr ) & RCC_PLLCFGR_PLLQ_MASK )
> > RCC_PLLCFGR_PLLQ_SHIFT ;
if ( priv - > info . v2 ) /*stm32f7 case */
pllsai = readl ( & regs - > dckcfgr2 ) & RCC_DCKCFGRX_CK48MSEL ;
return readl ( & regs - > dckcfgr2 ) & RCC_DCKCFGRX_CK48MSEL ;
else
pllsai = readl ( & regs - > dckcfgr ) & RCC_DCKCFGRX_CK48MSEL ;
if ( pllsai ) {
/* PLL48CLK is selected from PLLSAI, get PLLSAI value */
pllm = ( readl ( & regs - > pllcfgr ) & RCC_PLLCFGR_PLLM_MASK ) ;
pllsain = ( ( readl ( & regs - > pllsaicfgr ) & RCC_PLLSAICFGR_PLLSAIN_MASK )
> > RCC_PLLSAICFGR_PLLSAIN_SHIFT ) ;
pllsaip = ( ( ( ( readl ( & regs - > pllsaicfgr ) & RCC_PLLSAICFGR_PLLSAIP_MASK )
> > RCC_PLLSAICFGR_PLLSAIP_SHIFT ) + 1 ) < < 1 ) ;
return ( ( priv - > hse_rate / pllm ) * pllsain ) / pllsaip ;
return readl ( & regs - > dckcfgr ) & RCC_DCKCFGRX_CK48MSEL ;
}
static unsigned long stm32_clk_get_pllsai_vco_rate ( struct stm32_clk * priv )
{
struct stm32_rcc_regs * regs = priv - > base ;
u16 pllm , pllsain ;
pllm = ( readl ( & regs - > pllcfgr ) & RCC_PLLCFGR_PLLM_MASK ) ;
pllsain = ( ( readl ( & regs - > pllsaicfgr ) & RCC_PLLSAICFGR_PLLSAIN_MASK )
> > RCC_PLLSAICFGR_PLLSAIN_SHIFT ) ;
return ( ( priv - > hse_rate / pllm ) * pllsain ) ;
}
static unsigned long stm32_clk_get_pllsai_rate ( struct stm32_clk * priv ,
enum pllsai_div output )
{
struct stm32_rcc_regs * regs = priv - > base ;
u16 pll_div_output ;
switch ( output ) {
case PLLSAIP :
pll_div_output = ( ( ( ( readl ( & regs - > pllsaicfgr )
& RCC_PLLSAICFGR_PLLSAIP_MASK )
> > RCC_PLLSAICFGR_PLLSAIP_SHIFT ) + 1 ) < < 1 ) ;
break ;
case PLLSAIQ :
pll_div_output = ( readl ( & regs - > pllsaicfgr )
& RCC_PLLSAICFGR_PLLSAIQ_MASK )
> > RCC_PLLSAICFGR_PLLSAIQ_SHIFT ;
break ;
case PLLSAIR :
pll_div_output = ( readl ( & regs - > pllsaicfgr )
& RCC_PLLSAICFGR_PLLSAIR_MASK )
> > RCC_PLLSAICFGR_PLLSAIR_SHIFT ;
break ;
default :
pr_err ( " incorrect PLLSAI output %d \n " , output ) ;
return - EINVAL ;
}
/* PLL48CLK is selected from PLLQ */
return vco / pllq ;
return ( stm32_clk_get_pllsai_ vco_rate ( priv ) / pll_div_output ) ;
}
static bool stm32_get_timpre ( struct stm32_clk * priv )
@ -325,7 +360,8 @@ static ulong stm32_clk_get_rate(struct clk *clk)
struct stm32_rcc_regs * regs = priv - > base ;
u32 sysclk = 0 ;
u32 vco ;
u16 pllm , plln , pllp ;
u32 sdmmcxsel_bit ;
u16 pllm , plln , pllp , pllq ;
if ( ( readl ( & regs - > cfgr ) & RCC_CFGR_SWS_MASK ) = =
RCC_CFGR_SWS_PLL ) {
@ -334,6 +370,8 @@ static ulong stm32_clk_get_rate(struct clk *clk)
> > RCC_PLLCFGR_PLLN_SHIFT ) ;
pllp = ( ( ( ( readl ( & regs - > pllcfgr ) & RCC_PLLCFGR_PLLP_MASK )
> > RCC_PLLCFGR_PLLP_SHIFT ) + 1 ) < < 1 ) ;
pllq = ( ( readl ( & regs - > pllcfgr ) & RCC_PLLCFGR_PLLQ_MASK )
> > RCC_PLLCFGR_PLLQ_SHIFT ) ;
vco = ( priv - > hse_rate / pllm ) * plln ;
sysclk = vco / pllp ;
} else {
@ -366,25 +404,30 @@ static ulong stm32_clk_get_rate(struct clk *clk)
/* APB2 CLOCK */
case STM32F7_APB2_CLOCK ( TIM1 ) . . . STM32F7_APB2_CLOCK ( LTDC ) :
switch ( clk - > id ) {
/*
* particular case for SDMMC1 and SDMMC2 :
* 48 Mhz source clock can be from main PLL or from
* SAI PLL
* PLL SAIP
*/
switch ( clk - > id ) {
case STM32F7_APB2_CLOCK ( SDMMC1 ) :
if ( readl ( & regs - > dckcfgr2 ) & RCC_DCKCFGRX_SDMMC1SEL )
/* System clock is selected as SDMMC1 clock */
return sysclk ;
else
return stm32_clk_pll48clk_rate ( priv , vco ) ;
break ;
case STM32F7_APB2_CLOCK ( SDMMC2 ) :
if ( readl ( & regs - > dckcfgr2 ) & RCC_DCKCFGR2_SDMMC2SEL )
/* System clock is selected as SDMMC2 clock */
if ( clk - > id = = STM32F7_APB2_CLOCK ( SDMMC1 ) )
sdmmcxsel_bit = RCC_DCKCFGRX_SDMMC1SEL ;
else
sdmmcxsel_bit = RCC_DCKCFGR2_SDMMC2SEL ;
if ( readl ( & regs - > dckcfgr2 ) & sdmmcxsel_bit )
/* System clock is selected as SDMMC1 clock */
return sysclk ;
/*
* 48 MHz can be generated by either PLLSAIP
* or by PLLQ depending of CK48MSEL bit of RCC_DCKCFGR
*/
if ( stm32_clk_get_ck48msel ( priv ) )
return stm32_clk_get_pllsai_rate ( priv , PLLSAIP ) ;
else
return stm32_clk_pll48clk_rate ( priv , vco ) ;
return ( vco / pllq ) ;
break ;
/* For timer clock, an additionnal prescaler is used*/