forked from Minki/linux
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: Paul Walmsley <paul@pwsan.com> Tested-by: Vaibhav Hiremath <hvaibhav@ti.com>
This commit is contained in:
parent
b6ffa05091
commit
c4ceedcb18
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -78,9 +78,14 @@ extern bool omap3xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask);
|
||||
extern int omap3xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id,
|
||||
u8 idlest_shift);
|
||||
|
||||
extern int omap3xxx_cm_split_idlest_reg(void __iomem *idlest_reg,
|
||||
s16 *prcm_inst, u8 *idlest_reg_id);
|
||||
|
||||
extern void omap3_cm_save_context(void);
|
||||
extern void omap3_cm_restore_context(void);
|
||||
|
||||
extern int __init omap3xxx_cm_init(void);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -25,6 +25,54 @@
|
||||
static struct cm_ll_data null_cm_ll_data;
|
||||
static struct cm_ll_data *cm_ll_data = &null_cm_ll_data;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* Given an absolute CM_IDLEST register address @idlest_reg, passes
|
||||
* the PRCM instance offset and IDLEST register ID back to the caller
|
||||
* via the @prcm_inst and @idlest_reg_id. Returns -EINVAL upon error,
|
||||
* or 0 upon success. XXX This function is only needed until absolute
|
||||
* register addresses are removed from the OMAP struct clk records.
|
||||
*/
|
||||
int cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst,
|
||||
u8 *idlest_reg_id)
|
||||
{
|
||||
if (!cm_ll_data->split_idlest_reg) {
|
||||
WARN_ONCE(1, "cm: %s: no low-level function defined\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return cm_ll_data->split_idlest_reg(idlest_reg, prcm_inst,
|
||||
idlest_reg_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* cm_wait_module_ready - wait for a module to leave idle or standby
|
||||
* @prcm_mod: PRCM module offset
|
||||
* @idlest_id: CM_IDLESTx register ID (i.e., x = 1, 2, 3)
|
||||
* @idlest_shift: shift of the bit in the CM_IDLEST* register to check
|
||||
*
|
||||
* Wait for the PRCM to indicate that the module identified by
|
||||
* (@prcm_mod, @idlest_id, @idlest_shift) is clocked. Return 0 upon
|
||||
* success, -EBUSY if the module doesn't enable in time, or -EINVAL if
|
||||
* no per-SoC wait_module_ready() function pointer has been registered
|
||||
* or if the idlest register is unknown on the SoC.
|
||||
*/
|
||||
int cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift)
|
||||
{
|
||||
if (!cm_ll_data->wait_module_ready) {
|
||||
WARN_ONCE(1, "cm: %s: no low-level function defined\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return cm_ll_data->wait_module_ready(prcm_mod, idlest_id, idlest_shift);
|
||||
}
|
||||
|
||||
/**
|
||||
* cm_register - register per-SoC low-level data with the CM
|
||||
* @cld: low-level per-SoC OMAP CM data & function pointers to register
|
||||
|
@ -45,6 +45,8 @@
|
||||
#include "sdrc.h"
|
||||
#include "control.h"
|
||||
#include "serial.h"
|
||||
#include "cm2xxx.h"
|
||||
#include "cm3xxx.h"
|
||||
|
||||
/*
|
||||
* The machine specific code may provide the extra mapping besides the
|
||||
@ -388,6 +390,7 @@ void __init omap2420_init_early(void)
|
||||
OMAP2_L4_IO_ADDRESS(OMAP2420_CM_BASE),
|
||||
NULL, NULL);
|
||||
omap2xxx_check_revision();
|
||||
omap2xxx_cm_init();
|
||||
omap_common_init_early();
|
||||
omap2xxx_voltagedomains_init();
|
||||
omap242x_powerdomains_init();
|
||||
@ -417,6 +420,7 @@ void __init omap2430_init_early(void)
|
||||
OMAP2_L4_IO_ADDRESS(OMAP2430_CM_BASE),
|
||||
NULL, NULL);
|
||||
omap2xxx_check_revision();
|
||||
omap2xxx_cm_init();
|
||||
omap_common_init_early();
|
||||
omap2xxx_voltagedomains_init();
|
||||
omap243x_powerdomains_init();
|
||||
@ -451,6 +455,7 @@ void __init omap3_init_early(void)
|
||||
NULL, NULL);
|
||||
omap3xxx_check_revision();
|
||||
omap3xxx_check_features();
|
||||
omap3xxx_cm_init();
|
||||
omap_common_init_early();
|
||||
omap3xxx_voltagedomains_init();
|
||||
omap3xxx_powerdomains_init();
|
||||
|
Loading…
Reference in New Issue
Block a user