111 lines
2.6 KiB
C
111 lines
2.6 KiB
C
/*
|
|
* arch/metag/kernel/clock.c
|
|
*
|
|
* Copyright (C) 2012 Imagination Technologies Ltd.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include <linux/clk.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/io.h>
|
|
#include <linux/of.h>
|
|
|
|
#include <asm/param.h>
|
|
#include <asm/clock.h>
|
|
|
|
struct meta_clock_desc _meta_clock;
|
|
|
|
/* Default machine get_core_freq callback. */
|
|
static unsigned long get_core_freq_default(void)
|
|
{
|
|
#ifdef CONFIG_METAG_META21
|
|
/*
|
|
* Meta 2 cores divide down the core clock for the Meta timers, so we
|
|
* can estimate the core clock from the divider.
|
|
*/
|
|
return (metag_in32(EXPAND_TIMER_DIV) + 1) * 1000000;
|
|
#else
|
|
/*
|
|
* On Meta 1 we don't know the core clock, but assuming the Meta timer
|
|
* is correct it can be estimated based on loops_per_jiffy.
|
|
*/
|
|
return (loops_per_jiffy * HZ * 5) >> 1;
|
|
#endif
|
|
}
|
|
|
|
static struct clk *clk_core;
|
|
|
|
/* Clk based get_core_freq callback. */
|
|
static unsigned long get_core_freq_clk(void)
|
|
{
|
|
return clk_get_rate(clk_core);
|
|
}
|
|
|
|
/**
|
|
* init_metag_core_clock() - Set up core clock from devicetree.
|
|
*
|
|
* Checks to see if a "core" clock is provided in the device tree, and overrides
|
|
* the get_core_freq callback to use it.
|
|
*/
|
|
static void __init init_metag_core_clock(void)
|
|
{
|
|
/*
|
|
* See if a core clock is provided by the devicetree (and
|
|
* registered by the init callback above).
|
|
*/
|
|
struct device_node *node;
|
|
node = of_find_compatible_node(NULL, NULL, "img,meta");
|
|
if (!node) {
|
|
pr_warn("%s: no compatible img,meta DT node found\n",
|
|
__func__);
|
|
return;
|
|
}
|
|
|
|
clk_core = of_clk_get_by_name(node, "core");
|
|
if (IS_ERR(clk_core)) {
|
|
pr_warn("%s: no core clock found in DT\n",
|
|
__func__);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Override the core frequency callback to use
|
|
* this clk.
|
|
*/
|
|
_meta_clock.get_core_freq = get_core_freq_clk;
|
|
}
|
|
|
|
/**
|
|
* init_metag_clocks() - Set up clocks from devicetree.
|
|
*
|
|
* Set up important clocks from device tree. In particular any needed for clock
|
|
* sources.
|
|
*/
|
|
void __init init_metag_clocks(void)
|
|
{
|
|
init_metag_core_clock();
|
|
|
|
pr_info("Core clock frequency: %lu Hz\n", get_coreclock());
|
|
}
|
|
|
|
/**
|
|
* setup_meta_clocks() - Early set up of the Meta clock.
|
|
* @desc: Clock descriptor usually provided by machine description
|
|
*
|
|
* Ensures all callbacks are valid.
|
|
*/
|
|
void __init setup_meta_clocks(struct meta_clock_desc *desc)
|
|
{
|
|
/* copy callbacks */
|
|
if (desc)
|
|
_meta_clock = *desc;
|
|
|
|
/* set fallback functions */
|
|
if (!_meta_clock.get_core_freq)
|
|
_meta_clock.get_core_freq = get_core_freq_default;
|
|
}
|
|
|