summaryrefslogtreecommitdiffstats
path: root/drivers/clk
diff options
context:
space:
mode:
authorEnrico Jorns <ejo@pengutronix.de>2016-08-09 09:00:28 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2016-08-18 08:19:45 +0200
commit5679e3296f75de1d0dcac7d374d5169309c3f70a (patch)
tree953d552bfc85da8231c8035b981527a3153c3f86 /drivers/clk
parenta308f2eb318a862c1974ade82f1d0c399b313e9a (diff)
downloadbarebox-5679e3296f75de1d0dcac7d374d5169309c3f70a.tar.gz
barebox-5679e3296f75de1d0dcac7d374d5169309c3f70a.tar.xz
clk: socfpga: add divider registers to the main pll outputs
This patch is based on kernel patch 0691bb1b5a1865b3bbc9b7ce6e26eff546abb1cf by Dinh Nguyen <dinguyen@altera.com>. The C0(mpu_clk), C1(main_clk), and C2(dbg_base_clk) outputs from the main PLL go through a pre-divider before coming into the system. These registers were hidden for the CycloneV platform, but are now used for the ArriaV platform. This patch updates the clock driver to read the div-reg property for the socfpga-periph-clk clocks. Note: The registers used for the div-reg property are not documented but set by the preloader. Signed-off-by: Enrico Jorns <ejo@pengutronix.de> Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/clk')
-rw-r--r--drivers/clk/socfpga.c25
1 files changed, 22 insertions, 3 deletions
diff --git a/drivers/clk/socfpga.c b/drivers/clk/socfpga.c
index 37ed038be8..6af0632caf 100644
--- a/drivers/clk/socfpga.c
+++ b/drivers/clk/socfpga.c
@@ -116,18 +116,27 @@ struct clk_periph {
const char *parent;
unsigned regofs;
unsigned int fixed_div;
+ void __iomem *div_reg;
+ unsigned int width;
+ unsigned int shift;
};
static unsigned long clk_periph_recalc_rate(struct clk *clk,
unsigned long parent_rate)
{
struct clk_periph *periph = container_of(clk, struct clk_periph, clk);
- u32 div;
+ u32 div, val;
- if (periph->fixed_div)
+ if (periph->fixed_div) {
div = periph->fixed_div;
- else
+ } else {
+ if (periph->div_reg) {
+ val = readl(periph->div_reg) >> periph->shift;
+ val &= div_mask(periph->width);
+ parent_rate /= (val + 1);
+ }
div = ((readl(clk_mgr_base_addr + periph->regofs) & 0x1ff) + 1);
+ }
return parent_rate / div;
}
@@ -140,6 +149,7 @@ static struct clk *socfpga_periph_clk(struct device_node *node)
{
struct clk_periph *periph;
int ret;
+ u32 div_reg[3];
periph = xzalloc(sizeof(*periph));
@@ -152,6 +162,15 @@ static struct clk *socfpga_periph_clk(struct device_node *node)
periph->clk.name = xstrdup(node->name);
periph->clk.ops = &clk_periph_ops;
+ ret = of_property_read_u32_array(node, "div-reg", div_reg, 3);
+ if (!ret) {
+ periph->div_reg = clk_mgr_base_addr + div_reg[0];
+ periph->shift = div_reg[1];
+ periph->width = div_reg[2];
+ } else {
+ periph->div_reg = 0;
+ }
+
of_property_read_u32(node, "reg", &periph->regofs);
of_property_read_u32(node, "fixed-divider", &periph->fixed_div);