2013-05-13 21:46:37 +04:00
/*
* Zynq clock controller
*
* Copyright ( C ) 2012 - 2013 Xilinx
*
* Sören Brinkmann < soren . brinkmann @ xilinx . com >
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License v2 as published by
* the Free Software Foundation .
*
* This program is distributed in the hope that 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/>.
*/
# include <linux/clk/zynq.h>
2015-06-20 01:00:46 +03:00
# include <linux/clk.h>
2013-05-13 21:46:37 +04:00
# include <linux/clk-provider.h>
# include <linux/of.h>
2013-11-18 19:48:19 +04:00
# include <linux/of_address.h>
2013-05-13 21:46:37 +04:00
# include <linux/slab.h>
# include <linux/string.h>
# include <linux/io.h>
2013-11-18 19:48:19 +04:00
static void __iomem * zynq_clkc_base ;
# define SLCR_ARMPLL_CTRL (zynq_clkc_base + 0x00)
# define SLCR_DDRPLL_CTRL (zynq_clkc_base + 0x04)
# define SLCR_IOPLL_CTRL (zynq_clkc_base + 0x08)
# define SLCR_PLL_STATUS (zynq_clkc_base + 0x0c)
# define SLCR_ARM_CLK_CTRL (zynq_clkc_base + 0x20)
# define SLCR_DDR_CLK_CTRL (zynq_clkc_base + 0x24)
# define SLCR_DCI_CLK_CTRL (zynq_clkc_base + 0x28)
# define SLCR_APER_CLK_CTRL (zynq_clkc_base + 0x2c)
# define SLCR_GEM0_CLK_CTRL (zynq_clkc_base + 0x40)
# define SLCR_GEM1_CLK_CTRL (zynq_clkc_base + 0x44)
# define SLCR_SMC_CLK_CTRL (zynq_clkc_base + 0x48)
# define SLCR_LQSPI_CLK_CTRL (zynq_clkc_base + 0x4c)
# define SLCR_SDIO_CLK_CTRL (zynq_clkc_base + 0x50)
# define SLCR_UART_CLK_CTRL (zynq_clkc_base + 0x54)
# define SLCR_SPI_CLK_CTRL (zynq_clkc_base + 0x58)
# define SLCR_CAN_CLK_CTRL (zynq_clkc_base + 0x5c)
# define SLCR_CAN_MIOCLK_CTRL (zynq_clkc_base + 0x60)
# define SLCR_DBG_CLK_CTRL (zynq_clkc_base + 0x64)
# define SLCR_PCAP_CLK_CTRL (zynq_clkc_base + 0x68)
# define SLCR_FPGA0_CLK_CTRL (zynq_clkc_base + 0x70)
# define SLCR_621_TRUE (zynq_clkc_base + 0xc4)
# define SLCR_SWDT_CLK_SEL (zynq_clkc_base + 0x204)
2013-05-13 21:46:37 +04:00
# define NUM_MIO_PINS 54
2014-04-17 22:40:52 +04:00
# define DBG_CLK_CTRL_CLKACT_TRC BIT(0)
# define DBG_CLK_CTRL_CPU_1XCLKACT BIT(1)
2013-05-13 21:46:37 +04:00
enum zynq_clk {
armpll , ddrpll , iopll ,
cpu_6or4x , cpu_3or2x , cpu_2x , cpu_1x ,
ddr2x , ddr3x , dci ,
lqspi , smc , pcap , gem0 , gem1 , fclk0 , fclk1 , fclk2 , fclk3 , can0 , can1 ,
sdio0 , sdio1 , uart0 , uart1 , spi0 , spi1 , dma ,
usb0_aper , usb1_aper , gem0_aper , gem1_aper ,
sdio0_aper , sdio1_aper , spi0_aper , spi1_aper , can0_aper , can1_aper ,
i2c0_aper , i2c1_aper , uart0_aper , uart1_aper , gpio_aper , lqspi_aper ,
smc_aper , swdt , dbg_trc , dbg_apb , clk_max } ;
static struct clk * ps_clk ;
static struct clk * clks [ clk_max ] ;
static struct clk_onecell_data clk_data ;
static DEFINE_SPINLOCK ( armpll_lock ) ;
static DEFINE_SPINLOCK ( ddrpll_lock ) ;
static DEFINE_SPINLOCK ( iopll_lock ) ;
static DEFINE_SPINLOCK ( armclk_lock ) ;
2013-06-18 02:03:46 +04:00
static DEFINE_SPINLOCK ( swdtclk_lock ) ;
2013-05-13 21:46:37 +04:00
static DEFINE_SPINLOCK ( ddrclk_lock ) ;
static DEFINE_SPINLOCK ( dciclk_lock ) ;
static DEFINE_SPINLOCK ( gem0clk_lock ) ;
static DEFINE_SPINLOCK ( gem1clk_lock ) ;
static DEFINE_SPINLOCK ( canclk_lock ) ;
static DEFINE_SPINLOCK ( canmioclk_lock ) ;
static DEFINE_SPINLOCK ( dbgclk_lock ) ;
static DEFINE_SPINLOCK ( aperclk_lock ) ;
2015-05-28 11:45:51 +03:00
static const char * const armpll_parents [ ] __initconst = { " armpll_int " ,
" ps_clk " } ;
static const char * const ddrpll_parents [ ] __initconst = { " ddrpll_int " ,
" ps_clk " } ;
static const char * const iopll_parents [ ] __initconst = { " iopll_int " ,
" ps_clk " } ;
2015-02-18 12:59:45 +03:00
static const char * gem0_mux_parents [ ] __initdata = { " gem0_div1 " , " dummy_name " } ;
static const char * gem1_mux_parents [ ] __initdata = { " gem1_div1 " , " dummy_name " } ;
2015-05-28 11:45:51 +03:00
static const char * const can0_mio_mux2_parents [ ] __initconst = { " can0_gate " ,
2013-05-13 21:46:37 +04:00
" can0_mio_mux " } ;
2015-05-28 11:45:51 +03:00
static const char * const can1_mio_mux2_parents [ ] __initconst = { " can1_gate " ,
2013-05-13 21:46:37 +04:00
" can1_mio_mux " } ;
2015-02-18 12:59:45 +03:00
static const char * dbg_emio_mux_parents [ ] __initdata = { " dbg_div " ,
2014-09-03 03:02:09 +04:00
" dummy_name " } ;
2013-05-13 21:46:37 +04:00
2015-05-28 11:45:51 +03:00
static const char * const dbgtrc_emio_input_names [ ] __initconst = {
" trace_emio_clk " } ;
static const char * const gem0_emio_input_names [ ] __initconst = {
" gem0_emio_clk " } ;
static const char * const gem1_emio_input_names [ ] __initconst = {
" gem1_emio_clk " } ;
static const char * const swdt_ext_clk_input_names [ ] __initconst = {
" swdt_ext_clk " } ;
2013-05-13 21:46:37 +04:00
static void __init zynq_clk_register_fclk ( enum zynq_clk fclk ,
const char * clk_name , void __iomem * fclk_ctrl_reg ,
2013-11-28 00:16:23 +04:00
const char * * parents , int enable )
2013-05-13 21:46:37 +04:00
{
struct clk * clk ;
2013-11-28 00:16:23 +04:00
u32 enable_reg ;
2013-05-13 21:46:37 +04:00
char * mux_name ;
char * div0_name ;
char * div1_name ;
spinlock_t * fclk_lock ;
spinlock_t * fclk_gate_lock ;
void __iomem * fclk_gate_reg = fclk_ctrl_reg + 8 ;
fclk_lock = kmalloc ( sizeof ( * fclk_lock ) , GFP_KERNEL ) ;
if ( ! fclk_lock )
goto err ;
fclk_gate_lock = kmalloc ( sizeof ( * fclk_gate_lock ) , GFP_KERNEL ) ;
if ( ! fclk_gate_lock )
2013-10-08 06:25:44 +04:00
goto err_fclk_gate_lock ;
2013-05-13 21:46:37 +04:00
spin_lock_init ( fclk_lock ) ;
spin_lock_init ( fclk_gate_lock ) ;
mux_name = kasprintf ( GFP_KERNEL , " %s_mux " , clk_name ) ;
2013-10-08 06:25:44 +04:00
if ( ! mux_name )
goto err_mux_name ;
2013-05-13 21:46:37 +04:00
div0_name = kasprintf ( GFP_KERNEL , " %s_div0 " , clk_name ) ;
2013-10-08 06:25:44 +04:00
if ( ! div0_name )
goto err_div0_name ;
2013-05-13 21:46:37 +04:00
div1_name = kasprintf ( GFP_KERNEL , " %s_div1 " , clk_name ) ;
2013-10-08 06:25:44 +04:00
if ( ! div1_name )
goto err_div1_name ;
2013-05-13 21:46:37 +04:00
2013-07-29 15:25:01 +04:00
clk = clk_register_mux ( NULL , mux_name , parents , 4 ,
CLK_SET_RATE_NO_REPARENT , fclk_ctrl_reg , 4 , 2 , 0 ,
fclk_lock ) ;
2013-05-13 21:46:37 +04:00
clk = clk_register_divider ( NULL , div0_name , mux_name ,
0 , fclk_ctrl_reg , 8 , 6 , CLK_DIVIDER_ONE_BASED |
CLK_DIVIDER_ALLOW_ZERO , fclk_lock ) ;
clk = clk_register_divider ( NULL , div1_name , div0_name ,
CLK_SET_RATE_PARENT , fclk_ctrl_reg , 20 , 6 ,
CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO ,
fclk_lock ) ;
clks [ fclk ] = clk_register_gate ( NULL , clk_name ,
div1_name , CLK_SET_RATE_PARENT , fclk_gate_reg ,
0 , CLK_GATE_SET_TO_DISABLE , fclk_gate_lock ) ;
2014-02-20 12:55:46 +04:00
enable_reg = clk_readl ( fclk_gate_reg ) & 1 ;
2013-11-28 00:16:23 +04:00
if ( enable & & ! enable_reg ) {
if ( clk_prepare_enable ( clks [ fclk ] ) )
pr_warn ( " %s: FCLK%u enable failed \n " , __func__ ,
fclk - fclk0 ) ;
}
2013-05-13 21:46:37 +04:00
kfree ( mux_name ) ;
kfree ( div0_name ) ;
kfree ( div1_name ) ;
return ;
2013-10-08 06:25:44 +04:00
err_div1_name :
kfree ( div0_name ) ;
err_div0_name :
kfree ( mux_name ) ;
err_mux_name :
kfree ( fclk_gate_lock ) ;
err_fclk_gate_lock :
kfree ( fclk_lock ) ;
2013-05-13 21:46:37 +04:00
err :
clks [ fclk ] = ERR_PTR ( - ENOMEM ) ;
}
static void __init zynq_clk_register_periph_clk ( enum zynq_clk clk0 ,
enum zynq_clk clk1 , const char * clk_name0 ,
const char * clk_name1 , void __iomem * clk_ctrl ,
const char * * parents , unsigned int two_gates )
{
struct clk * clk ;
char * mux_name ;
char * div_name ;
spinlock_t * lock ;
lock = kmalloc ( sizeof ( * lock ) , GFP_KERNEL ) ;
if ( ! lock )
goto err ;
spin_lock_init ( lock ) ;
mux_name = kasprintf ( GFP_KERNEL , " %s_mux " , clk_name0 ) ;
div_name = kasprintf ( GFP_KERNEL , " %s_div " , clk_name0 ) ;
2013-07-29 15:25:01 +04:00
clk = clk_register_mux ( NULL , mux_name , parents , 4 ,
CLK_SET_RATE_NO_REPARENT , clk_ctrl , 4 , 2 , 0 , lock ) ;
2013-05-13 21:46:37 +04:00
clk = clk_register_divider ( NULL , div_name , mux_name , 0 , clk_ctrl , 8 , 6 ,
CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO , lock ) ;
clks [ clk0 ] = clk_register_gate ( NULL , clk_name0 , div_name ,
CLK_SET_RATE_PARENT , clk_ctrl , 0 , 0 , lock ) ;
if ( two_gates )
clks [ clk1 ] = clk_register_gate ( NULL , clk_name1 , div_name ,
CLK_SET_RATE_PARENT , clk_ctrl , 1 , 0 , lock ) ;
kfree ( mux_name ) ;
kfree ( div_name ) ;
return ;
err :
clks [ clk0 ] = ERR_PTR ( - ENOMEM ) ;
if ( two_gates )
clks [ clk1 ] = ERR_PTR ( - ENOMEM ) ;
}
static void __init zynq_clk_setup ( struct device_node * np )
{
int i ;
u32 tmp ;
int ret ;
struct clk * clk ;
char * clk_name ;
2013-11-28 00:16:23 +04:00
unsigned int fclk_enable = 0 ;
2013-05-13 21:46:37 +04:00
const char * clk_output_name [ clk_max ] ;
const char * cpu_parents [ 4 ] ;
const char * periph_parents [ 4 ] ;
const char * swdt_ext_clk_mux_parents [ 2 ] ;
const char * can_mio_mux_parents [ NUM_MIO_PINS ] ;
2014-09-03 03:02:09 +04:00
const char * dummy_nm = " dummy_name " ;
2013-05-13 21:46:37 +04:00
pr_info ( " Zynq clock init \n " ) ;
/* get clock output names from DT */
for ( i = 0 ; i < clk_max ; i + + ) {
if ( of_property_read_string_index ( np , " clock-output-names " ,
i , & clk_output_name [ i ] ) ) {
pr_err ( " %s: clock output name not in DT \n " , __func__ ) ;
BUG ( ) ;
}
}
cpu_parents [ 0 ] = clk_output_name [ armpll ] ;
cpu_parents [ 1 ] = clk_output_name [ armpll ] ;
cpu_parents [ 2 ] = clk_output_name [ ddrpll ] ;
cpu_parents [ 3 ] = clk_output_name [ iopll ] ;
periph_parents [ 0 ] = clk_output_name [ iopll ] ;
periph_parents [ 1 ] = clk_output_name [ iopll ] ;
periph_parents [ 2 ] = clk_output_name [ armpll ] ;
periph_parents [ 3 ] = clk_output_name [ ddrpll ] ;
2013-11-28 00:16:23 +04:00
of_property_read_u32 ( np , " fclk-enable " , & fclk_enable ) ;
2013-05-13 21:46:37 +04:00
/* ps_clk */
ret = of_property_read_u32 ( np , " ps-clk-frequency " , & tmp ) ;
if ( ret ) {
pr_warn ( " ps_clk frequency not specified, using 33 MHz. \n " ) ;
tmp = 33333333 ;
}
ps_clk = clk_register_fixed_rate ( NULL , " ps_clk " , NULL , CLK_IS_ROOT ,
tmp ) ;
/* PLLs */
clk = clk_register_zynq_pll ( " armpll_int " , " ps_clk " , SLCR_ARMPLL_CTRL ,
SLCR_PLL_STATUS , 0 , & armpll_lock ) ;
clks [ armpll ] = clk_register_mux ( NULL , clk_output_name [ armpll ] ,
2013-07-29 15:25:01 +04:00
armpll_parents , 2 , CLK_SET_RATE_NO_REPARENT ,
SLCR_ARMPLL_CTRL , 4 , 1 , 0 , & armpll_lock ) ;
2013-05-13 21:46:37 +04:00
clk = clk_register_zynq_pll ( " ddrpll_int " , " ps_clk " , SLCR_DDRPLL_CTRL ,
SLCR_PLL_STATUS , 1 , & ddrpll_lock ) ;
clks [ ddrpll ] = clk_register_mux ( NULL , clk_output_name [ ddrpll ] ,
2013-07-29 15:25:01 +04:00
ddrpll_parents , 2 , CLK_SET_RATE_NO_REPARENT ,
SLCR_DDRPLL_CTRL , 4 , 1 , 0 , & ddrpll_lock ) ;
2013-05-13 21:46:37 +04:00
clk = clk_register_zynq_pll ( " iopll_int " , " ps_clk " , SLCR_IOPLL_CTRL ,
SLCR_PLL_STATUS , 2 , & iopll_lock ) ;
clks [ iopll ] = clk_register_mux ( NULL , clk_output_name [ iopll ] ,
2013-07-29 15:25:01 +04:00
iopll_parents , 2 , CLK_SET_RATE_NO_REPARENT ,
SLCR_IOPLL_CTRL , 4 , 1 , 0 , & iopll_lock ) ;
2013-05-13 21:46:37 +04:00
/* CPU clocks */
2014-02-20 12:55:46 +04:00
tmp = clk_readl ( SLCR_621_TRUE ) & 1 ;
2013-07-29 15:25:01 +04:00
clk = clk_register_mux ( NULL , " cpu_mux " , cpu_parents , 4 ,
CLK_SET_RATE_NO_REPARENT , SLCR_ARM_CLK_CTRL , 4 , 2 , 0 ,
& armclk_lock ) ;
2013-05-13 21:46:37 +04:00
clk = clk_register_divider ( NULL , " cpu_div " , " cpu_mux " , 0 ,
SLCR_ARM_CLK_CTRL , 8 , 6 , CLK_DIVIDER_ONE_BASED |
CLK_DIVIDER_ALLOW_ZERO , & armclk_lock ) ;
clks [ cpu_6or4x ] = clk_register_gate ( NULL , clk_output_name [ cpu_6or4x ] ,
" cpu_div " , CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED ,
SLCR_ARM_CLK_CTRL , 24 , 0 , & armclk_lock ) ;
clk = clk_register_fixed_factor ( NULL , " cpu_3or2x_div " , " cpu_div " , 0 ,
1 , 2 ) ;
clks [ cpu_3or2x ] = clk_register_gate ( NULL , clk_output_name [ cpu_3or2x ] ,
" cpu_3or2x_div " , CLK_IGNORE_UNUSED ,
SLCR_ARM_CLK_CTRL , 25 , 0 , & armclk_lock ) ;
clk = clk_register_fixed_factor ( NULL , " cpu_2x_div " , " cpu_div " , 0 , 1 ,
2 + tmp ) ;
clks [ cpu_2x ] = clk_register_gate ( NULL , clk_output_name [ cpu_2x ] ,
" cpu_2x_div " , CLK_IGNORE_UNUSED , SLCR_ARM_CLK_CTRL ,
26 , 0 , & armclk_lock ) ;
2015-01-27 22:05:27 +03:00
clk_prepare_enable ( clks [ cpu_2x ] ) ;
2013-05-13 21:46:37 +04:00
clk = clk_register_fixed_factor ( NULL , " cpu_1x_div " , " cpu_div " , 0 , 1 ,
4 + 2 * tmp ) ;
clks [ cpu_1x ] = clk_register_gate ( NULL , clk_output_name [ cpu_1x ] ,
" cpu_1x_div " , CLK_IGNORE_UNUSED , SLCR_ARM_CLK_CTRL , 27 ,
0 , & armclk_lock ) ;
/* Timers */
swdt_ext_clk_mux_parents [ 0 ] = clk_output_name [ cpu_1x ] ;
for ( i = 0 ; i < ARRAY_SIZE ( swdt_ext_clk_input_names ) ; i + + ) {
int idx = of_property_match_string ( np , " clock-names " ,
swdt_ext_clk_input_names [ i ] ) ;
if ( idx > = 0 )
swdt_ext_clk_mux_parents [ i + 1 ] =
of_clk_get_parent_name ( np , idx ) ;
else
swdt_ext_clk_mux_parents [ i + 1 ] = dummy_nm ;
}
clks [ swdt ] = clk_register_mux ( NULL , clk_output_name [ swdt ] ,
2013-07-29 15:25:01 +04:00
swdt_ext_clk_mux_parents , 2 , CLK_SET_RATE_PARENT |
CLK_SET_RATE_NO_REPARENT , SLCR_SWDT_CLK_SEL , 0 , 1 , 0 ,
2013-09-10 02:49:04 +04:00
& swdtclk_lock ) ;
2013-05-13 21:46:37 +04:00
/* DDR clocks */
clk = clk_register_divider ( NULL , " ddr2x_div " , " ddrpll " , 0 ,
SLCR_DDR_CLK_CTRL , 26 , 6 , CLK_DIVIDER_ONE_BASED |
CLK_DIVIDER_ALLOW_ZERO , & ddrclk_lock ) ;
clks [ ddr2x ] = clk_register_gate ( NULL , clk_output_name [ ddr2x ] ,
" ddr2x_div " , 0 , SLCR_DDR_CLK_CTRL , 1 , 0 , & ddrclk_lock ) ;
clk_prepare_enable ( clks [ ddr2x ] ) ;
clk = clk_register_divider ( NULL , " ddr3x_div " , " ddrpll " , 0 ,
SLCR_DDR_CLK_CTRL , 20 , 6 , CLK_DIVIDER_ONE_BASED |
CLK_DIVIDER_ALLOW_ZERO , & ddrclk_lock ) ;
clks [ ddr3x ] = clk_register_gate ( NULL , clk_output_name [ ddr3x ] ,
" ddr3x_div " , 0 , SLCR_DDR_CLK_CTRL , 0 , 0 , & ddrclk_lock ) ;
clk_prepare_enable ( clks [ ddr3x ] ) ;
clk = clk_register_divider ( NULL , " dci_div0 " , " ddrpll " , 0 ,
SLCR_DCI_CLK_CTRL , 8 , 6 , CLK_DIVIDER_ONE_BASED |
CLK_DIVIDER_ALLOW_ZERO , & dciclk_lock ) ;
clk = clk_register_divider ( NULL , " dci_div1 " , " dci_div0 " ,
CLK_SET_RATE_PARENT , SLCR_DCI_CLK_CTRL , 20 , 6 ,
CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO ,
& dciclk_lock ) ;
clks [ dci ] = clk_register_gate ( NULL , clk_output_name [ dci ] , " dci_div1 " ,
CLK_SET_RATE_PARENT , SLCR_DCI_CLK_CTRL , 0 , 0 ,
& dciclk_lock ) ;
clk_prepare_enable ( clks [ dci ] ) ;
/* Peripheral clocks */
2013-11-28 00:16:23 +04:00
for ( i = fclk0 ; i < = fclk3 ; i + + ) {
int enable = ! ! ( fclk_enable & BIT ( i - fclk0 ) ) ;
2013-05-13 21:46:37 +04:00
zynq_clk_register_fclk ( i , clk_output_name [ i ] ,
SLCR_FPGA0_CLK_CTRL + 0x10 * ( i - fclk0 ) ,
2013-11-28 00:16:23 +04:00
periph_parents , enable ) ;
}
2013-05-13 21:46:37 +04:00
zynq_clk_register_periph_clk ( lqspi , 0 , clk_output_name [ lqspi ] , NULL ,
SLCR_LQSPI_CLK_CTRL , periph_parents , 0 ) ;
zynq_clk_register_periph_clk ( smc , 0 , clk_output_name [ smc ] , NULL ,
SLCR_SMC_CLK_CTRL , periph_parents , 0 ) ;
zynq_clk_register_periph_clk ( pcap , 0 , clk_output_name [ pcap ] , NULL ,
SLCR_PCAP_CLK_CTRL , periph_parents , 0 ) ;
zynq_clk_register_periph_clk ( sdio0 , sdio1 , clk_output_name [ sdio0 ] ,
clk_output_name [ sdio1 ] , SLCR_SDIO_CLK_CTRL ,
periph_parents , 1 ) ;
zynq_clk_register_periph_clk ( uart0 , uart1 , clk_output_name [ uart0 ] ,
clk_output_name [ uart1 ] , SLCR_UART_CLK_CTRL ,
periph_parents , 1 ) ;
zynq_clk_register_periph_clk ( spi0 , spi1 , clk_output_name [ spi0 ] ,
clk_output_name [ spi1 ] , SLCR_SPI_CLK_CTRL ,
periph_parents , 1 ) ;
for ( i = 0 ; i < ARRAY_SIZE ( gem0_emio_input_names ) ; i + + ) {
int idx = of_property_match_string ( np , " clock-names " ,
gem0_emio_input_names [ i ] ) ;
if ( idx > = 0 )
gem0_mux_parents [ i + 1 ] = of_clk_get_parent_name ( np ,
idx ) ;
}
2013-07-29 15:25:01 +04:00
clk = clk_register_mux ( NULL , " gem0_mux " , periph_parents , 4 ,
CLK_SET_RATE_NO_REPARENT , SLCR_GEM0_CLK_CTRL , 4 , 2 , 0 ,
& gem0clk_lock ) ;
2013-05-13 21:46:37 +04:00
clk = clk_register_divider ( NULL , " gem0_div0 " , " gem0_mux " , 0 ,
SLCR_GEM0_CLK_CTRL , 8 , 6 , CLK_DIVIDER_ONE_BASED |
CLK_DIVIDER_ALLOW_ZERO , & gem0clk_lock ) ;
clk = clk_register_divider ( NULL , " gem0_div1 " , " gem0_div0 " ,
CLK_SET_RATE_PARENT , SLCR_GEM0_CLK_CTRL , 20 , 6 ,
CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO ,
& gem0clk_lock ) ;
2013-06-18 02:47:40 +04:00
clk = clk_register_mux ( NULL , " gem0_emio_mux " , gem0_mux_parents , 2 ,
2013-09-10 02:49:04 +04:00
CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT ,
SLCR_GEM0_CLK_CTRL , 6 , 1 , 0 ,
2013-06-18 02:47:40 +04:00
& gem0clk_lock ) ;
2013-05-13 21:46:37 +04:00
clks [ gem0 ] = clk_register_gate ( NULL , clk_output_name [ gem0 ] ,
" gem0_emio_mux " , CLK_SET_RATE_PARENT ,
SLCR_GEM0_CLK_CTRL , 0 , 0 , & gem0clk_lock ) ;
for ( i = 0 ; i < ARRAY_SIZE ( gem1_emio_input_names ) ; i + + ) {
int idx = of_property_match_string ( np , " clock-names " ,
gem1_emio_input_names [ i ] ) ;
if ( idx > = 0 )
gem1_mux_parents [ i + 1 ] = of_clk_get_parent_name ( np ,
idx ) ;
}
2013-07-29 15:25:01 +04:00
clk = clk_register_mux ( NULL , " gem1_mux " , periph_parents , 4 ,
CLK_SET_RATE_NO_REPARENT , SLCR_GEM1_CLK_CTRL , 4 , 2 , 0 ,
& gem1clk_lock ) ;
2013-05-13 21:46:37 +04:00
clk = clk_register_divider ( NULL , " gem1_div0 " , " gem1_mux " , 0 ,
SLCR_GEM1_CLK_CTRL , 8 , 6 , CLK_DIVIDER_ONE_BASED |
CLK_DIVIDER_ALLOW_ZERO , & gem1clk_lock ) ;
clk = clk_register_divider ( NULL , " gem1_div1 " , " gem1_div0 " ,
CLK_SET_RATE_PARENT , SLCR_GEM1_CLK_CTRL , 20 , 6 ,
CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO ,
& gem1clk_lock ) ;
2013-06-18 02:47:40 +04:00
clk = clk_register_mux ( NULL , " gem1_emio_mux " , gem1_mux_parents , 2 ,
2013-09-10 02:49:04 +04:00
CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT ,
SLCR_GEM1_CLK_CTRL , 6 , 1 , 0 ,
2013-06-18 02:47:40 +04:00
& gem1clk_lock ) ;
2013-05-13 21:46:37 +04:00
clks [ gem1 ] = clk_register_gate ( NULL , clk_output_name [ gem1 ] ,
" gem1_emio_mux " , CLK_SET_RATE_PARENT ,
SLCR_GEM1_CLK_CTRL , 0 , 0 , & gem1clk_lock ) ;
tmp = strlen ( " mio_clk_00x " ) ;
clk_name = kmalloc ( tmp , GFP_KERNEL ) ;
for ( i = 0 ; i < NUM_MIO_PINS ; i + + ) {
int idx ;
snprintf ( clk_name , tmp , " mio_clk_%2.2d " , i ) ;
idx = of_property_match_string ( np , " clock-names " , clk_name ) ;
if ( idx > = 0 )
can_mio_mux_parents [ i ] = of_clk_get_parent_name ( np ,
idx ) ;
else
can_mio_mux_parents [ i ] = dummy_nm ;
}
kfree ( clk_name ) ;
2013-07-29 15:25:01 +04:00
clk = clk_register_mux ( NULL , " can_mux " , periph_parents , 4 ,
CLK_SET_RATE_NO_REPARENT , SLCR_CAN_CLK_CTRL , 4 , 2 , 0 ,
& canclk_lock ) ;
2013-05-13 21:46:37 +04:00
clk = clk_register_divider ( NULL , " can_div0 " , " can_mux " , 0 ,
SLCR_CAN_CLK_CTRL , 8 , 6 , CLK_DIVIDER_ONE_BASED |
CLK_DIVIDER_ALLOW_ZERO , & canclk_lock ) ;
clk = clk_register_divider ( NULL , " can_div1 " , " can_div0 " ,
CLK_SET_RATE_PARENT , SLCR_CAN_CLK_CTRL , 20 , 6 ,
CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO ,
& canclk_lock ) ;
clk = clk_register_gate ( NULL , " can0_gate " , " can_div1 " ,
CLK_SET_RATE_PARENT , SLCR_CAN_CLK_CTRL , 0 , 0 ,
& canclk_lock ) ;
clk = clk_register_gate ( NULL , " can1_gate " , " can_div1 " ,
CLK_SET_RATE_PARENT , SLCR_CAN_CLK_CTRL , 1 , 0 ,
& canclk_lock ) ;
clk = clk_register_mux ( NULL , " can0_mio_mux " ,
2013-07-29 15:25:01 +04:00
can_mio_mux_parents , 54 , CLK_SET_RATE_PARENT |
CLK_SET_RATE_NO_REPARENT , SLCR_CAN_MIOCLK_CTRL , 0 , 6 , 0 ,
& canmioclk_lock ) ;
2013-05-13 21:46:37 +04:00
clk = clk_register_mux ( NULL , " can1_mio_mux " ,
2013-07-29 15:25:01 +04:00
can_mio_mux_parents , 54 , CLK_SET_RATE_PARENT |
CLK_SET_RATE_NO_REPARENT , SLCR_CAN_MIOCLK_CTRL , 16 , 6 ,
0 , & canmioclk_lock ) ;
2013-05-13 21:46:37 +04:00
clks [ can0 ] = clk_register_mux ( NULL , clk_output_name [ can0 ] ,
2013-07-29 15:25:01 +04:00
can0_mio_mux2_parents , 2 , CLK_SET_RATE_PARENT |
CLK_SET_RATE_NO_REPARENT , SLCR_CAN_MIOCLK_CTRL , 6 , 1 , 0 ,
& canmioclk_lock ) ;
2013-05-13 21:46:37 +04:00
clks [ can1 ] = clk_register_mux ( NULL , clk_output_name [ can1 ] ,
2013-07-29 15:25:01 +04:00
can1_mio_mux2_parents , 2 , CLK_SET_RATE_PARENT |
CLK_SET_RATE_NO_REPARENT , SLCR_CAN_MIOCLK_CTRL , 22 , 1 ,
0 , & canmioclk_lock ) ;
2013-05-13 21:46:37 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( dbgtrc_emio_input_names ) ; i + + ) {
int idx = of_property_match_string ( np , " clock-names " ,
dbgtrc_emio_input_names [ i ] ) ;
if ( idx > = 0 )
dbg_emio_mux_parents [ i + 1 ] = of_clk_get_parent_name ( np ,
idx ) ;
}
2013-07-29 15:25:01 +04:00
clk = clk_register_mux ( NULL , " dbg_mux " , periph_parents , 4 ,
CLK_SET_RATE_NO_REPARENT , SLCR_DBG_CLK_CTRL , 4 , 2 , 0 ,
& dbgclk_lock ) ;
2013-05-13 21:46:37 +04:00
clk = clk_register_divider ( NULL , " dbg_div " , " dbg_mux " , 0 ,
SLCR_DBG_CLK_CTRL , 8 , 6 , CLK_DIVIDER_ONE_BASED |
CLK_DIVIDER_ALLOW_ZERO , & dbgclk_lock ) ;
2013-07-29 15:25:01 +04:00
clk = clk_register_mux ( NULL , " dbg_emio_mux " , dbg_emio_mux_parents , 2 ,
CLK_SET_RATE_NO_REPARENT , SLCR_DBG_CLK_CTRL , 6 , 1 , 0 ,
& dbgclk_lock ) ;
2013-05-13 21:46:37 +04:00
clks [ dbg_trc ] = clk_register_gate ( NULL , clk_output_name [ dbg_trc ] ,
" dbg_emio_mux " , CLK_SET_RATE_PARENT , SLCR_DBG_CLK_CTRL ,
0 , 0 , & dbgclk_lock ) ;
clks [ dbg_apb ] = clk_register_gate ( NULL , clk_output_name [ dbg_apb ] ,
clk_output_name [ cpu_1x ] , 0 , SLCR_DBG_CLK_CTRL , 1 , 0 ,
& dbgclk_lock ) ;
2014-04-17 22:40:52 +04:00
/* leave debug clocks in the state the bootloader set them up to */
tmp = clk_readl ( SLCR_DBG_CLK_CTRL ) ;
if ( tmp & DBG_CLK_CTRL_CLKACT_TRC )
if ( clk_prepare_enable ( clks [ dbg_trc ] ) )
pr_warn ( " %s: trace clk enable failed \n " , __func__ ) ;
if ( tmp & DBG_CLK_CTRL_CPU_1XCLKACT )
if ( clk_prepare_enable ( clks [ dbg_apb ] ) )
pr_warn ( " %s: debug APB clk enable failed \n " , __func__ ) ;
2013-05-13 21:46:37 +04:00
/* One gated clock for all APER clocks. */
clks [ dma ] = clk_register_gate ( NULL , clk_output_name [ dma ] ,
clk_output_name [ cpu_2x ] , 0 , SLCR_APER_CLK_CTRL , 0 , 0 ,
& aperclk_lock ) ;
clks [ usb0_aper ] = clk_register_gate ( NULL , clk_output_name [ usb0_aper ] ,
clk_output_name [ cpu_1x ] , 0 , SLCR_APER_CLK_CTRL , 2 , 0 ,
& aperclk_lock ) ;
clks [ usb1_aper ] = clk_register_gate ( NULL , clk_output_name [ usb1_aper ] ,
clk_output_name [ cpu_1x ] , 0 , SLCR_APER_CLK_CTRL , 3 , 0 ,
& aperclk_lock ) ;
clks [ gem0_aper ] = clk_register_gate ( NULL , clk_output_name [ gem0_aper ] ,
clk_output_name [ cpu_1x ] , 0 , SLCR_APER_CLK_CTRL , 6 , 0 ,
& aperclk_lock ) ;
clks [ gem1_aper ] = clk_register_gate ( NULL , clk_output_name [ gem1_aper ] ,
clk_output_name [ cpu_1x ] , 0 , SLCR_APER_CLK_CTRL , 7 , 0 ,
& aperclk_lock ) ;
clks [ sdio0_aper ] = clk_register_gate ( NULL , clk_output_name [ sdio0_aper ] ,
clk_output_name [ cpu_1x ] , 0 , SLCR_APER_CLK_CTRL , 10 , 0 ,
& aperclk_lock ) ;
clks [ sdio1_aper ] = clk_register_gate ( NULL , clk_output_name [ sdio1_aper ] ,
clk_output_name [ cpu_1x ] , 0 , SLCR_APER_CLK_CTRL , 11 , 0 ,
& aperclk_lock ) ;
clks [ spi0_aper ] = clk_register_gate ( NULL , clk_output_name [ spi0_aper ] ,
clk_output_name [ cpu_1x ] , 0 , SLCR_APER_CLK_CTRL , 14 , 0 ,
& aperclk_lock ) ;
clks [ spi1_aper ] = clk_register_gate ( NULL , clk_output_name [ spi1_aper ] ,
clk_output_name [ cpu_1x ] , 0 , SLCR_APER_CLK_CTRL , 15 , 0 ,
& aperclk_lock ) ;
clks [ can0_aper ] = clk_register_gate ( NULL , clk_output_name [ can0_aper ] ,
clk_output_name [ cpu_1x ] , 0 , SLCR_APER_CLK_CTRL , 16 , 0 ,
& aperclk_lock ) ;
clks [ can1_aper ] = clk_register_gate ( NULL , clk_output_name [ can1_aper ] ,
clk_output_name [ cpu_1x ] , 0 , SLCR_APER_CLK_CTRL , 17 , 0 ,
& aperclk_lock ) ;
clks [ i2c0_aper ] = clk_register_gate ( NULL , clk_output_name [ i2c0_aper ] ,
clk_output_name [ cpu_1x ] , 0 , SLCR_APER_CLK_CTRL , 18 , 0 ,
& aperclk_lock ) ;
clks [ i2c1_aper ] = clk_register_gate ( NULL , clk_output_name [ i2c1_aper ] ,
clk_output_name [ cpu_1x ] , 0 , SLCR_APER_CLK_CTRL , 19 , 0 ,
& aperclk_lock ) ;
clks [ uart0_aper ] = clk_register_gate ( NULL , clk_output_name [ uart0_aper ] ,
clk_output_name [ cpu_1x ] , 0 , SLCR_APER_CLK_CTRL , 20 , 0 ,
& aperclk_lock ) ;
clks [ uart1_aper ] = clk_register_gate ( NULL , clk_output_name [ uart1_aper ] ,
clk_output_name [ cpu_1x ] , 0 , SLCR_APER_CLK_CTRL , 21 , 0 ,
& aperclk_lock ) ;
clks [ gpio_aper ] = clk_register_gate ( NULL , clk_output_name [ gpio_aper ] ,
clk_output_name [ cpu_1x ] , 0 , SLCR_APER_CLK_CTRL , 22 , 0 ,
& aperclk_lock ) ;
clks [ lqspi_aper ] = clk_register_gate ( NULL , clk_output_name [ lqspi_aper ] ,
clk_output_name [ cpu_1x ] , 0 , SLCR_APER_CLK_CTRL , 23 , 0 ,
& aperclk_lock ) ;
clks [ smc_aper ] = clk_register_gate ( NULL , clk_output_name [ smc_aper ] ,
clk_output_name [ cpu_1x ] , 0 , SLCR_APER_CLK_CTRL , 24 , 0 ,
& aperclk_lock ) ;
for ( i = 0 ; i < ARRAY_SIZE ( clks ) ; i + + ) {
if ( IS_ERR ( clks [ i ] ) ) {
pr_err ( " Zynq clk %d: register failed with %ld \n " ,
i , PTR_ERR ( clks [ i ] ) ) ;
BUG ( ) ;
}
}
clk_data . clks = clks ;
clk_data . clk_num = ARRAY_SIZE ( clks ) ;
of_clk_add_provider ( np , of_clk_src_onecell_get , & clk_data ) ;
}
CLK_OF_DECLARE ( zynq_clkc , " xlnx,ps7-clkc " , zynq_clk_setup ) ;
2013-11-18 19:48:19 +04:00
void __init zynq_clock_init ( void )
2013-05-13 21:46:37 +04:00
{
2013-11-18 19:48:19 +04:00
struct device_node * np ;
struct device_node * slcr ;
struct resource res ;
np = of_find_compatible_node ( NULL , NULL , " xlnx,ps7-clkc " ) ;
if ( ! np ) {
pr_err ( " %s: clkc node not found \n " , __func__ ) ;
goto np_err ;
}
if ( of_address_to_resource ( np , 0 , & res ) ) {
pr_err ( " %s: failed to get resource \n " , np - > name ) ;
goto np_err ;
}
slcr = of_get_parent ( np ) ;
if ( slcr - > data ) {
zynq_clkc_base = ( __force void __iomem * ) slcr - > data + res . start ;
} else {
pr_err ( " %s: Unable to get I/O memory \n " , np - > name ) ;
of_node_put ( slcr ) ;
goto np_err ;
}
pr_info ( " %s: clkc starts at %p \n " , __func__ , zynq_clkc_base ) ;
of_node_put ( slcr ) ;
of_node_put ( np ) ;
return ;
np_err :
of_node_put ( np ) ;
BUG ( ) ;
2013-05-13 21:46:37 +04:00
}