OSHW-DEIMOS/SOFTWARE/A64-TERES/linux-a64/drivers/clk/sunxi/clk-default.c
Dimitar Gamishev f9b0e7a283 linux
2017-10-13 14:07:04 +03:00

361 lines
9.2 KiB
C
Executable File

/*
* Copyright (C) 2013 Allwinnertech, kevin.z.m <kevin@allwinnertech.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 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.
*/
#include <linux/clk-private.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/clk/sunxi.h>
#include <mach/sys_config.h>
#include "clk-sunxi.h"
#include "clk-factors.h"
#include "clk-periph.h"
#include "clk-sun8iw1.h"
#ifdef CONFIG_ARCH_SUN8IW3
#define SYS_CONFIG_PAT_EN 1
static struct sunxi_clk_pat_item clkpat_table[]=
{
{"pll3","pll3pat"},
{"pll_mipi","pll_mipipat"},
};
#endif
#ifdef CONFIG_ARCH_SUN8IW5
#define SYS_CONFIG_PAT_EN 1
static struct sunxi_clk_pat_item clkpat_table[]=
{
{"pll_cpu","pll_cpupat"},
{"pll_video","pll_videopat"},
{"pll_ve","pll_vepat"},
{"pll_gpu","pll_gpupat"},
{"pll_hsic","pll_hsicpat"},
{"pll_de","pll_depat"},
{"pll_mipi","pll_mipipat"},
};
#endif
#ifdef CONFIG_ARCH_SUN8IW6
#define SYS_CONFIG_PAT_EN 1
static struct sunxi_clk_pat_item clkpat_table[]=
{
{"pll_video0","pll_video0pat"},
};
#endif
#ifdef CONFIG_ARCH_SUN9IW1
#define SYS_CONFIG_PAT_EN 1
static struct sunxi_clk_pat_item clkpat_table[]=
{
{"pll7","pll7pat"},
{"pll8","pll8pat"},
{"pll9","pll9pat"},
};
#endif
static void sunxi_clk_default_source(void)
{
script_item_u script_item;
struct clk *clk = NULL;
struct clk *parent_clk = NULL;
unsigned int org_rate;
#if defined(CONFIG_SUNXI_CLK_AHB_FROM_PLL6) && !defined(CONFIG_ARCH_SUN9IW1)
clk = clk_get(NULL,"ahb1");
if(!clk || IS_ERR(clk))
printk("Error not get clk ahb1\n");
else
{
parent_clk = clk_get(NULL,"pll6ahb1");
if(!parent_clk || IS_ERR(parent_clk))
{
clk_put(clk);
printk("Error not get clk pll6ahb1");
}
else
{
printk("try to set ahb clk source to pll6ahb1\n");
clk_set_parent(clk,parent_clk);
printk("set ahb clk source to pll6ahb1\n");
clk_put(parent_clk);
clk_put(clk);
}
}
#else
if((script_get_item("clock", "ahb1_parent", &script_item) == SCIRPT_ITEM_VALUE_TYPE_STR) && script_item.str)
{
clk = clk_get(NULL,"ahb1");
if(!clk || IS_ERR(clk))
printk("Error not get clk ahb1\n");
else
{
parent_clk = clk_get(NULL,script_item.str);
if(!parent_clk || IS_ERR(parent_clk))
{
clk_put(clk);
printk("Error not get clk %s\n",script_item.str);
}
else
{
clk_set_parent(clk,parent_clk);
printk("set ahb1 clk source to %s\n",script_item.str);
clk_put(parent_clk);
clk_put(clk);
}
}
}
#endif
if((script_get_item("clock", "apb1_parent", &script_item) == SCIRPT_ITEM_VALUE_TYPE_STR) && script_item.str)
{
clk = clk_get(NULL,"apb1");
if(!clk || IS_ERR(clk))
printk("Error not get clk apb1\n");
else
{
parent_clk = clk_get(NULL,script_item.str);
if(!parent_clk || IS_ERR(parent_clk))
{
clk_put(clk);
printk("Error not get clk %s\n",script_item.str);
}
else
{
// switch to 1.2 M
org_rate = clk_get_rate(clk);
printk(KERN_INFO "set apb1 to low freq 1.2 Mhz\n");
clk_set_rate(clk, 1200000);
clk_set_parent(clk,parent_clk);
printk("set apb1 clk source to %s\n",script_item.str);
printk(KERN_INFO "recover apb1 to pre freq %d\n",org_rate);
clk_set_rate(clk, org_rate);
clk_put(parent_clk);
clk_put(clk);
}
}
}
if((script_get_item("clock", "apb2_parent", &script_item) == SCIRPT_ITEM_VALUE_TYPE_STR) && script_item.str)
{
clk = clk_get(NULL,"apb2");
if(!clk || IS_ERR(clk))
printk("Error not get clk apb2\n");
else
{
parent_clk = clk_get(NULL,script_item.str);
if(!parent_clk || IS_ERR(parent_clk))
{
clk_put(clk);
printk("Error not get clk %s\n",script_item.str);
}
else
{
// switch to 1.2 M
org_rate = clk_get_rate(clk);
printk(KERN_INFO "set apb2 to low freq 1.2 Mhz\n");
clk_set_rate(clk, 1200000);
clk_set_parent(clk,parent_clk);
printk("set ahb clk source to %s\n",script_item.str);
printk(KERN_INFO "recove apb2 to pre freq %d\n",org_rate);
clk_set_rate(clk, org_rate);
clk_put(parent_clk);
clk_put(clk);
}
}
}
}
#ifdef CONFIG_SUNXI_CLK_DEFAULT_INIT
#if defined (CONFIG_ARCH_SUN9IW1)
static char *init_clks[] ={"pll3","pll7","pll8","pll10","ahb1"};
#elif defined (CONFIG_ARCH_SUN8IW3) || defined (CONFIG_ARCH_SUN8IW5)
static char *init_clks[] = {"pll3", "pll4","pll6","pll8","pll9","pll10"};
#elif defined (CONFIG_ARCH_SUN8IW6)
static char *init_clks[] = {"pll_video1", "pll_ve","pll_periph","pll_gpu","pll_hsic","pll_de"};
#elif defined (CONFIG_ARCH_SUN8IW8)
static char *init_clks[] = {"pll_isp", "pll_video", "pll_ve","pll_periph0","pll_de"};
//add pll_isp for camera.
#elif defined (CONFIG_ARCH_SUN8IW7)
static char *init_clks[] = {"pll_video","pll_de","pll_ve"};
#else
static char *init_clks[] = {"pll3", "pll4","pll6","pll7","pll8","pll9","pll10"};
#endif
static int __init sunxi_clk_default_plls(void)
{
int i;
script_item_u script_item;
struct clk *clk = NULL;
for(i=0;i < ARRAY_SIZE(init_clks);i++)
{
if(script_get_item("clock", init_clks[i], &script_item) == SCIRPT_ITEM_VALUE_TYPE_INT)
{
if(script_item.val) {
clk = clk_get(NULL,init_clks[i]);
if(!clk || IS_ERR(clk))
{
clk = NULL;
printk("Error not get clk %s\n",init_clks[i]);
continue;
}
printk(KERN_INFO "script config %s to %d Mhz\n", init_clks[i],script_item.val);
clk_set_rate(clk, script_item.val*1000000);
clk_put(clk);
clk=NULL;
}
}
else
printk(KERN_NOTICE "Not Found clk %s in script \n",init_clks[i]);
}
printk("sunxi_default_clk_init\n");
#if defined(CONFIG_PLL6AHB1_CLK_DFT_VALUE) && (CONFIG_PLL6AHB1_CLK_DFT_VALUE > 0)
printk("try to set pll6ahb1 to %d\n",CONFIG_PLL6AHB1_CLK_DFT_VALUE);
#if defined (CONFIG_ARCH_SUN8IW6)
clk = clk_get(NULL,"pll_periphahb1");
#else
clk = clk_get(NULL,"pll6ahb1");
#endif
if(!clk || IS_ERR(clk))
{
clk = NULL;
#if defined (CONFIG_ARCH_SUN8IW6)
printk("Error not get clk pll_periphahb1\n");
#else
printk("Error not get clk pll6ahb1\n");
#endif
return 0;
}
clk_set_rate(clk,CONFIG_PLL6AHB1_CLK_DFT_VALUE);
clk_put(clk);
#endif
return 0;
}
static int __init sunxi_clk_default_devices(void)
{
script_item_u script_item;
struct clk *clk = NULL;
#if defined(CONFIG_AHB1_CLK_DFT_VALUE) && (CONFIG_AHB1_CLK_DFT_VALUE > 0)
printk("try to set ahb1 to %d\n",CONFIG_AHB1_CLK_DFT_VALUE);
clk = clk_get(NULL,"ahb1");
if(!clk || IS_ERR(clk))
{
clk = NULL;
printk("Error not get clk ahb1\n");
}
else
{
clk_set_rate(clk,CONFIG_AHB1_CLK_DFT_VALUE);
clk_put(clk);
}
#endif
#if defined(CONFIG_APB1_CLK_DFT_VALUE) && (CONFIG_APB1_CLK_DFT_VALUE > 0)
printk("try to set apb1 to %d\n",CONFIG_APB1_CLK_DFT_VALUE);
clk = clk_get(NULL,"apb1");
if(!clk || IS_ERR(clk))
{
clk = NULL;
printk("Error not get clk apb1\n");
}
else
{
clk_set_rate(clk,CONFIG_APB1_CLK_DFT_VALUE);
clk_put(clk);
}
#endif
if((script_get_item("clock", "apb1", &script_item) == SCIRPT_ITEM_VALUE_TYPE_INT) && script_item.val)
{
clk = clk_get(NULL,"apb1");
if(!clk || IS_ERR(clk))
{
clk = NULL;
printk("Error not get clk %s\n","apb1");
}
else
{
printk(KERN_INFO "script config apb1 to %d Mhz\n",script_item.val);
clk_set_rate(clk, script_item.val*1000000);
clk_put(clk);
clk=NULL;
}
}
if((script_get_item("clock", "apb2", &script_item) == SCIRPT_ITEM_VALUE_TYPE_INT) && script_item.val)
{
clk = clk_get(NULL,"apb2");
if(!clk || IS_ERR(clk))
{
clk = NULL;
printk("Error not get clk %s\n","apb2");
}
else
{
printk(KERN_INFO "script config apb2 to %d Mhz\n",script_item.val);
clk_set_rate(clk, script_item.val*1000000);
clk_put(clk);
clk=NULL;
}
}
return 0;
}
static int __init sunxi_clk_default_sdm(void)
{
#ifdef SYS_CONFIG_PAT_EN
struct clk *clk = NULL;
script_item_u script_item;
struct sunxi_clk_factors *factor=NULL;
int i;
unsigned long reg;
for(i=0;i<sizeof(clkpat_table)/sizeof(struct sunxi_clk_pat_item);i++)
{
if((script_get_item("clock", clkpat_table[i].patname, &script_item) == SCIRPT_ITEM_VALUE_TYPE_INT))
{
clk = clk_get(NULL,clkpat_table[i].name);
if(!IS_ERR_OR_NULL(clk))
{
factor = to_clk_factor(clk->hw);
if(script_item.val)
{
factor->config->sdmwidth = 1;
if(script_item.val != 1) //avoid old format usage to only enable
factor->config->sdmval=script_item.val;
//sync with already enable PLLs
if (clk->enable_count && __clk_is_enabled(clk))
{
reg = readl(factor->reg);
writel(factor->config->sdmval, (void __iomem *)factor->config->sdmpat);
reg = SET_BITS(factor->config->sdmshift, factor->config->sdmwidth, reg, 1);
writel(reg, factor->reg);
}
}
else
factor->config->sdmwidth = 0;
clk_put(clk);
clk=NULL;
}
}
}
#endif
return 0;
}
static int __init sunx_clk_default_value(void)
{
sunxi_clk_default_plls();
sunxi_clk_default_sdm();
sunxi_clk_default_source();
sunxi_clk_default_devices();
return 0;
}
arch_initcall(sunx_clk_default_value);
#endif