Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b1f6cfe4 authored by Paul Mundt's avatar Paul Mundt
Browse files

sh: clkfwk: refactor rate propagation.



This resyncs the rate propagation strategy with the scheme used by the
OMAP clock framework. Child clocks are tracked on a list under each
parent and propagation happens there specifically rather than constantly
iterating over the global clock list.

Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
parent a02cb230
Loading
Loading
Loading
Loading
+6 −3
Original line number Original line Diff line number Diff line
@@ -27,6 +27,9 @@ struct clk {
	struct clk		*parent;
	struct clk		*parent;
	struct clk_ops		*ops;
	struct clk_ops		*ops;


	struct list_head	children;
	struct list_head	sibling;	/* node for children */

	int			usecount;
	int			usecount;


	unsigned long		rate;
	unsigned long		rate;
@@ -35,7 +38,6 @@ struct clk {
};
};


#define CLK_ALWAYS_ENABLED	(1 << 0)
#define CLK_ALWAYS_ENABLED	(1 << 0)
#define CLK_RATE_PROPAGATES	(1 << 1)
#define CLK_NEEDS_INIT		(1 << 2)
#define CLK_NEEDS_INIT		(1 << 2)


/* Should be defined by processor-specific code */
/* Should be defined by processor-specific code */
@@ -44,9 +46,10 @@ int __init arch_clk_init(void);


/* arch/sh/kernel/cpu/clock.c */
/* arch/sh/kernel/cpu/clock.c */
int clk_init(void);
int clk_init(void);
unsigned long followparent_recalc(struct clk *clk);
unsigned long followparent_recalc(struct clk *);
void recalculate_root_clocks(void);
void propagate_rate(struct clk *);
void clk_recalc_rate(struct clk *);
void clk_recalc_rate(struct clk *);

int clk_register(struct clk *);
int clk_register(struct clk *);
void clk_unregister(struct clk *);
void clk_unregister(struct clk *);


+78 −42
Original line number Original line Diff line number Diff line
/*
/*
 * arch/sh/kernel/cpu/clock.c - SuperH clock framework
 * arch/sh/kernel/cpu/clock.c - SuperH clock framework
 *
 *
 *  Copyright (C) 2005, 2006, 2007  Paul Mundt
 *  Copyright (C) 2005 - 2009  Paul Mundt
 *
 *
 * This clock framework is derived from the OMAP version by:
 * This clock framework is derived from the OMAP version by:
 *
 *
 *	Copyright (C) 2004 - 2005 Nokia Corporation
 *	Copyright (C) 2004 - 2008 Nokia Corporation
 *	Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
 *	Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
 *
 *
 *  Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com>
 *  Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com>
@@ -43,20 +43,20 @@ static DEFINE_MUTEX(clock_list_sem);
 */
 */
static struct clk master_clk = {
static struct clk master_clk = {
	.name		= "master_clk",
	.name		= "master_clk",
	.flags		= CLK_ALWAYS_ENABLED | CLK_RATE_PROPAGATES,
	.flags		= CLK_ALWAYS_ENABLED,
	.rate		= CONFIG_SH_PCLK_FREQ,
	.rate		= CONFIG_SH_PCLK_FREQ,
};
};


static struct clk module_clk = {
static struct clk module_clk = {
	.name		= "module_clk",
	.name		= "module_clk",
	.parent		= &master_clk,
	.parent		= &master_clk,
	.flags		= CLK_ALWAYS_ENABLED | CLK_RATE_PROPAGATES,
	.flags		= CLK_ALWAYS_ENABLED,
};
};


static struct clk bus_clk = {
static struct clk bus_clk = {
	.name		= "bus_clk",
	.name		= "bus_clk",
	.parent		= &master_clk,
	.parent		= &master_clk,
	.flags		= CLK_ALWAYS_ENABLED | CLK_RATE_PROPAGATES,
	.flags		= CLK_ALWAYS_ENABLED,
};
};


static struct clk cpu_clk = {
static struct clk cpu_clk = {
@@ -75,27 +75,24 @@ static struct clk *onchip_clocks[] = {
	&cpu_clk,
	&cpu_clk,
};
};


/* Used for clocks that always have same value as the parent clock */
unsigned long followparent_recalc(struct clk *clk)
{
	return clk->parent->rate;
}

/* Propagate rate to children */
/* Propagate rate to children */
static void propagate_rate(struct clk *clk)
void propagate_rate(struct clk *tclk)
{
{
	struct clk *clkp;
	struct clk *clkp;


	list_for_each_entry(clkp, &clock_list, node) {
	list_for_each_entry(clkp, &tclk->children, sibling) {
		if (likely(clkp->parent != clk))
		if (clkp->ops->recalc)
			continue;
		if (likely(clkp->ops && clkp->ops->recalc))
			clkp->rate = clkp->ops->recalc(clkp);
			clkp->rate = clkp->ops->recalc(clkp);
		if (unlikely(clkp->flags & CLK_RATE_PROPAGATES))
		propagate_rate(clkp);
		propagate_rate(clkp);
	}
	}
}
}


/* Used for clocks that always have same value as the parent clock */
unsigned long followparent_recalc(struct clk *clk)
{
	return clk->parent->rate;
}

static void __clk_init(struct clk *clk)
static void __clk_init(struct clk *clk)
{
{
	/*
	/*
@@ -180,10 +177,46 @@ void clk_disable(struct clk *clk)
}
}
EXPORT_SYMBOL_GPL(clk_disable);
EXPORT_SYMBOL_GPL(clk_disable);


static LIST_HEAD(root_clks);

/**
 * recalculate_root_clocks - recalculate and propagate all root clocks
 *
 * Recalculates all root clocks (clocks with no parent), which if the
 * clock's .recalc is set correctly, should also propagate their rates.
 * Called at init.
 */
void recalculate_root_clocks(void)
{
	struct clk *clkp;

	list_for_each_entry(clkp, &root_clks, sibling) {
		if (clkp->ops->recalc)
			clkp->rate = clkp->ops->recalc(clkp);
		propagate_rate(clkp);
	}
}

int clk_register(struct clk *clk)
int clk_register(struct clk *clk)
{
{
	if (clk == NULL || IS_ERR(clk))
		return -EINVAL;

	/*
	 * trap out already registered clocks
	 */
	if (clk->node.next || clk->node.prev)
		return 0;

	mutex_lock(&clock_list_sem);
	mutex_lock(&clock_list_sem);


	INIT_LIST_HEAD(&clk->children);

	if (clk->parent)
		list_add(&clk->sibling, &clk->parent->children);
	else
		list_add(&clk->sibling, &root_clks);

	list_add(&clk->node, &clock_list);
	list_add(&clk->node, &clock_list);
	clk->usecount = 0;
	clk->usecount = 0;
	clk->flags |= CLK_NEEDS_INIT;
	clk->flags |= CLK_NEEDS_INIT;
@@ -205,6 +238,7 @@ EXPORT_SYMBOL_GPL(clk_register);
void clk_unregister(struct clk *clk)
void clk_unregister(struct clk *clk)
{
{
	mutex_lock(&clock_list_sem);
	mutex_lock(&clock_list_sem);
	list_del(&clk->sibling);
	list_del(&clk->node);
	list_del(&clk->node);
	mutex_unlock(&clock_list_sem);
	mutex_unlock(&clock_list_sem);
}
}
@@ -231,50 +265,53 @@ int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id)


		spin_lock_irqsave(&clock_lock, flags);
		spin_lock_irqsave(&clock_lock, flags);
		ret = clk->ops->set_rate(clk, rate, algo_id);
		ret = clk->ops->set_rate(clk, rate, algo_id);
		if (ret == 0) {
			if (clk->ops->recalc)
				clk->rate = clk->ops->recalc(clk);
			propagate_rate(clk);
		}
		spin_unlock_irqrestore(&clock_lock, flags);
		spin_unlock_irqrestore(&clock_lock, flags);
	}
	}


	if (unlikely(clk->flags & CLK_RATE_PROPAGATES))
		propagate_rate(clk);

	return ret;
	return ret;
}
}
EXPORT_SYMBOL_GPL(clk_set_rate_ex);
EXPORT_SYMBOL_GPL(clk_set_rate_ex);


void clk_recalc_rate(struct clk *clk)
void clk_recalc_rate(struct clk *clk)
{
{
	if (likely(clk->ops && clk->ops->recalc)) {
	unsigned long flags;
	unsigned long flags;


	if (!clk->ops->recalc)
		return;

	spin_lock_irqsave(&clock_lock, flags);
	spin_lock_irqsave(&clock_lock, flags);
	clk->rate = clk->ops->recalc(clk);
	clk->rate = clk->ops->recalc(clk);
		spin_unlock_irqrestore(&clock_lock, flags);
	}

	if (unlikely(clk->flags & CLK_RATE_PROPAGATES))
	propagate_rate(clk);
	propagate_rate(clk);
	spin_unlock_irqrestore(&clock_lock, flags);
}
}
EXPORT_SYMBOL_GPL(clk_recalc_rate);
EXPORT_SYMBOL_GPL(clk_recalc_rate);


int clk_set_parent(struct clk *clk, struct clk *parent)
int clk_set_parent(struct clk *clk, struct clk *parent)
{
{
	unsigned long flags;
	int ret = -EINVAL;
	int ret = -EINVAL;
	struct clk *old;


	if (!parent || !clk)
	if (!parent || !clk)
		return ret;
		return ret;


	old = clk->parent;
	if (likely(clk->ops && clk->ops->set_parent)) {
		unsigned long flags;
	spin_lock_irqsave(&clock_lock, flags);
	spin_lock_irqsave(&clock_lock, flags);
	if (clk->usecount == 0) {
		if (clk->ops->set_parent)
			ret = clk->ops->set_parent(clk, parent);
			ret = clk->ops->set_parent(clk, parent);
		spin_unlock_irqrestore(&clock_lock, flags);
		if (ret == 0) {
		clk->parent = (ret ? old : parent);
			if (clk->ops->recalc)
				clk->rate = clk->ops->recalc(clk);
			propagate_rate(clk);
		}
		}
	} else
		ret = -EBUSY;
	spin_unlock_irqrestore(&clock_lock, flags);


	if (unlikely(clk->flags & CLK_RATE_PROPAGATES))
		propagate_rate(clk);
	return ret;
	return ret;
}
}
EXPORT_SYMBOL_GPL(clk_set_parent);
EXPORT_SYMBOL_GPL(clk_set_parent);
@@ -457,8 +494,7 @@ int __init clk_init(void)
	ret |= arch_clk_init();
	ret |= arch_clk_init();


	/* Kick the child clocks.. */
	/* Kick the child clocks.. */
	propagate_rate(&master_clk);
	recalculate_root_clocks();
	propagate_rate(&bus_clk);


	return ret;
	return ret;
}
}
+1 −7
Original line number Original line Diff line number Diff line
@@ -161,9 +161,7 @@ static unsigned long master_clk_recalc(struct clk *clk)
static void master_clk_init(struct clk *clk)
static void master_clk_init(struct clk *clk)
{
{
	clk->parent = NULL;
	clk->parent = NULL;
	clk->flags |= CLK_RATE_PROPAGATES;
	clk->rate = master_clk_recalc(clk);
	clk->rate = CONFIG_SH_PCLK_FREQ;
	master_clk_recalc(clk);
}
}


static unsigned long module_clk_recalc(struct clk *clk)
static unsigned long module_clk_recalc(struct clk *clk)
@@ -541,19 +539,16 @@ static struct clk_ops sh7722_video_clk_ops = {
static struct clk sh7722_umem_clock = {
static struct clk sh7722_umem_clock = {
	.name = "umem_clk",
	.name = "umem_clk",
	.ops = &sh7722_frqcr_clk_ops,
	.ops = &sh7722_frqcr_clk_ops,
	.flags = CLK_RATE_PROPAGATES,
};
};


static struct clk sh7722_sh_clock = {
static struct clk sh7722_sh_clock = {
	.name = "sh_clk",
	.name = "sh_clk",
	.ops = &sh7722_frqcr_clk_ops,
	.ops = &sh7722_frqcr_clk_ops,
	.flags = CLK_RATE_PROPAGATES,
};
};


static struct clk sh7722_peripheral_clock = {
static struct clk sh7722_peripheral_clock = {
	.name = "peripheral_clk",
	.name = "peripheral_clk",
	.ops = &sh7722_frqcr_clk_ops,
	.ops = &sh7722_frqcr_clk_ops,
	.flags = CLK_RATE_PROPAGATES,
};
};


static struct clk sh7722_sdram_clock = {
static struct clk sh7722_sdram_clock = {
@@ -564,7 +559,6 @@ static struct clk sh7722_sdram_clock = {
static struct clk sh7722_r_clock = {
static struct clk sh7722_r_clock = {
	.name = "r_clk",
	.name = "r_clk",
	.rate = 32768,
	.rate = 32768,
	.flags = CLK_RATE_PROPAGATES,
};
};


#if !defined(CONFIG_CPU_SUBTYPE_SH7343) &&\
#if !defined(CONFIG_CPU_SUBTYPE_SH7343) &&\