clock changes for mvebu for v3.18

- correct timer drift caused by SSCG deviation
  - fix typo in comment
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQIcBAABAgAGBQJUFVIYAAoJEP45WPkGe8Zns1MQAJeD6jSRzNyqc5Hn0Z2+ibGK
 TQhFcGF2KTySOSnqP7OpdR/LQXaKIb8bcbslfG7FZBXICEVpkHBibf4DoHQtEwoY
 fx1QB73jio3ks9UGpQgVPFTgysfxHsuL8/RTT6QOeyUU8Z0pyOSjDqWDh7z5ZPjY
 aaiT9Ckq1KRzSkMGRqeXZgSqR2lPG1UYet49AlLp1QpjR7i7WfQuQ2W07D2YJQfy
 ault8QKMhNKQ2U8sB69IV/hBpkf6GAKSos8KMAH0+FwxzlfsP5gMTLUyhxFDQ5sA
 4d8qYEPTPj4Acw+uSVI8EDlCWMTyMASCi+Tk6eY9wy2j8zPbfuw1IKtsXqVf3eu9
 huIkdrcLlVeQNnSEu7M35GLCmNVc0bG2qKQKSvrJhaDmVSP+5fVP7jJdStDHVhC/
 GViuJ8SpS147oTV7yL3hh12UNIORsjvjB+MZL7g60bnHyuAEU5Sd0vQBdqcTqBnF
 VE1qMawGdI6lzulhGJ4j+yz766ut9x1je9DwLtj218pfyg0nvg4ujrxF2yGkYdVE
 tQahztzH3DaAX+wPoCybM+HFEtXmlX773Q0TkU7XA7XeFTkXUz5b/CY/A6HertCE
 4sGNxw2Wn8m6kvMVkFJ4oKN8VEFvu73SOWmq9Hz9apYMVWvwFeDplqt4zUjb7oCa
 1Oofky2uBsHpXYa0v9Yi
 =CGwg
 -----END PGP SIGNATURE-----

Merge tag 'clk-mvebu-3.18' of git://git.infradead.org/linux-mvebu into clk-next

clock changes for mvebu for v3.18

 - correct timer drift caused by SSCG deviation
 - fix typo in comment
This commit is contained in:
Mike Turquette 2014-09-26 17:04:08 -07:00
commit 8791db53a9
4 changed files with 99 additions and 2 deletions

View file

@ -23,6 +23,7 @@
*/
#define SARL 0 /* Low part [0:31] */
#define SARL_A370_SSCG_ENABLE BIT(10)
#define SARL_A370_PCLK_FREQ_OPT 11
#define SARL_A370_PCLK_FREQ_OPT_MASK 0xF
#define SARL_A370_FAB_FREQ_OPT 15
@ -133,10 +134,17 @@ static void __init a370_get_clk_ratio(
}
}
static bool a370_is_sscg_enabled(void __iomem *sar)
{
return !(readl(sar) & SARL_A370_SSCG_ENABLE);
}
static const struct coreclk_soc_desc a370_coreclks = {
.get_tclk_freq = a370_get_tclk_freq,
.get_cpu_freq = a370_get_cpu_freq,
.get_clk_ratio = a370_get_clk_ratio,
.is_sscg_enabled = a370_is_sscg_enabled,
.fix_sscg_deviation = kirkwood_fix_sscg_deviation,
.ratios = a370_coreclk_ratios,
.num_ratios = ARRAY_SIZE(a370_coreclk_ratios),
};

View file

@ -27,14 +27,14 @@
* all modified at the same time, and not separately as for the Armada
* 370 or the Armada XP SoCs.
*
* SAR0[21:17] : CPU frequency DDR frequency L2 frequency
* SAR1[21:17] : CPU frequency DDR frequency L2 frequency
* 6 = 400 MHz 400 MHz 200 MHz
* 15 = 600 MHz 600 MHz 300 MHz
* 21 = 800 MHz 534 MHz 400 MHz
* 25 = 1000 MHz 500 MHz 500 MHz
* others reserved.
*
* SAR0[22] : TCLK frequency
* SAR1[22] : TCLK frequency
* 0 = 166 MHz
* 1 = 200 MHz
*/

View file

@ -26,8 +26,85 @@
* Core Clocks
*/
#define SSCG_CONF_MODE(reg) (((reg) >> 16) & 0x3)
#define SSCG_SPREAD_DOWN 0x0
#define SSCG_SPREAD_UP 0x1
#define SSCG_SPREAD_CENTRAL 0x2
#define SSCG_CONF_LOW(reg) (((reg) >> 8) & 0xFF)
#define SSCG_CONF_HIGH(reg) ((reg) & 0xFF)
static struct clk_onecell_data clk_data;
/*
* This function can be used by the Kirkwood, the Armada 370, the
* Armada XP and the Armada 375 SoC. The name of the function was
* chosen following the dt convention: using the first known SoC
* compatible with it.
*/
u32 kirkwood_fix_sscg_deviation(struct device_node *np, u32 system_clk)
{
struct device_node *sscg_np = NULL;
void __iomem *sscg_map;
u32 sscg_reg;
s32 low_bound, high_bound;
u64 freq_swing_half;
sscg_np = of_find_node_by_name(np, "sscg");
if (sscg_np == NULL) {
pr_err("cannot get SSCG register node\n");
return system_clk;
}
sscg_map = of_iomap(sscg_np, 0);
if (sscg_map == NULL) {
pr_err("cannot map SSCG register\n");
goto out;
}
sscg_reg = readl(sscg_map);
high_bound = SSCG_CONF_HIGH(sscg_reg);
low_bound = SSCG_CONF_LOW(sscg_reg);
if ((high_bound - low_bound) <= 0)
goto out;
/*
* From Marvell engineer we got the following formula (when
* this code was written, the datasheet was erroneous)
* Spread percentage = 1/96 * (H - L) / H
* H = SSCG_High_Boundary
* L = SSCG_Low_Boundary
*
* As the deviation is half of spread then it lead to the
* following formula in the code.
*
* To avoid an overflow and not lose any significant digit in
* the same time we have to use a 64 bit integer.
*/
freq_swing_half = (((u64)high_bound - (u64)low_bound)
* (u64)system_clk);
do_div(freq_swing_half, (2 * 96 * high_bound));
switch (SSCG_CONF_MODE(sscg_reg)) {
case SSCG_SPREAD_DOWN:
system_clk -= freq_swing_half;
break;
case SSCG_SPREAD_UP:
system_clk += freq_swing_half;
break;
case SSCG_SPREAD_CENTRAL:
default:
break;
}
iounmap(sscg_map);
out:
of_node_put(sscg_np);
return system_clk;
}
void __init mvebu_coreclk_setup(struct device_node *np,
const struct coreclk_soc_desc *desc)
{
@ -62,6 +139,11 @@ void __init mvebu_coreclk_setup(struct device_node *np,
of_property_read_string_index(np, "clock-output-names", 1,
&cpuclk_name);
rate = desc->get_cpu_freq(base);
if (desc->is_sscg_enabled && desc->fix_sscg_deviation
&& desc->is_sscg_enabled(base))
rate = desc->fix_sscg_deviation(np, rate);
clk_data.clks[1] = clk_register_fixed_rate(NULL, cpuclk_name, NULL,
CLK_IS_ROOT, rate);
WARN_ON(IS_ERR(clk_data.clks[1]));

View file

@ -30,6 +30,8 @@ struct coreclk_soc_desc {
u32 (*get_tclk_freq)(void __iomem *sar);
u32 (*get_cpu_freq)(void __iomem *sar);
void (*get_clk_ratio)(void __iomem *sar, int id, int *mult, int *div);
bool (*is_sscg_enabled)(void __iomem *sar);
u32 (*fix_sscg_deviation)(struct device_node *np, u32 system_clk);
const struct coreclk_ratio *ratios;
int num_ratios;
};
@ -47,4 +49,9 @@ void __init mvebu_coreclk_setup(struct device_node *np,
void __init mvebu_clk_gating_setup(struct device_node *np,
const struct clk_gating_soc_desc *desc);
/*
* This function is shared among the Kirkwood, Armada 370, Armada XP
* and Armada 375 SoC
*/
u32 kirkwood_fix_sscg_deviation(struct device_node *np, u32 system_clk);
#endif