diff options
Diffstat (limited to 'packages/linux/linux-ezx/dpm-pxa27x-2.6.16.patch')
-rw-r--r-- | packages/linux/linux-ezx/dpm-pxa27x-2.6.16.patch | 2469 |
1 files changed, 0 insertions, 2469 deletions
diff --git a/packages/linux/linux-ezx/dpm-pxa27x-2.6.16.patch b/packages/linux/linux-ezx/dpm-pxa27x-2.6.16.patch deleted file mode 100644 index e429a7b754..0000000000 --- a/packages/linux/linux-ezx/dpm-pxa27x-2.6.16.patch +++ /dev/null @@ -1,2469 +0,0 @@ -Source: MontaVista Software, Inc. -MR: 9340 -Type: Enhancment -Disposition: submitted to -Keywords: DPM, PXA27x -Description: - Platform core support for DPM functions (NOT including drivers) - - -Index: linux-2.6.16/arch/arm/mach-pxa/Makefile -=================================================================== ---- linux-2.6.16.orig/arch/arm/mach-pxa/Makefile -+++ linux-2.6.16/arch/arm/mach-pxa/Makefile -@@ -31,4 +31,5 @@ obj-$(CONFIG_PXA_SSP) += ssp.o - - ifeq ($(CONFIG_PXA27x),y) - obj-$(CONFIG_PM) += standby.o -+obj-$(CONFIG_DPM) += dpm-pxa27x.o - endif -Index: linux-2.6.16/include/asm-arm/arch-pxa/dpm.h -=================================================================== ---- /dev/null -+++ linux-2.6.16/include/asm-arm/arch-pxa/dpm.h -@@ -0,0 +1,157 @@ -+/* -+ * include/asm-arm/arch-pxa/dpm.h -+ * -+ * Bulverde-specific definitions for DPM. If further PXA boards are -+ * supported in the future, will split into board-specific files. -+ * -+ * 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 -+ * -+ * Copyright (C) 2002 MontaVista Software <source@mvista.com> -+ * -+ * Based on arch/ppc/platforms/ibm405lp_dpm.h by Bishop Brock. -+ */ -+ -+#ifndef __ASM_ARM_PXA_DPM_H__ -+#define __ASM_ARM_PXA_DPM_H__ -+ -+/* -+ * machine dependent operating state -+ * -+ * An operating state is a cpu execution state that has implications for power -+ * management. The DPM will select operating points based largely on the -+ * current operating state. -+ * -+ * DPM_STATES is the number of supported operating states. Valid operating -+ * states are from 0 to DPM_STATES-1 but when setting an operating state the -+ * kernel should only specify a state from the set of "base states" and should -+ * do so by name. During the context switch the new operating state is simply -+ * extracted from current->dpm_state. -+ * -+ * task states: -+ * -+ * APIs that reference task states use the range -(DPM_TASK_STATE_LIMIT + 1) -+ * through +DPM_TASK_STATE_LIMIT. This value is added to DPM_TASK_STATE to -+ * obtain the downward or upward adjusted task state value. The -+ * -(DPM_TASK_STATE_LIMIT + 1) value is interpreted specially, and equates to -+ * DPM_NO_STATE. -+ * -+ * Tasks inherit their task operating states across calls to -+ * fork(). DPM_TASK_STATE is the default operating state for all tasks, and is -+ * inherited from init. Tasks can change (or have changed) their tasks states -+ * using the DPM_SET_TASK_STATE variant of the sys_dpm() system call. */ -+ -+#define DPM_NO_STATE -1 -+ -+#define DPM_IDLE_TASK_STATE 0 -+#define DPM_IDLE_STATE 1 -+#define DPM_SLEEP_STATE 2 -+#define DPM_BASE_STATES 3 -+ -+#define DPM_TASK_STATE_LIMIT 4 -+#define DPM_TASK_STATE (DPM_BASE_STATES + DPM_TASK_STATE_LIMIT) -+#define DPM_STATES (DPM_TASK_STATE + DPM_TASK_STATE_LIMIT + 1) -+#define DPM_TASK_STATES (DPM_STATES - DPM_BASE_STATES) -+ -+/* -+ *length of DPM_STATE_NAMES is DPM_STATES, -+ */ -+#define DPM_STATE_NAMES \ -+{ "idle-task", "idle", "sleep",\ -+ "task-4", "task-3", "task-2", "task-1",\ -+ "task", \ -+ "task+1", "task+2", "task+3", "task+4" \ -+} -+ -+/* Operating point parameters */ -+#define DPM_MD_V 0 /* Voltage */ -+#define DPM_MD_PLL_L 1 /* L */ -+#define DPM_MD_PLL_N 2 /* N */ -+#define DPM_MD_PLL_B 3 /* B */ -+#define DPM_MD_HALF_TURBO 4 /* Cuts turbo mode in half */ -+#define DPM_MD_CCCRA 5 /* The A bit in the CCCR is -+ for MEMC clocks */ -+#define DPM_MD_CPLL_ON 6 /* Core PLL on/off */ -+#define DPM_MD_PPLL_ON 7 /* Peripheral PLL on/off */ -+#define DPM_MD_SLEEP_MODE 8 /* Sleep mode, from pm.h */ -+#define DPM_MD_PLL_LCD 9 /* calculated value */ -+ -+ -+enum -+{ -+ CPUMODE_RUN, -+ CPUMODE_IDLE, -+ CPUMODE_STANDBY, -+ CPUMODE_SLEEP, -+ CPUMODE_RESERVED, -+ CPUMODE_SENSE, -+ CPUMODE_RESERVED2, -+ CPUMODE_DEEPSLEEP, -+}; -+ -+/* this is the number of specifiable operating point parameters, -+ * used by arch-independent DPM-core driver -+ */ -+#define DPM_PP_NBR 10 -+#define DPM_PARAM_NAMES {"v","l","n","b","ht","a","cpll", "ppll","sleep", "lcd"}; -+ -+#ifndef __ASSEMBLER__ -+ -+#include <linux/types.h> -+#include <linux/proc_fs.h> -+#include <asm/hardware.h> -+#include <asm/arch/pxa-regs.h> -+ -+#define dpm_time() (OSCR) -+#define DPM_NSEC_PER_TICK 308 /* nanoseconds per tick */ -+#define dpm_time_to_usec(ticks) ({ \ -+ unsigned long long quot = \ -+ ((ticks) * DPM_NSEC_PER_TICK * 2 + 1); \ -+ do_div(quot, (unsigned long) 1000*2); \ -+ quot; }) -+ -+struct dpm_regs { -+ unsigned int cccr; -+ unsigned int clkcfg; -+ unsigned int voltage; /*This is not a register.*/ -+}; -+ -+/* Instances of this structure define valid Bulverde operating points for DPM. -+ Voltages are represented in mV, and frequencies are represented in KHz. */ -+ -+struct dpm_md_opt { -+ /* Specified values */ -+ int v; /* Target voltage in mV*/ -+ int l; /* Run Mode to Oscillator ratio */ -+ int n; /* Turbo-Mode to Run-Mode ratio */ -+ int b; /* Fast Bus Mode */ -+ int half_turbo;/* Half Turbo bit */ -+ int cccra; /* the 'A' bit of the CCCR register, -+ alternate MEMC clock */ -+ int cpll_enabled; /* core PLL is ON? (Bulverde >="C0" feature)*/ -+ int ppll_enabled; /* peripherial PLL is ON? (Bulverde >="C0" feature)*/ -+ -+ int sleep_mode; -+ /*Calculated values*/ -+ unsigned int lcd; /*in KHz */ -+ unsigned int lpj; /*New value for loops_per_jiffy */ -+ unsigned int cpu; /*CPU frequency in KHz */ -+ unsigned int turbo; /* Turbo bit in clkcfg */ -+ -+ struct dpm_regs regs; /* Register values */ -+}; -+ -+#endif /* __ASSEMBLER__ */ -+#endif /* __ASM_BULVERDE_DPM_H__ */ -+ -Index: linux-2.6.16/arch/arm/mach-pxa/dpm-pxa27x.c -=================================================================== ---- /dev/null -+++ linux-2.6.16/arch/arm/mach-pxa/dpm-pxa27x.c -@@ -0,0 +1,2110 @@ -+/* -+ * arch/arm/mach-pxa/dpm-pxa27x.c DPM support for Intel PXA27x -+ * -+ * 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 -+ * -+ * Copyright (C) 2002, 2005 MontaVista Software <source@mvista.com>. -+ * -+ * Includes code from David Burrage, Alexandre Rusev, and Todd Poynor, -+ * based on DPM code by Matthew Locke, Dmitry Chigirev and Bishop Brock. -+ * -+ * Includes cpufreq/ipm code by Chao Xie and Cain Yuan -+ * Copyright (C) 2003-2004 Intel Corporation. -+ */ -+ -+#include <linux/config.h> -+ -+#include <linux/dpm.h> -+#include <linux/errno.h> -+#include <linux/init.h> -+#include <linux/kernel.h> -+ -+#include <linux/delay.h> -+ -+#include <asm/uaccess.h> -+#include <asm/pgtable.h> -+#include <asm/pgalloc.h> -+#include <asm/hardware.h> -+#include <asm/system.h> -+#include <asm/io.h> -+#include <asm/arch/pxa-regs.h> -+#include <asm/arch/system.h> -+#include <asm/arch/dpm.h> -+#include <asm/mach/time.h> -+ -+static int saved_loops_per_jiffy = 0; -+static int saved_cpu_freq = 0; -+ -+#define CCCR_CPDIS_BIT_ON (1 << 31) -+#define CCCR_PPDIS_BIT_ON (1 << 30) -+#define CCCR_CPDIS_BIT_OFF (0 << 31) -+#define CCCR_PPDIS_BIT_OFF (0 << 30) -+#define CCCR_PLL_EARLY_EN_BIT_ON (1 << 26) -+#define CCSR_CPLL_LOCKED (1 << 29) -+#define CCSR_PPLL_LOCKED (1 << 28) -+ -+/* CLKCFG -+ | 31------------------------------------------- | 3 | 2 | 1 | 0 | -+ | --------------------------------------------- | B | HT | F | T | -+*/ -+#define CLKCFG_B_BIT (1 << 3) -+#define CLKCFG_HT_BIT (1 << 2) -+#define CLKCFG_F_BIT (1 << 1) -+#define CLKCFG_T_BIT 1 -+ -+#define PLL_L_MAX 31 -+#define PLL_N_MAX 8 -+ -+/* The MIN for L is 2 in the Yellow Book tables, but L=1 really means -+ 13M mode, so L min includes 1 */ -+#define PLL_L_MIN 1 -+#define PLL_N_MIN 2 -+ -+#define CCLKCFG_TURBO 0x1 -+#define CCLKCFG_FCS 0x2 -+ -+#define L_NUM 31 /* 30 different L numbers. */ -+#define N_NUM 7 /* 7 N numbers. */ -+ -+#define BLVD_MIN_FREQ 13000 -+/* latest PowerPoint documentation indicates 624000*/ -+#define BLVD_MAX_FREQ 520000 -+ -+#define MAX_VOL 1400 /* in mV. */ -+#define MIN_VOL 850 /* in Mv. */ -+ -+#define MDREFR_DRI 0xFFF -+#define MSC0_RDF (0xF << 20) -+#define MSC0_RDN (0xF << 24) -+#define MSC0_RRR (0x7 << 12) -+#define MDREFR_RFU 0xC0200000 -+#define MDCNFG_DTC0 (0x3 << 8) -+#define MDCNFG_DTC2 (0x3 << 24) -+ -+/* memory timing (MSC0,DTC,DRI) constants (see Blob and Intel BBU sources) */ -+#define XLLI_MSC0_13 0x11101110 -+#define XLLI_MSC0_19 0x11101110 -+#define XLLI_MSC0_26 0x11201120 /* 26 MHz setting */ -+#define XLLI_MSC0_32 0x11201120 -+#define XLLI_MSC0_39 0x11301130 /* 39 MHz setting */ -+#define XLLI_MSC0_45 0x11301130 -+#define XLLI_MSC0_52 0x11401140 /* @ 52 MHz setting */ -+#define XLLI_MSC0_58 0x11401140 -+#define XLLI_MSC0_65 0x11501150 /* @ 65 MHz setting */ -+#define XLLI_MSC0_68 0x11501150 -+#define XLLI_MSC0_71 0x11501150 /* @ 71.5 MHz setting */ -+#define XLLI_MSC0_74 0x11601160 -+#define XLLI_MSC0_78 0x12601260 /* @ 78 MHz setting */ -+#define XLLI_MSC0_81 0x12601260 -+#define XLLI_MSC0_84 0x12601260 /* @ 84.5 MHz setting */ -+#define XLLI_MSC0_87 0x12701270 -+#define XLLI_MSC0_91 0x12701270 /* 91 MHz setting */ -+#define XLLI_MSC0_94 0x12701270 /* 94.2 MHz setting */ -+#define XLLI_MSC0_97 0x12701270 /* 97.5 MHz setting */ -+#define XLLI_MSC0_100 0x12801280 /* 100.7 MHz setting */ -+#define XLLI_MSC0_104 0x12801280 /* 104 MHz setting */ -+#define XLLI_MSC0_110 0x12901290 -+#define XLLI_MSC0_117 0x13901390 /* 117 MHz setting */ -+#define XLLI_MSC0_124 0x13A013A0 -+#define XLLI_MSC0_130 0x13A013A0 /* 130 MHz setting */ -+#define XLLI_MSC0_136 0x13B013B0 -+#define XLLI_MSC0_143 0x13B013B0 -+#define XLLI_MSC0_149 0x13C013C0 -+#define XLLI_MSC0_156 0x14C014C0 -+#define XLLI_MSC0_162 0x14C014C0 -+#define XLLI_MSC0_169 0x14C014C0 -+#define XLLI_MSC0_175 0x14C014C0 -+#define XLLI_MSC0_182 0x14C014C0 -+#define XLLI_MSC0_188 0x14C014C0 -+#define XLLI_MSC0_195 0x15C015C0 -+#define XLLI_MSC0_201 0x15D015D0 -+#define XLLI_MSC0_208 0x15D015D0 -+ -+/* DTC settings depend on 16/32 bit SDRAM we have (32 is chosen) */ -+#define XLLI_DTC_13 0x00000000 -+#define XLLI_DTC_19 0x00000000 -+#define XLLI_DTC_26 0x00000000 -+#define XLLI_DTC_32 0x00000000 -+#define XLLI_DTC_39 0x00000000 -+#define XLLI_DTC_45 0x00000000 -+#define XLLI_DTC_52 0x00000000 -+#define XLLI_DTC_58 0x01000100 -+#define XLLI_DTC_65 0x01000100 -+#define XLLI_DTC_68 0x01000100 -+#define XLLI_DTC_71 0x01000100 -+#define XLLI_DTC_74 0x01000100 -+#define XLLI_DTC_78 0x01000100 -+#define XLLI_DTC_81 0x01000100 -+#define XLLI_DTC_84 0x01000100 -+#define XLLI_DTC_87 0x01000100 -+#define XLLI_DTC_91 0x02000200 -+#define XLLI_DTC_94 0x02000200 -+#define XLLI_DTC_97 0x02000200 -+#define XLLI_DTC_100 0x02000200 -+#define XLLI_DTC_104 0x02000200 -+/* 110-208 MHz setting - SDCLK Halved*/ -+#define XLLI_DTC_110 0x01000100 -+#define XLLI_DTC_117 0x01000100 -+#define XLLI_DTC_124 0x01000100 -+#define XLLI_DTC_130 0x01000100 -+#define XLLI_DTC_136 0x01000100 -+#define XLLI_DTC_143 0x01000100 -+#define XLLI_DTC_149 0x01000100 -+#define XLLI_DTC_156 0x01000100 -+#define XLLI_DTC_162 0x01000100 -+#define XLLI_DTC_169 0x01000100 -+#define XLLI_DTC_175 0x01000100 -+/* 182-208 MHz setting - SDCLK Halved - Close to edge, so bump up */ -+#define XLLI_DTC_182 0x02000200 -+#define XLLI_DTC_188 0x02000200 -+#define XLLI_DTC_195 0x02000200 -+#define XLLI_DTC_201 0x02000200 -+#define XLLI_DTC_208 0x02000200 -+ -+/* Optimal values for DRI (refreash interval) settings for -+ * various MemClk settings (MDREFR) -+ */ -+#define XLLI_DRI_13 0x002 -+#define XLLI_DRI_19 0x003 -+#define XLLI_DRI_26 0x005 -+#define XLLI_DRI_32 0x006 -+#define XLLI_DRI_39 0x008 -+#define XLLI_DRI_45 0x00A -+#define XLLI_DRI_52 0x00B -+#define XLLI_DRI_58 0x00D -+#define XLLI_DRI_65 0x00E -+#define XLLI_DRI_68 0x00F -+#define XLLI_DRI_71 0x010 -+#define XLLI_DRI_74 0x011 -+#define XLLI_DRI_78 0x012 -+#define XLLI_DRI_81 0x012 -+#define XLLI_DRI_84 0x013 -+#define XLLI_DRI_87 0x014 -+#define XLLI_DRI_91 0x015 -+#define XLLI_DRI_94 0x016 -+#define XLLI_DRI_97 0x016 -+#define XLLI_DRI_100 0x017 -+#define XLLI_DRI_104 0x018 -+#define XLLI_DRI_110 0x01A -+#define XLLI_DRI_117 0x01B -+#define XLLI_DRI_124 0x01D -+#define XLLI_DRI_130 0x01E -+#define XLLI_DRI_136 0x020 -+#define XLLI_DRI_143 0x021 -+#define XLLI_DRI_149 0x023 -+#define XLLI_DRI_156 0x025 -+#define XLLI_DRI_162 0x026 -+#define XLLI_DRI_169 0x028 -+#define XLLI_DRI_175 0x029 -+#define XLLI_DRI_182 0x02B -+#define XLLI_DRI_188 0x02D -+#define XLLI_DRI_195 0x02E -+#define XLLI_DRI_201 0x030 -+#define XLLI_DRI_208 0x031 -+ -+ -+ -+/* timings for memory controller set up (masked values) */ -+struct mem_timings{ -+ unsigned int msc0; /* for MSC0 */ -+ unsigned int dtc; /* for MDCNFG */ -+ unsigned int dri; /* for MDREFR */ -+}; -+ -+static unsigned int cpufreq_matrix[N_NUM][L_NUM + 1]; -+static volatile int *ramstart; -+ -+#define CP15R0_REV_MASK 0x0000000f -+#define PXA270_C5 0x7 -+ -+static u32 chiprev; -+static int mvdt_size; -+ -+struct MvDAC { -+ unsigned int mv; -+ unsigned int DACIn; -+} *mvDACtable; -+ -+/* -+ * Transfer desired mv to required DAC value. -+ * Vcore = 1.3v - ( 712uv * DACIn ) -+ */ -+static struct MvDAC table_c0[] = { -+ {1425, 0}, -+ {1400, 69}, -+ {1300, 248}, -+ {1200, 428}, -+ {1100, 601}, -+ {1000, 777}, -+ {950, 872}, -+ {868, 1010}, -+ {861, 0xFFFFFFFF}, -+}; -+ -+/* -+ * Transfer desired mv to required DAC value, update for new boards, -+ * according to "Intel PXA27x Processor Developer's Kit User's Guide, -+ * April 2004, Revision 4.001" -+ * Vcore = 1.5V - (587uV * DAC(input)). -+ */ -+static struct MvDAC table_c5[] = { -+ {1500, 0}, -+ {1484,25}, -+ {1471,50}, -+ {1456,75}, -+ {1441,100}, -+ {1427,125}, -+ {1412,150}, -+ {1397,175}, -+ {1383,200}, -+ {1368,225}, -+ {1353,250}, -+ {1339,275}, -+ {1323,300}, -+ {1309,325}, -+ {1294,350}, -+ {1280,375}, -+ {1265,400}, -+ {1251,425}, -+ {1236,450}, -+ {1221,475}, -+ {1207,500}, -+ {1192,525}, -+ {1177,550}, -+ {1162,575}, -+ {1148,600}, -+ {1133,625}, -+ {1118,650}, -+ {1104,675}, -+ {1089,700}, -+ {1074,725}, -+ {1060,750}, -+ {1045,775}, -+ {1030,800}, -+ {1016,825}, -+ {1001,850}, -+ {986,875}, -+ {972,900}, -+ {957,925}, -+ {942,950}, -+ {928,975}, -+ {913,1000}, -+ {899, 1023}, -+}; -+ -+static unsigned int mv2DAC(unsigned int mv) -+{ -+ int i, num = mvdt_size; -+ -+ if (mvDACtable[0].mv <= mv) { /* Max or bigger */ -+ /* Return the first one */ -+ return mvDACtable[0].DACIn; -+ } -+ -+ if (mvDACtable[num - 1].mv >= mv) { /* Min or smaller */ -+ /* Return the last one */ -+ return mvDACtable[num - 1].DACIn; -+ } -+ -+ /* The biggest and smallest value cases are covered, now the -+ loop may skip those */ -+ for (i = 1; i <= (num - 1); i++) { -+ if ((mvDACtable[i].mv >= mv) && (mvDACtable[i + 1].mv < mv)) { -+ return mvDACtable[i].DACIn; -+ } -+ } -+ -+ /* Should never get here */ -+ return 0; -+} -+ -+static void clr_all_sqc(void) -+{ -+ int i = 0; -+ for (i = 0; i < 32; i++) -+ PCMD(i) &= ~PCMD_SQC; -+} -+ -+static void clr_all_mbc(void) -+{ -+ int i = 0; -+ for (i = 0; i < 32; i++) -+ PCMD(i) &= ~PCMD_MBC; -+} -+ -+static void clr_all_dce(void) -+{ -+ int i = 0; -+ for (i = 0; i < 32; i++) -+ PCMD(i) &= ~PCMD_DCE; -+} -+ -+static void set_mbc_bit(int ReadPointer, int NumOfBytes) -+{ -+ PCMD0 |= PCMD_MBC; -+ PCMD1 |= PCMD_MBC; -+} -+ -+static void set_lc_bit(int ReadPointer, int NumOfBytes) -+{ -+ PCMD0 |= PCMD_LC; -+ PCMD1 |= PCMD_LC; -+ PCMD2 |= PCMD_LC; -+} -+ -+static void set_cmd_data(unsigned char *DataArray, int StartPoint, int size) -+{ -+ PCMD0 &= 0xFFFFFF00; -+ PCMD0 |= DataArray[0]; -+ PCMD1 &= 0xFFFFFF00; -+ PCMD1 |= DataArray[1]; -+ PCMD2 &= 0xFFFFFF00; -+ PCMD2 |= DataArray[2]; -+} -+ -+/* coupled indicates that this VCS is to be coupled with a FCS */ -+static void power_change_cmd(unsigned int DACValue, int coupled) -+{ -+ unsigned char dataArray[3]; -+ -+ dataArray[0] = 0; /* Command 0 */ -+ dataArray[1] = (DACValue & 0x000000FF); /* data LSB */ -+ dataArray[2] = (DACValue & 0x0000FF00) >> 8; /* data MSB */ -+ -+ PVCR = 0; -+ -+ PCFR &= ~PCFR_FVC; -+ PVCR &= 0xFFFFF07F; /* no delay is necessary */ -+ PVCR &= 0xFFFFFF80; /* clear slave address */ -+ PVCR |= 0x20; /* set slave address */ -+ -+ PVCR &= 0xFE0FFFFF; /* clear read pointer 0 */ -+ PVCR |= 0; -+ -+ /* DCE and SQC are not necessary for single command */ -+ clr_all_sqc(); -+ clr_all_dce(); -+ -+ clr_all_mbc(); -+ set_mbc_bit(0, 2); -+ -+ /* indicate the last byte of this command is holded in this register */ -+ PCMD2 &= ~PCMD_MBC; -+ -+ /* indicate this is the first command and last command also */ -+ set_lc_bit(0, 3); -+ -+ /* programming the command data bit */ -+ set_cmd_data(dataArray, 0, 2); -+ -+ if (coupled) { -+ /* Enable Power I2C and FVC */ -+ PCFR |= (PCFR_PI2CEN | PCFR_FVC); -+ } else { -+ /* Enable Power I2C */ -+ PCFR |= PCFR_PI2CEN; -+ } -+} -+ -+static void change_voltage(void) -+{ -+ unsigned long flags; -+ unsigned int unused; -+ -+ -+ local_irq_save(flags); -+ -+ __asm__ __volatile__("\n\ -+ @ WOKAROUND - Core hangs on voltage change at different\n\ -+ @ alignments and at different core clock frequencies\n\ -+ @ To ensure that no external fetches occur, we want to store the next\n\ -+ @ several instructions that occur after the voltage change inside\n\ -+ @ the cache. The load dependency stall near the retry label ensures \n\ -+ @ that any outstanding instruction cacheline loads are complete before \n\ -+ @ the mcr instruction is executed on the 2nd pass. This procedure \n\ -+ @ ensures us that the internal bus will not be busy. \n\ -+ \n\ -+ b 2f \n\ -+ nop \n\ -+ .align 5 \n\ -+2: \n\ -+ ldr r0, [%1] @ APB register read and compare \n\ -+ cmp r0, #0 @ fence for pending slow apb reads \n\ -+ \n\ -+ mov r0, #8 @ VC bit for PWRMODE \n\ -+ movs r1, #1 @ don't execute mcr on 1st pass \n\ -+ \n\ -+ @ %1 points to uncacheable memory to force memory read \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\ -+ \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 @ update conditional execution counter\n\ -+ beq retry":"=&r"(unused) -+ :"r"(&CCCR), "r"(ramstart) -+ :"r0", "r1", "r3"); -+ -+ local_irq_restore(flags); -+} -+ -+void vm_setvoltage(unsigned int DACValue) -+{ -+ power_change_cmd(DACValue, 0 /* not-coupled */ ); -+ /* Execute voltage change sequence */ -+ change_voltage(); /* set VC on the PWRMODE on CP14 */ -+} -+ -+static void set_voltage(unsigned int mv) -+{ -+ vm_setvoltage(mv2DAC(mv)); -+} -+ -+static int vcs_init(void) -+{ -+ /* we distinguish new and old boards by proc chip -+ * revision, we assume new boards have C5 proc -+ * revision and we use the new table (table_c5) for them, -+ * for all other boards we use the old table (table_c0). -+ * Note, the logics won't work and inaccurate voltage -+ * will be set if C5 proc installed to old board -+ * and vice versa. -+ */ -+ -+ asm("mrc%? p15, 0, %0, c0, c0" : "=r" (chiprev)); -+ -+ chiprev &= CP15R0_REV_MASK; -+ -+ if (chiprev == PXA270_C5) { -+ mvDACtable = table_c5; -+ mvdt_size = sizeof(table_c5) / sizeof(struct MvDAC); -+ } else { -+ mvDACtable = table_c0; -+ mvdt_size = sizeof(table_c0) / sizeof(struct MvDAC); -+ } -+ -+ CKEN |= 0x1 << 15; -+ CKEN |= 0x1 << 14; -+ PCFR = PCFR_PI2CEN; -+ return 0; -+} -+ -+static void initialize_freq_matrix(void) -+{ -+ int n, l; -+ -+ memset(&cpufreq_matrix, 0, sizeof(cpufreq_matrix)); -+ -+ for (n = 2; n < N_NUM + 2; n++) { -+ for (l = 2; l <= L_NUM; l++) { -+ cpufreq_matrix[n - 2][l - 2] = (13 * n * l / 2) * 1000; -+ if (cpufreq_matrix[n - 2][l - 2] > BLVD_MAX_FREQ) -+ cpufreq_matrix[n - 2][l - 2] = 0; -+ } -+ } -+} -+ -+/* -+ This should be called with a valid freq point that was -+ obtained via validate_speed -+*/ -+static void set_freq(unsigned int CLKCFGValue) -+{ -+ unsigned long flags; -+ unsigned int unused; -+ unsigned int fcsbits = 0xe3dfeff; -+ volatile int v; -+ -+ local_irq_save(flags); -+ -+ /* -+ force a tlb fault to get the mapping into the tlb -+ (otherwise this will occur below when the sdram is turned off and -+ something-bad(tm) will happen) -+ */ -+ -+ v = *(volatile unsigned long *)ramstart; -+ *(volatile unsigned long *)ramstart = v; -+ -+ __asm__ __volatile__(" \n\ -+ ldr r4, [%1] @load MDREFR \n\ -+ mcr p14, 0, %2, c6, c0, 0 @ set CCLKCFG[FCS] \n\ -+ ldr r5, [%3] \n\ -+ and r4, r4, r5 \n\ -+ str r4, [%1] @restore \n\ -+ ":"=&r"(unused) -+ :"r"(&MDREFR), "r"(CLKCFGValue), "r"(&fcsbits) -+ :"r4", "r5"); -+ -+ local_irq_restore(flags); -+} -+ -+static int get_freq(void) -+{ -+ unsigned int freq, n, l, ccsr; -+ -+ ccsr = CCSR; -+ -+ l = ccsr & CCCR_L_MASK; /* Get L */ -+ n = (ccsr & CCCR_N_MASK) >> 7; /* Get 2N */ -+ -+ if (n < 2) -+ n = 2; -+ -+ /* Shift to divide by 2 because N is really 2N */ -+ freq = (13000 * l * n) >> 1; /* in kHz */ -+ -+ return freq; -+} -+ -+static unsigned int read_clkcfg(void) -+{ -+ unsigned int value = 0; -+ unsigned int un_used; -+ -+ __asm__ __volatile__("mrc p14, 0, %1, c6, c0, 0": "=&r"(un_used):"r"(value)); -+ -+ return value; -+} -+ -+static int init_freqs(void) -+{ -+ int cpu_ver; -+ -+ asm volatile ("mrc%? p15, 0, %0, c0, c0":"=r" (cpu_ver)); -+ -+ /* -+ Bulverde A0: 0x69054110, -+ A1: 0x69054111 -+ */ -+ if ((cpu_ver & 0x0000f000) >> 12 == 4 && -+ (cpu_ver & 0xffff0000) >> 16 == 0x6905) { -+ /* It is a PXA27x chip. */ -+ return 1; -+ } -+ -+ return 0; -+} -+ -+static int freq_init(void) -+{ -+ unsigned int freq; -+ -+ /* -+ * In order to turn the sdram back on (see below) we need to -+ * r/w the sdram. We need to do this without the cache and -+ * write buffer in the way. So, we temporarily ioremap the -+ * first page of sdram as uncached i/o memory and use the -+ * aliased address -+ */ -+ -+ /* map the first page of sdram to an uncached virtual page */ -+ ramstart = (int *)ioremap(PHYS_OFFSET, 4096); -+ -+ if (! ramstart) { -+ printk(KERN_ERR "PXA27x DPM: ioremap of first page failed."); -+ return -1; -+ } -+ -+ initialize_freq_matrix(); -+ -+ if (init_freqs()) { -+ freq = get_freq(); /* in kHz */ -+ printk(KERN_INFO "PXA27x DPM: Initial frequency is %dkHz.\n", freq); -+ return 0; -+ } -+ -+ return -1; -+} -+ -+void freq_cleanup(void) -+{ -+ /* unmap the page we used*/ -+ iounmap((void *)ramstart); -+} -+ -+static unsigned long -+calculate_memclk(unsigned long cccr, unsigned long clkcfg) -+{ -+ unsigned long M, memclk; -+ u32 L; -+ -+ L = cccr & 0x1f; -+ if (cccr & (1 << 25)) { -+ if (clkcfg & CLKCFG_B_BIT) -+ memclk = (L*13); -+ else -+ memclk = (L*13)/2; -+ } -+ else { -+ if (L <= 10) M = 1; -+ else if (L <= 20) M = 2; -+ else M = 4; -+ -+ memclk = (L*13)/M; -+ } -+ -+ return memclk; -+} -+ -+static unsigned long -+calculate_new_memclk(struct dpm_regs *regs) -+{ -+ return calculate_memclk(regs->cccr, regs->clkcfg); -+} -+ -+static unsigned long -+calculate_cur_memclk(void) -+{ -+ unsigned long cccr = CCCR; -+ return calculate_memclk(cccr, read_clkcfg()); -+} -+ -+/* Returns optimal timings for memory controller -+ * a - [A] -+ * b - [B] -+ * l - value of L -+ */ -+static struct mem_timings get_optimal_mem_timings(int a, int b, int l){ -+ struct mem_timings ret = { -+ .msc0 = 0, -+ .dtc = 0, -+ .dri = 0, -+ }; -+ -+ if(a!=0 && b==0){ -+ switch(l){ -+ case 2: -+ ret.msc0 = XLLI_MSC0_13; -+ ret.dtc = XLLI_DTC_13; -+ ret.dri = XLLI_DRI_13; -+ break; -+ case 3: -+ ret.msc0 = XLLI_MSC0_19; -+ ret.dtc = XLLI_DTC_19; -+ ret.dri = XLLI_DRI_19; -+ break; -+ case 4: -+ ret.msc0 = XLLI_MSC0_26; -+ ret.dtc = XLLI_DTC_26; -+ ret.dri = XLLI_DRI_26; -+ break; -+ case 5: -+ ret.msc0 = XLLI_MSC0_32; -+ ret.dtc = XLLI_DTC_32; -+ ret.dri = XLLI_DRI_32; -+ break; -+ case 6: -+ ret.msc0 = XLLI_MSC0_39; -+ ret.dtc = XLLI_DTC_39; -+ ret.dri = XLLI_DRI_39; -+ break; -+ case 7: -+ ret.msc0 = XLLI_MSC0_45; -+ ret.dtc = XLLI_DTC_45; -+ ret.dri = XLLI_DRI_45; -+ break; -+ case 8: -+ ret.msc0 = XLLI_MSC0_52; -+ ret.dtc = XLLI_DTC_52; -+ ret.dri = XLLI_DRI_52; -+ break; -+ case 9: -+ ret.msc0 = XLLI_MSC0_58; -+ ret.dtc = XLLI_DTC_58; -+ ret.dri = XLLI_DRI_58; -+ break; -+ case 10: -+ ret.msc0 = XLLI_MSC0_65; -+ ret.dtc = XLLI_DTC_65; -+ ret.dri = XLLI_DRI_65; -+ break; -+ /* -+ * L11 - L20 ARE THE SAME for A0Bx -+ */ -+ case 11: -+ ret.msc0 = XLLI_MSC0_71; -+ ret.dtc = XLLI_DTC_71; -+ ret.dri = XLLI_DRI_71; -+ break; -+ case 12: -+ ret.msc0 = XLLI_MSC0_78; -+ ret.dtc = XLLI_DTC_78; -+ ret.dri = XLLI_DRI_78; -+ break; -+ case 13: -+ ret.msc0 = XLLI_MSC0_84; -+ ret.dtc = XLLI_DTC_84; -+ ret.dri = XLLI_DRI_84; -+ break; -+ case 14: -+ ret.msc0 = XLLI_MSC0_91; -+ ret.dtc = XLLI_DTC_91; -+ ret.dri = XLLI_DRI_91; -+ break; -+ case 15: -+ ret.msc0 = XLLI_MSC0_97; -+ ret.dtc = XLLI_DTC_97; -+ ret.dri = XLLI_DRI_97; -+ break; -+ case 16: -+ ret.msc0 = XLLI_MSC0_104; -+ ret.dtc = XLLI_DTC_104; -+ ret.dri = XLLI_DRI_104; -+ break; -+ case 17: -+ ret.msc0 = XLLI_MSC0_110; -+ ret.dtc = XLLI_DTC_110; -+ ret.dri = XLLI_DRI_110; -+ break; -+ case 18: -+ ret.msc0 = XLLI_MSC0_117; -+ ret.dtc = XLLI_DTC_117; -+ ret.dri = XLLI_DRI_117; -+ break; -+ case 19: -+ ret.msc0 = XLLI_MSC0_124; -+ ret.dtc = XLLI_DTC_124; -+ ret.dri = XLLI_DRI_124; -+ break; -+ case 20: -+ ret.msc0 = XLLI_MSC0_130; -+ ret.dtc = XLLI_DTC_130; -+ ret.dri = XLLI_DRI_130; -+ break; -+ case 21: -+ ret.msc0 = XLLI_MSC0_136; -+ ret.dtc = XLLI_DTC_136; -+ ret.dri = XLLI_DRI_136; -+ break; -+ case 22: -+ ret.msc0 = XLLI_MSC0_143; -+ ret.dtc = XLLI_DTC_143; -+ ret.dri = XLLI_DRI_143; -+ break; -+ case 23: -+ ret.msc0 = XLLI_MSC0_149; -+ ret.dtc = XLLI_DTC_149; -+ ret.dri = XLLI_DRI_149; -+ break; -+ case 24: -+ ret.msc0 = XLLI_MSC0_156; -+ ret.dtc = XLLI_DTC_156; -+ ret.dri = XLLI_DRI_156; -+ break; -+ case 25: -+ ret.msc0 = XLLI_MSC0_162; -+ ret.dtc = XLLI_DTC_162; -+ ret.dri = XLLI_DRI_162; -+ break; -+ case 26: -+ ret.msc0 = XLLI_MSC0_169; -+ ret.dtc = XLLI_DTC_169; -+ ret.dri = XLLI_DRI_169; -+ break; -+ case 27: -+ ret.msc0 = XLLI_MSC0_175; -+ ret.dtc = XLLI_DTC_175; -+ ret.dri = XLLI_DRI_175; -+ break; -+ case 28: -+ ret.msc0 = XLLI_MSC0_182; -+ ret.dtc = XLLI_DTC_182; -+ ret.dri = XLLI_DRI_182; -+ break; -+ case 29: -+ ret.msc0 = XLLI_MSC0_188; -+ ret.dtc = XLLI_DTC_188; -+ ret.dri = XLLI_DRI_188; -+ break; -+ case 30: -+ ret.msc0 = XLLI_MSC0_195; -+ ret.dtc = XLLI_DTC_195; -+ ret.dri = XLLI_DRI_195; -+ break; -+ case 31: -+ ret.msc0 = XLLI_MSC0_201; -+ ret.dtc = XLLI_DTC_201; -+ ret.dri = XLLI_DRI_201; -+ } -+ -+ }else if(a!=0 && b!=0){ -+ switch(l){ -+ case 2: -+ ret.msc0 = XLLI_MSC0_26; -+ ret.dtc = XLLI_DTC_26; -+ ret.dri = XLLI_DRI_26; -+ break; -+ case 3: -+ ret.msc0 = XLLI_MSC0_39; -+ ret.dtc = XLLI_DTC_39; -+ ret.dri = XLLI_DRI_39; -+ break; -+ case 4: -+ ret.msc0 = XLLI_MSC0_52; -+ ret.dtc = XLLI_DTC_52; -+ ret.dri = XLLI_DRI_52; -+ break; -+ case 5: -+ ret.msc0 = XLLI_MSC0_65; -+ ret.dtc = XLLI_DTC_65; -+ ret.dri = XLLI_DRI_65; -+ break; -+ case 6: -+ ret.msc0 = XLLI_MSC0_78; -+ ret.dtc = XLLI_DTC_78; -+ ret.dri = XLLI_DRI_78; -+ break; -+ case 7: -+ ret.msc0 = XLLI_MSC0_91; -+ ret.dtc = XLLI_DTC_91; -+ ret.dri = XLLI_DRI_91; -+ break; -+ case 8: -+ ret.msc0 = XLLI_MSC0_104; -+ ret.dtc = XLLI_DTC_104; -+ ret.dri = XLLI_DRI_104; -+ break; -+ case 9: -+ ret.msc0 = XLLI_MSC0_117; -+ ret.dtc = XLLI_DTC_117; -+ ret.dri = XLLI_DRI_117; -+ break; -+ case 10: -+ ret.msc0 = XLLI_MSC0_130; -+ ret.dtc = XLLI_DTC_130; -+ ret.dri = XLLI_DRI_130; -+ break; -+ case 11: -+ ret.msc0 = XLLI_MSC0_143; -+ ret.dtc = XLLI_DTC_143; -+ ret.dri = XLLI_DRI_143; -+ break; -+ case 12: -+ ret.msc0 = XLLI_MSC0_156; -+ ret.dtc = XLLI_DTC_156; -+ ret.dri = XLLI_DRI_156; -+ break; -+ case 13: -+ ret.msc0 = XLLI_MSC0_169; -+ ret.dtc = XLLI_DTC_169; -+ ret.dri = XLLI_DRI_169; -+ break; -+ case 14: -+ ret.msc0 = XLLI_MSC0_182; -+ ret.dtc = XLLI_DTC_182; -+ ret.dri = XLLI_DRI_182; -+ break; -+ case 15: -+ ret.msc0 = XLLI_MSC0_195; -+ ret.dtc = XLLI_DTC_195; -+ ret.dri = XLLI_DRI_195; -+ break; -+ case 16: -+ ret.msc0 = XLLI_MSC0_208; -+ ret.dtc = XLLI_DTC_208; -+ ret.dri = XLLI_DRI_208; -+ } -+ }else{ -+ /* A0Bx */ -+ switch(l){ -+ case 2: -+ ret.msc0 = XLLI_MSC0_26; -+ ret.dtc = XLLI_DTC_26; -+ ret.dri = XLLI_DRI_26; -+ break; -+ case 3: -+ ret.msc0 = XLLI_MSC0_39; -+ ret.dtc = XLLI_DTC_39; -+ ret.dri = XLLI_DRI_39; -+ break; -+ case 4: -+ ret.msc0 = XLLI_MSC0_52; -+ ret.dtc = XLLI_DTC_52; -+ ret.dri = XLLI_DRI_52; -+ break; -+ case 5: -+ ret.msc0 = XLLI_MSC0_65; -+ ret.dtc = XLLI_DTC_65; -+ ret.dri = XLLI_DRI_65; -+ break; -+ case 6: -+ ret.msc0 = XLLI_MSC0_78; -+ ret.dtc = XLLI_DTC_78; -+ ret.dri = XLLI_DRI_78; -+ break; -+ case 7: -+ ret.msc0 = XLLI_MSC0_91; -+ ret.dtc = XLLI_DTC_91; -+ ret.dri = XLLI_DRI_91; -+ break; -+ case 8: -+ ret.msc0 = XLLI_MSC0_104; -+ ret.dtc = XLLI_DTC_104; -+ ret.dri = XLLI_DRI_104; -+ break; -+ case 9: -+ ret.msc0 = XLLI_MSC0_117; -+ ret.dtc = XLLI_DTC_117; -+ ret.dri = XLLI_DRI_117; -+ break; -+ case 10: -+ ret.msc0 = XLLI_MSC0_130; -+ ret.dtc = XLLI_DTC_130; -+ ret.dri = XLLI_DRI_130; -+ break; -+ case 11: -+ ret.msc0 = XLLI_MSC0_71; -+ ret.dtc = XLLI_DTC_71; -+ ret.dri = XLLI_DRI_71; -+ break; -+ case 12: -+ ret.msc0 = XLLI_MSC0_78; -+ ret.dtc = XLLI_DTC_78; -+ ret.dri = XLLI_DRI_78; -+ break; -+ case 13: -+ ret.msc0 = XLLI_MSC0_84; -+ ret.dtc = XLLI_DTC_84; -+ ret.dri = XLLI_DRI_84; -+ break; -+ case 14: -+ ret.msc0 = XLLI_MSC0_91; -+ ret.dtc = XLLI_DTC_91; -+ ret.dri = XLLI_DRI_91; -+ break; -+ case 15: -+ ret.msc0 = XLLI_MSC0_97; -+ ret.dtc = XLLI_DTC_97; -+ ret.dri = XLLI_DRI_97; -+ break; -+ case 16: -+ ret.msc0 = XLLI_MSC0_104; -+ ret.dtc = XLLI_DTC_104; -+ ret.dri = XLLI_DRI_104; -+ break; -+ case 17: -+ ret.msc0 = XLLI_MSC0_110; -+ ret.dtc = XLLI_DTC_110; -+ ret.dri = XLLI_DRI_110; -+ break; -+ case 18: -+ ret.msc0 = XLLI_MSC0_117; -+ ret.dtc = XLLI_DTC_117; -+ ret.dri = XLLI_DRI_117; -+ break; -+ case 19: -+ ret.msc0 = XLLI_MSC0_124; -+ ret.dtc = XLLI_DTC_124; -+ ret.dri = XLLI_DRI_124; -+ break; -+ case 20: -+ ret.msc0 = XLLI_MSC0_130; -+ ret.dtc = XLLI_DTC_130; -+ ret.dri = XLLI_DRI_130; -+ break; -+ case 21: -+ ret.msc0 = XLLI_MSC0_68; -+ ret.dtc = XLLI_DTC_68; -+ ret.dri = XLLI_DRI_68; -+ break; -+ case 22: -+ ret.msc0 = XLLI_MSC0_71; -+ ret.dtc = XLLI_DTC_71; -+ ret.dri = XLLI_DRI_71; -+ break; -+ case 23: -+ ret.msc0 = XLLI_MSC0_74; -+ ret.dtc = XLLI_DTC_74; -+ ret.dri = XLLI_DRI_74; -+ break; -+ case 24: -+ ret.msc0 = XLLI_MSC0_78; -+ ret.dtc = XLLI_DTC_78; -+ ret.dri = XLLI_DRI_78; -+ break; -+ case 25: -+ ret.msc0 = XLLI_MSC0_81; -+ ret.dtc = XLLI_DTC_81; -+ ret.dri = XLLI_DRI_81; -+ break; -+ case 26: -+ ret.msc0 = XLLI_MSC0_84; -+ ret.dtc = XLLI_DTC_84; -+ ret.dri = XLLI_DRI_84; -+ break; -+ case 27: -+ ret.msc0 = XLLI_MSC0_87; -+ ret.dtc = XLLI_DTC_87; -+ ret.dri = XLLI_DRI_87; -+ break; -+ case 28: -+ ret.msc0 = XLLI_MSC0_91; -+ ret.dtc = XLLI_DTC_91; -+ ret.dri = XLLI_DRI_91; -+ break; -+ case 29: -+ ret.msc0 = XLLI_MSC0_94; -+ ret.dtc = XLLI_DTC_94; -+ ret.dri = XLLI_DRI_94; -+ break; -+ case 30: -+ ret.msc0 = XLLI_MSC0_97; -+ ret.dtc = XLLI_DTC_97; -+ ret.dri = XLLI_DRI_97; -+ break; -+ case 31: -+ ret.msc0 = XLLI_MSC0_100; -+ ret.dtc = XLLI_DTC_100; -+ ret.dri = XLLI_DRI_100; -+ } -+ } -+ -+ return ret; -+} -+ -+static void assign_optimal_mem_timings( -+ unsigned int* msc0_reg, -+ unsigned int* mdrefr_reg, -+ unsigned int* mdcnfg_reg, -+ int a, int b, int l -+ ) -+{ -+ unsigned int msc0_reg_tmp = (*msc0_reg); -+ unsigned int mdrefr_reg_tmp = (*mdrefr_reg); -+ unsigned int mdcnfg_reg_tmp = (*mdcnfg_reg); -+ struct mem_timings timings = get_optimal_mem_timings(a,b,l); -+ -+ /* clear bits which are set by get_optimal_mem_timings*/ -+ msc0_reg_tmp &= ~(MSC0_RDF & MSC0_RDN & MSC0_RRR); -+ mdrefr_reg_tmp &= ~(MDREFR_RFU & MDREFR_DRI); -+ mdcnfg_reg_tmp &= ~(MDCNFG_DTC0 & MDCNFG_DTC2); -+ -+ /* prepare appropriate timings */ -+ msc0_reg_tmp |= timings.msc0; -+ mdrefr_reg_tmp |= timings.dri; -+ mdcnfg_reg_tmp |= timings.dtc; -+ -+ /* set timings (all bits one time) */ -+ (*msc0_reg) = msc0_reg_tmp; -+ (*mdrefr_reg) = mdrefr_reg_tmp; -+ (*mdcnfg_reg) = mdcnfg_reg_tmp; -+} -+ -+static void set_mdrefr_value(u32 new_mdrefr){ -+ unsigned long s, old_mdrefr, errata62; -+ old_mdrefr = MDREFR; -+ /* E62 (28007106.pdf): Memory controller may hang while clearing -+ * MDREFR[K1DB2] or MDREFR[K2DB2] -+ */ -+ errata62 = -+ (((old_mdrefr & MDREFR_K1DB2) != 0) && ((new_mdrefr & MDREFR_K1DB2) == 0)) || -+ (((old_mdrefr & MDREFR_K2DB2) != 0) && ((new_mdrefr & MDREFR_K2DB2) == 0)); -+ -+ if(errata62){ -+ unsigned long oscr_0 = OSCR; -+ unsigned long oscr_1 = oscr_0; -+ /* Step 1 - disable interrupts */ -+ local_irq_save(s); -+ /* Step 2 - leave KxDB2, but set MDREFR[DRI] (bits 0-11) to -+ * 0xFFF -+ */ -+ MDREFR = MDREFR | MDREFR_DRI; -+ /* Step 3 - read MDREFR one time */ -+ MDREFR; -+ /* Step 4 - wait 1.6167us -+ * (3.25MHz clock increments OSCR0 7 times) -+ */ -+ while(oscr_1-oscr_0 < 7){ -+ cpu_relax(); -+ oscr_1 = OSCR; -+ } -+ -+ } -+ -+ /* Step 5 - clear K1DB1 and/or K2DB2, and set MDREFR[DRI] to -+ * proper value at the same time -+ */ -+ -+ /*Set MDREFR as if no errata workaround is needed*/ -+ MDREFR = new_mdrefr; -+ -+ if(errata62){ -+ /* Step 6 - read MDREFR one time*/ -+ MDREFR; -+ /* Step 7 - enable interrupts*/ -+ local_irq_restore(s); -+ } -+} -+ -+static void scale_cpufreq(struct dpm_regs *regs) -+{ -+ unsigned long new_memclk, cur_memclk; -+ u32 new_mdrefr, cur_mdrefr, read_mdrefr; -+ u32 new_msc0, new_mdcnfg; -+ int set_mdrefr = 0, scaling_up = 0; -+ int l, a, b; -+ -+ l = regs->cccr & CCCR_L_MASK; /* Get L */ -+ b = (regs->clkcfg >> 3) & 0x1; -+ a = (regs->cccr >> 25) & 0x1; /* cccr[A]: bit 25 */ -+ cur_memclk = calculate_cur_memclk(); -+ new_memclk = calculate_new_memclk(regs); -+ -+ new_mdrefr = cur_mdrefr = MDREFR; -+ new_msc0 = MSC0; -+ new_mdcnfg = MDCNFG; -+ -+ if (new_memclk != cur_memclk) { -+ new_mdrefr &= ~( MDREFR_K0DB2 | MDREFR_K0DB4 | -+ MDREFR_K1DB2 | MDREFR_K2DB2 ); -+ -+ if ((new_memclk > 52) && (new_memclk <= 104)) { -+ /* SDCLK0 = MEMCLK/2, SDCLK1,SDCLK2 = MEMCLK */ -+ new_mdrefr |= MDREFR_K0DB2; -+ } -+ else if (new_memclk > 104){ -+ /* SDCLK0 = MEMCLK/4, SDCLK1 and SDCLK2 = MEMCLK/2 */ -+ new_mdrefr |= (MDREFR_K0DB4 | MDREFR_K1DB2 | MDREFR_K2DB2); -+ } -+ -+ /* clock increasing or decreasing? */ -+ if (new_memclk > cur_memclk) scaling_up = 1; -+ } -+ -+ /* set MDREFR if necessary */ -+ if (new_mdrefr != cur_mdrefr){ -+ set_mdrefr = 1; -+ /* also adjust timings as long as we change MDREFR value */ -+ assign_optimal_mem_timings( -+ &new_msc0, -+ &new_mdrefr, -+ &new_mdcnfg, -+ a,b,l -+ ); -+ } -+ -+ /* if memclk is scaling up, set MDREFR before freq change -+ * (2800002.pdf:6.5.1.4) -+ */ -+ if (set_mdrefr && scaling_up) { -+ MSC0 = new_msc0; -+ set_mdrefr_value(new_mdrefr); -+ MDCNFG = new_mdcnfg; -+ read_mdrefr = MDREFR; -+ } -+ -+ CCCR = regs->cccr; -+ set_freq(regs->clkcfg); -+ -+ /* if memclk is scaling down, set MDREFR after freq change -+ * (2800002.pdf:6.5.1.4) -+ */ -+ if (set_mdrefr && !scaling_up) { -+ MSC0 = new_msc0; -+ set_mdrefr_value(new_mdrefr); -+ MDCNFG = new_mdcnfg; -+ read_mdrefr = MDREFR; -+ } -+} -+ -+static void scale_voltage(struct dpm_regs *regs) -+{ -+ set_voltage(regs->voltage); -+} -+ -+static void scale_voltage_coupled(struct dpm_regs *regs) -+{ -+ power_change_cmd(mv2DAC(regs->voltage), 1 /* coupled */ ); -+} -+ -+static void calculate_lcd_freq(struct dpm_md_opt *opt) -+{ -+ int k = 1; /* lcd divisor */ -+ -+ /* L is verified to be between PLL_L_MAX and PLL_L_MIN in -+ dpm_bulverde_init_opt(). -+ */ -+ if (opt->l == -1) { -+ opt->lcd = -1; -+ return; -+ } -+ -+ if (opt->l > 16) { -+ /* When L=17-31, K=4 */ -+ k = 4; -+ } else if (opt->l > 7) { -+ /* When L=8-16, K=2 */ -+ k = 2; -+ } -+ -+ /* Else, when L=2-7, K=1 */ -+ -+ opt->lcd = 13000 * opt->l / k; -+} -+ -+static void calculate_reg_values(struct dpm_md_opt *opt) -+{ -+ int f = 0; /* frequency change bit */ -+ int turbo = 0; /* turbo mode bit; depends on N value */ -+ -+ opt->regs.voltage = opt->v; -+ -+/* -+ CCCR: -+ -+ A: Alternate setting for MEMC clock -+ 0 = MEM clock frequency as specified in user guide table -+ 1 = MEM clock frq = System Bus Frequency -+ -+ CLKCFG: -+ -+ B = Fast-Bus Mode 0: System Bus is half of run-mode -+ 1: System Bus is equal to run-mode -+ NOTE: only allowed when L <= 16 -+ -+ HT = Half-Turbo 0: core frequency = run or turbo, depending on T bit -+ 1: core frequency = turbo frequency / 2 -+ NOTE: only allowed when 2N = 6 or 2N = 8 -+ -+ F = Frequency change -+ 0: No frequency change is performed -+ 1: Do frequency-change -+ -+ T = Turbo Mode 0: CPU operates at run Frequency -+ 1: CPU operates at Turbo Frequency (when n2 > 2) -+*/ -+ /* Set the CLKCFG with B, T, and HT */ -+ if (opt->b != -1 && opt->n != -1) { -+ f = 1; -+ -+ /*When 2N=2, Turbo Mode equals Run Mode, so it -+ does not really matter if this is >2 or >=2 -+ */ -+ if (opt->n > 2) { -+ turbo = 0x1; -+ } -+ opt->regs.clkcfg = (opt->b << 3) + (f << 1) + turbo; -+ } else { -+ f = 0x1; -+ opt->regs.clkcfg = (f << 1); -+ } -+ -+ /* -+ What about when 2N=0 ... it is not defined by the yellow -+ book -+ */ -+ if (opt->n != -1) { -+ /* 2N is 4 bits, L is 5 bits */ -+ opt->regs.cccr = ((opt->n & 0xF) << 7) + (opt->l & 0x1F); -+ } -+ -+ if (opt->cccra > 0) { -+ /* Turn on the CCCR[A] bit */ -+ opt->regs.cccr |= (1 << 25); -+ } -+ -+ if(opt->cpll_enabled == 0) { -+ opt->regs.cccr |= (CCCR_CPDIS_BIT_ON); -+ } -+ if(opt->ppll_enabled == 0) { -+ opt->regs.cccr |= (CCCR_PPDIS_BIT_ON); -+ } -+ -+} -+ -+static int init_opt(struct dpm_opt *opt) -+{ -+ int v = -1; -+ int l = -1; -+ int n2 = -1; -+ int b = -1; -+ int half_turbo = -1; -+ int cccra = -1; -+ int cpll_enabled = -1; -+ int ppll_enabled = -1; -+ int sleep_mode = -1; -+ struct dpm_md_opt *md_opt = NULL; -+ -+ v = opt->pp[DPM_MD_V]; -+ l = opt->pp[DPM_MD_PLL_L]; -+ n2 = opt->pp[DPM_MD_PLL_N]; /* 2*N */ -+ b = opt->pp[DPM_MD_PLL_B]; /* Fast bus mode bit. */ -+ half_turbo = opt->pp[DPM_MD_HALF_TURBO]; -+ cccra = opt->pp[DPM_MD_CCCRA]; /* Alternate setting -+ for the MEM clock */ -+ cpll_enabled = opt->pp[DPM_MD_CPLL_ON]; -+ ppll_enabled = opt->pp[DPM_MD_PPLL_ON]; -+ sleep_mode = opt->pp[DPM_MD_SLEEP_MODE]; -+ -+ md_opt = &opt->md_opt; -+ -+ /* Up-front error checking. If we fail any of these, then the -+ whole operating point is suspect and therefore invalid. -+ */ -+ -+ /*PXA27x manual ("Yellow book") 3.5.5 (Table 3-7) states that CPLL-"On" and -+ *PPLL-"Off" -+ *configuration is forbidden (all others seam to be OK for "B0") -+ *for "C0" boards we suppose that this configuration is also enabled. -+ *PXA27x manual ("Yellow book") also states at 3.5.7.1 (page 3-25) -+ *that "CCCR[PPDIS] and CCCR[CPDIS] must always be identical and -+ *changed together". "If PLLs are to be turned off using xPDIS then -+ *set xPDIS before frequency change and clear xPDIS after frequency -+ *change" -+ */ -+ -+ if( (l > PLL_L_MIN) && ( cpll_enabled == 0 ) ){ -+ printk(KERN_WARNING -+ "DPM: when l>0 (NOT 13M mode) CPLL must be On \n"); -+ return -EINVAL; -+ } -+ if( (cpll_enabled>0) && (ppll_enabled==0) ){ -+ printk(KERN_WARNING -+ "DPM: illegal combination CPLL=On PPLL=Off\n"); -+ return -EINVAL; -+ } -+ -+ /* Check if voltage is correct */ -+ if(v < -1){ -+ printk(KERN_WARNING -+ "DPM: incorrect voltage %d\n", -+ v); -+ return -EINVAL; -+ } -+ -+ if ((l != -1) && (n2 != -1)) { -+ if (((l && n2) == 0) && (l || n2) != 0) { -+ /* If one of L or N2 is 0, but they are not both 0 */ -+ printk(KERN_WARNING -+ "DPM: L/N (%d/%d) must both be 0 or both be non-zero\n", -+ l, n2); -+ return -EINVAL; -+ } -+ -+ /* Standard range checking */ -+ if (((l > 0) && (n2 > 0)) && /* Don't complain about 0, it means sleep */ -+ ((l > PLL_L_MAX) || -+ (n2 > PLL_N_MAX) || (l < PLL_L_MIN) || (n2 < PLL_N_MIN))) { -+ /* Range checking */ -+ printk(KERN_WARNING -+ "DPM: L/N (%d/%d) out of range, L=1-31, N=2-8 \n", -+ l, n2); -+ return -EINVAL; -+ } -+ -+ /* If this is for 13M mode, do some more checking */ -+ if (l == PLL_L_MIN) { -+ /* -+ NOTE: the Yellow Book does not require any -+ particular setting for N, but we think it really -+ should be 2 -+ */ -+ if (n2 != 2) { -+ printk(KERN_WARNING -+ "DPM: When L=1 (13M Mode), N must be 2 (%d)\n", -+ n2); -+ return -EINVAL; -+ } -+ -+ if ((cpll_enabled != 0) && (cpll_enabled != -1)) { -+ printk(KERN_WARNING -+ "DPM: When L=1 (13M Mode), CPLL must be OFF (%d)\n", -+ cpll_enabled); -+ return -EINVAL; -+ } -+ -+ /* Page 3-32, section 3.5.7.5.2 of the Yellow Book -+ says, "Notes: Other bits in the CLKCFG can not be -+ changed while entering or exiting the 13M -+ mode. While in 13M mode, it is illegal to write to -+ CLKCFG's B, HT, or T bits" -+ */ -+ if ((b > 0) || (half_turbo > 0)) { -+ printk(KERN_WARNING -+ "DPM: When L=1 (13M Mode), B (%d) and " -+ "Half-Turbo (%d) must be off\n", b, half_turbo); -+ return -EINVAL; -+ } -+ } -+ } -+ -+ if (half_turbo > 1) { -+ printk(KERN_WARNING "DPM: Half-Turbo must be 0 or 1 (%d)\n", -+ half_turbo); -+ return -EINVAL; -+ } -+ -+ if (b > 1) { -+ printk(KERN_WARNING -+ "DPM: Fast-Bus Mode (B) must be 0 or 1 (%d)\n", b); -+ return -EINVAL; -+ } -+ -+ /* 2800002.pdf 3.5.7.1 It is illegal to set B if CCCR[CPDIS] is set. */ -+ if( cpll_enabled==0 && b == 1){ -+ printk(KERN_WARNING -+ "DPM: fast bus (b=%d) must both be 0 if CPLL is Off\n", -+ b); -+ return -EINVAL; -+ } -+ -+ if (cccra > 1) { -+ printk(KERN_WARNING -+ "DPM: CCCR[A] (alternate MEMC clock) must be 0 or 1 (%d)\n", -+ cccra); -+ return -EINVAL; -+ } -+ -+ /* This (when CCCR[A] is on and FastBus is on, L must be <=16) -+ is explicitly stated in text at the bottom of one of the -+ CPU frequency tables--the one where CCCR[A] is on */ -+ if ((b == 1) && (cccra == 1) && (l > 16)) { -+ printk(KERN_WARNING -+ "DPM: when B=1 and CCCR[A]=1, L must be <= 16 (L is %d)\n", -+ l); -+ return -EINVAL; -+ } -+ -+ /* This one is not explicitly stated the Yellow Book as a bad -+ thing (as the previous restriction is), but according to -+ the CPU frequency tables, fast bus mode *cannot* be -+ supported, even when CCCR[A] is not 1. -+ */ -+ if ((b == 1) && (l > 16)) { -+ printk(KERN_WARNING -+ "DPM: when B=1, L must be <= 16 (L is %d)\n", l); -+ return -EINVAL; -+ } -+ -+ if (n2 != -1) { -+ if ((half_turbo == 1) && (n2 != 6) && (n2 != 8)) { -+ printk(KERN_WARNING -+ "DPM: Half Turbo only allowed when N2 is 6 or 8\n" -+ "(N2 is %d)\n", n2); -+ return -EINVAL; -+ } -+ } -+ -+ /* Check Sleep Mode versus modes from pm.h -+ NOTE: CPUMODE_SENSE is not implemented. -+ */ -+ if ((l == 0) && (n2 == 0) && (sleep_mode != -1) && -+ (sleep_mode != CPUMODE_STANDBY) && -+ (sleep_mode != CPUMODE_SLEEP) && -+ (sleep_mode != CPUMODE_DEEPSLEEP)) { -+ printk(KERN_WARNING -+ "DPM: Sleep Mode value %d is not allowed" -+ " (only %d, %d, or %d) l=%d n2=%d\n", -+ sleep_mode, -+ CPUMODE_STANDBY, CPUMODE_SLEEP, CPUMODE_DEEPSLEEP, -+ l, n2); -+ return -EINVAL; -+ } -+ -+ /* save the values for this operating point */ -+ md_opt->v = v; -+ md_opt->l = l; -+ md_opt->n = n2; -+ md_opt->b = b; -+ md_opt->cccra = cccra; -+ md_opt->half_turbo = half_turbo; -+ md_opt->cpll_enabled = cpll_enabled; -+ md_opt->ppll_enabled = ppll_enabled; -+ md_opt->sleep_mode = sleep_mode; -+ calculate_lcd_freq(md_opt); -+ -+ if ((md_opt->l == -1) || (md_opt->n == -1)) { -+ md_opt->cpu = -1; -+ } else { -+ /* shift 1 to divide by 2 because opt->n is 2*N */ -+ md_opt->cpu = (13000 * md_opt->l * md_opt->n) >> 1; -+ if (md_opt->half_turbo == 1) { -+ /* divide by 2 */ -+ md_opt->cpu = md_opt->cpu >> 1; -+ } -+ } -+ -+ return 0; -+} -+ -+static void fully_define_opt(struct dpm_md_opt *cur, struct dpm_md_opt *new) -+{ -+ if (new->v == -1) -+ new->v = cur->v; -+ if (new->l == -1) -+ new->l = cur->l; -+ if (new->n == -1) -+ new->n = cur->n; -+ if (new->b == -1) -+ new->b = cur->b; -+ if (new->half_turbo == -1) -+ new->half_turbo = cur->half_turbo; -+ if (new->cccra == -1) -+ new->cccra = cur->cccra; -+ if (new->cpll_enabled == -1) -+ new->cpll_enabled = cur->cpll_enabled; -+ if (new->ppll_enabled == -1) -+ new->ppll_enabled = cur->ppll_enabled; -+ if (new->sleep_mode == -1) -+ new->sleep_mode = cur->sleep_mode; -+ -+ if (new->n > 2) { -+ new->turbo = 1; -+ /* turbo mode: 13K * L * (N/2) -+ Shift at the end to divide N by 2 for Turbo mode or -+ by 4 for Half-Turbo mode ) -+ */ -+ new->cpu = (13000 * new->l * new->n) >> -+ ((new->half_turbo == 1) ? 2 : 1); -+ } else { -+ new->turbo = 0; -+ /* run mode */ -+ new->cpu = 13000 * new->l; -+ } -+ /* lcd freq is derived from L */ -+ calculate_lcd_freq(new); -+ calculate_reg_values(new); -+ /* We want to keep a baseline loops_per_jiffy/cpu-freq ratio -+ to work off of for future calculations, especially when -+ emerging from sleep when there is no current cpu frequency -+ to calculate from (because cpu-freq of 0 means sleep). -+ */ -+ if (!saved_loops_per_jiffy) { -+ saved_loops_per_jiffy = loops_per_jiffy; -+ saved_cpu_freq = cur->cpu; -+ } -+ -+ if (new->cpu) { -+ /* Normal change (not sleep), just compute. Always use -+ the "baseline" lpj and freq */ -+ new->lpj = -+ dpm_compute_lpj(saved_loops_per_jiffy, saved_cpu_freq, -+ new->cpu); -+ } else { -+ /* If sleeping, keep the old LPJ */ -+ new->lpj = loops_per_jiffy; -+ } -+} -+ -+static void xpll_on(struct dpm_regs *regs) -+{ -+ int tmp_cccr, tmp_ccsr; -+ int new_cpllon=0, new_ppllon=0, cur_cpllon=0; -+ int cur_ppllon=0, start_cpll=0, start_ppll=0; -+ -+ tmp_ccsr = CCSR; -+ -+ if ((regs->cccr & CCCR_CPDIS_BIT_ON) == 0) -+ new_cpllon = 1; -+ if ((regs->cccr & CCCR_PPDIS_BIT_ON) == 0) -+ new_ppllon = 1; -+ if (((tmp_ccsr >> 31) & 0x1) == 0) -+ cur_cpllon = 1; -+ if (((tmp_ccsr >> 30) & 0x1) == 0) -+ cur_ppllon = 1; -+ -+ if ((new_cpllon == 1) && (cur_cpllon == 0)) -+ start_cpll=1; -+ -+ if ((new_ppllon == 1) && (cur_ppllon == 0)) -+ start_ppll=1; -+ -+ if ((start_cpll == 0) && (start_ppll == 0)) -+ return; -+ -+ /* NOTE: the Yellow Book says that exiting 13M mode requires a -+ PLL relock, which takes at least 120uS, so the book suggests -+ the OS could use a timer to keep busy until it is time to -+ check the CCSR bits which must happen before changing the -+ frequency back. -+ -+ For now, we'll just loop. -+ */ -+ -+ /* From Yellow Book, page 3-31, section 3.5.7.5 13M Mode -+ -+ Exiting 13M Mode: -+ -+ 1. Remain in 13M mode, but early enable the PLL via -+ CCCR[CPDIS, PPDIS]=11, and CCCR[PLL_EARLY_EN]=1. Doing -+ so will allow the PLL to be started early. -+ -+ 2. Read CCCR and compare to make sure that the data was -+ correctly written. -+ -+ 3. Check to see if CCS[CPLOCK] and CCSR[PPLOCK] bits are -+ both set. Once these bits are both high, the PLLs are -+ locked and you may move on. -+ -+ 4. Note that the CPU is still in 13M mode, but the PLLs are -+ started. -+ -+ 5. Exit from 13M mode by writing CCCR[CPDIS, PPDIS]=00, but -+ maintain CCCR[PLL_EARLY_EN]=1. This bit will be cleared -+ by the imminent frequency change. -+ */ -+ -+ /* Step 1 */ -+ tmp_cccr = CCCR; -+ -+ if (start_cpll) -+ tmp_cccr |= CCCR_CPDIS_BIT_ON; -+ -+ if(start_ppll) -+ tmp_cccr |= CCCR_PPDIS_BIT_ON; -+ -+ tmp_cccr |= CCCR_PLL_EARLY_EN_BIT_ON; -+ CCCR = tmp_cccr; -+ -+ /* Step 2 */ -+ tmp_cccr = CCCR; -+ -+#ifdef DEBUG -+ if ((tmp_cccr & CCCR_PLL_EARLY_EN_BIT_ON) != CCCR_PLL_EARLY_EN_BIT_ON) -+ printk(KERN_WARNING -+ "DPM: Warning: PLL_EARLY_EN is NOT on\n"); -+ -+ if ((start_cpll==1) && -+ ((tmp_cccr & CCCR_CPDIS_BIT_ON) != CCCR_CPDIS_BIT_ON)) -+ printk(KERN_WARNING -+ "DPM: Warning: CPDIS is NOT on\n"); -+ -+ if ((start_ppll==1) && -+ (tmp_cccr & CCCR_PPDIS_BIT_ON) != CCCR_PPDIS_BIT_ON) -+ printk(KERN_WARNING -+ "DPM: Warning: PPDIS is NOT on\n"); -+#endif -+ -+ /* Step 3 */ -+ { -+ /* Note: the point of this is to "wait" for the lock -+ bits to be set; the Yellow Book says this may take -+ a while, but observation indicates that it is -+ instantaneous. -+ */ -+ -+ long volatile int i = 0; -+ -+ int cpll_complete=1; -+ int ppll_complete=1; -+ -+ if (start_cpll == 1) -+ cpll_complete=0; -+ -+ if (start_ppll == 1) -+ ppll_complete=0; -+ -+ /*loop arbitrary big value to prevent looping forever */ -+ for (i = 0; i < 999999; i++) { -+ tmp_ccsr = CCSR; -+ -+ if (tmp_ccsr & CCSR_CPLL_LOCKED) -+ cpll_complete=1; -+ -+ if (tmp_ccsr & CCSR_PPLL_LOCKED) -+ ppll_complete=1; -+ -+ if ((cpll_complete == 1) && (ppll_complete == 1)) -+ break; -+ } -+ } -+ -+ /* Step 4: NOP */ -+ -+ /* Step 5 -+ Clear the PLL disable bits - do NOT do it here. -+ */ -+ -+ /* But leave EARLY_EN on; it will be cleared by the frequency change */ -+ regs->cccr |= CCCR_PLL_EARLY_EN_BIT_ON; -+ -+ /* -+ Step 6: Now go continue on with frequency change -+ We do this step later as if voltage is too low, -+ we must ensure that it rised up before entereng to higher -+ freq mode or simultaniously. -+ */ -+} -+ -+static int set_opt(struct dpm_opt *curop, struct dpm_opt *newop) -+{ -+ struct dpm_md_opt *cur, *new; -+ int current_n = (CCSR & CCCR_N_MASK) >> 7; -+ int set_opt_flags = 0; -+ unsigned int cccr, clkcfg = 0; -+ unsigned long s; -+ -+#define SET_OPT_CPUFREQ (1 << 0) -+#define SET_OPT_VOLTAGE (1 << 1) -+#define SET_OPT_TURBO_ON (1 << 2) -+#define SET_OPT_TURBO_OFF (1 << 3) -+#define SET_OPT_TURBO (SET_OPT_TURBO_ON | SET_OPT_TURBO_OFF) -+ -+ pr_debug("set_opt: %s => %s\n", curop->name, newop->name); -+ -+ cur = &curop->md_opt; -+ new = &newop->md_opt; -+ fully_define_opt(cur, new); -+ -+ if (new->regs.voltage != cur->regs.voltage) -+ set_opt_flags |= SET_OPT_VOLTAGE; -+ -+ if (new->cpu) { -+ if ((new->regs.cccr != cur->regs.cccr) || -+ (new->regs.clkcfg != cur->regs.clkcfg)) { -+ -+ /* Find out if it is *just* a turbo bit change */ -+ -+ if ((cur->l == new->l) && -+ (cur->cccra == new->cccra) && -+ (cur->b == new->b) && -+ (cur->half_turbo == new->half_turbo)) { -+ /* If the real, current N is a turbo freq and -+ the new N is not a turbo freq, then set -+ TURBO_OFF and do not change N. -+ */ -+ if ((cur->n > 1) && (new->n == 2)) -+ set_opt_flags |= SET_OPT_TURBO_OFF; -+ -+ /* Else if the current operating point's N is -+ not-turbo and the new N is the desired -+ destination N, then set TURBO_ON -+ */ -+ else if ((cur->n == 2) && (new->n == current_n)) { -+ /* Desired N must be what is current -+ set in the CCCR/CCSR. -+ */ -+ set_opt_flags |= SET_OPT_TURBO_ON; -+ } -+ /* Else, fall through to regular FCS */ -+ } -+ -+ if (!(set_opt_flags & SET_OPT_TURBO)) { -+ /* It this is not a Turbo bit only change, it -+ must be a regular FCS. -+ */ -+ set_opt_flags |= SET_OPT_CPUFREQ; -+ } -+ loops_per_jiffy = new->lpj; -+ } -+ -+ local_irq_save(s); -+ -+ /* If exiting 13M mode (turn on PLL(s)), do some extra work -+ before changing the CPU frequency or voltage. -+ We may turn on a combination of PLLs supported by hardware -+ only. Otherwise xpll_on(...) hang the system. -+ */ -+ -+ if ((!cur->cpll_enabled && new->cpll_enabled) || -+ (!cur->ppll_enabled && new->ppll_enabled)) -+ xpll_on(&new->regs); -+ -+ /* In accordance with Yellow Book section 3.7.6.3, "Coupling -+ Voltage Change with Frequency Change", always set the -+ voltage first (setting the FVC bit in the PCFR) and then do -+ the frequency change -+ */ -+ -+ if (set_opt_flags & SET_OPT_VOLTAGE) { -+ if (set_opt_flags & SET_OPT_CPUFREQ) -+ /* coupled voltage & freq change */ -+ scale_voltage_coupled(&new->regs); -+ else -+ /* Scale CPU voltage un-coupled with freq */ -+ scale_voltage(&new->regs); -+ } -+ -+ if (set_opt_flags & SET_OPT_CPUFREQ) /* Scale CPU freq */ -+ scale_cpufreq(&new->regs); -+ -+ if ((set_opt_flags & SET_OPT_VOLTAGE) && -+ (set_opt_flags & SET_OPT_CPUFREQ)) -+ PCFR &= ~PCFR_FVC; -+ -+ if (set_opt_flags & SET_OPT_TURBO) { -+ clkcfg = read_clkcfg(); -+ -+ /* Section 3.5.7 of the Yellow Book says that the F -+ bit will be left on after a FCS, so we need to -+ explicitly clear it. But do not change the B bit. -+ */ -+ -+ clkcfg &= ~(CLKCFG_F_BIT); -+ -+ if (set_opt_flags & SET_OPT_TURBO_ON) -+ clkcfg = clkcfg | (CLKCFG_T_BIT); -+ else -+ clkcfg = clkcfg & ~(CLKCFG_T_BIT); -+ -+ /* enable */ -+ set_freq(clkcfg); -+ } -+ -+ if (new->half_turbo != cur->half_turbo) { -+ if ((set_opt_flags & SET_OPT_CPUFREQ) || -+ (set_opt_flags & SET_OPT_VOLTAGE)) { -+ /* -+ From the Yellow Book, p 3-106: -+ -+ "Any two writes to CLKCFG or PWRMODE -+ registers must be separated by six 13-MHz -+ cycles. This requirement is achieved by -+ doing the write to the CLKCFG or POWERMODE -+ register, performing a read of CCCR, and -+ then comparing the value in the CLKCFG or -+ POWERMODE register to the written value -+ until it matches." -+ -+ Since the setting of half turbo is a -+ separate write to CLKCFG, we need to adhere -+ to this requirement. -+ */ -+ -+ cccr = CCCR; -+ clkcfg = read_clkcfg(); -+ while (clkcfg != new->regs.clkcfg) -+ clkcfg = read_clkcfg(); -+ } -+ -+ if (clkcfg == 0) -+ clkcfg = new->regs.clkcfg; -+ -+ /* Turn off f-bit. -+ -+ According to the Yellow Book, page 3-23, "If only -+ HT is set, F is clear, and B is not altered, then -+ the core PLL is not stopped." */ -+ -+ clkcfg = clkcfg & ~(CLKCFG_F_BIT); -+ -+ /* set half turbo bit */ -+ -+ if (new->half_turbo) -+ clkcfg = clkcfg | (CLKCFG_HT_BIT); -+ else -+ clkcfg = clkcfg & ~(CLKCFG_HT_BIT); -+ -+ /* enable */ -+ -+ set_freq(clkcfg); -+ loops_per_jiffy = new->lpj; -+ } -+ -+ local_irq_restore(s); -+ -+ } else { -+ -+ /* -+ * A sleep operating point. -+ */ -+ -+#ifdef CONFIG_PM -+ /* NOTE: voltage needs i2c, so be sure to change -+ voltage BEFORE* calling device_suspend -+ */ -+ -+ if (set_opt_flags & SET_OPT_VOLTAGE) -+ /* Scale CPU voltage un-coupled with freq */ -+ scale_voltage(&new->regs); -+ -+ if (new->sleep_mode == CPUMODE_STANDBY) -+ pm_suspend(PM_SUSPEND_STANDBY); -+ else if (new->sleep_mode == CPUMODE_DEEPSLEEP) -+ ; // not supported upstream yet -+ else -+ pm_suspend(PM_SUSPEND_MEM); -+ -+ /* Here when we wake up. */ -+#endif /*CONFIG_PM*/ -+ -+ /* Recursive call to switch back to to task state. */ -+ dpm_set_os(DPM_TASK_STATE); -+ } -+ -+#ifdef CONFIG_DPM_STATS -+ dpm_update_stats(&newop->stats, &dpm_active_opt->stats); -+#endif -+ dpm_active_opt = newop; -+ mb(); -+ -+ /* Devices only need to scale on a core frequency -+ change. Half-Turbo changes are separate from the regular -+ frequency changes, so Half-Turbo changes do not need to -+ trigger a device recalculation. -+ -+ NOTE: turbo-mode-only changes could someday also be -+ optimized like Half-Turbo (to not trigger a device -+ recalc). -+ */ -+ -+ if (new->cpu && (set_opt_flags & SET_OPT_CPUFREQ)) -+ /* Normal change (not sleep), just compute. Always use -+ the "baseline" lpj and freq */ -+ dpm_driver_scale(SCALE_POSTCHANGE, newop); -+ -+ return 0; -+} -+ -+/* Fully determine the current machine-dependent operating point, and fill in a -+ structure presented by the caller. This should only be called when the -+ dpm_sem is held. This call can return an error if the system is currently at -+ an operating point that could not be constructed by dpm_md_init_opt(). */ -+ -+static int get_opt(struct dpm_opt *opt) -+{ -+ unsigned int tmp_cccr; -+ unsigned int cpdis; -+ unsigned int ppdis; -+ struct dpm_md_opt *md_opt = &opt->md_opt; -+ -+ /* You should read CCSR to see what's up...but there is no A -+ bit in the CCSR, so we'll grab it from the CCCR. -+ */ -+ tmp_cccr = CCCR; -+ md_opt->cccra = (tmp_cccr >> 25) & 0x1; /* cccr[A]: bit 25 */ -+ -+ /* NOTE: the current voltage is not obtained, but will be left -+ as 0 in the opt which will mean no voltage change at all. -+ */ -+ -+ md_opt->regs.cccr = CCSR; -+ -+ md_opt->l = md_opt->regs.cccr & CCCR_L_MASK; /* Get L */ -+ md_opt->n = (md_opt->regs.cccr & CCCR_N_MASK) >> 7; /* Get 2N */ -+ -+ /* This should never really be less than 2 */ -+ if (md_opt->n < 2) { -+ md_opt->n = 2; -+ } -+ -+ md_opt->regs.clkcfg = read_clkcfg(); -+ md_opt->b = (md_opt->regs.clkcfg >> 3) & 0x1; /* Fast Bus (b): bit 3 */ -+ md_opt->turbo = md_opt->regs.clkcfg & 0x1; /* Turbo is bit 1 */ -+ md_opt->half_turbo = (md_opt->regs.clkcfg >> 2) & 0x1; /* HalfTurbo: bit 2 */ -+ -+ calculate_lcd_freq(md_opt); -+ -+ /* are any of the PLLs is on? */ -+ cpdis = ((md_opt->regs.cccr >> 31) & 0x1); -+ ppdis = ((md_opt->regs.cccr >> 30) & 0x1); -+ /* Newer revisions still require that if CPLL is On -+ then PPLL must also be On. -+ */ -+ if ((cpdis == 0) && (ppdis != 0)) { -+ /* CPLL=On PPLL=Off is NOT supported with hardware. -+ NOTE:"B0"-revision has even more restrictive requirments -+ to PLLs -+ */ -+ printk("DPM: cpdis and ppdis are not in sync!\n"); -+ } -+ -+ md_opt->cpll_enabled = (cpdis == 0); -+ md_opt->ppll_enabled = (ppdis == 0); -+ -+ /* Shift 1 to divide by 2 (because opt->n is really 2*N */ -+ if (md_opt->turbo) { -+ md_opt->cpu = (13000 * md_opt->l * md_opt->n) >> 1; -+ } else { -+ /* turbo bit is off, so skip N multiplier (no matter -+ what N really is) and use Run frequency (13K * L) -+ */ -+ md_opt->cpu = 13000 * md_opt->l; -+ } -+ -+ return 0; -+} -+ -+/**************************************************************************** -+ * DPM Idle Handler -+ ****************************************************************************/ -+ -+static void (*orig_idle) (void); -+ -+static void dpm_pxa27x_idle(void) -+{ -+ extern void default_idle(void); -+ -+ if (orig_idle) -+ orig_idle(); -+ else { -+ /* -+ * arch/arm/kernel/process.c: default_idle() -+ * do be sure to watch for updates :( -+ */ -+ -+ local_irq_disable(); -+ if (!need_resched()) { -+ timer_dyn_reprogram(); -+ arch_idle(); -+ } -+ local_irq_enable(); -+ } -+} -+ -+/**************************************************************************** -+ * Initialization/Exit -+ ****************************************************************************/ -+ -+extern void (*pm_idle) (void); -+ -+static void startup(void) -+{ -+ orig_idle = pm_idle; -+ pm_idle = dpm_idle; -+} -+ -+static void cleanup(void) -+{ -+ pm_idle = orig_idle; -+} -+ -+static int __init dpm_pxa27x_init(void) -+{ -+ printk("PXA27x Dynamic Power Management\n"); -+ -+ if (freq_init()) { -+ printk("PXA27x DPM init failed\n"); -+ return -1; -+ } -+ -+ vcs_init(); -+ dpm_md.init_opt = init_opt; -+ dpm_md.set_opt = set_opt; -+ dpm_md.get_opt = get_opt; -+ dpm_md.check_constraint = dpm_default_check_constraint; -+ dpm_md.idle = dpm_pxa27x_idle; -+ dpm_md.startup = startup; -+ dpm_md.cleanup = cleanup; -+ return 0; -+} -+ -+static void __exit dpm_pxa27x_exit(void){ -+ freq_cleanup(); -+} -+ -+__initcall(dpm_pxa27x_init); -+__exitcall(dpm_pxa27x_exit); -Index: linux-2.6.16/drivers/serial/pxa.c -=================================================================== ---- linux-2.6.16.orig/drivers/serial/pxa.c -+++ linux-2.6.16/drivers/serial/pxa.c -@@ -43,6 +43,8 @@ - #include <linux/tty.h> - #include <linux/tty_flip.h> - #include <linux/serial_core.h> -+#include <linux/dpm.h> -+#include <linux/notifier.h> - - #include <asm/io.h> - #include <asm/hardware.h> -@@ -57,6 +59,7 @@ struct uart_pxa_port { - unsigned char mcr; - unsigned int lsr_break_flag; - unsigned int cken; -+ unsigned int baud; - char *name; - }; - -@@ -473,6 +476,7 @@ serial_pxa_set_termios(struct uart_port - */ - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); - quot = uart_get_divisor(port, baud); -+ up->baud = baud; // save for DPM scale callback - - if ((up->port.uartclk / quot) < (2400 * 16)) - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR1; -@@ -817,6 +821,44 @@ static int serial_pxa_resume(struct plat - return 0; - } - -+static int serial_pxa_scale(struct notifier_block *self, -+ unsigned long level, void *newop) -+{ -+ int n=0;int i=0; -+ int ccsr=CCSR; -+ n=sizeof(serial_pxa_ports)/sizeof(struct uart_pxa_port); -+ -+ for (i=0; i<n; ++i) { -+ struct uart_pxa_port *up = (struct uart_pxa_port *) &serial_pxa_ports[i]; -+ -+ if(up->baud) { -+ unsigned int quot; -+ -+ if ((ccsr & (1<<30))){ -+ if (up->port.uartclk == 13000000) -+ return 0; -+ -+ /*if PPLL is Off (clocking with 13MHz now)*/ -+ up->port.uartclk = 13000000; -+ } else { -+ if (up->port.uartclk == 921600 * 16) -+ return 0; -+ -+ /*clocking with 14.7456 MHz*/ -+ up->port.uartclk = 921600 * 16; -+ } -+ -+ quot = uart_get_divisor(&up->port, up->baud); -+ serial_out(up, UART_LCR, up->lcr | UART_LCR_DLAB);/* set DLAB */ -+ serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */ -+ serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */ -+ serial_out(up, UART_LCR, up->lcr); /* reset DLAB */ -+ } -+ } -+ -+ return 0; -+} -+ - static int serial_pxa_probe(struct platform_device *dev) - { - serial_pxa_ports[dev->id].port.dev = &dev->dev; -@@ -848,6 +890,10 @@ static struct platform_driver serial_pxa - }, - }; - -+static struct notifier_block serial_pxa_nb = { -+ .notifier_call = serial_pxa_scale, -+}; -+ - int __init serial_pxa_init(void) - { - int ret; -@@ -860,6 +906,9 @@ int __init serial_pxa_init(void) - if (ret != 0) - uart_unregister_driver(&serial_pxa_reg); - -+ if (! ret) -+ dpm_register_scale(&serial_pxa_nb, SCALE_POSTCHANGE); -+ - return ret; - } - -@@ -867,6 +916,7 @@ void __exit serial_pxa_exit(void) - { - platform_driver_unregister(&serial_pxa_driver); - uart_unregister_driver(&serial_pxa_reg); -+ dpm_unregister_scale(&serial_pxa_nb, SCALE_POSTCHANGE); - } - - module_init(serial_pxa_init); -Index: linux-2.6.16/drivers/video/pxafb.c -=================================================================== ---- linux-2.6.16.orig/drivers/video/pxafb.c -+++ linux-2.6.16/drivers/video/pxafb.c -@@ -1000,6 +1000,39 @@ static int pxafb_resume(struct platform_ - #define pxafb_resume NULL - #endif - -+#ifdef CONFIG_DPM -+#include <linux/dpm.h> -+ -+#define WAIT_FOR_LCD_INTR(reg,intr,timeout) ({ \ -+ int __done =0; \ -+ int __t = timeout; \ -+ while (__t) { \ -+ __done = (reg) & (intr); \ -+ if (__done) break; \ -+ udelay(50); \ -+ __t--; \ -+ } \ -+ __done; \ -+}) -+ -+static int pxafb_scale(struct notifier_block *nb, unsigned long val, void *data) -+{ -+#if 0 // Without disable.enable overlays, doesn't work well yet -+ struct pxafb_info *fbi = TO_INF(nb, scale); -+ u_int pcd; -+ -+ LCSR = 0xffffffff; /* Clear LCD Status Register */ -+ LCCR0 &= ~LCCR0_LDM; /* Enable LCD Disable Done Interrupt */ -+ LCCR0 |= LCCR0_DIS; /* Disable LCD Controller */ -+ WAIT_FOR_LCD_INTR(LCSR,LCSR_LDD,20); -+ pcd = get_pcd(fbi->fb.var.pixclock); -+ fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd); -+ pxafb_enable_controller(fbi); -+#endif -+ return 0; -+} -+#endif -+ - /* - * pxafb_map_video_memory(): - * Allocates the DRAM memory for the frame buffer. This buffer is -@@ -1367,6 +1400,10 @@ int __init pxafb_probe(struct platform_d - cpufreq_register_notifier(&fbi->freq_transition, CPUFREQ_TRANSITION_NOTIFIER); - cpufreq_register_notifier(&fbi->freq_policy, CPUFREQ_POLICY_NOTIFIER); - #endif -+#ifdef CONFIG_DPM -+ fbi->scale.notifier_call = pxafb_scale; -+ dpm_register_scale(&fbi->scale, SCALE_POSTCHANGE); -+#endif - - /* - * Ok, now enable the LCD controller -Index: linux-2.6.16/drivers/video/pxafb.h -=================================================================== ---- linux-2.6.16.orig/drivers/video/pxafb.h -+++ linux-2.6.16/drivers/video/pxafb.h -@@ -95,6 +95,10 @@ struct pxafb_info { - struct notifier_block freq_transition; - struct notifier_block freq_policy; - #endif -+ -+#ifdef CONFIG_DPM -+ struct notifier_block scale; -+#endif - }; - - #define TO_INF(ptr,member) container_of(ptr,struct pxafb_info,member) |