mirror of https://gitee.com/openkylin/linux.git
Fix some OMAP4 clock problems, and deal with some sparse warnings from
the OMAP CPUIdle code. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAABAgAGBQJQz2w5AAoJEMePsQ0LvSpLWVoP/jVAPysH5PbRaeCQJkxLRs6f Ha0OarqOQ+jl34jc9PGv4hVKsaq885SpcOt0DrBHcJBmtmfWgsUVaXN9R25hzxGa 1y6nT1+qKPImTkZMAVSw05Cw6GdxpImoTRXex7KlNrq92KYR+N5gZQltzeAYkuEi SSo55wvthntn3flxebMBeZJROo48TYKvGa+2hSJvfQkDUkp3UCqrFlOZwygyu3nf crO1KpY9HNVgrGuQ5g+PASB0R1IiTUiM6pItCMAJOD/Eix6WWbuCMVK0PWOqbh4+ yUET5P2N7gK1tT+ytS/4KJyGqtihRgM3TkuHZwiUKV17nLzKIM1fzqufG4QobrV/ pxHL2wArqrQqU1ITlb4/+a6LaIwPc7iO0BmqfNog8mzjx0mcZa9liF2inyVuGMvU wsybKYo5p5f7ggLmwJhCZU6nifFoZIov9iSICIeWj0xClRiP5tQb+j7sczVqEPwd V1m9yUiNzFLjgDalk3ZkOd+SAm/OlBEfuzzsNwTHYBPObxxxVF25OLp3N/e+zbhm 4v/EMbVEXSQg8oQyX5EGidgPyox6GTA7My5VbgldYlSLadoPBXy25pwV3iykYS+w 7SlvJjmrC4iJGYOnH3xEYBC6z8Q4uj38PEv7IAQo/ITFcVkVyBxVR7iJa2LFPksn zepWeJQeC+nea6b3YSkG =RfYH -----END PGP SIGNATURE----- Merge tag 'omap-fixes-a-for-v3.8-window' of git://git.kernel.org/pub/scm/linux/kernel/git/pjw/omap-pending into fixes From Paul Walmsley per Tony Lindgrens request: Fix some OMAP4 clock problems, and deal with some sparse warnings from the OMAP CPUIdle code. * tag 'omap-fixes-a-for-v3.8-window' of git://git.kernel.org/pub/scm/linux/kernel/git/pjw/omap-pending: ARM: OMAP3/4: cpuidle: fix sparse and checkpatch warnings ARM: OMAP4: clock data: DPLLs are missing bypass clocks in their parent lists ARM: OMAP4: clock data: div_iva_hs_clk is a power-of-two divider ARM: OMAP4: Fix EMU clock domain always on ARM: OMAP4460: Workaround ABE DPLL failing to turn-on ARM: OMAP4: Enhance support for DPLLs with 4X multiplier ARM: OMAP4: Add function table for non-M4X dplls ARM: OMAP4: Update timer clock aliases
This commit is contained in:
commit
10be289d07
|
@ -40,6 +40,14 @@
|
|||
#define OMAP4430_MODULEMODE_HWCTRL_SHIFT 0
|
||||
#define OMAP4430_MODULEMODE_SWCTRL_SHIFT 1
|
||||
|
||||
/*
|
||||
* OMAP4 ABE DPLL default frequency. In OMAP4460 TRM version V, section
|
||||
* "3.6.3.2.3 CM1_ABE Clock Generator" states that the "DPLL_ABE_X2_CLK
|
||||
* must be set to 196.608 MHz" and hence, the DPLL locked frequency is
|
||||
* half of this value.
|
||||
*/
|
||||
#define OMAP4_DPLL_ABE_DEFFREQ 98304000
|
||||
|
||||
/* Root clocks */
|
||||
|
||||
DEFINE_CLK_FIXED_RATE(extalt_clkin_ck, CLK_IS_ROOT, 59000000, 0x0);
|
||||
|
@ -124,6 +132,8 @@ static struct dpll_data dpll_abe_dd = {
|
|||
.enable_mask = OMAP4430_DPLL_EN_MASK,
|
||||
.autoidle_mask = OMAP4430_AUTO_DPLL_MODE_MASK,
|
||||
.idlest_mask = OMAP4430_ST_DPLL_CLK_MASK,
|
||||
.m4xen_mask = OMAP4430_DPLL_REGM4XEN_MASK,
|
||||
.lpmode_mask = OMAP4430_DPLL_LPMODE_EN_MASK,
|
||||
.max_multiplier = 2047,
|
||||
.max_divider = 128,
|
||||
.min_divider = 1,
|
||||
|
@ -233,7 +243,7 @@ static struct dpll_data dpll_core_dd = {
|
|||
|
||||
|
||||
static const char *dpll_core_ck_parents[] = {
|
||||
"sys_clkin_ck",
|
||||
"sys_clkin_ck", "core_hsd_byp_clk_mux_ck"
|
||||
};
|
||||
|
||||
static struct clk dpll_core_ck;
|
||||
|
@ -286,9 +296,9 @@ DEFINE_CLK_DIVIDER(div_core_ck, "dpll_core_m5x2_ck", &dpll_core_m5x2_ck, 0x0,
|
|||
OMAP4430_CM_CLKSEL_CORE, OMAP4430_CLKSEL_CORE_SHIFT,
|
||||
OMAP4430_CLKSEL_CORE_WIDTH, 0x0, NULL);
|
||||
|
||||
DEFINE_CLK_OMAP_HSDIVIDER(div_iva_hs_clk, "dpll_core_m5x2_ck",
|
||||
&dpll_core_m5x2_ck, 0x0, OMAP4430_CM_BYPCLK_DPLL_IVA,
|
||||
OMAP4430_CLKSEL_0_1_MASK);
|
||||
DEFINE_CLK_DIVIDER(div_iva_hs_clk, "dpll_core_m5x2_ck", &dpll_core_m5x2_ck,
|
||||
0x0, OMAP4430_CM_BYPCLK_DPLL_IVA, OMAP4430_CLKSEL_0_1_SHIFT,
|
||||
OMAP4430_CLKSEL_0_1_WIDTH, CLK_DIVIDER_POWER_OF_TWO, NULL);
|
||||
|
||||
DEFINE_CLK_DIVIDER(div_mpu_hs_clk, "dpll_core_m5x2_ck", &dpll_core_m5x2_ck,
|
||||
0x0, OMAP4430_CM_BYPCLK_DPLL_MPU, OMAP4430_CLKSEL_0_1_SHIFT,
|
||||
|
@ -363,8 +373,21 @@ static struct dpll_data dpll_iva_dd = {
|
|||
.min_divider = 1,
|
||||
};
|
||||
|
||||
static const char *dpll_iva_ck_parents[] = {
|
||||
"sys_clkin_ck", "iva_hsd_byp_clk_mux_ck"
|
||||
};
|
||||
|
||||
static struct clk dpll_iva_ck;
|
||||
|
||||
static const struct clk_ops dpll_ck_ops = {
|
||||
.enable = &omap3_noncore_dpll_enable,
|
||||
.disable = &omap3_noncore_dpll_disable,
|
||||
.recalc_rate = &omap3_dpll_recalc,
|
||||
.round_rate = &omap2_dpll_round_rate,
|
||||
.set_rate = &omap3_noncore_dpll_set_rate,
|
||||
.get_parent = &omap2_init_dpll_parent,
|
||||
};
|
||||
|
||||
static struct clk_hw_omap dpll_iva_ck_hw = {
|
||||
.hw = {
|
||||
.clk = &dpll_iva_ck,
|
||||
|
@ -373,7 +396,7 @@ static struct clk_hw_omap dpll_iva_ck_hw = {
|
|||
.ops = &clkhwops_omap3_dpll,
|
||||
};
|
||||
|
||||
DEFINE_STRUCT_CLK(dpll_iva_ck, dpll_core_ck_parents, dpll_abe_ck_ops);
|
||||
DEFINE_STRUCT_CLK(dpll_iva_ck, dpll_iva_ck_parents, dpll_ck_ops);
|
||||
|
||||
static const char *dpll_iva_x2_ck_parents[] = {
|
||||
"dpll_iva_ck",
|
||||
|
@ -416,6 +439,10 @@ static struct dpll_data dpll_mpu_dd = {
|
|||
.min_divider = 1,
|
||||
};
|
||||
|
||||
static const char *dpll_mpu_ck_parents[] = {
|
||||
"sys_clkin_ck", "div_mpu_hs_clk"
|
||||
};
|
||||
|
||||
static struct clk dpll_mpu_ck;
|
||||
|
||||
static struct clk_hw_omap dpll_mpu_ck_hw = {
|
||||
|
@ -426,7 +453,7 @@ static struct clk_hw_omap dpll_mpu_ck_hw = {
|
|||
.ops = &clkhwops_omap3_dpll,
|
||||
};
|
||||
|
||||
DEFINE_STRUCT_CLK(dpll_mpu_ck, dpll_core_ck_parents, dpll_abe_ck_ops);
|
||||
DEFINE_STRUCT_CLK(dpll_mpu_ck, dpll_mpu_ck_parents, dpll_ck_ops);
|
||||
|
||||
DEFINE_CLK_FIXED_FACTOR(mpu_periphclk, "dpll_mpu_ck", &dpll_mpu_ck, 0x0, 1, 2);
|
||||
|
||||
|
@ -464,6 +491,9 @@ static struct dpll_data dpll_per_dd = {
|
|||
.min_divider = 1,
|
||||
};
|
||||
|
||||
static const char *dpll_per_ck_parents[] = {
|
||||
"sys_clkin_ck", "per_hsd_byp_clk_mux_ck"
|
||||
};
|
||||
|
||||
static struct clk dpll_per_ck;
|
||||
|
||||
|
@ -475,7 +505,7 @@ static struct clk_hw_omap dpll_per_ck_hw = {
|
|||
.ops = &clkhwops_omap3_dpll,
|
||||
};
|
||||
|
||||
DEFINE_STRUCT_CLK(dpll_per_ck, dpll_core_ck_parents, dpll_abe_ck_ops);
|
||||
DEFINE_STRUCT_CLK(dpll_per_ck, dpll_per_ck_parents, dpll_ck_ops);
|
||||
|
||||
DEFINE_CLK_DIVIDER(dpll_per_m2_ck, "dpll_per_ck", &dpll_per_ck, 0x0,
|
||||
OMAP4430_CM_DIV_M2_DPLL_PER, OMAP4430_DPLL_CLKOUT_DIV_SHIFT,
|
||||
|
@ -559,6 +589,10 @@ static struct dpll_data dpll_usb_dd = {
|
|||
.min_divider = 1,
|
||||
};
|
||||
|
||||
static const char *dpll_usb_ck_parents[] = {
|
||||
"sys_clkin_ck", "usb_hs_clk_div_ck"
|
||||
};
|
||||
|
||||
static struct clk dpll_usb_ck;
|
||||
|
||||
static struct clk_hw_omap dpll_usb_ck_hw = {
|
||||
|
@ -569,7 +603,7 @@ static struct clk_hw_omap dpll_usb_ck_hw = {
|
|||
.ops = &clkhwops_omap3_dpll,
|
||||
};
|
||||
|
||||
DEFINE_STRUCT_CLK(dpll_usb_ck, dpll_core_ck_parents, dpll_abe_ck_ops);
|
||||
DEFINE_STRUCT_CLK(dpll_usb_ck, dpll_usb_ck_parents, dpll_ck_ops);
|
||||
|
||||
static const char *dpll_usb_clkdcoldo_ck_parents[] = {
|
||||
"dpll_usb_ck",
|
||||
|
@ -696,9 +730,13 @@ DEFINE_CLK_DIVIDER(syc_clk_div_ck, "sys_clkin_ck", &sys_clkin_ck, 0x0,
|
|||
OMAP4430_CM_ABE_DSS_SYS_CLKSEL, OMAP4430_CLKSEL_0_0_SHIFT,
|
||||
OMAP4430_CLKSEL_0_0_WIDTH, 0x0, NULL);
|
||||
|
||||
static const char *dbgclk_mux_ck_parents[] = {
|
||||
"sys_clkin_ck"
|
||||
};
|
||||
|
||||
static struct clk dbgclk_mux_ck;
|
||||
DEFINE_STRUCT_CLK_HW_OMAP(dbgclk_mux_ck, NULL);
|
||||
DEFINE_STRUCT_CLK(dbgclk_mux_ck, dpll_core_ck_parents,
|
||||
DEFINE_STRUCT_CLK(dbgclk_mux_ck, dbgclk_mux_ck_parents,
|
||||
dpll_usb_clkdcoldo_ck_ops);
|
||||
|
||||
/* Leaf clocks controlled by modules */
|
||||
|
@ -1935,10 +1973,10 @@ static struct omap_clk omap44xx_clks[] = {
|
|||
CLK("4803e000.timer", "timer_sys_ck", &sys_clkin_ck, CK_443X),
|
||||
CLK("48086000.timer", "timer_sys_ck", &sys_clkin_ck, CK_443X),
|
||||
CLK("48088000.timer", "timer_sys_ck", &sys_clkin_ck, CK_443X),
|
||||
CLK("49038000.timer", "timer_sys_ck", &syc_clk_div_ck, CK_443X),
|
||||
CLK("4903a000.timer", "timer_sys_ck", &syc_clk_div_ck, CK_443X),
|
||||
CLK("4903c000.timer", "timer_sys_ck", &syc_clk_div_ck, CK_443X),
|
||||
CLK("4903e000.timer", "timer_sys_ck", &syc_clk_div_ck, CK_443X),
|
||||
CLK("40138000.timer", "timer_sys_ck", &syc_clk_div_ck, CK_443X),
|
||||
CLK("4013a000.timer", "timer_sys_ck", &syc_clk_div_ck, CK_443X),
|
||||
CLK("4013c000.timer", "timer_sys_ck", &syc_clk_div_ck, CK_443X),
|
||||
CLK("4013e000.timer", "timer_sys_ck", &syc_clk_div_ck, CK_443X),
|
||||
CLK(NULL, "cpufreq_ck", &dpll_mpu_ck, CK_443X),
|
||||
};
|
||||
|
||||
|
@ -1955,6 +1993,7 @@ int __init omap4xxx_clk_init(void)
|
|||
{
|
||||
u32 cpu_clkflg;
|
||||
struct omap_clk *c;
|
||||
int rc;
|
||||
|
||||
if (cpu_is_omap443x()) {
|
||||
cpu_mask = RATE_IN_4430;
|
||||
|
@ -1983,5 +2022,18 @@ int __init omap4xxx_clk_init(void)
|
|||
omap2_clk_enable_init_clocks(enable_init_clks,
|
||||
ARRAY_SIZE(enable_init_clks));
|
||||
|
||||
/*
|
||||
* On OMAP4460 the ABE DPLL fails to turn on if in idle low-power
|
||||
* state when turning the ABE clock domain. Workaround this by
|
||||
* locking the ABE DPLL on boot.
|
||||
*/
|
||||
if (cpu_is_omap446x()) {
|
||||
rc = clk_set_parent(&abe_dpll_refclk_mux_ck, &sys_32k_ck);
|
||||
if (!rc)
|
||||
rc = clk_set_rate(&dpll_abe_ck, OMAP4_DPLL_ABE_DEFFREQ);
|
||||
if (rc)
|
||||
pr_err("%s: failed to configure ABE DPLL!\n", __func__);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -195,6 +195,10 @@ struct clksel {
|
|||
* @enable_mask: mask of the DPLL mode bitfield in @control_reg
|
||||
* @last_rounded_rate: cache of the last rate result of omap2_dpll_round_rate()
|
||||
* @last_rounded_m: cache of the last M result of omap2_dpll_round_rate()
|
||||
* @last_rounded_m4xen: cache of the last M4X result of
|
||||
* omap4_dpll_regm4xen_round_rate()
|
||||
* @last_rounded_lpmode: cache of the last lpmode result of
|
||||
* omap4_dpll_lpmode_recalc()
|
||||
* @max_multiplier: maximum valid non-bypass multiplier value (actual)
|
||||
* @last_rounded_n: cache of the last N result of omap2_dpll_round_rate()
|
||||
* @min_divider: minimum valid non-bypass divider value (actual)
|
||||
|
@ -205,6 +209,8 @@ struct clksel {
|
|||
* @autoidle_mask: mask of the DPLL autoidle mode bitfield in @autoidle_reg
|
||||
* @freqsel_mask: mask of the DPLL jitter correction bitfield in @control_reg
|
||||
* @idlest_mask: mask of the DPLL idle status bitfield in @idlest_reg
|
||||
* @lpmode_mask: mask of the DPLL low-power mode bitfield in @control_reg
|
||||
* @m4xen_mask: mask of the DPLL M4X multiplier bitfield in @control_reg
|
||||
* @auto_recal_bit: bitshift of the driftguard enable bit in @control_reg
|
||||
* @recal_en_bit: bitshift of the PRM_IRQENABLE_* bit for recalibration IRQs
|
||||
* @recal_st_bit: bitshift of the PRM_IRQSTATUS_* bit for recalibration IRQs
|
||||
|
@ -233,6 +239,8 @@ struct dpll_data {
|
|||
u32 enable_mask;
|
||||
unsigned long last_rounded_rate;
|
||||
u16 last_rounded_m;
|
||||
u8 last_rounded_m4xen;
|
||||
u8 last_rounded_lpmode;
|
||||
u16 max_multiplier;
|
||||
u8 last_rounded_n;
|
||||
u8 min_divider;
|
||||
|
@ -245,6 +253,8 @@ struct dpll_data {
|
|||
u32 idlest_mask;
|
||||
u32 dco_mask;
|
||||
u32 sddiv_mask;
|
||||
u32 lpmode_mask;
|
||||
u32 m4xen_mask;
|
||||
u8 auto_recal_bit;
|
||||
u8 recal_en_bit;
|
||||
u8 recal_st_bit;
|
||||
|
|
|
@ -998,7 +998,8 @@ int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
|
|||
spin_lock_irqsave(&clkdm->lock, flags);
|
||||
|
||||
/* corner case: disabling unused clocks */
|
||||
if (__clk_get_enable_count(clk) == 0)
|
||||
if ((__clk_get_enable_count(clk) == 0) &&
|
||||
(atomic_read(&clkdm->usecount) == 0))
|
||||
goto ccd_exit;
|
||||
|
||||
if (atomic_read(&clkdm->usecount) == 0) {
|
||||
|
|
|
@ -40,6 +40,8 @@ struct omap3_idle_statedata {
|
|||
u32 core_state;
|
||||
};
|
||||
|
||||
static struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd;
|
||||
|
||||
static struct omap3_idle_statedata omap3_idle_data[] = {
|
||||
{
|
||||
.mpu_state = PWRDM_POWER_ON,
|
||||
|
@ -71,7 +73,7 @@ static struct omap3_idle_statedata omap3_idle_data[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd;
|
||||
/* Private functions */
|
||||
|
||||
static int __omap3_enter_idle(struct cpuidle_device *dev,
|
||||
struct cpuidle_driver *drv,
|
||||
|
@ -260,11 +262,11 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev);
|
||||
static DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev);
|
||||
|
||||
struct cpuidle_driver omap3_idle_driver = {
|
||||
.name = "omap3_idle",
|
||||
.owner = THIS_MODULE,
|
||||
static struct cpuidle_driver omap3_idle_driver = {
|
||||
.name = "omap3_idle",
|
||||
.owner = THIS_MODULE,
|
||||
.states = {
|
||||
{
|
||||
.enter = omap3_enter_idle_bm,
|
||||
|
@ -327,6 +329,8 @@ struct cpuidle_driver omap3_idle_driver = {
|
|||
.safe_state_index = 0,
|
||||
};
|
||||
|
||||
/* Public functions */
|
||||
|
||||
/**
|
||||
* omap3_idle_init - Init routine for OMAP3 idle
|
||||
*
|
||||
|
|
|
@ -54,6 +54,8 @@ static struct clockdomain *cpu_clkdm[NR_CPUS];
|
|||
static atomic_t abort_barrier;
|
||||
static bool cpu_done[NR_CPUS];
|
||||
|
||||
/* Private functions */
|
||||
|
||||
/**
|
||||
* omap4_enter_idle_coupled_[simple/coupled] - OMAP4 cpuidle entry functions
|
||||
* @dev: cpuidle device
|
||||
|
@ -161,9 +163,19 @@ static int omap4_enter_idle_coupled(struct cpuidle_device *dev,
|
|||
return index;
|
||||
}
|
||||
|
||||
DEFINE_PER_CPU(struct cpuidle_device, omap4_idle_dev);
|
||||
/*
|
||||
* For each cpu, setup the broadcast timer because local timers
|
||||
* stops for the states above C1.
|
||||
*/
|
||||
static void omap_setup_broadcast_timer(void *arg)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu);
|
||||
}
|
||||
|
||||
struct cpuidle_driver omap4_idle_driver = {
|
||||
static DEFINE_PER_CPU(struct cpuidle_device, omap4_idle_dev);
|
||||
|
||||
static struct cpuidle_driver omap4_idle_driver = {
|
||||
.name = "omap4_idle",
|
||||
.owner = THIS_MODULE,
|
||||
.en_core_tk_irqen = 1,
|
||||
|
@ -178,7 +190,7 @@ struct cpuidle_driver omap4_idle_driver = {
|
|||
.desc = "MPUSS ON"
|
||||
},
|
||||
{
|
||||
/* C2 - CPU0 OFF + CPU1 OFF + MPU CSWR */
|
||||
/* C2 - CPU0 OFF + CPU1 OFF + MPU CSWR */
|
||||
.exit_latency = 328 + 440,
|
||||
.target_residency = 960,
|
||||
.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED,
|
||||
|
@ -200,15 +212,7 @@ struct cpuidle_driver omap4_idle_driver = {
|
|||
.safe_state_index = 0,
|
||||
};
|
||||
|
||||
/*
|
||||
* For each cpu, setup the broadcast timer because local timers
|
||||
* stops for the states above C1.
|
||||
*/
|
||||
static void omap_setup_broadcast_timer(void *arg)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu);
|
||||
}
|
||||
/* Public functions */
|
||||
|
||||
/**
|
||||
* omap4_idle_init - Init routine for OMAP4 idle
|
||||
|
|
|
@ -291,16 +291,13 @@ static void _lookup_sddiv(struct clk_hw_omap *clk, u8 *sd_div, u16 m, u8 n)
|
|||
|
||||
/*
|
||||
* _omap3_noncore_dpll_program - set non-core DPLL M,N values directly
|
||||
* @clk: struct clk * of DPLL to set
|
||||
* @m: DPLL multiplier to set
|
||||
* @n: DPLL divider to set
|
||||
* @freqsel: FREQSEL value to set
|
||||
* @clk: struct clk * of DPLL to set
|
||||
* @freqsel: FREQSEL value to set
|
||||
*
|
||||
* Program the DPLL with the supplied M, N values, and wait for the DPLL to
|
||||
* lock.. Returns -EINVAL upon error, or 0 upon success.
|
||||
* Program the DPLL with the last M, N values calculated, and wait for
|
||||
* the DPLL to lock. Returns -EINVAL upon error, or 0 upon success.
|
||||
*/
|
||||
static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 m, u8 n,
|
||||
u16 freqsel)
|
||||
static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel)
|
||||
{
|
||||
struct dpll_data *dd = clk->dpll_data;
|
||||
u8 dco, sd_div;
|
||||
|
@ -323,23 +320,45 @@ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 m, u8 n,
|
|||
/* Set DPLL multiplier, divider */
|
||||
v = __raw_readl(dd->mult_div1_reg);
|
||||
v &= ~(dd->mult_mask | dd->div1_mask);
|
||||
v |= m << __ffs(dd->mult_mask);
|
||||
v |= (n - 1) << __ffs(dd->div1_mask);
|
||||
v |= dd->last_rounded_m << __ffs(dd->mult_mask);
|
||||
v |= (dd->last_rounded_n - 1) << __ffs(dd->div1_mask);
|
||||
|
||||
/* Configure dco and sd_div for dplls that have these fields */
|
||||
if (dd->dco_mask) {
|
||||
_lookup_dco(clk, &dco, m, n);
|
||||
_lookup_dco(clk, &dco, dd->last_rounded_m, dd->last_rounded_n);
|
||||
v &= ~(dd->dco_mask);
|
||||
v |= dco << __ffs(dd->dco_mask);
|
||||
}
|
||||
if (dd->sddiv_mask) {
|
||||
_lookup_sddiv(clk, &sd_div, m, n);
|
||||
_lookup_sddiv(clk, &sd_div, dd->last_rounded_m,
|
||||
dd->last_rounded_n);
|
||||
v &= ~(dd->sddiv_mask);
|
||||
v |= sd_div << __ffs(dd->sddiv_mask);
|
||||
}
|
||||
|
||||
__raw_writel(v, dd->mult_div1_reg);
|
||||
|
||||
/* Set 4X multiplier and low-power mode */
|
||||
if (dd->m4xen_mask || dd->lpmode_mask) {
|
||||
v = __raw_readl(dd->control_reg);
|
||||
|
||||
if (dd->m4xen_mask) {
|
||||
if (dd->last_rounded_m4xen)
|
||||
v |= dd->m4xen_mask;
|
||||
else
|
||||
v &= ~dd->m4xen_mask;
|
||||
}
|
||||
|
||||
if (dd->lpmode_mask) {
|
||||
if (dd->last_rounded_lpmode)
|
||||
v |= dd->lpmode_mask;
|
||||
else
|
||||
v &= ~dd->lpmode_mask;
|
||||
}
|
||||
|
||||
__raw_writel(v, dd->control_reg);
|
||||
}
|
||||
|
||||
/* We let the clock framework set the other output dividers later */
|
||||
|
||||
/* REVISIT: Set ramp-up delay? */
|
||||
|
@ -492,8 +511,7 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
pr_debug("%s: %s: set rate: locking rate to %lu.\n",
|
||||
__func__, __clk_get_name(hw->clk), rate);
|
||||
|
||||
ret = omap3_noncore_dpll_program(clk, dd->last_rounded_m,
|
||||
dd->last_rounded_n, freqsel);
|
||||
ret = omap3_noncore_dpll_program(clk, freqsel);
|
||||
if (!ret)
|
||||
new_parent = dd->clk_ref;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,15 @@
|
|||
#include "clock44xx.h"
|
||||
#include "cm-regbits-44xx.h"
|
||||
|
||||
/*
|
||||
* Maximum DPLL input frequency (FINT) and output frequency (FOUT) that
|
||||
* can supported when using the DPLL low-power mode. Frequencies are
|
||||
* defined in OMAP4430/60 Public TRM section 3.6.3.3.2 "Enable Control,
|
||||
* Status, and Low-Power Operation Mode".
|
||||
*/
|
||||
#define OMAP4_DPLL_LP_FINT_MAX 1000000
|
||||
#define OMAP4_DPLL_LP_FOUT_MAX 100000000
|
||||
|
||||
/* Supported only on OMAP4 */
|
||||
int omap4_dpllmx_gatectrl_read(struct clk_hw_omap *clk)
|
||||
{
|
||||
|
@ -81,6 +90,31 @@ const struct clk_hw_omap_ops clkhwops_omap4_dpllmx = {
|
|||
.deny_idle = omap4_dpllmx_deny_gatectrl,
|
||||
};
|
||||
|
||||
/**
|
||||
* omap4_dpll_lpmode_recalc - compute DPLL low-power setting
|
||||
* @dd: pointer to the dpll data structure
|
||||
*
|
||||
* Calculates if low-power mode can be enabled based upon the last
|
||||
* multiplier and divider values calculated. If low-power mode can be
|
||||
* enabled, then the bit to enable low-power mode is stored in the
|
||||
* last_rounded_lpmode variable. This implementation is based upon the
|
||||
* criteria for enabling low-power mode as described in the OMAP4430/60
|
||||
* Public TRM section 3.6.3.3.2 "Enable Control, Status, and Low-Power
|
||||
* Operation Mode".
|
||||
*/
|
||||
static void omap4_dpll_lpmode_recalc(struct dpll_data *dd)
|
||||
{
|
||||
long fint, fout;
|
||||
|
||||
fint = __clk_get_rate(dd->clk_ref) / (dd->last_rounded_n + 1);
|
||||
fout = fint * dd->last_rounded_m;
|
||||
|
||||
if ((fint < OMAP4_DPLL_LP_FINT_MAX) && (fout < OMAP4_DPLL_LP_FOUT_MAX))
|
||||
dd->last_rounded_lpmode = 1;
|
||||
else
|
||||
dd->last_rounded_lpmode = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* omap4_dpll_regm4xen_recalc - compute DPLL rate, considering REGM4XEN bit
|
||||
* @clk: struct clk * of the DPLL to compute the rate for
|
||||
|
@ -130,7 +164,6 @@ long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw,
|
|||
unsigned long *parent_rate)
|
||||
{
|
||||
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
|
||||
u32 v;
|
||||
struct dpll_data *dd;
|
||||
long r;
|
||||
|
||||
|
@ -139,18 +172,31 @@ long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw,
|
|||
|
||||
dd = clk->dpll_data;
|
||||
|
||||
/* regm4xen adds a multiplier of 4 to DPLL calculations */
|
||||
v = __raw_readl(dd->control_reg) & OMAP4430_DPLL_REGM4XEN_MASK;
|
||||
|
||||
if (v)
|
||||
target_rate = target_rate / OMAP4430_REGM4XEN_MULT;
|
||||
dd->last_rounded_m4xen = 0;
|
||||
|
||||
/*
|
||||
* First try to compute the DPLL configuration for
|
||||
* target rate without using the 4X multiplier.
|
||||
*/
|
||||
r = omap2_dpll_round_rate(hw, target_rate, NULL);
|
||||
if (r != ~0)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* If we did not find a valid DPLL configuration, try again, but
|
||||
* this time see if using the 4X multiplier can help. Enabling the
|
||||
* 4X multiplier is equivalent to dividing the target rate by 4.
|
||||
*/
|
||||
r = omap2_dpll_round_rate(hw, target_rate / OMAP4430_REGM4XEN_MULT,
|
||||
NULL);
|
||||
if (r == ~0)
|
||||
return r;
|
||||
|
||||
if (v)
|
||||
clk->dpll_data->last_rounded_rate *= OMAP4430_REGM4XEN_MULT;
|
||||
dd->last_rounded_rate *= OMAP4430_REGM4XEN_MULT;
|
||||
dd->last_rounded_m4xen = 1;
|
||||
|
||||
return clk->dpll_data->last_rounded_rate;
|
||||
out:
|
||||
omap4_dpll_lpmode_recalc(dd);
|
||||
|
||||
return dd->last_rounded_rate;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue