Hi all,
Core voltage chaning patch attached and waiting for comments.
As for now there is no voltage changing done during suspend, because of
http://www.handhelds.org/hypermail/hx4700-port/19/1907.html . There are
no replies for that problem. I'll wait a little more here and will ask in
arm-linux mailing list.
Thanks,
-- Anton (irc: bd2)
Index: arch/arm/mach-pxa/hx4700/Kconfig
===================================================================
RCS file: /cvs/linux/kernel26/arch/arm/mach-pxa/hx4700/Kconfig,v
retrieving revision 1.22
diff -u -p -b -B -r1.22 Kconfig
--- arch/arm/mach-pxa/hx4700/Kconfig 28 Mar 2006 19:12:12 -0000 1.22
+++ arch/arm/mach-pxa/hx4700/Kconfig 4 Jun 2006 21:31:26 -0000
@@ -55,3 +55,10 @@ config HX4700_LEDS
This enables support for HP iPAQ hx4700 color LED control
(via the ASIC3 chip).
+config HX4700_VOLTAGE
+ tristate "HP iPAQ hx4700 core voltage changing"
+ depends on MACH_H4700 && CPU_FREQ_PXA
+ help
+ This enables support for core voltage changing coupled with
+ freqency change.
+
Index: arch/arm/mach-pxa/hx4700/Makefile
===================================================================
RCS file: /cvs/linux/kernel26/arch/arm/mach-pxa/hx4700/Makefile,v
retrieving revision 1.14
diff -u -p -b -B -r1.14 Makefile
--- arch/arm/mach-pxa/hx4700/Makefile 28 Mar 2006 19:12:12 -0000 1.14
+++ arch/arm/mach-pxa/hx4700/Makefile 4 Jun 2006 21:31:26 -0000
@@ -11,3 +11,4 @@ obj-$(CONFIG_HX4700_PCMCIA) += hx4700_p
obj-$(CONFIG_HX4700_LCD) += hx4700_lcd.o
obj-$(CONFIG_HX4700_TS) += hx4700_ts.o
obj-$(CONFIG_HX4700_BLUETOOTH) += hx4700_bt.o
+obj-$(CONFIG_HX4700_VOLTAGE) += hx4700_voltage.o
--- arch/arm/mach-pxa/hx4700/hx4700_voltage.c 2006-05-15 11:34:26.000000000
+0400
+++ arch/arm/mach-pxa/hx4700/hx4700_voltage.c 2006-06-05 01:48:39.000000000
+0400
@@ -0,0 +1,189 @@
+/* Helper module for cpufreq. Is't responsible for changing core voltage
+ * of cpu. Send commands to MAX1586B through pwr_i2c controller integrated
+ * in pxa270.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * History:
+ * 2006-02-04 : Michal Sroczynski <[EMAIL PROTECTED]>
+ * initial driver for Asus730
+ * 2006-06-05 : Anton Vorontsov <[EMAIL PROTECTED]>
+ * hx4700 port, various changes
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/cpufreq.h>
+#include <asm/hardware.h>
+#include <asm/arch/pxa-regs.h>
+
+#define DEBUG 0
+#if DEBUG
+#define dprintk(msg...) do {printk("hx4700_voltage:%s: ", __FUNCTION__);\
+ printk(msg);} while(0);
+#else
+#define dprintk(msg...)
+#endif
+
+struct freq2mv_table_t {
+ unsigned int khz;
+ unsigned int mv;
+};
+
+static struct freq2mv_table_t freq2mv_table[] = {
+ /* Voltage values are lined up experimentally, official Intel docs
+ * lists much higher values. These lower values makes no harm. */
+ {104000, 825},
+ {156000, 850},
+ {208000, 900},
+ {312000, 1050},
+ {416000, 1100},
+ {520000, 1150},
+ {624000, 1200}
+};
+
+static inline unsigned int freq2mv(unsigned int khz)
+{
+ int i;
+ for (i = 0; i <= ARRAY_SIZE(freq2mv_table); i++) {
+ if (freq2mv_table[i].khz == khz)
+ return freq2mv_table[i].mv;
+ }
+ // Return maximal voltage we know if no freq2mv record found
+ printk(KERN_WARNING "hx4700_voltage: unknown freq: %d\n", khz);
+ return freq2mv_table[ARRAY_SIZE(freq2mv_table)-1].mv;
+}
+
+static inline uint8_t mv2cmd (const unsigned int mv)
+{
+ uint8_t val = (mv - 700) / 25;
+ if (val > 31)
+ val = 31;
+ return val;
+}
+
+static void change_voltage(void)
+{
+ /* It is Errata 28 workaround, see Intel Specification Update
+ * POWER MANAGER: Core hangs during voltage change when there are
+ * outstanding transactions on the bus */
+
+ unsigned int unused;
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ __asm__ __volatile__("
\n\
+ b 1f
\n\
+ nop
\n\
+ .align 5
\n\
+1:
\n\
+ ldr r0, [%1] @ APB register read and compare
\n\
+ cmp r0, #0 @ fence for pending slow apb reads
\n\
+
\n\
+ mov r0, #0x8 @ VC bit for PWRMODE
\n\
+ movs r1, #1 @ don't execute mcr on 1st pass
\n\
+
\n\
+retry:
\n\
+ ldreq r3, [%2] @ only stall on the 2nd pass
\n\
+ cmpeq r3, #0 @ cmp causes fence on mem
transfers\n\
+ cmp r1, #0 @ is this the 2nd pass?
\n\
+ mcreq p14, 0, r0, c7, c0, 0 @ write to PWRMODE on 2nd pass
only\n\
+
\n\
+ @ Read VC bit until it is 0, indicates that the VoltageChange is
done.\n\
+ @ On first pass, we never set the VC bit, so it will be clear
already.\n\
+VoltageChange_loop:
\n\
+ mrc p14, 0, r3, c7, c0, 0
\n\
+ tst r3, #0x8
\n\
+ bne VoltageChange_loop
\n\
+
\n\
+ subs r1, r1, #1
\n\
+ beq retry"
+ :"=&r"(unused)
+ :"r"(&CCCR), "r"(UNCACHED_ADDR)
+ :"r0", "r1", "r3");
+
+ while (PVCR & PVCR_VCSA) { // Wait for PMIC to finish all operations
+ udelay(1);
+ }
+
+ local_irq_restore(flags);
+
+ return;
+}
+
+static void send_cmd(uint8_t cmd)
+{
+ PVCR = 0x14; /* MAX1586B address */
+ PCMD0 = PCMD_LC | cmd;
+ change_voltage();
+ return;
+}
+
+static int do_freq_transition(struct notifier_block *nb,
+ unsigned long val, void *data)
+{
+ struct cpufreq_freqs *f = data;
+ unsigned int new_mv = freq2mv(f->new);
+
+ dprintk("v=%ld cpu=%u old=%u new=%u flags=%hu new_mv=%u\n",
+ val,f->cpu,f->old,f->new,f->flags,new_mv);
+
+ switch (val) {
+ case CPUFREQ_PRECHANGE:
+ if (f->new < f->old) break;
+ send_cmd( mv2cmd(new_mv) );
+ break;
+
+ case CPUFREQ_POSTCHANGE:
+ if (f->new > f->old) break;
+ send_cmd( mv2cmd(new_mv) );
+ break;
+
+ default:
+ printk(KERN_WARNING "hx4700_voltage: "
+ "Unhandled cpufreq event\n");
+ break;
+ }
+
+ return 0;
+}
+
+struct notifier_block freq_transition = {
+ .notifier_call = do_freq_transition,
+};
+
+static int __init hx4700_voltage_init(void)
+{
+ PCFR |= PCFR_PI2C_EN;
+ pxa_set_cken(CKEN15_PWRI2C,1);
+ cpufreq_register_notifier(&freq_transition,
CPUFREQ_TRANSITION_NOTIFIER);
+ return 0;
+}
+
+static void __exit hx4700_voltage_exit(void)
+{
+ cpufreq_unregister_notifier(&freq_transition,
CPUFREQ_TRANSITION_NOTIFIER);
+ pxa_set_cken(CKEN15_PWRI2C,0);
+ return;
+}
+
+module_init(hx4700_voltage_init);
+module_exit(hx4700_voltage_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michal Sroczynski <[EMAIL PROTECTED]>");
+MODULE_DESCRIPTION("Core-voltage change helper for PXA270 and MAX Power IC");
_______________________________________________
Hx4700-port mailing list
[email protected]
https://www.handhelds.org/mailman/listinfo/hx4700-port