Commit c4ceedcb authored by Paul Walmsley's avatar Paul Walmsley
Browse files

ARM: OMAP2+: CM/clock: convert _omap2_module_wait_ready() to use SoC-independent CM functions



Convert the OMAP clock code's _omap2_module_wait_ready() to use
SoC-independent CM functions that are provided by the CM code, rather
than using a deprecated function from mach-omap2/prcm.c.

This facilitates the future conversion of the CM code to a driver, and
also removes a mach-omap2/prcm.c user.  mach-omap2/prcm.c will be removed
by a subsequent patch.

Some modules have IDLEST registers that aren't in the CM module, such
as the AM3517 IDLEST bits.  So we also need a fallback function for
these non-CM odd cases.  Create a temporary one in mach-omap2/clock.c,
intended to exist until the SCM drivers are ready.

Signed-off-by: default avatarPaul Walmsley <paul@pwsan.com>
Tested-by: default avatarVaibhav Hiremath <hvaibhav@ti.com>
parent b6ffa050
Loading
Loading
Loading
Loading
+53 −3
Original line number Diff line number Diff line
@@ -33,10 +33,18 @@
#include "soc.h"
#include "clockdomain.h"
#include "clock.h"
#include "cm.h"
#include "cm2xxx.h"
#include "cm3xxx.h"
#include "cm-regbits-24xx.h"
#include "cm-regbits-34xx.h"
#include "common.h"

/*
 * MAX_MODULE_ENABLE_WAIT: maximum of number of microseconds to wait
 * for a module to indicate that it is no longer in idle
 */
#define MAX_MODULE_ENABLE_WAIT		100000

u16 cpu_mask;

@@ -58,6 +66,40 @@ static DEFINE_SPINLOCK(clockfw_lock);

/* Private functions */


/**
 * _wait_idlest_generic - wait for a module to leave the idle state
 * @reg: virtual address of module IDLEST register
 * @mask: value to mask against to determine if the module is active
 * @idlest: idle state indicator (0 or 1) for the clock
 * @name: name of the clock (for printk)
 *
 * Wait for a module to leave idle, where its idle-status register is
 * not inside the CM module.  Returns 1 if the module left idle
 * promptly, or 0 if the module did not leave idle before the timeout
 * elapsed.  XXX Deprecated - should be moved into drivers for the
 * individual IP block that the IDLEST register exists in.
 */
static int _wait_idlest_generic(void __iomem *reg, u32 mask, u8 idlest,
				const char *name)
{
	int i = 0, ena = 0;

	ena = (idlest) ? 0 : mask;

	omap_test_timeout(((__raw_readl(reg) & mask) == ena),
			  MAX_MODULE_ENABLE_WAIT, i);

	if (i < MAX_MODULE_ENABLE_WAIT)
		pr_debug("omap clock: module associated with clock %s ready after %d loops\n",
			 name, i);
	else
		pr_err("omap clock: module associated with clock %s didn't enable in %d tries\n",
		       name, MAX_MODULE_ENABLE_WAIT);

	return (i < MAX_MODULE_ENABLE_WAIT) ? 1 : 0;
};

/**
 * _omap2_module_wait_ready - wait for an OMAP module to leave IDLE
 * @clk: struct clk * belonging to the module
@@ -71,7 +113,9 @@ static DEFINE_SPINLOCK(clockfw_lock);
static void _omap2_module_wait_ready(struct clk *clk)
{
	void __iomem *companion_reg, *idlest_reg;
	u8 other_bit, idlest_bit, idlest_val;
	u8 other_bit, idlest_bit, idlest_val, idlest_reg_id;
	s16 prcm_mod;
	int r;

	/* Not all modules have multiple clocks that their IDLEST depends on */
	if (clk->ops->find_companion) {
@@ -82,8 +126,14 @@ static void _omap2_module_wait_ready(struct clk *clk)

	clk->ops->find_idlest(clk, &idlest_reg, &idlest_bit, &idlest_val);

	omap2_cm_wait_idlest(idlest_reg, (1 << idlest_bit), idlest_val,
			     __clk_get_name(clk));
	r = cm_split_idlest_reg(idlest_reg, &prcm_mod, &idlest_reg_id);
	if (r) {
		/* IDLEST register not in the CM module */
		_wait_idlest_generic(idlest_reg, (1 << idlest_bit), idlest_val,
				     clk->name);
	} else {
		cm_wait_module_ready(prcm_mod, idlest_reg_id, idlest_bit);
	};
}

/* Public functions */
+11 −1
Original line number Diff line number Diff line
@@ -37,8 +37,18 @@

/**
 * struct cm_ll_data - fn ptrs to per-SoC CM function implementations
 * @split_idlest_reg: ptr to the SoC CM-specific split_idlest_reg impl
 * @wait_module_ready: ptr to the SoC CM-specific wait_module_ready impl
 */
struct cm_ll_data {};
struct cm_ll_data {
	int (*split_idlest_reg)(void __iomem *idlest_reg, s16 *prcm_inst,
				u8 *idlest_reg_id);
	int (*wait_module_ready)(s16 prcm_mod, u8 idlest_id, u8 idlest_shift);
};

extern int cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst,
			       u8 *idlest_reg_id);
extern int cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift);

extern int cm_register(struct cm_ll_data *cld);
extern int cm_unregister(struct cm_ll_data *cld);
+65 −0
Original line number Diff line number Diff line
@@ -198,6 +198,43 @@ void omap2xxx_cm_apll96_disable(void)
	_omap2xxx_apll_disable(OMAP24XX_EN_96M_PLL_SHIFT);
}

/**
 * omap2xxx_cm_split_idlest_reg - split CM_IDLEST reg addr into its components
 * @idlest_reg: CM_IDLEST* virtual address
 * @prcm_inst: pointer to an s16 to return the PRCM instance offset
 * @idlest_reg_id: pointer to a u8 to return the CM_IDLESTx register ID
 *
 * XXX This function is only needed until absolute register addresses are
 * removed from the OMAP struct clk records.
 */
int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst,
				 u8 *idlest_reg_id)
{
	unsigned long offs;
	u8 idlest_offs;
	int i;

	if (idlest_reg < cm_base || idlest_reg > (cm_base + 0x0fff))
		return -EINVAL;

	idlest_offs = (unsigned long)idlest_reg & 0xff;
	for (i = 0; i < ARRAY_SIZE(omap2xxx_cm_idlest_offs); i++) {
		if (idlest_offs == omap2xxx_cm_idlest_offs[i]) {
			*idlest_reg_id = i + 1;
			break;
		}
	}

	if (i == ARRAY_SIZE(omap2xxx_cm_idlest_offs))
		return -EINVAL;

	offs = idlest_reg - cm_base;
	offs &= 0xff00;
	*prcm_inst = offs;

	return 0;
}

/*
 *
 */
@@ -314,3 +351,31 @@ struct clkdm_ops omap2_clkdm_operations = {
	.clkdm_clk_enable	= omap2xxx_clkdm_clk_enable,
	.clkdm_clk_disable	= omap2xxx_clkdm_clk_disable,
};

/*
 *
 */

static struct cm_ll_data omap2xxx_cm_ll_data = {
	.split_idlest_reg	= &omap2xxx_cm_split_idlest_reg,
	.wait_module_ready	= &omap2xxx_cm_wait_module_ready,
};

int __init omap2xxx_cm_init(void)
{
	if (!cpu_is_omap24xx())
		return 0;

	return cm_register(&omap2xxx_cm_ll_data);
}

static void __exit omap2xxx_cm_exit(void)
{
	if (!cpu_is_omap24xx())
		return;

	/* Should never happen */
	WARN(cm_unregister(&omap2xxx_cm_ll_data),
	     "%s: cm_ll_data function pointer mismatch\n", __func__);
}
__exitcall(omap2xxx_cm_exit);
+4 −0
Original line number Diff line number Diff line
@@ -60,6 +60,10 @@ extern void omap2xxx_cm_set_apll96_auto_low_power_stop(void);
extern bool omap2xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask);
extern int omap2xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id,
					 u8 idlest_shift);
extern int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg,
					s16 *prcm_inst, u8 *idlest_reg_id);

extern int __init omap2xxx_cm_init(void);

#endif

+66 −0
Original line number Diff line number Diff line
@@ -110,6 +110,44 @@ int omap3xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift)
	return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
}

/**
 * omap3xxx_cm_split_idlest_reg - split CM_IDLEST reg addr into its components
 * @idlest_reg: CM_IDLEST* virtual address
 * @prcm_inst: pointer to an s16 to return the PRCM instance offset
 * @idlest_reg_id: pointer to a u8 to return the CM_IDLESTx register ID
 *
 * XXX This function is only needed until absolute register addresses are
 * removed from the OMAP struct clk records.
 */
int omap3xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst,
				 u8 *idlest_reg_id)
{
	unsigned long offs;
	u8 idlest_offs;
	int i;

	if (idlest_reg < (cm_base + OMAP3430_IVA2_MOD) ||
	    idlest_reg > (cm_base + 0x1ffff))
		return -EINVAL;

	idlest_offs = (unsigned long)idlest_reg & 0xff;
	for (i = 0; i < ARRAY_SIZE(omap3xxx_cm_idlest_offs); i++) {
		if (idlest_offs == omap3xxx_cm_idlest_offs[i]) {
			*idlest_reg_id = i + 1;
			break;
		}
	}

	if (i == ARRAY_SIZE(omap3xxx_cm_idlest_offs))
		return -EINVAL;

	offs = idlest_reg - cm_base;
	offs &= 0xff00;
	*prcm_inst = offs;

	return 0;
}

/* Clockdomain low-level operations */

static int omap3xxx_clkdm_add_sleepdep(struct clockdomain *clkdm1,
@@ -597,3 +635,31 @@ void omap3_cm_restore_context(void)
	omap2_cm_write_mod_reg(cm_context.cm_clkout_ctrl, OMAP3430_CCR_MOD,
			       OMAP3_CM_CLKOUT_CTRL_OFFSET);
}

/*
 *
 */

static struct cm_ll_data omap3xxx_cm_ll_data = {
	.split_idlest_reg	= &omap3xxx_cm_split_idlest_reg,
	.wait_module_ready	= &omap3xxx_cm_wait_module_ready,
};

int __init omap3xxx_cm_init(void)
{
	if (!cpu_is_omap34xx())
		return 0;

	return cm_register(&omap3xxx_cm_ll_data);
}

static void __exit omap3xxx_cm_exit(void)
{
	if (!cpu_is_omap34xx())
		return;

	/* Should never happen */
	WARN(cm_unregister(&omap3xxx_cm_ll_data),
	     "%s: cm_ll_data function pointer mismatch\n", __func__);
}
__exitcall(omap3xxx_cm_exit);
Loading