2019-05-27 09:55:06 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2014-01-06 20:27:37 +04:00
/*
* Copyright 2011 - 2012 Calxeda , Inc .
* Copyright ( C ) 2012 - 2013 Altera Corporation < www . altera . com >
*
* Based from clk - highbank . c
*/
2015-06-20 01:00:46 +03:00
# include <linux/slab.h>
2014-01-06 20:27:37 +04:00
# include <linux/clk-provider.h>
# include <linux/io.h>
# include <linux/of.h>
2014-04-14 16:59:32 +04:00
# include <linux/of_address.h>
2014-01-06 20:27:37 +04:00
# include "clk.h"
/* Clock bypass bits */
# define MAINPLL_BYPASS (1<<0)
# define SDRAMPLL_BYPASS (1<<1)
# define SDRAMPLL_SRC_BYPASS (1<<2)
# define PERPLL_BYPASS (1<<3)
# define PERPLL_SRC_BYPASS (1<<4)
# define SOCFPGA_PLL_BG_PWRDWN 0
# define SOCFPGA_PLL_EXT_ENA 1
# define SOCFPGA_PLL_PWR_DOWN 2
# define SOCFPGA_PLL_DIVF_MASK 0x0000FFF8
# define SOCFPGA_PLL_DIVF_SHIFT 3
# define SOCFPGA_PLL_DIVQ_MASK 0x003F0000
# define SOCFPGA_PLL_DIVQ_SHIFT 16
2014-02-20 01:11:11 +04:00
# define CLK_MGR_PLL_CLK_SRC_SHIFT 22
# define CLK_MGR_PLL_CLK_SRC_MASK 0x3
2014-01-06 20:27:37 +04:00
# define to_socfpga_clk(p) container_of(p, struct socfpga_pll, hw.hw)
2014-04-14 16:59:32 +04:00
void __iomem * clk_mgr_base_addr ;
2014-01-06 20:27:37 +04:00
static unsigned long clk_pll_recalc_rate ( struct clk_hw * hwclk ,
unsigned long parent_rate )
{
struct socfpga_pll * socfpgaclk = to_socfpga_clk ( hwclk ) ;
2014-02-20 01:11:10 +04:00
unsigned long divf , divq , reg ;
unsigned long long vco_freq ;
2014-01-06 20:27:37 +04:00
unsigned long bypass ;
reg = readl ( socfpgaclk - > hw . reg ) ;
bypass = readl ( clk_mgr_base_addr + CLKMGR_BYPASS ) ;
if ( bypass & MAINPLL_BYPASS )
return parent_rate ;
divf = ( reg & SOCFPGA_PLL_DIVF_MASK ) > > SOCFPGA_PLL_DIVF_SHIFT ;
divq = ( reg & SOCFPGA_PLL_DIVQ_MASK ) > > SOCFPGA_PLL_DIVQ_SHIFT ;
2014-02-20 01:11:10 +04:00
vco_freq = ( unsigned long long ) parent_rate * ( divf + 1 ) ;
do_div ( vco_freq , ( 1 + divq ) ) ;
return ( unsigned long ) vco_freq ;
2014-01-06 20:27:37 +04:00
}
2014-02-20 01:11:11 +04:00
static u8 clk_pll_get_parent ( struct clk_hw * hwclk )
{
u32 pll_src ;
struct socfpga_pll * socfpgaclk = to_socfpga_clk ( hwclk ) ;
pll_src = readl ( socfpgaclk - > hw . reg ) ;
return ( pll_src > > CLK_MGR_PLL_CLK_SRC_SHIFT ) &
CLK_MGR_PLL_CLK_SRC_MASK ;
}
2020-05-12 21:16:45 +03:00
static const struct clk_ops clk_pll_ops = {
2014-01-06 20:27:37 +04:00
. recalc_rate = clk_pll_recalc_rate ,
2014-02-20 01:11:11 +04:00
. get_parent = clk_pll_get_parent ,
2014-01-06 20:27:37 +04:00
} ;
2022-12-09 18:29:12 +03:00
static void __init __socfpga_pll_init ( struct device_node * node ,
const struct clk_ops * ops )
2014-01-06 20:27:37 +04:00
{
u32 reg ;
2021-03-03 00:41:49 +03:00
struct clk_hw * hw_clk ;
2014-01-06 20:27:37 +04:00
struct socfpga_pll * pll_clk ;
const char * clk_name = node - > name ;
2014-02-20 01:11:11 +04:00
const char * parent_name [ SOCFPGA_MAX_PARENTS ] ;
2014-01-06 20:27:37 +04:00
struct clk_init_data init ;
2014-04-14 16:59:32 +04:00
struct device_node * clkmgr_np ;
2022-12-09 18:29:12 +03:00
int rc ;
2014-01-06 20:27:37 +04:00
of_property_read_u32 ( node , " reg " , & reg ) ;
pll_clk = kzalloc ( sizeof ( * pll_clk ) , GFP_KERNEL ) ;
if ( WARN_ON ( ! pll_clk ) )
2022-12-09 18:29:12 +03:00
return ;
2014-01-06 20:27:37 +04:00
2014-04-14 16:59:32 +04:00
clkmgr_np = of_find_compatible_node ( NULL , NULL , " altr,clk-mgr " ) ;
clk_mgr_base_addr = of_iomap ( clkmgr_np , 0 ) ;
2018-12-26 16:29:02 +03:00
of_node_put ( clkmgr_np ) ;
2014-04-14 16:59:32 +04:00
BUG_ON ( ! clk_mgr_base_addr ) ;
2014-01-06 20:27:37 +04:00
pll_clk - > hw . reg = clk_mgr_base_addr + reg ;
of_property_read_string ( node , " clock-output-names " , & clk_name ) ;
init . name = clk_name ;
init . ops = ops ;
init . flags = 0 ;
2015-06-05 19:26:14 +03:00
init . num_parents = of_clk_parent_fill ( node , parent_name , SOCFPGA_MAX_PARENTS ) ;
2014-02-20 01:11:11 +04:00
init . parent_names = parent_name ;
2014-01-06 20:27:37 +04:00
pll_clk - > hw . hw . init = & init ;
pll_clk - > hw . bit_idx = SOCFPGA_PLL_EXT_ENA ;
2021-03-03 00:41:49 +03:00
hw_clk = & pll_clk - > hw . hw ;
2022-12-09 18:29:12 +03:00
rc = clk_hw_register ( NULL , hw_clk ) ;
if ( rc ) {
pr_err ( " Could not register clock:%s \n " , clk_name ) ;
goto err_clk_hw_register ;
2014-01-06 20:27:37 +04:00
}
2022-12-09 18:29:12 +03:00
rc = of_clk_add_hw_provider ( node , of_clk_hw_simple_get , hw_clk ) ;
if ( rc ) {
pr_err ( " Could not register clock provider for node:%s \n " ,
clk_name ) ;
goto err_of_clk_add_hw_provider ;
}
return ;
err_of_clk_add_hw_provider :
clk_hw_unregister ( hw_clk ) ;
err_clk_hw_register :
kfree ( pll_clk ) ;
2014-01-06 20:27:37 +04:00
}
void __init socfpga_pll_init ( struct device_node * node )
{
__socfpga_pll_init ( node , & clk_pll_ops ) ;
}