2018-09-12 16:40:17 +03:00
// SPDX-License-Identifier: GPL-2.0
2017-02-07 23:28:15 +03:00
/*
* Marvell MV98DX3236 SoC clocks
*
* Copyright ( C ) 2012 Marvell
*
* Gregory CLEMENT < gregory . clement @ free - electrons . com >
* Sebastian Hesselbarth < sebastian . hesselbarth @ gmail . com >
* Andrew Lunn < andrew @ lunn . ch >
*
*/
# include <linux/kernel.h>
# include <linux/clk-provider.h>
# include <linux/io.h>
# include <linux/of.h>
# include "common.h"
/*
* For 98 DX4251 Sample At Reset the CPU , DDR and Main PLL clocks are all
* defined at the same time
*
* SAR1 [ 20 : 18 ] : CPU frequency DDR frequency MPLL frequency
* 0 = 400 MHz 400 MHz 800 MHz
* 2 = 667 MHz 667 MHz 2000 MHz
* 3 = 800 MHz 800 MHz 1600 MHz
* others reserved .
*
* For 98 DX3236 Sample At Reset the CPU , DDR and Main PLL clocks are all
* defined at the same time
*
* SAR1 [ 20 : 18 ] : CPU frequency DDR frequency MPLL frequency
* 1 = 667 MHz 667 MHz 2000 MHz
* 2 = 400 MHz 400 MHz 400 MHz
* 3 = 800 MHz 800 MHz 800 MHz
* 5 = 800 MHz 400 MHz 800 MHz
* others reserved .
*/
# define SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT 18
# define SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT_MASK 0x7
static u32 __init mv98dx3236_get_tclk_freq ( void __iomem * sar )
{
/* Tclk = 200MHz, no SaR dependency */
return 200000000 ;
}
static const u32 mv98dx3236_cpu_frequencies [ ] __initconst = {
0 ,
667000000 ,
400000000 ,
800000000 ,
0 ,
800000000 ,
0 , 0 ,
} ;
static const u32 mv98dx4251_cpu_frequencies [ ] __initconst = {
400000000 ,
0 ,
667000000 ,
800000000 ,
0 , 0 , 0 , 0 ,
} ;
static u32 __init mv98dx3236_get_cpu_freq ( void __iomem * sar )
{
u32 cpu_freq = 0 ;
u8 cpu_freq_select = 0 ;
cpu_freq_select = ( ( readl ( sar ) > > SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT ) &
SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT_MASK ) ;
if ( of_machine_is_compatible ( " marvell,armadaxp-98dx4251 " ) )
cpu_freq = mv98dx4251_cpu_frequencies [ cpu_freq_select ] ;
else if ( of_machine_is_compatible ( " marvell,armadaxp-98dx3236 " ) )
cpu_freq = mv98dx3236_cpu_frequencies [ cpu_freq_select ] ;
if ( ! cpu_freq )
pr_err ( " CPU freq select unsupported %d \n " , cpu_freq_select ) ;
return cpu_freq ;
}
enum {
MV98DX3236_CPU_TO_DDR ,
MV98DX3236_CPU_TO_MPLL
} ;
static const struct coreclk_ratio mv98dx3236_core_ratios [ ] __initconst = {
{ . id = MV98DX3236_CPU_TO_DDR , . name = " ddrclk " } ,
{ . id = MV98DX3236_CPU_TO_MPLL , . name = " mpll " } ,
} ;
static const int __initconst mv98dx3236_cpu_mpll_ratios [ 8 ] [ 2 ] = {
{ 0 , 1 } , { 3 , 1 } , { 1 , 1 } , { 1 , 1 } ,
{ 0 , 1 } , { 1 , 1 } , { 0 , 1 } , { 0 , 1 } ,
} ;
static const int __initconst mv98dx3236_cpu_ddr_ratios [ 8 ] [ 2 ] = {
{ 0 , 1 } , { 1 , 1 } , { 1 , 1 } , { 1 , 1 } ,
{ 0 , 1 } , { 1 , 2 } , { 0 , 1 } , { 0 , 1 } ,
} ;
static const int __initconst mv98dx4251_cpu_mpll_ratios [ 8 ] [ 2 ] = {
{ 2 , 1 } , { 0 , 1 } , { 3 , 1 } , { 2 , 1 } ,
{ 0 , 1 } , { 0 , 1 } , { 0 , 1 } , { 0 , 1 } ,
} ;
static const int __initconst mv98dx4251_cpu_ddr_ratios [ 8 ] [ 2 ] = {
{ 1 , 1 } , { 0 , 1 } , { 1 , 1 } , { 1 , 1 } ,
{ 0 , 1 } , { 0 , 1 } , { 0 , 1 } , { 0 , 1 } ,
} ;
static void __init mv98dx3236_get_clk_ratio (
void __iomem * sar , int id , int * mult , int * div )
{
u32 opt = ( ( readl ( sar ) > > SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT ) &
SAR1_MV98DX3236_CPU_DDR_MPLL_FREQ_OPT_MASK ) ;
switch ( id ) {
case MV98DX3236_CPU_TO_DDR :
if ( of_machine_is_compatible ( " marvell,armadaxp-98dx4251 " ) ) {
* mult = mv98dx4251_cpu_ddr_ratios [ opt ] [ 0 ] ;
* div = mv98dx4251_cpu_ddr_ratios [ opt ] [ 1 ] ;
} else if ( of_machine_is_compatible ( " marvell,armadaxp-98dx3236 " ) ) {
* mult = mv98dx3236_cpu_ddr_ratios [ opt ] [ 0 ] ;
* div = mv98dx3236_cpu_ddr_ratios [ opt ] [ 1 ] ;
}
break ;
case MV98DX3236_CPU_TO_MPLL :
if ( of_machine_is_compatible ( " marvell,armadaxp-98dx4251 " ) ) {
* mult = mv98dx4251_cpu_mpll_ratios [ opt ] [ 0 ] ;
* div = mv98dx4251_cpu_mpll_ratios [ opt ] [ 1 ] ;
} else if ( of_machine_is_compatible ( " marvell,armadaxp-98dx3236 " ) ) {
* mult = mv98dx3236_cpu_mpll_ratios [ opt ] [ 0 ] ;
* div = mv98dx3236_cpu_mpll_ratios [ opt ] [ 1 ] ;
}
break ;
}
}
static const struct coreclk_soc_desc mv98dx3236_core_clocks = {
. get_tclk_freq = mv98dx3236_get_tclk_freq ,
. get_cpu_freq = mv98dx3236_get_cpu_freq ,
. get_clk_ratio = mv98dx3236_get_clk_ratio ,
. ratios = mv98dx3236_core_ratios ,
. num_ratios = ARRAY_SIZE ( mv98dx3236_core_ratios ) ,
} ;
/*
* Clock Gating Control
*/
static const struct clk_gating_soc_desc mv98dx3236_gating_desc [ ] __initconst = {
{ " ge1 " , NULL , 3 , 0 } ,
{ " ge0 " , NULL , 4 , 0 } ,
{ " pex00 " , NULL , 5 , 0 } ,
{ " sdio " , NULL , 17 , 0 } ,
{ " usb0 " , NULL , 18 , 0 } ,
{ " xor0 " , NULL , 22 , 0 } ,
{ }
} ;
static void __init mv98dx3236_clk_init ( struct device_node * np )
{
struct device_node * cgnp =
of_find_compatible_node ( NULL , NULL , " marvell,mv98dx3236-gating-clock " ) ;
mvebu_coreclk_setup ( np , & mv98dx3236_core_clocks ) ;
2018-12-26 16:48:05 +03:00
if ( cgnp ) {
2017-02-07 23:28:15 +03:00
mvebu_clk_gating_setup ( cgnp , mv98dx3236_gating_desc ) ;
2018-12-26 16:48:05 +03:00
of_node_put ( cgnp ) ;
}
2017-02-07 23:28:15 +03:00
}
CLK_OF_DECLARE ( mv98dx3236_clk , " marvell,mv98dx3236-core-clock " , mv98dx3236_clk_init ) ;