1
0
mirror of https://git.yoctoproject.org/meta-ti synced 2026-07-16 22:38:04 +00:00
Files
meta-ti/recipes-kernel/linux/linux-3.0/bias/0007-OMAP3-ABB-initialization-transition-functions.patch
Koen Kooi ad47faedaf linux 3.0: refresh all patches against 3.0.7
This makes 'git am' work again, patch is more forgiving with fuzz.

Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
2011-10-20 17:58:01 +02:00

275 lines
8.1 KiB
Diff

From 35fc68e090a4f4241c7b3488fd24e82b3f839994 Mon Sep 17 00:00:00 2001
From: Mike Turquette <mturquette@ti.com>
Date: Wed, 29 Jun 2011 17:25:59 -0700
Subject: [PATCH 7/8] OMAP3+: ABB: initialization & transition functions
The Adaptive Body-Bias ldo can be set to bypass or Forward Body-Bias
after voltage scaling is performed.
This patch implements the Adaptive Body-Bias ldo initialization routine
and the transition sequence which is needed after a vc_bypass or
vp_forceupdate sequence completes.
Signed-off-by: Mike Turquette <mturquette@ti.com>
---
arch/arm/mach-omap2/Makefile | 2 +-
arch/arm/mach-omap2/abb.c | 218 ++++++++++++++++++++++++++++++++++++++++++
arch/arm/mach-omap2/abb.h | 5 +
3 files changed, 224 insertions(+), 1 deletions(-)
create mode 100644 arch/arm/mach-omap2/abb.c
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 5bc306c..d0dd488 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -94,7 +94,7 @@ obj-$(CONFIG_ARCH_OMAP4) += prcm.o cm2xxx_3xxx.o cminst44xx.o \
# OMAP voltage domains
ifeq ($(CONFIG_PM),y)
-voltagedomain-common := voltage.o vc.o vp.o
+voltagedomain-common := voltage.o vc.o vp.o abb.o
obj-$(CONFIG_ARCH_OMAP2) += $(voltagedomain-common) \
voltagedomains2xxx_data.o
obj-$(CONFIG_ARCH_OMAP3) += $(voltagedomain-common) \
diff --git a/arch/arm/mach-omap2/abb.c b/arch/arm/mach-omap2/abb.c
new file mode 100644
index 0000000..4d42b67
--- /dev/null
+++ b/arch/arm/mach-omap2/abb.c
@@ -0,0 +1,218 @@
+/*
+ * OMAP Adaptive Body-Bias core
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Mike Turquette <mturquette@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include "abb.h"
+#include "voltage.h"
+
+/*
+ * omap_abb_set_opp - program ABB ldo based on new voltage
+ *
+ * @voltdm - pointer to voltage domain that just finished scaling voltage
+ *
+ * Look up the ABB ldo state for the new voltage that voltdm just finished
+ * transitioning to and compare it to current ldo state. If a change is needed
+ * then clear appropriate PRM_IRQSTATUS bit, transition ldo and then clear
+ * PRM_IRQSTATUS bit again. Returns 0 on success, -EERROR otherwise.
+ */
+int omap_abb_set_opp(struct voltagedomain *voltdm)
+{
+ struct omap_abb_instance *abb = voltdm->abb;
+ struct omap_volt_data *volt_data;
+ int ret, timeout;
+ u8 opp_sel;
+
+ /* fetch the ABB ldo OPP_SEL value for the new voltage */
+ volt_data = omap_voltage_get_voltdata(voltdm, voltdm->nominal_volt);
+
+ if (IS_ERR_OR_NULL(volt_data))
+ return -EINVAL;
+
+ opp_sel = volt_data->opp_sel;
+
+ /* bail early if no transition is necessary */
+ if (opp_sel == abb->_opp_sel)
+ return 0;
+
+ /* clear interrupt status */
+ timeout = 0;
+ while (timeout++ < ABB_TRANXDONE_TIMEOUT) {
+ abb->common->ops->clear_tranxdone(abb->prm_irq_id);
+
+ ret = abb->common->ops->check_tranxdone(abb->prm_irq_id);
+ if (!ret)
+ break;
+
+ udelay(1);
+ }
+
+ if (timeout>= ABB_TRANXDONE_TIMEOUT) {
+ pr_warning("%s: vdd_%s ABB TRANXDONE timeout\n",
+ __func__, voltdm->name);
+ return -ETIMEDOUT;
+ }
+
+ /* program next state of ABB ldo */
+ voltdm->rmw(abb->common->opp_sel_mask,
+ opp_sel << __ffs(abb->common->opp_sel_mask),
+ abb->ctrl_offs);
+
+ /* initiate ABB ldo change */
+ voltdm->rmw(abb->common->opp_change_mask,
+ abb->common->opp_change_mask,
+ abb->ctrl_offs);
+
+ /* clear interrupt status */
+ timeout = 0;
+ while (timeout++ < ABB_TRANXDONE_TIMEOUT) {
+ abb->common->ops->clear_tranxdone(abb->prm_irq_id);
+
+ ret = abb->common->ops->check_tranxdone(abb->prm_irq_id);
+ if (!ret)
+ break;
+
+ udelay(1);
+ }
+
+ if (timeout>= ABB_TRANXDONE_TIMEOUT) {
+ pr_warning("%s: vdd_%s ABB TRANXDONE timeout\n",
+ __func__, voltdm->name);
+ return -ETIMEDOUT;
+ }
+
+ /* track internal state */
+ abb->_opp_sel = opp_sel;
+
+ return 0;
+}
+
+/*
+ * omap_abb_enable - enable ABB ldo on a particular voltage domain
+ *
+ * @voltdm - pointer to particular voltage domain
+ */
+void omap_abb_enable(struct voltagedomain *voltdm)
+{
+ struct omap_abb_instance *abb = voltdm->abb;
+
+ if (abb->enabled)
+ return;
+
+ abb->enabled = true;
+
+ voltdm->rmw(abb->common->sr2en_mask, abb->common->sr2en_mask,
+ abb->setup_offs);
+}
+
+/*
+ * omap_abb_disable - disable ABB ldo on a particular voltage domain
+ *
+ * @voltdm - pointer to particular voltage domain
+ *
+ * Included for completeness. Not currently used but will be needed in the
+ * future if ABB is converted to a loadable module.
+ */
+void omap_abb_disable(struct voltagedomain *voltdm)
+{
+ struct omap_abb_instance *abb = voltdm->abb;
+
+ if (!abb->enabled)
+ return;
+
+ abb->enabled = false;
+
+ voltdm->rmw(abb->common->sr2en_mask,
+ (0 << __ffs(abb->common->sr2en_mask)),
+ abb->setup_offs);
+}
+
+/*
+ * omap_abb_init - Initialize an ABB ldo instance
+ *
+ * @voltdm: voltage domain upon which ABB ldo resides
+ *
+ * Initializes an individual ABB ldo for Forward Body-Bias. FBB is used to
+ * insure stability at higher voltages. Note that some older OMAP chips have a
+ * Reverse Body-Bias mode meant to save power at low voltage, but that mode is
+ * unsupported and phased out on newer chips.
+ */
+void __init omap_abb_init(struct voltagedomain *voltdm)
+{
+ struct omap_abb_instance *abb = voltdm->abb;
+ u32 sys_clk_rate;
+ u32 sr2_wt_cnt_val;
+ u32 clock_cycles;
+ u32 settling_time;
+ u32 val;
+
+ if(IS_ERR_OR_NULL(abb))
+ return;
+
+ /*
+ * SR2_WTCNT_VALUE is the settling time for the ABB ldo after a
+ * transition and must be programmed with the correct time at boot.
+ * The value programmed into the register is the number of SYS_CLK
+ * clock cycles that match a given wall time profiled for the ldo.
+ * This value depends on:
+ * settling time of ldo in micro-seconds (varies per OMAP family)
+ * # of clock cycles per SYS_CLK period (varies per OMAP family)
+ * the SYS_CLK frequency in MHz (varies per board)
+ * The formula is:
+ *
+ * ldo settling time (in micro-seconds)
+ * SR2_WTCNT_VALUE = ------------------------------------------
+ * (# system clock cycles) * (sys_clk period)
+ *
+ * Put another way:
+ *
+ * SR2_WTCNT_VALUE = settling time / (# SYS_CLK cycles / SYS_CLK rate))
+ *
+ * To avoid dividing by zero multiply both "# clock cycles" and
+ * "settling time" by 10 such that the final result is the one we want.
+ */
+
+ /* convert SYS_CLK rate to MHz & prevent divide by zero */
+ sys_clk_rate = DIV_ROUND_CLOSEST(voltdm->sys_clk.rate, 1000000);
+ clock_cycles = abb->common->clock_cycles * 10;
+ settling_time = abb->common->settling_time * 10;
+
+ /* calculate cycle rate */
+ clock_cycles = DIV_ROUND_CLOSEST(clock_cycles, sys_clk_rate);
+
+ /* calulate SR2_WTCNT_VALUE */
+ sr2_wt_cnt_val = DIV_ROUND_CLOSEST(settling_time, clock_cycles);
+
+ voltdm->rmw(abb->common->sr2_wtcnt_value_mask,
+ (sr2_wt_cnt_val << __ffs(abb->common->sr2_wtcnt_value_mask)),
+ abb->setup_offs);
+
+ /* allow Forward Body-Bias */
+ voltdm->rmw(abb->common->active_fbb_sel_mask,
+ abb->common->active_fbb_sel_mask,
+ abb->setup_offs);
+
+ /* did bootloader set OPP_SEL? */
+ val = voltdm->read(abb->ctrl_offs);
+ val &= abb->common->opp_sel_mask;
+ abb->_opp_sel = val >> __ffs(abb->common->opp_sel_mask);
+
+ /* enable the ldo if not done by bootloader */
+ val = voltdm->read(abb->setup_offs);
+ val &= abb->common->sr2en_mask;
+ if (val)
+ abb->enabled = true;
+ else
+ omap_abb_enable(voltdm);
+
+ return;
+}
diff --git a/arch/arm/mach-omap2/abb.h b/arch/arm/mach-omap2/abb.h
index 74f2044..c06c7d6 100644
--- a/arch/arm/mach-omap2/abb.h
+++ b/arch/arm/mach-omap2/abb.h
@@ -82,4 +82,9 @@ extern struct omap_abb_instance omap36xx_abb_mpu;
extern struct omap_abb_instance omap4_abb_mpu;
extern struct omap_abb_instance omap4_abb_iva;
+void omap_abb_init(struct voltagedomain *voltdm);
+void omap_abb_enable(struct voltagedomain *voltdm);
+void omap_abb_disble(struct voltagedomain *voltdm);
+int omap_abb_set_opp(struct voltagedomain *voltdm);
+
#endif
--
1.6.6.1