msm: acpuclock-krait: Port additional functionality from acpuclock-8960
The following features from acpuclock-8960 are copied to acpuclock-krait:
- HFPLL droop controller programming
- aux_clk_sel MUX programming at init
- "vmin" fix-up, for enforcing limits on voltages for some CPUs
- PLL8 support in frequency tables
This will allow for future migration of various targets from using
acpuclock-8960 to the new-and-improved acpuclock-krait driver
Change-Id: Ic1c3f1eab7caba21ea7d6d4244748b2a05d8dbb8
Signed-off-by: Matt Wagantall <mattw@codeaurora.org>
diff --git a/arch/arm/mach-msm/acpuclock-krait.c b/arch/arm/mach-msm/acpuclock-krait.c
index d747704..4dc47d2 100644
--- a/arch/arm/mach-msm/acpuclock-krait.c
+++ b/arch/arm/mach-msm/acpuclock-krait.c
@@ -53,7 +53,7 @@
static DEFINE_SPINLOCK(l2_lock);
static struct drv_data {
- const struct acpu_level *acpu_freq_tbl;
+ struct acpu_level *acpu_freq_tbl;
const struct l2_level *l2_freq_tbl;
struct scalable *scalable;
u32 bus_perf_client;
@@ -473,6 +473,11 @@
writel_relaxed(0, sc->hfpll_base + sc->hfpll_data->m_offset);
writel_relaxed(1, sc->hfpll_base + sc->hfpll_data->n_offset);
+ /* Program droop controller, if supported */
+ if (sc->hfpll_data->has_droop_ctl)
+ writel_relaxed(sc->hfpll_data->droop_val,
+ sc->hfpll_base + sc->hfpll_data->droop_offset);
+
/* Set an initial rate and enable the PLL. */
hfpll_set_rate(sc, tgt_s);
hfpll_enable(sc, false);
@@ -573,10 +578,15 @@
const struct core_speed *tgt_s)
{
u32 regval;
+ void __iomem *aux_reg;
/* Program AUX source input to the secondary MUX. */
- if (sc->aux_clk_sel_addr)
- writel_relaxed(sc->aux_clk_sel, sc->aux_clk_sel_addr);
+ if (sc->aux_clk_sel_phys) {
+ aux_reg = ioremap(sc->aux_clk_sel_phys, 4);
+ BUG_ON(!aux_reg);
+ writel_relaxed(sc->aux_clk_sel, aux_reg);
+ iounmap(aux_reg);
+ }
/* Switch away from the HFPLL while it's re-initialized. */
set_sec_clk_src(sc, SEC_SRC_SEL_AUX);
@@ -693,8 +703,27 @@
.notifier_call = acpuclk_cpu_callback,
};
+static const int krait_needs_vmin(void)
+{
+ switch (read_cpuid_id()) {
+ case 0x511F04D0: /* KR28M2A20 */
+ case 0x511F04D1: /* KR28M2A21 */
+ case 0x510F06F0: /* KR28M4A10 */
+ return 1;
+ default:
+ return 0;
+ };
+}
+
+static void krait_apply_vmin(struct acpu_level *tbl)
+{
+ for (; tbl->speed.khz != 0; tbl++)
+ if (tbl->vdd_core < 1150000)
+ tbl->vdd_core = 1150000;
+}
+
static const struct acpu_level __init *select_freq_plan(
- const struct acpu_level *const *pvs_tbl, u32 qfprom_phys)
+ struct acpu_level *const *pvs_tbl, u32 qfprom_phys)
{
const struct acpu_level *l, *max_acpu_level = NULL;
void __iomem *qfprom_base;
@@ -737,6 +766,9 @@
}
drv.acpu_freq_tbl = pvs_tbl[tbl_idx];
+ if (krait_needs_vmin())
+ krait_apply_vmin(drv.acpu_freq_tbl);
+
/* Find the max supported scaling frequency. */
for (l = drv.acpu_freq_tbl; l->speed.khz != 0; l++)
if (l->use_for_scaling)
diff --git a/arch/arm/mach-msm/acpuclock-krait.h b/arch/arm/mach-msm/acpuclock-krait.h
index 19629de..7c1d2b6 100644
--- a/arch/arm/mach-msm/acpuclock-krait.h
+++ b/arch/arm/mach-msm/acpuclock-krait.h
@@ -40,6 +40,7 @@
PLL_0 = 0,
HFPLL,
QSB,
+ PLL_8,
};
/**
@@ -146,7 +147,7 @@
const int use_for_scaling;
const struct core_speed speed;
const struct l2_level *l2_level;
- const int vdd_core;
+ int vdd_core;
};
/**
@@ -157,6 +158,10 @@
* @n_offset: "N" value register offset from base address.
* @config_offset: Configuration register offset from base address.
* @config_val: Value to initialize the @config_offset register to.
+ * @has_droop_ctl: Indicates the presence of a voltage droop controller.
+ * @droop_offset: Droop controller register offset from base address.
+ * @droop_val: Value to initialize the @config_offset register to.
+ * @low_vdd_l_max: Maximum "L" value supported at HFPLL_VDD_LOW.
* @vdd: voltage requirements for each VDD level.
*/
struct hfpll_data {
@@ -166,6 +171,9 @@
const u32 n_offset;
const u32 config_offset;
const u32 config_val;
+ const bool has_droop_ctl;
+ const u32 droop_offset;
+ const u32 droop_val;
const u32 low_vdd_l_max;
const int vdd[NUM_HFPLL_VDD];
};
@@ -174,7 +182,7 @@
* struct scalable - Register locations and state associated with a scalable HW.
* @hfpll_phys_base: Physical base address of HFPLL register.
* @hfpll_base: Virtual base address of HFPLL registers.
- * @aux_clk_sel_addr: Virtual address of auxiliary MUX.
+ * @aux_clk_sel_phys: Physical address of auxiliary MUX.
* @aux_clk_sel: Auxiliary mux input to select at boot.
* @l2cpmr_iaddr: Indirect address of the CPMR MUX/divider CP15 register.
* @hfpll_data: Descriptive data of HFPLL hardware.
@@ -183,9 +191,9 @@
* @vreg: Array of voltage regulators needed by the scalable.
*/
struct scalable {
- const u32 hfpll_phys_base;
+ const phys_addr_t hfpll_phys_base;
void __iomem *hfpll_base;
- void __iomem *aux_clk_sel_addr;
+ const phys_addr_t aux_clk_sel_phys;
const u32 aux_clk_sel;
const u32 l2cpmr_iaddr;
const struct hfpll_data *hfpll_data;
@@ -205,10 +213,10 @@
*/
struct acpuclk_krait_params {
struct scalable *scalable;
- const struct acpu_level *pvs_acpu_freq_tbl[NUM_PVS];
+ struct acpu_level *pvs_acpu_freq_tbl[NUM_PVS];
const struct l2_level *l2_freq_tbl;
const size_t l2_freq_tbl_size;
- const u32 qfprom_phys_base;
+ const phys_addr_t qfprom_phys_base;
struct msm_bus_scale_pdata *bus_scale_data;
};