summaryrefslogtreecommitdiff
path: root/arch/arm/mach-wmt/wmt_clk.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-wmt/wmt_clk.c')
-rw-r--r--arch/arm/mach-wmt/wmt_clk.c2378
1 files changed, 2378 insertions, 0 deletions
diff --git a/arch/arm/mach-wmt/wmt_clk.c b/arch/arm/mach-wmt/wmt_clk.c
new file mode 100644
index 00000000..c7d5a322
--- /dev/null
+++ b/arch/arm/mach-wmt/wmt_clk.c
@@ -0,0 +1,2378 @@
+/*++
+linux/arch/arm/mach-wmt/wmt_clk.c
+
+Copyright (c) 2008 WonderMedia Technologies, Inc.
+
+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, see <http://www.gnu.org/licenses/>.
+
+WonderMedia Technologies, Inc.
+10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C.
+--*/
+
+#include <linux/mtd/mtd.h>
+#include "wmt_clk.h"
+#include <mach/hardware.h>
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/cpufreq.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/mach/map.h>
+#include <asm/irq.h>
+#include <asm/sizes.h>
+#include <linux/i2c.h>
+#include <asm/div64.h>
+#include <linux/mutex.h>
+#include <linux/regulator/consumer.h>
+#include <linux/interrupt.h>
+
+#include "generic.h"
+
+#define MMFREQ_VD DEV_CNMVDU // DEV_MSVD
+int mmfreq_num = ~0;
+int mmfreq_cur_num = ~0;
+int mmfreq_type_mask;
+int mmfreq_debug;
+struct regulator *re;
+
+#define PMC_BASE PM_CTRL_BASE_ADDR
+#define PMC_PLL (PM_CTRL_BASE_ADDR + 0x200)
+#define PMC_CLK (PM_CTRL_BASE_ADDR + 0x250)
+#define WM8980_SCC_BASE 0xD8110110
+#define CPINFO (WM8980_SCC_BASE + WMT_MMAP_OFFSET)
+
+#define PLL_BUSY 0x7F0038
+#define MAX_DF ((1<<7) - 1)
+#define MAX_DR 1 //((1<<5) - 1)
+#define MAX_DQ ((1<<2) - 1)
+#define GET_DIVF(d) ((((d>>16)&MAX_DF)+1)*2)
+#define GET_DIVR(d) (((d>>8)&MAX_DR)+1)
+#define GET_DIVQ(d) (1<<(d&MAX_DQ))
+
+#define SRC_FREQ25 25
+#define SRC_FREQ24 24
+#define SRC_FREQ SRC_FREQ24
+/*#define debug_clk*/
+extern int wmt_getsyspara(char *varname, char *varval, int *varlen);
+#define DEBUG_PLLA
+/*
+#define DEBUG
+*/
+#ifdef DEBUG
+static int dbg_mask = 1;
+module_param(dbg_mask, int, S_IRUGO | S_IWUSR);
+#define fq_dbg(fmt, args...) \
+ do {\
+ if (dbg_mask) \
+ printk(KERN_ERR "[%s]_%d_%d: " fmt, __func__ , __LINE__, smp_processor_id(), ## args);\
+ } while (0)
+#define fq_trace() \
+ do {\
+ if (dbg_mask) \
+ printk(KERN_ERR "trace in %s %d\n", __func__, __LINE__);\
+ } while (0)
+#else
+#define fq_dbg(fmt, args...)
+#define fq_trace()
+#endif
+extern int wmt_getsyspara(char *varname, char *varval, int *varlen);
+static int dev_en_count[128] = {0};
+struct pll_map pllmap[] = {//total 168
+{126, 0x00290103},{129, 0x002A0103},{132, 0x002B0103},{135, 0x002C0103},{138, 0x002D0103},
+{141, 0x002E0103},{144, 0x002F0103},{147, 0x00300103},{150, 0x00310103},{153, 0x00320103},
+{156, 0x00330103},{159, 0x00340103},{162, 0x00350103},{165, 0x00360103},{168, 0x00370103},
+{171, 0x00380103},{174, 0x00390103},{177, 0x003A0103},{180, 0x003B0103},{183, 0x003C0103},
+{186, 0x003D0103},{189, 0x003E0103},{192, 0x003F0103},{195, 0x00400103},{198, 0x00410103},
+{201, 0x00420103},{204, 0x00430103},{207, 0x00440103},{210, 0x00450103},{213, 0x00460103},
+{216, 0x00470103},{219, 0x00480103},{222, 0x00490103},{225, 0x004A0103},{228, 0x004B0103},
+{231, 0x004C0103},{234, 0x004D0103},{237, 0x004E0103},{240, 0x004F0103},{243, 0x00500103},
+{246, 0x00510103},{249, 0x00520103},{252, 0x00290102},{258, 0x002A0102},{264, 0x002B0102},
+{270, 0x002C0102},{276, 0x002D0102},{282, 0x002E0102},{288, 0x002F0102},{294, 0x00300102},
+{300, 0x00310102},{306, 0x00320102},{312, 0x00330102},{318, 0x00340102},{324, 0x00350102},
+{330, 0x00360102},{336, 0x00370102},{342, 0x00380102},{348, 0x00390102},{354, 0x003A0102},
+{360, 0x003B0102},{366, 0x003C0102},{372, 0x003D0102},{378, 0x003E0102},{384, 0x003F0102},
+{390, 0x00400102},{396, 0x00410102},{402, 0x00420102},{408, 0x00430102},{414, 0x00440102},
+{420, 0x00450102},{426, 0x00460102},{432, 0x00470102},{438, 0x00480102},{444, 0x00490102},
+{450, 0x004A0102},{456, 0x004B0102},{462, 0x004C0102},{468, 0x004D0102},{474, 0x004E0102},
+{480, 0x004F0102},{486, 0x00500102},{492, 0x00510102},{498, 0x00520102},{504, 0x00290101},
+{516, 0x002A0101},{528, 0x002B0101},{540, 0x002C0101},{552, 0x002D0101},{564, 0x002E0101},
+{576, 0x002F0101},{588, 0x00300101},{600, 0x00310101},{612, 0x00320101},{624, 0x00330101},
+{636, 0x00340101},{648, 0x00350101},{660, 0x00360101},{672, 0x00370101},{684, 0x00380101},
+{696, 0x00390101},{708, 0x003A0101},{720, 0x003B0101},{732, 0x003C0101},{744, 0x003D0101},
+{756, 0x003E0101},{768, 0x003F0101},{780, 0x00400101},{792, 0x00410101},{804, 0x00420101},
+{816, 0x00430101},{828, 0x00440101},{840, 0x00450101},{852, 0x00460101},{864, 0x00470101},
+{876, 0x00480101},{888, 0x00490101},{900, 0x004A0101},{912, 0x004B0101},{924, 0x004C0101},
+{936, 0x004D0101},{948, 0x004E0101},{960, 0x004F0101},{972, 0x00500101},{984, 0x00510101},
+{996, 0x00520101},{1008, 0x00290100},{1032, 0x002A0100},{1056, 0x002B0100},{1080, 0x002C0100},
+{1104, 0x002D0100},{1128, 0x002E0100},{1152, 0x002F0100},{1176, 0x00300100},{1200, 0x00310100},
+{1224, 0x00320100},{1248, 0x00330100},{1272, 0x00340100},{1296, 0x00350100},{1320, 0x00360100},
+{1344, 0x00370100},{1368, 0x00380100},{1392, 0x00390100},{1416, 0x003A0100},{1440, 0x003B0100},
+{1464, 0x003C0100},{1488, 0x003D0100},{1512, 0x003E0100},{1536, 0x003F0100},{1560, 0x00400100},
+{1584, 0x00410100},{1608, 0x00420100},{1632, 0x00430100},{1656, 0x00440100},{1680, 0x00450100},
+{1704, 0x00460100},{1728, 0x00470100},{1752, 0x00480100},{1776, 0x00490100},{1800, 0x004A0100},
+{1824, 0x004B0100},{1848, 0x004C0100},{1872, 0x004D0100},{1896, 0x004E0100},{1920, 0x004F0100},
+{1944, 0x00500100},{1968, 0x00510100},{1992, 0x00520100}//,2016, 0x00530100
+};
+
+//total 43+88+88+172 = 391
+struct pll_map pllmapAll[] = {
+{1008, 0x00290100},{504, 0x00290101},{252, 0x00290102},{126, 0x00290103},
+{1032, 0x002A0100},{516, 0x002A0101},{258, 0x002A0102},{129, 0x002A0103},
+{1056, 0x002B0100},{528, 0x002B0101},{264, 0x002B0102},{132, 0x002B0103},
+{1080, 0x002C0100},{540, 0x002C0101},{270, 0x002C0102},{135, 0x002C0103},
+{1104, 0x002D0100},{552, 0x002D0101},{276, 0x002D0102},{138, 0x002D0103},
+{1128, 0x002E0100},{564, 0x002E0101},{282, 0x002E0102},{141, 0x002E0103},
+{1152, 0x002F0100},{576, 0x002F0101},{288, 0x002F0102},{144, 0x002F0103},
+{1176, 0x00300100},{588, 0x00300101},{294, 0x00300102},{147, 0x00300103},
+{1200, 0x00310100},{600, 0x00310101},{300, 0x00310102},{150, 0x00310103},
+{1224, 0x00320100},{612, 0x00320101},{306, 0x00320102},{153, 0x00320103},
+{1248, 0x00330100},{624, 0x00330101},{312, 0x00330102},{156, 0x00330103},
+{1272, 0x00340100},{636, 0x00340101},{318, 0x00340102},{159, 0x00340103},
+{1296, 0x00350100},{648, 0x00350101},{324, 0x00350102},{162, 0x00350103},
+{1320, 0x00360100},{660, 0x00360101},{330, 0x00360102},{165, 0x00360103},
+{1344, 0x00370100},{672, 0x00370101},{336, 0x00370102},{168, 0x00370103},
+{1368, 0x00380100},{684, 0x00380101},{342, 0x00380102},{171, 0x00380103},
+{1392, 0x00390100},{696, 0x00390101},{348, 0x00390102},{174, 0x00390103},
+{1416, 0x003A0100},{708, 0x003A0101},{354, 0x003A0102},{177, 0x003A0103},
+{1440, 0x003B0100},{720, 0x003B0101},{360, 0x003B0102},{180, 0x003B0103},
+{1464, 0x003C0100},{732, 0x003C0101},{366, 0x003C0102},{183, 0x003C0103},
+{1488, 0x003D0100},{744, 0x003D0101},{372, 0x003D0102},{186, 0x003D0103},
+{1512, 0x003E0100},{756, 0x003E0101},{378, 0x003E0102},{189, 0x003E0103},
+{1536, 0x003F0100},{768, 0x003F0101},{384, 0x003F0102},{192, 0x003F0103},
+{1560, 0x00400100},{780, 0x00400101},{390, 0x00400102},{195, 0x00400103},
+{1584, 0x00410100},{792, 0x00410101},{396, 0x00410102},{198, 0x00410103},
+{1608, 0x00420100},{804, 0x00420101},{402, 0x00420102},{201, 0x00420103},
+{1632, 0x00430100},{816, 0x00430101},{408, 0x00430102},{204, 0x00430103},
+{1656, 0x00440100},{828, 0x00440101},{414, 0x00440102},{207, 0x00440103},
+{1680, 0x00450100},{840, 0x00450101},{420, 0x00450102},{210, 0x00450103},
+{1704, 0x00460100},{852, 0x00460101},{426, 0x00460102},{213, 0x00460103},
+{1728, 0x00470100},{864, 0x00470101},{432, 0x00470102},{216, 0x00470103},
+{1752, 0x00480100},{876, 0x00480101},{438, 0x00480102},{219, 0x00480103},
+{1776, 0x00490100},{888, 0x00490101},{444, 0x00490102},{222, 0x00490103},
+{1800, 0x004A0100},{900, 0x004A0101},{450, 0x004A0102},{225, 0x004A0103},
+{1824, 0x004B0100},{912, 0x004B0101},{456, 0x004B0102},{228, 0x004B0103},
+{1848, 0x004C0100},{924, 0x004C0101},{462, 0x004C0102},{231, 0x004C0103},
+{1872, 0x004D0100},{936, 0x004D0101},{468, 0x004D0102},{234, 0x004D0103},
+{1896, 0x004E0100},{948, 0x004E0101},{474, 0x004E0102},{237, 0x004E0103},
+{1920, 0x004F0100},{960, 0x004F0101},{480, 0x004F0102},{240, 0x004F0103},
+{1944, 0x00500100},{972, 0x00500101},{486, 0x00500102},{243, 0x00500103},
+{1968, 0x00510100},{984, 0x00510101},{492, 0x00510102},{246, 0x00510103},
+{1992, 0x00520100},{996, 0x00520101},{498, 0x00520102},{249, 0x00520103},
+{2016, 0x00530100},{1008, 0x00530101},{504, 0x00530102},{252, 0x00530103},
+
+
+{1008, 0x00140000}, {504, 0x00140001}, {252, 0x00140002}, {126, 0x00140003},
+{1056, 0x00150000}, {528, 0x00150001}, {264, 0x00150002}, {132, 0x00150003},
+{1104, 0x00160000}, {552, 0x00160001}, {276, 0x00160002}, {138, 0x00160003},
+{1152, 0x00170000}, {576, 0x00170001}, {288, 0x00170002}, {144, 0x00170003},
+{1200, 0x00180000}, {600, 0x00180001}, {300, 0x00180002}, {150, 0x00180003},
+{1248, 0x00190000}, {624, 0x00190001}, {312, 0x00190002}, {156, 0x00190003},
+{1296, 0x001A0000}, {648, 0x001A0001}, {324, 0x001A0002}, {162, 0x001A0003},
+{1344, 0x001B0000}, {672, 0x001B0001}, {336, 0x001B0002}, {168, 0x001B0003},
+{1392, 0x001C0000}, {696, 0x001C0001}, {348, 0x001C0002}, {174, 0x001C0003},
+{1440, 0x001D0000}, {720, 0x001D0001}, {360, 0x001D0002}, {180, 0x001D0003},
+{1488, 0x001E0000}, {744, 0x001E0001}, {372, 0x001E0002}, {186, 0x001E0003},
+{1536, 0x001F0000}, {768, 0x001F0001}, {384, 0x001F0002}, {192, 0x001F0003},
+{1584, 0x00200000}, {792, 0x00200001}, {396, 0x00200002}, {198, 0x00200003},
+{1632, 0x00210000}, {816, 0x00210001}, {408, 0x00210002}, {204, 0x00210003},
+{1680, 0x00220000}, {840, 0x00220001}, {420, 0x00220002}, {210, 0x00220003},
+{1728, 0x00230000}, {864, 0x00230001}, {432, 0x00230002}, {216, 0x00230003},
+{1776, 0x00240000}, {888, 0x00240001}, {444, 0x00240002}, {222, 0x00240003},
+{1824, 0x00250000}, {912, 0x00250001}, {456, 0x00250002}, {228, 0x00250003},
+{1872, 0x00260000}, {936, 0x00260001}, {468, 0x00260002}, {234, 0x00260003},
+{1920, 0x00270000}, {960, 0x00270001}, {480, 0x00270002}, {240, 0x00270003},
+{1968, 0x00280000}, {984, 0x00280001}, {492, 0x00280002}, {246, 0x00280003},
+{2016, 0x00290000}, {1008, 0x00290001}, {504, 0x00290002}, {252, 0x00290003},
+
+{144, 0x00020000},
+{192, 0x00030000},
+{240, 0x00040000},
+{288, 0x00050000}, {144, 0x00050001},
+{336, 0x00060000}, {168, 0x00060001},
+{384, 0x00070000}, {192, 0x00070001},
+{432, 0x00080000}, {216, 0x00080001},
+{480, 0x00090000}, {240, 0x00090001},
+{528, 0x000A0000}, {264, 0x000A0001}, {132, 0x000A0002},
+{576, 0x000B0000}, {288, 0x000B0001}, {144, 0x000B0002},
+{624, 0x000C0000}, {312, 0x000C0001}, {156, 0x000C0002},
+{672, 0x000D0000}, {336, 0x000D0001}, {168, 0x000D0002},
+{720, 0x000E0000}, {360, 0x000E0001}, {180, 0x000E0002},
+{768, 0x000F0000}, {384, 0x000F0001}, {192, 0x000F0002},
+{816, 0x00100000}, {408, 0x00100001}, {204, 0x00100002},
+{864, 0x00110000}, {432, 0x00110001}, {216, 0x00110002},
+{912, 0x00120000}, {456, 0x00120001}, {228, 0x00120002},
+{960, 0x00130000}, {480, 0x00130001}, {240, 0x00130002},
+
+{144, 0x00050100},
+{168, 0x00060100},
+{192, 0x00070100},
+{216, 0x00080100},
+{240, 0x00090100},
+{264, 0x000A0100}, {132, 0x000A0101},
+{288, 0x000B0100}, {144, 0x000B0101},
+{312, 0x000C0100}, {156, 0x000C0101},
+{336, 0x000D0100}, {168, 0x000D0101},
+{360, 0x000E0100}, {180, 0x000E0101},
+{384, 0x000F0100}, {192, 0x000F0101},
+{408, 0x00100100}, {204, 0x00100101},
+{432, 0x00110100}, {216, 0x00110101},
+{456, 0x00120100}, {228, 0x00120101},
+{480, 0x00130100}, {240, 0x00130101},
+{504, 0x00140100}, {252, 0x00140101}, {126, 0x00140102},
+{528, 0x00150100}, {264, 0x00150101}, {132, 0x00150102},
+{552, 0x00160100}, {276, 0x00160101}, {138, 0x00160102},
+{576, 0x00170100}, {288, 0x00170101}, {144, 0x00170102},
+{600, 0x00180100}, {300, 0x00180101}, {150, 0x00180102},
+{624, 0x00190100}, {312, 0x00190101}, {156, 0x00190102},
+{648, 0x001A0100}, {324, 0x001A0101}, {162, 0x001A0102},
+{672, 0x001B0100}, {336, 0x001B0101}, {168, 0x001B0102},
+{696, 0x001C0100}, {348, 0x001C0101}, {174, 0x001C0102},
+{720, 0x001D0100}, {360, 0x001D0101}, {180, 0x001D0102},
+{744, 0x001E0100}, {372, 0x001E0101}, {186, 0x001E0102},
+{768, 0x001F0100}, {384, 0x001F0101}, {192, 0x001F0102},
+{792, 0x00200100}, {396, 0x00200101}, {198, 0x00200102},
+{816, 0x00210100}, {408, 0x00210101}, {204, 0x00210102},
+{840, 0x00220100}, {420, 0x00220101}, {210, 0x00220102},
+{864, 0x00230100}, {432, 0x00230101}, {216, 0x00230102},
+{888, 0x00240100}, {444, 0x00240101}, {222, 0x00240102},
+{912, 0x00250100}, {456, 0x00250101}, {228, 0x00250102},
+{936, 0x00260100}, {468, 0x00260101}, {234, 0x00260102},
+{960, 0x00270100}, {480, 0x00270101}, {240, 0x00270102},
+{984, 0x00280100}, {492, 0x00280101}, {246, 0x00280102}
+};
+
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(a) (sizeof(a) / sizeof(a[0]))
+#endif
+#define MAXPLL 3515625*(1<<8)
+unsigned int tblpll = MAXPLL/1000000;
+unsigned int fr_rdn = 0;
+static DEFINE_SPINLOCK(wmt_clk_irqlock);
+unsigned long wmt_clk_irqlock_flags;
+
+void wmt_mc5_autotune(void)//gri
+{
+ unsigned int reg_val, reg_tmp;
+
+ MC_CLOCK_CTRL0_VAL = 0x0;
+ wmb();
+ MC_CLOCK_CTRL0_VAL = 0x80000000;
+ while(MC_CLOCK_CTRL0_VAL != 0xC0000000);
+ if ((MC_CONF_VAL & 0x3) == 0x2) {
+ //ddr3
+ reg_val = (MC_CLOCK_CTRL1_VAL & 0xffff8080);
+ reg_tmp = (0x7f0000 & reg_val);
+ reg_tmp |= ((0x7f0000 & reg_val) >> 8);
+ reg_tmp |= ((0x7f0000 & reg_val) >> 16);
+ reg_val |= reg_tmp;
+ MC_CLOCK_CTRL1_VAL = reg_val;
+ } else {
+ //lpddr2
+ reg_val = (MC_CLOCK_CTRL1_VAL & 0xffff0000);
+ reg_tmp = (0x7f000000 & reg_val);
+ reg_tmp |= ((0x7f000000 & reg_val) >> 16);
+ reg_tmp |= ((0x7f000000 & reg_val) >> 24);
+ reg_val |= reg_tmp;
+ MC_CLOCK_CTRL1_VAL = reg_val;
+ }
+}
+
+void wmt_clk_mutex_lock(int lock)
+{
+ if (lock) {
+ spin_lock_irqsave(&wmt_clk_irqlock, wmt_clk_irqlock_flags);
+ } else {
+ spin_unlock_irqrestore(&wmt_clk_irqlock, wmt_clk_irqlock_flags);
+ }
+}
+
+static void check_PLL_DIV_busy(void)
+{
+ while ((*(volatile unsigned int *)(PMC_BASE+0x18))&PLL_BUSY)
+ ;
+}
+
+#ifdef debug_clk
+static void print_refer_count(void)
+{
+ int i;
+ for (i = 0; i < 4; i++) {
+ printk("clk cnt %d ~ %d: %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",i*16,(i*16)+15,
+ dev_en_count[i*16],dev_en_count[i*16+1],dev_en_count[i*16+2],dev_en_count[i*16+3],dev_en_count[i*16+4],dev_en_count[i*16+5],dev_en_count[i*16+6],dev_en_count[i*16+7],
+ dev_en_count[i*16+8],dev_en_count[i*16+9],dev_en_count[i*16+10],dev_en_count[i*16+11],dev_en_count[i*16+12],dev_en_count[i*16+13],dev_en_count[i*16+14],dev_en_count[i*16+15]);
+ }
+}
+#endif
+#if 0
+static int disable_dev_clk(enum dev_id dev)
+{
+ int en_count;
+
+ if (dev >= 128) {
+ printk(KERN_INFO"device dev_id = %d > 128\n",dev);
+ return -1;
+ }
+
+ #ifdef debug_clk
+ print_refer_count();
+ #endif
+
+ en_count = dev_en_count[dev];
+
+ if (en_count <= 1) {
+ dev_en_count[dev] = en_count = 0;
+ *(volatile unsigned int *)(PMC_CLK + 4*(dev/32))
+ &= ~(1 << (dev - 32*(dev/32)));
+ *(volatile unsigned char *)(PMC_BASE + 0x604) = 0;
+ while((REG32_VAL((PMC_BASE + 0x604)) & 0xf5) != 0x00){};
+ *(volatile unsigned char *)(PMC_BASE + 0x62C) = 0;
+ while((REG32_VAL((PMC_BASE + 0x62C)) & 0xf5) != 0x00){};
+ /*printk(KERN_INFO" really disable clock\n");*/
+ } else if (en_count > 1) {
+ dev_en_count[dev] = (--en_count);
+ }
+
+ #ifdef debug_clk
+ print_refer_count();
+ #endif
+
+ return en_count;
+}
+#endif
+/*
+* ON : clock enable : 1, clock disable : 0
+*
+*/
+static int enable_dev_clk(enum dev_id dev, int ON)
+{
+ int en_count, tmp;
+
+ if (dev > 128) {
+ printk(KERN_INFO"device dev_id = %d > 128\n",dev);
+ return -1;
+ }
+
+ #ifdef debug_clk
+ printk(KERN_INFO"device dev_id = %d\n",dev);
+ print_refer_count();
+ #endif
+
+ //mutex_lock(&clk_cnt_lock);
+ wmt_clk_mutex_lock(1);
+ en_count = dev_en_count[dev];
+
+ if (ON) {
+ tmp = *(volatile unsigned int *)(PMC_CLK + 4*(dev/32));
+ if (en_count <= 0 || !(tmp&(1 << (dev - 32*(dev/32))))) {
+ dev_en_count[dev] = en_count = 1;
+ *(volatile unsigned int *)(PMC_CLK + 4*(dev/32))
+ |= 1 << (dev - 32*(dev/32));
+ /*if (dev == DEV_MSVD) {
+ *(volatile unsigned char *)(PMC_BASE + 0x604) = 1;
+ while((REG32_VAL((PMC_BASE + 0x604)) & 0xf5) != 0xf1){};
+ *(volatile unsigned char *)(PMC_BASE + 0x62C) = 1;
+ while((REG32_VAL((PMC_BASE + 0x62C)) & 0xf5) != 0xf1){};
+ }*/
+ /*printk(KERN_INFO" really enable clock\n");*/
+ } else
+ dev_en_count[dev] = (++en_count);
+ } else {
+ if (en_count <= 1) {
+ dev_en_count[dev] = en_count = 0;
+ *(volatile unsigned int *)(PMC_CLK + 4*(dev/32))
+ &= ~(1 << (dev - 32*(dev/32)));
+ /**(volatile unsigned char *)(PMC_BASE + 0x604) = 0;
+ while((REG32_VAL((PMC_BASE + 0x604)) & 0xf5) != 0x00){};
+ *(volatile unsigned char *)(PMC_BASE + 0x62C) = 0;
+ while((REG32_VAL((PMC_BASE + 0x62C)) & 0xf5) != 0x00){};*/
+ /*printk(KERN_INFO" really disable clock\n");*/
+ } else if (en_count > 1) {
+ dev_en_count[dev] = (--en_count);
+ }
+ }
+ //mutex_unlock(&clk_cnt_lock);
+ wmt_clk_mutex_lock(0);
+
+ #ifdef debug_clk
+ print_refer_count();
+ #endif
+
+ /* mmfreq */
+ if ((dev == MMFREQ_VD) && (mmfreq_num != ~0)) {
+ int cnt;
+ wmt_clk_mutex_lock(1);
+ cnt = dev_en_count[MMFREQ_VD];
+ wmt_clk_mutex_lock(0);
+ if (cnt == 0)
+ wmt_set_mmfreq(mmfreq_num);
+ }
+
+ return en_count;
+}
+/*
+* PLLA return 0, PLLB return 1,
+* PLLC return 2, PLLD return 3,
+* PLLE return 4, PLLF return 5,
+* PLLG return 6,
+* device not found return -1.
+* device has no divisor but has clock enable return -2.
+*/
+static int calc_pll_num(enum dev_id dev, int *div_offset)
+{
+ switch (dev) {
+ case DEV_UART0:
+ case DEV_UART1:
+ case DEV_UART2:
+ case DEV_UART3: /*case DEV_UART4: case DEV_UART5:*/
+ case DEV_AHBB:
+ case DEV_CIR:
+ case DEV_SYS: /* no use */
+ case DEV_RTC:
+ case DEV_UHDC:
+ case DEV_PERM: /* no use */
+ case DEV_PDMA: /* no use */
+ case DEV_VID:
+ *div_offset = 0;
+ return -2;
+ case DEV_SAE:
+ *div_offset = 0x348;
+ return 1;
+ case DEV_C24MOUT:
+ *div_offset = 0x3E4;
+ return 1;
+ case DEV_I2C0:
+ *div_offset = 0x3A0;
+ return 1;
+ case DEV_I2C1:
+ *div_offset = 0x3A4;
+ return 1;
+ case DEV_I2C2:
+ *div_offset = 0x3A8;
+ return 1;
+ case DEV_I2C3:
+ *div_offset = 0x3AC;
+ return 1;
+ case DEV_I2C4:
+ *div_offset = 0x39C;
+ return 1;
+ case DEV_PWM:
+ *div_offset = 0x350;
+ return 1;
+ case DEV_SPI0:
+ *div_offset = 0x340;
+ return 1;
+ case DEV_SPI1:
+ *div_offset = 0x344;
+ return 1;
+ case DEV_HDMILVDS:
+ case DEV_SDTV:
+ case DEV_HDMI:
+ *div_offset = 0x36C;
+ return 2;
+ case DEV_DVO:
+ case DEV_LVDS:
+ *div_offset = 0x370;
+ return 6;
+ case DEV_CSI0:
+ *div_offset = 0x380;
+ return 1;
+ case DEV_CSI1:
+ *div_offset = 0x384;
+ return 1;
+ case DEV_MALI:
+ *div_offset = 0x388;
+ return 1;
+ case DEV_DDRMC:
+ *div_offset = 0x310;
+ return 3;
+ case DEV_WMTNA:
+ *div_offset = 0x358;
+ return 3;
+ case DEV_CNMNA:
+ *div_offset = 0x360;
+ return 3;
+ case DEV_WMTVDU:
+ case DEV_JENC:
+ case DEV_HDCE:
+ case DEV_H264:
+ case DEV_JDEC:
+ case DEV_MSVD:
+ case DEV_AMP:
+ case DEV_VPU:
+ case DEV_MBOX:
+ *div_offset = 0x368;
+ return 3;
+ case DEV_CNMVDU:
+ case DEV_VP8DEC:
+ *div_offset = 0x38C;
+ return 3;
+ case DEV_NA12:
+ case DEV_VPP:
+ case DEV_GE:
+ case DEV_DISP:
+ case DEV_GOVRHD:
+ case DEV_SCL444U:
+ case DEV_GOVW:
+ *div_offset = 0x35C;
+ return 1;
+ case DEV_PAXI:
+ case DEV_DMA:
+ *div_offset = 0x354;
+ return 1;
+ case DEV_L2C:
+ *div_offset = 0x30C;
+ return 0;
+ case DEV_L2CAXI:
+ *div_offset = 0x3B0;
+ return 0;
+ case DEV_AT:
+ *div_offset = 0x3B4;
+ return 0;
+ case DEV_PERI:
+ *div_offset = 0x3B8;
+ return 0;
+ case DEV_TRACE:
+ *div_offset = 0x3BC;
+ return 0;
+ case DEV_L2CPAXI:
+ *div_offset = 0x3C0;
+ return 0;
+ case DEV_DBG:
+ *div_offset = 0x3D0;
+ return 0;
+ case DEV_NAND:
+ *div_offset = 0x318;
+ return 1;
+ /*case DEV_NOR:
+ *div_offset = 0x31C;
+ return 1;*/
+ case DEV_SDMMC0:
+ *div_offset = 0x330;
+ return 1;
+ case DEV_SDMMC1:
+ *div_offset = 0x334;
+ return 1;
+ case DEV_SDMMC2:
+ *div_offset = 0x338;
+ return 1;
+ /*case DEV_SDMMC3:
+ *div_offset = 0x33C;
+ return 1;*/
+ case DEV_ADC:
+ *div_offset = 0x394;
+ return 1;
+ case DEV_HDMII2C: /* div 1~63 */
+ *div_offset = 0x390;
+ return 4;
+ case DEV_SF:
+ *div_offset = 0x314;
+ return 1;
+ case DEV_PCM0:
+ *div_offset = 0x324;
+ return 1;
+ case DEV_PCM1:
+ *div_offset = 0x328;
+ return 1;
+ case DEV_I2S:
+ case DEV_ARF:
+ case DEV_ARFP:
+ *div_offset = 0x374;
+ return 4;
+ case DEV_ARM:
+ *div_offset = 0x300;
+ return 0;
+ case DEV_AHB:
+ *div_offset = 0x304;
+ return 1;
+ case DEV_APB:
+ case DEV_SCC:
+ case DEV_GPIO:
+ *div_offset = 0x320;
+ return 1;
+ /*case DEV_ETHPHY:
+ *div_offset = 25;
+ return -2;*/
+ default:
+ return -1;
+ }
+}
+
+
+/* if the clk of the dev is not enable, then enable it or fail */
+int check_clk_enabled(enum dev_id dev, enum clk_cmd cmd) {
+ unsigned int pmc_clk_en;
+ if (dev < 128) {
+ pmc_clk_en = *(volatile unsigned int *)(PMC_CLK + 4*(dev/32));
+ if (!(pmc_clk_en & (1 << (dev - 32*(dev/32))))) {
+ if (dev == DEV_ARM)
+ return 0;
+ /*enable_dev_clk(dev);*/
+ printk(KERN_INFO"dev[%d] clock disabled\n", dev);
+ return -1;
+ }
+ }
+ return 0;
+}
+#if 0
+static int get_freq(enum dev_id dev, int *divisor) {
+
+ unsigned int div = 0, freq;
+ int PLL_NO, j = 0, div_addr_offs;
+ unsigned long long freq_llu, base = 1000000, tmp, mod;
+
+ PLL_NO = calc_pll_num(dev, &div_addr_offs);
+ if (PLL_NO == -1) {
+ printk(KERN_INFO"device not found");
+ return -1;
+ }
+
+ if (PLL_NO == -2)
+ return div_addr_offs*1000000;
+
+ *(volatile unsigned char *)(PMC_BASE + div_addr_offs + 2) = (dev == DEV_SDTV) ? 1 : 0;
+
+ check_PLL_DIV_busy();
+
+ div = *divisor = *(volatile unsigned char *)(PMC_BASE + div_addr_offs);
+ //printk(KERN_INFO"div_addr_offs=0x%x PLL_NO=%d PMC_PLL=0x%x\n", div_addr_offs, PLL_NO, PMC_PLL);
+ tmp = *(volatile unsigned int *)(PMC_PLL + 4*PLL_NO);
+
+ if ((dev != DEV_SDMMC0) && (dev != DEV_SDMMC1) && (dev != DEV_SDMMC2)) {
+ div = div&0x1F;
+ } else {
+ if (div & (1<<5))
+ j = 1;
+ div &= 0x1F;
+ div = div*(j?64:1)*2;
+ }
+
+ freq_llu = (SRC_FREQ*GET_DIVF(tmp)) * base;
+ //printk(KERN_INFO" freq_llu =%llu\n", freq_llu);
+ tmp = GET_DIVR(tmp) * GET_DIVQ(tmp) * div;
+ mod = do_div(freq_llu, tmp);
+ freq = (unsigned int)freq_llu;
+ //printk("get_freq cmd: freq=%d freq(unsigned long long)=%llu div=%llu mod=%llu\n", freq, freq_llu, tmp, mod);
+
+ return freq;
+}
+#endif
+extern unsigned int wmt_read_oscr(void);
+static int get_freq_t(enum dev_id dev, int *divisor) {
+
+ unsigned int div = 0, freq = 0, div_ahb = 1;
+ int PLL_NO, i, j = 0, div_addr_offs;
+ unsigned long long freq_llu = 0, base = 1000000, tmp, mod;
+ #ifdef DEBUG_CLK
+ unsigned int t1 = 0, t2 = 0;
+ #endif
+
+ if (dev == DEV_APB) {
+ PLL_NO = calc_pll_num(DEV_AHB, &div_addr_offs);
+ if (PLL_NO < 0) {
+ printk(KERN_INFO"device not found");
+ return -1;
+ }
+ div_ahb = *(volatile unsigned char *)(PMC_BASE + div_addr_offs);
+ }
+
+ PLL_NO = calc_pll_num(dev, &div_addr_offs);
+ if (PLL_NO == -1) {
+ printk(KERN_INFO"device not found");
+ return -1;
+ }
+
+ if (PLL_NO == -2)
+ return div_addr_offs*1000000;
+
+ *(volatile unsigned char *)(PMC_BASE + div_addr_offs + 2) = (dev == DEV_SDTV) ? 1 : 0;
+
+ check_PLL_DIV_busy();
+
+ div = *divisor = *(volatile unsigned char *)(PMC_BASE + div_addr_offs);
+
+ if ((dev != DEV_SDMMC0) && (dev != DEV_SDMMC1) && (dev != DEV_SDMMC2)) {
+ div = div&0x1F;
+ } else {
+ if (div & (1<<5))
+ j = 1;
+ div &= 0x1F;
+ div = div*(j?64:1)*2;
+ }
+
+ #ifdef DEBUG_CLK
+ printk(KERN_INFO"div_addr_offs=0x%x PLL_NO=%d PMC_PLL=0x%x\n", div_addr_offs, PLL_NO, PMC_PLL);
+ t1 = wmt_read_oscr();
+ #endif
+ //mutex_lock(&clk_cnt_lock);
+ tmp = *(volatile unsigned int *)(PMC_PLL + 4*PLL_NO);
+ //mutex_unlock(&clk_cnt_lock);
+ for (i = 0; i < ARRAYSIZE(pllmapAll); i++) {
+ if (pllmapAll[i].pll == tmp) {
+ freq = pllmapAll[i].freq;
+ #ifdef DEBUG_CLK
+ printk("********dev%d---PLL_NO=%X---get freq=%d set0x%x\n", dev, PLL_NO+10, freq, pllmapAll[i].pll);
+ #endif
+ break;
+ }
+ }
+ if (i >= ARRAYSIZE(pllmapAll) || freq == 0) {
+ printk(KERN_INFO"gfreq : dev%d********************pll not match table**************\n", dev);
+ freq_llu = (SRC_FREQ*GET_DIVF(tmp)) * base;
+ //printk(KERN_INFO" freq_llu =%llu\n", freq_llu);
+ tmp = GET_DIVR(tmp) * GET_DIVQ(tmp) * div * div_ahb;
+ mod = do_div(freq_llu, tmp);
+ freq = (unsigned int)freq_llu;
+ } else {
+ freq = (freq * 15625)<<6;
+ freq = freq/(div*div_ahb);
+ }
+
+ #ifdef DEBUG_CLK
+ t2 = wmt_read_oscr() - t1;
+ printk("************delay_time=%d\n", t2);
+ printk("get_freq cmd: freq=%d freq(unsigned long long)=%llu div=%llu mod=%llu\n",
+ freq, freq_llu, tmp, mod);
+ #endif
+
+ #ifdef DEBUG_PLLA
+ if (dev == DEV_ARM && fr_rdn > (tblpll*1000000))
+ return fr_rdn;
+ #endif
+
+ return freq;
+}
+#if 0
+static int set_divisor(enum dev_id dev, int unit, int freq, int *divisor) {
+
+ unsigned int div = 0, tmp;
+ int PLL_NO, i, j = 0, div_addr_offs, SD_MMC = 1, ret;
+ unsigned long long base = 1000000, PLL, PLL_tmp, mod, div_llu, freq_target = freq, mini,tmp1;
+ if ((dev != DEV_SDMMC0) && (dev != DEV_SDMMC1) && (dev != DEV_SDMMC2))
+ SD_MMC = 0;
+
+ PLL_NO = calc_pll_num(dev, &div_addr_offs);
+ if (PLL_NO == -1) {
+ printk(KERN_INFO"device not found");
+ return -1;
+ }
+
+ if (PLL_NO == -2) {
+ printk(KERN_INFO"device has no divisor");
+ return -1;
+ }
+
+ *(volatile unsigned char *)(PMC_BASE + div_addr_offs + 2) = (dev == DEV_SDTV) ? 1 : 0;
+
+ check_PLL_DIV_busy();
+
+ tmp = *(volatile unsigned int *)(PMC_PLL + 4*PLL_NO);
+ PLL = SRC_FREQ*GET_DIVF(tmp)*base;
+ //printk(KERN_INFO" PLL =%llu, dev_id=%d, PLL_NO=%d, PMC_PLL=0x%x, tmp = 0x%x\n", PLL, dev, PLL_NO,PMC_PLL,(unsigned int)&tmp);
+ div_llu = GET_DIVR(tmp)*GET_DIVQ(tmp);
+
+ ret = check_clk_enabled(dev, SET_DIV);
+ if (ret)
+ return -1;
+
+ if (unit == 1)
+ freq_target *= 1000;
+ else if (unit == 2)
+ freq_target *= 1000000;
+
+ if (SD_MMC == 0) {
+ for (i = 1; i < 33; i++) {
+ if ((i > 1 && (i%2)) && (PLL_NO == 2))
+ continue;
+ PLL_tmp = PLL;
+ mod = do_div(PLL_tmp, div_llu*i);
+ if (PLL_tmp <= freq_target) {
+ *divisor = div = i;
+ break;
+ }
+ }
+ } else {
+ mini = freq_target;
+ tmp1 = PLL;
+ do_div(tmp1, div_llu);
+ do_div(tmp1, 64);
+ if ((tmp1) >= freq_target)
+ j = 1;
+ for (i = 1; i < 33; i++) {
+ PLL_tmp = PLL;
+ mod = do_div(PLL_tmp, div_llu*(i*(j?64:1)*2));
+ if (PLL_tmp <= freq_target) {
+ *divisor = div = i;
+ break;
+ }
+ }
+ }
+ if (div != 0 && div < 33) {
+ check_PLL_DIV_busy();
+ if (dev == DEV_WMTNA)
+ *(volatile unsigned int *)(PMC_BASE + div_addr_offs) = (0x200 | ((div == 32) ? 0 : div));
+ else
+ *(volatile unsigned int *)(PMC_BASE + div_addr_offs)
+ = ((dev == DEV_SDTV)?0x10000:0) + (j?32:0) + ((div == 32) ? 0 : div);
+ check_PLL_DIV_busy();
+ freq = (unsigned int)PLL_tmp;
+ /*printk("set_divisor: freq=%d freq(unsigned long long)=%llu div=%llu mod=%llu divisor%d pmc_pll=0x%x\n",
+ freq, PLL_tmp, div_llu, mod, *divisor, tmp);*/
+ return freq;
+ }
+ printk(KERN_INFO"no suitable divisor");
+ return -1;
+}
+#endif
+static int set_divisor_t(enum dev_id dev, int unit, int freq, int *divisor) {
+
+ unsigned int div = 0, tmp;
+ int /*ret,*/ PLL_NO, i, j = 1, div_addr_offs, SD_MMC = 1;
+ unsigned int PLL = 0, freq_target = freq;
+ if ((dev != DEV_SDMMC0) && (dev != DEV_SDMMC1) && (dev != DEV_SDMMC2))
+ SD_MMC = 0;
+
+ PLL_NO = calc_pll_num(dev, &div_addr_offs);
+ if (PLL_NO == -1) {
+ printk(KERN_INFO"device not found");
+ return -1;
+ } else if (PLL_NO == -2) {
+ printk(KERN_INFO"device has no divisor");
+ return -1;
+ }
+
+ *(volatile unsigned char *)(PMC_BASE + div_addr_offs + 2) = (dev == DEV_SDTV) ? 1 : 0;
+
+ check_PLL_DIV_busy();
+ tmp = *(volatile unsigned int *)(PMC_PLL + 4*PLL_NO);
+
+ /*ret = check_clk_enabled(dev, SET_DIV);
+ if (ret)
+ return -1;*/
+
+ if (unit == 1)
+ freq_target *= 1000;
+ else if (unit == 2)
+ freq_target *= 1000000;
+
+ for (i = 0; i < ARRAYSIZE(pllmapAll); i++) {
+ if (pllmapAll[i].pll == tmp) {
+ PLL = pllmapAll[i].freq;
+ break;
+ }
+ }
+ if (i >= ARRAYSIZE(pllmapAll) || PLL == 0) {
+ printk(KERN_INFO"set div : dev%d********************pll not match table**************\n", dev);
+ PLL = (SRC_FREQ/GET_DIVQ(tmp)) * (GET_DIVF(tmp)/GET_DIVR(tmp));
+ }
+ PLL = (PLL * 15625)<<6;
+
+ if (SD_MMC == 0) {
+ for (i = 1; i < 64; i++) {
+ if ((i > 1 && (i%2)) && (PLL_NO == 2))
+ continue;
+ freq = PLL/i;
+ if (freq <= freq_target) {
+ *divisor = div = i;
+ break;
+ }
+ }
+ } else {
+ if ((PLL>>6) >= freq_target)
+ j = 1<<6;
+ for (i = 1; i < 64; i++) {
+ freq = PLL/(i*j);
+ if (freq <= freq_target) {
+ *divisor = div = i;
+ break;
+ }
+ }
+ }
+ if (div > 32)
+ div = 32;
+
+ if (div != 0 && div < 33) {
+ //mutex_lock(&clk_cnt_lock);
+ check_PLL_DIV_busy();
+ if (dev == DEV_WMTNA)
+ *(volatile unsigned int *)(PMC_BASE + div_addr_offs) = (0x200 | ((div == 32) ? 0 : div));
+ else
+ *(volatile unsigned int *)(PMC_BASE + div_addr_offs)
+ = ((dev == DEV_SDTV)?0x10000:0) + (j==64?32:0) + ((div == 32) ? 0 : div);
+ #ifdef DEBUG_CLK
+ printk("SETDIV********dev%d PLL_%X PLL=0x%x div%d cal_freq=%d target_freq%d\n",
+ dev, PLL_NO+10, PLL, div, freq, freq_target);
+ #endif
+ check_PLL_DIV_busy();
+ //mutex_unlock(&clk_cnt_lock);
+ return freq;
+ }
+ printk(KERN_INFO"no suitable divisor\n");
+ return -1;
+}
+#if 0
+static int set_pll_speed(enum dev_id dev, int unit, int freq, int *divisor, int wait) {
+
+ unsigned int PLL, DIVF=1, DIVR=1, DIVQ=1;
+ unsigned int last_freq, div=1;
+ unsigned long long minor, min_minor = 0xFF000000;
+ int PLL_NO, div_addr_offs, DF, DR, VD, DQ;
+ unsigned long long base = 1000000, base_f = 1, PLL_llu, div_llu, freq_llu, mod;
+ PLL_NO = calc_pll_num(dev, &div_addr_offs);
+ if (PLL_NO == -1) {
+ printk(KERN_INFO"device not belong to PLL A B C D E");
+ return -1;
+ }
+
+ if (PLL_NO == -2) {
+ printk(KERN_INFO"device has no divisor");
+ return -1;
+ }
+
+ *(volatile unsigned char *)(PMC_BASE + div_addr_offs + 2) = (dev == DEV_SDTV) ? 1 : 0;
+
+ check_PLL_DIV_busy();
+ VD = *divisor = *(volatile unsigned char *)(PMC_BASE + div_addr_offs);
+
+ if (unit == 1)
+ base_f = 1000;
+ else if (unit == 2)
+ base_f = 1000000;
+ else if (unit != 0) {
+ printk(KERN_INFO"unit is out of range");
+ return -1;
+ }
+ freq_llu = freq * base_f;
+ for (DR = MAX_DR; DR >= 0; DR--) {
+ for (DQ = MAX_DQ; DQ >= 0; DQ--) {
+ for (DF = 0; DF <= MAX_DF; DF++) {
+ if (SRC_FREQ/(DR+1) < 10)
+ break;
+ if ((1000/SRC_FREQ) > ((2*(DF+1))/(DR+1)))
+ continue;
+ if ((2000/SRC_FREQ) < ((2*(DF+1))/(DR+1)))
+ break;
+ PLL_llu = (unsigned long long)(SRC_FREQ * 2 * (DF+1) * base);
+ div_llu = (unsigned long long)(VD * (DR+1)*(1<<DQ));
+ mod = do_div(PLL_llu, div_llu);
+ if (PLL_llu == freq_llu) {
+ DIVF = DF;
+ DIVR = DR;
+ DIVQ = DQ;
+ div = VD;
+ /*printk(KERN_INFO"find the equal value");*/
+ goto find;
+ } else if (PLL_llu < freq_llu) {
+ minor = freq_llu - PLL_llu;
+ //printk(KERN_INFO"minor=0x%x, min_minor=0x%x", minor, min_minor);
+ if (minor < min_minor) {
+ DIVF = DF;
+ DIVR = DR;
+ DIVQ = DQ;
+ div = VD;
+ min_minor = minor;
+ }
+ } else if (PLL_llu > freq_llu) {
+ if (PLL_NO == 2) {
+ minor = PLL_llu - freq_llu;
+ if (minor < min_minor) {
+ DIVF = DF;
+ DIVR = DR;
+ DIVQ = DQ;
+ div = VD;
+ min_minor = minor;
+ }
+ }
+ break;
+ }
+ }//DF
+ }//DQ
+ }//DR
+/*minimun:*/
+ //printk(KERN_INFO"minimum minor=0x%x, unit=%d \n", (unsigned int)min_minor, unit);
+find:
+
+ PLL_llu = (unsigned long long)(SRC_FREQ * 2 * (DIVF+1) * base);
+ div_llu = (unsigned long long)((DIVR+1)*(1<<DIVQ)*(*divisor));
+ mod = do_div(PLL_llu, div_llu);
+ last_freq = (unsigned int)PLL_llu;
+ /*printk("set_pll cmd: freq=%d freq(unsigned long long)=%llu div=%llu mod=%llu\n", last_freq, PLL_llu, div_llu, mod);
+ printk(KERN_INFO"DIVF%d, DIVR%d, DIVQ%d, divisor%d freq=%dHz \n",
+ DIVF, DIVR, DIVQ, *divisor, last_freq);*/
+ PLL = (DIVF<<16) + (DIVR<<8) + DIVQ;
+
+ /* if the clk of the device is not enable, then enable it */
+ /*if (dev < 128) {
+ pmc_clk_en = *(volatile unsigned int *)(PMC_CLK + 4*(dev/32));
+ if (!(pmc_clk_en & (1 << (dev - 32*(dev/32)))))
+ enable_dev_clk(dev);
+ }*/
+
+ check_PLL_DIV_busy();
+ /*printk(KERN_INFO"PLL0x%x, pll addr =0x%x\n", PLL, PMC_PLL + 4*PLL_NO);*/
+ *(volatile unsigned int *)(PMC_PLL + 4*PLL_NO) = PLL;
+ if (wait)
+ check_PLL_DIV_busy();
+ return last_freq;
+
+ printk(KERN_INFO"no suitable pll");
+ return -1;
+}
+#endif
+static int set_pll_speed_t(enum dev_id dev, int unit, int freq, int *divisor, int wait) {
+
+ unsigned int PLL, VD;
+ unsigned int minor, min_minor = 0x7F000000, set_freq = 0;
+ int PLL_NO, div_addr_offs, i;
+ unsigned int tmp_freq, tmp_PLL = 0;
+ PLL_NO = calc_pll_num(dev, &div_addr_offs);
+ if (PLL_NO == -1) {
+ printk(KERN_INFO"device not belong to PLL A B C D E");
+ return -1;
+ }
+
+ if (PLL_NO == -2) {
+ printk(KERN_INFO"device has no divisor");
+ return -1;
+ }
+
+ *(volatile unsigned char *)(PMC_BASE + div_addr_offs + 2) = (dev == DEV_SDTV) ? 1 : 0;
+
+ check_PLL_DIV_busy();
+ VD = *divisor = *(volatile unsigned char *)(PMC_BASE + div_addr_offs);
+
+ if (unit == 1)
+ freq *= 1000;
+ else if (unit == 2)
+ freq *= 1000000;
+ else if (unit != 0) {
+ printk(KERN_INFO"unit is out of range");
+ return -1;
+ }
+
+ for (i = 0; i < ARRAYSIZE(pllmap); i++) {
+ if (pllmap[i].freq > 1150 && PLL_NO == 4)
+ continue;
+ if (pllmap[i].freq > 1250 && ((PLL_NO == 2) || (PLL_NO == 6)))
+ continue;
+ tmp_freq = ((pllmap[i].freq*15625)<<6) / VD;
+ if (tmp_freq == freq) {
+ tmp_PLL = pllmap[i].pll;
+ set_freq = tmp_freq;
+ min_minor = 0;
+ goto find;
+ } else if (tmp_freq < freq) {
+ minor = freq - tmp_freq;
+ if (minor < min_minor) {
+ tmp_PLL = pllmap[i].pll;
+ set_freq = tmp_freq;
+ min_minor = minor;
+ }
+ } else if (tmp_freq > freq) {
+ if (PLL_NO == 2) {
+ minor = tmp_freq - freq;
+ if (minor < min_minor) {
+ tmp_PLL = pllmap[i].pll;
+ set_freq = tmp_freq;
+ min_minor = minor;
+ }
+ }
+ break;
+ }
+ }
+find:
+ #ifdef DEBUG_CLK
+ if (min_minor)
+ printk(KERN_INFO"minimum minor=0x%x, unit=%d \n", (unsigned int)min_minor, unit);
+ printk("SETPLL********dev%d PLL_%X PLL=0x%x div%d cal_freq=%d target_freq%d\n",
+ dev, PLL_NO+10, tmp_PLL, div, set_freq, freq);
+ #endif
+ PLL = tmp_PLL;
+
+ //mutex_lock(&clk_cnt_lock);
+ check_PLL_DIV_busy();
+ *(volatile unsigned int *)(PMC_PLL + 4*PLL_NO) = PLL;
+ if (wait)
+ check_PLL_DIV_busy();
+ //mutex_unlock(&clk_cnt_lock);
+
+ return set_freq;
+}
+#if 0
+static int set_pll_divisor(enum dev_id dev, int unit, int freq, int *divisor) {
+
+ unsigned int PLL, DIVF=1, DIVR=1, DIVQ=1, pmc_clk_en, old_divisor;
+ unsigned int last_freq, div=1;
+ unsigned long long minor, min_minor = 0xFF000000;
+ int PLL_NO, div_addr_offs, DF, DR, VD, DQ;
+ unsigned long long base = 1000000, base_f = 1, PLL_llu, div_llu, freq_llu, mod;
+ PLL_NO = calc_pll_num(dev, &div_addr_offs);
+ if (PLL_NO == -1) {
+ printk(KERN_INFO"device not belong to PLL A B C D E");
+ return -1;
+ }
+
+ if (PLL_NO == -2) {
+ printk(KERN_INFO"device has no divisor");
+ return -1;
+ }
+
+ *(volatile unsigned char *)(PMC_BASE + div_addr_offs + 2) = (dev == DEV_SDTV) ? 1 : 0;
+
+ check_PLL_DIV_busy();
+
+ old_divisor = *(volatile unsigned char *)(PMC_BASE + div_addr_offs);
+
+ if (unit == 1)
+ base_f = 1000;
+ else if (unit == 2)
+ base_f = 1000000;
+ else if (unit != 0) {
+ printk(KERN_INFO"unit is out of range");
+ return -1;
+ }
+//printk(KERN_INFO"target freq=%d unit=%d PLL_NO=%d\n", freq, unit, PLL_NO);
+ freq_llu = freq * base_f;
+ //tmp = div * freq;
+ for (DR = MAX_DR; DR >= 0; DR--) {
+ for (DQ = MAX_DQ; DQ >= 0; DQ--) {
+ for (VD = 32; VD >= 1; VD--) {
+ if ((VD > 1 && (VD%2)) && ((PLL_NO == 2) || (PLL_NO == 6)))
+ continue;
+ for (DF = 0; DF <= MAX_DF; DF++) {
+ if (SRC_FREQ/(DR+1) < 10)
+ break;
+ if ((1000/SRC_FREQ) > ((2*(DF+1))/(DR+1)))
+ continue;
+ if ((2000/SRC_FREQ) < ((2*(DF+1))/(DR+1)))
+ break;
+ PLL_llu = (unsigned long long)(SRC_FREQ * 2 * (DF+1) * base);
+ div_llu = (unsigned long long)(VD * (DR+1)*(1<<DQ));
+ mod = do_div(PLL_llu, div_llu);
+ if (PLL_llu == freq_llu) {
+ DIVF = DF;
+ DIVR = DR;
+ DIVQ = DQ;
+ div = VD;
+ /*printk(KERN_INFO"find the equal value");*/
+ goto find;
+ } else if ((PLL_llu < freq_llu) /*&& (dev != DEV_I2S)*/) {
+ minor = freq_llu - PLL_llu;
+ //printk(KERN_INFO"minor=0x%x, min_minor=0x%x", minor, min_minor);
+ if (minor < min_minor) {
+ DIVF = DF;
+ DIVR = DR;
+ DIVQ = DQ;
+ div = VD;
+ min_minor = minor;
+ /*printk(KERN_INFO"< target :DIVF%d, DIVR%d, DIVQ%d, divisor%d min_minor=%lluHz \n",
+ DIVF, DIVR, DIVQ, div, min_minor);*/
+ }
+ } else if (PLL_llu > freq_llu) {
+ if ((PLL_NO == 2) || (PLL_NO == 6)) {
+ minor = PLL_llu - freq_llu;
+ if (minor < min_minor) {
+ DIVF = DF;
+ DIVR = DR;
+ DIVQ = DQ;
+ div = VD;
+ min_minor = minor;
+ /*printk(KERN_INFO" > target DIVF%d, DIVR%d, DIVQ%d, divisor%d min_minor=%lluHz \n",
+ DIVF, DIVR, DIVQ, div, min_minor);*/
+ }
+ }
+ break;
+ }
+ }//DF
+ }//VD
+ }//DQ
+ }//DR
+/*minimun:*/
+ //printk(KERN_INFO"minimum minor=%llu, unit=%d \n", min_minor, unit);
+find:
+
+ *divisor = div;
+
+ PLL_llu = (unsigned long long)(SRC_FREQ * 2 * (DIVF+1) * base);
+ div_llu = (unsigned long long)((DIVR+1)*(1<<DIVQ)*(*divisor));
+ mod = do_div(PLL_llu, div_llu);
+ last_freq = (unsigned int)PLL_llu;
+ /*printk("set_pll_divisor cmd: freq=%d freq(unsigned long long)=%llu div=%llu mod=%llu\n", last_freq, PLL_llu, div_llu, mod);
+ printk(KERN_INFO"DIVF%d, DIVR%d, DIVQ%d, divisor%d freq=%dHz \n",
+ DIVF, DIVR, DIVQ, *divisor, last_freq);*/
+ PLL = (DIVF<<16) + (DIVR<<8) + DIVQ;
+
+ /* if the clk of the device is not enable, then enable it */
+ if (dev < 128) {
+ pmc_clk_en = *(volatile unsigned int *)(PMC_CLK + 4*(dev/32));
+ if (!(pmc_clk_en & (1 << (dev - 32*(dev/32)))) && dev != DEV_ARM) {
+ /*enable_dev_clk(dev);*/
+ printk(KERN_INFO"device clock is disabled");
+ return -1;
+ }
+ }
+
+ check_PLL_DIV_busy();
+ if (old_divisor < *divisor) {
+ if (dev == DEV_WMTNA)
+ *(volatile unsigned int *)(PMC_BASE + div_addr_offs) = (0x200 | ((div == 32) ? 0 : div));
+ else
+ *(volatile unsigned int *)(PMC_BASE + div_addr_offs)
+ = ((dev == DEV_SDTV)?0x10000:0) +/*(j?32:0) + */((div == 32) ? 0 : div)/* + (div&1) ? (1<<8): 0*/;
+ check_PLL_DIV_busy();
+ }
+ //printk(KERN_INFO"PLL0x%x, pll addr =0x%x\n", PLL, PMC_PLL + 4*PLL_NO);
+ *(volatile unsigned int *)(PMC_PLL + 4*PLL_NO) = PLL;
+ check_PLL_DIV_busy();
+ /*printk(KERN_INFO"DIVF%d, DIVR%d, DIVQ%d, div%d div_addr_offs=0x%x\n",
+ DIVF, DIVR, DIVQ, div, div_addr_offs);*/
+
+ if (old_divisor > *divisor) {
+ if (dev == DEV_WMTNA)
+ *(volatile unsigned int *)(PMC_BASE + div_addr_offs) = (0x200 | ((div == 32) ? 0 : div));
+ else
+ *(volatile unsigned int *)(PMC_BASE + div_addr_offs)
+ = ((dev == DEV_SDTV)?0x10000:0) +/*(j?32:0) + */((div == 32) ? 0 : div)/* + (div&1) ? (1<<8): 0*/;
+ check_PLL_DIV_busy();
+ }
+
+
+ /*ddv = *(volatile unsigned int *)(PMC_BASE + div_addr_offs);
+ check_PLL_DIV_busy();
+ pllx = *(volatile unsigned int *)(PMC_PLL + 4*PLL_NO);
+ printk(KERN_INFO"read divisor=%d, pll=0x%x from register\n", 0x1F&ddv, pllx);*/
+ return last_freq;
+
+ /*printk(KERN_INFO"no suitable divisor");
+ return -1;*/
+}
+#endif
+
+static int set_pll_divisor_t(enum dev_id dev, int unit, int freq, int *divisor) {
+
+ unsigned int PLL, old_divisor, div=1, set_freq = 0;
+ unsigned int minor, min_minor = 0x7F000000, tmp_freq = 0, tmp_PLL = 0, tfreq = (unsigned int)freq;
+ int i, PLL_NO, div_addr_offs, VD/*, ret*/;
+
+ PLL_NO = calc_pll_num(dev, &div_addr_offs);
+ if (PLL_NO == -1) {
+ printk(KERN_INFO"device not belong to PLL A B C D E");
+ return -1;
+ } else if (PLL_NO == -2) {
+ printk(KERN_INFO"device has no divisor");
+ return -1;
+ }
+
+ *(volatile unsigned char *)(PMC_BASE + div_addr_offs + 2) = (dev == DEV_SDTV) ? 1 : 0;
+
+ check_PLL_DIV_busy();
+ old_divisor = *(volatile unsigned char *)(PMC_BASE + div_addr_offs);
+
+ if (unit == 1)
+ tfreq *= 1000;
+ else if (unit == 2)
+ tfreq *= 1000000;
+ else if (unit != 0) {
+ printk(KERN_INFO"unit is out of range");
+ return -1;
+ }
+
+ for (i = 0; i < ARRAYSIZE(pllmap); i++) {
+ if (pllmap[i].freq > 1150 && PLL_NO == 4)
+ continue;
+ if (pllmap[i].freq > 1250 && ((PLL_NO == 2) || (PLL_NO == 6)))
+ continue;
+ for (VD = 32; VD >= 1; VD--) {
+ if ((VD > 1 && (VD == 3)) && ((PLL_NO == 2) || (PLL_NO == 6)))
+ continue;
+ tmp_freq = ((pllmap[i].freq*15625)<<6) / VD;
+ if (tmp_freq == tfreq) {
+ tmp_PLL = pllmap[i].pll;
+ set_freq = tmp_freq;
+ div = VD;
+ min_minor = 0;
+ goto find;
+ } else if (tmp_freq < tfreq) {
+ minor = tfreq - tmp_freq;
+ if (minor < min_minor) {
+ tmp_PLL = pllmap[i].pll;
+ set_freq = tmp_freq;
+ div = VD;
+ min_minor = minor;
+ }
+ } else if (tmp_freq > tfreq) {
+ if ((PLL_NO == 2) || (PLL_NO == 6)) {
+ minor = tmp_freq - tfreq;
+ if (minor < min_minor) {
+ tmp_PLL = pllmap[i].pll;
+ set_freq = tmp_freq;
+ div = VD;
+ min_minor = minor;
+ }
+ }
+ break;
+ }
+ }
+ }
+find:
+ #ifdef DEBUG_CLK
+ if (min_minor)
+ printk(KERN_INFO"minimum minor=0x%x, unit=%d \n", (unsigned int)min_minor, unit);
+ printk("SETPLLDIV********dev%d PLL_%X PLL=0x%x div%d cal_freq=%d target_freq%d\n",
+ dev, PLL_NO+10, tmp_PLL, div, set_freq, tfreq);
+ #endif
+
+ *divisor = div;
+ PLL = tmp_PLL;
+
+ /*ret = check_clk_enabled(dev, SET_PLLDIV);
+ if (ret)
+ return -1;*/
+
+ //mutex_lock(&clk_cnt_lock);
+ wmt_clk_mutex_lock(1);
+ check_PLL_DIV_busy();
+ if (old_divisor < *divisor) {
+ if (dev == DEV_WMTNA)
+ *(volatile unsigned int *)(PMC_BASE + div_addr_offs) = (0x200 | ((div == 32) ? 0 : div));
+ else
+ *(volatile unsigned int *)(PMC_BASE + div_addr_offs)
+ = ((dev == DEV_SDTV)?0x10000:0) +/*(j?32:0) + */((div == 32) ? 0 : div)/* + (div&1) ? (1<<8): 0*/;
+ check_PLL_DIV_busy();
+ }
+ *(volatile unsigned int *)(PMC_PLL + 4*PLL_NO) = PLL;
+ check_PLL_DIV_busy();
+
+ if (old_divisor > *divisor) {
+ if (dev == DEV_WMTNA)
+ *(volatile unsigned int *)(PMC_BASE + div_addr_offs) = (0x200 | ((div == 32) ? 0 : div));
+ else
+ *(volatile unsigned int *)(PMC_BASE + div_addr_offs)
+ = ((dev == DEV_SDTV)?0x10000:0) +/*(j?32:0) + */((div == 32) ? 0 : div)/* + (div&1) ? (1<<8): 0*/;
+ check_PLL_DIV_busy();
+ }
+ wmt_clk_mutex_lock(0);
+ //mutex_unlock(&clk_cnt_lock);
+
+ return set_freq;
+}
+
+static int get_freq_timer(enum dev_id dev, int *divisor) {
+
+ unsigned int div = 0, freq = 0, div_ahb = 1;
+ int PLL_NO, i, j = 0, div_addr_offs;
+ unsigned long long freq_llu = 0, base = 1000000, tmp, mod;
+ #ifdef DEBUG_CLK
+ unsigned int t1 = 0, t2 = 0;
+ #endif
+
+ if (dev == DEV_APB) {
+ PLL_NO = calc_pll_num(DEV_AHB, &div_addr_offs);
+ if (PLL_NO < 0) {
+ printk(KERN_INFO"device not found");
+ return -1;
+ }
+ div_ahb = *(volatile unsigned char *)(PMC_BASE + div_addr_offs);
+ }
+
+ PLL_NO = calc_pll_num(dev, &div_addr_offs);
+ if (PLL_NO == -1) {
+ printk(KERN_INFO"device not found");
+ return -1;
+ }
+
+ if (PLL_NO == -2)
+ return div_addr_offs*1000000;
+
+ *(volatile unsigned char *)(PMC_BASE + div_addr_offs + 2) = (dev == DEV_SDTV) ? 1 : 0;
+
+ check_PLL_DIV_busy();
+
+ div = *divisor = *(volatile unsigned char *)(PMC_BASE + div_addr_offs);
+
+ if ((dev != DEV_SDMMC0) && (dev != DEV_SDMMC1) && (dev != DEV_SDMMC2)) {
+ div = div&0x1F;
+ } else {
+ if (div & (1<<5))
+ j = 1;
+ div &= 0x1F;
+ div = div*(j?64:1)*2;
+ }
+
+ #ifdef DEBUG_CLK
+ printk(KERN_INFO"div_addr_offs=0x%x PLL_NO=%d PMC_PLL=0x%x\n", div_addr_offs, PLL_NO, PMC_PLL);
+ t1 = wmt_read_oscr();
+ #endif
+ //mutex_lock(&clk_cnt_lock);
+ tmp = *(volatile unsigned int *)(PMC_PLL + 4*PLL_NO);
+ //mutex_unlock(&clk_cnt_lock);
+ for (i = 0; i < ARRAYSIZE(pllmapAll); i++) {
+ if (pllmapAll[i].pll == tmp) {
+ freq = pllmapAll[i].freq;
+ #ifdef DEBUG_CLK
+ printk("********dev%d---PLL_NO=%X---get freq=%d set0x%x\n", dev, PLL_NO+10, freq, pllmapAll[i].pll);
+ #endif
+ break;
+ }
+ }
+ if (i >= ARRAYSIZE(pllmapAll) || freq == 0) {
+ printk(KERN_INFO"gfreq : dev%d********************pll not match table**************\n", dev);
+ freq_llu = (SRC_FREQ*GET_DIVF(tmp)) * base;
+ //printk(KERN_INFO" freq_llu =%llu\n", freq_llu);
+ tmp = GET_DIVR(tmp) * GET_DIVQ(tmp) * div * div_ahb;
+ mod = do_div(freq_llu, tmp);
+ freq = (unsigned int)freq_llu;
+ } else {
+ freq = (freq * 15625)<<6;
+ freq = freq/(div*div_ahb);
+ }
+
+ #ifdef DEBUG_CLK
+ t2 = wmt_read_oscr() - t1;
+ printk("************delay_time=%d\n", t2);
+ printk("get_freq cmd: freq=%d freq(unsigned long long)=%llu div=%llu mod=%llu\n",
+ freq, freq_llu, tmp, mod);
+ #endif
+
+ return freq;
+}
+
+/*
+* cmd : CLK_DISABLE : disable clock,
+* CLK_ENABLE : enable clock,
+* GET_FREQ : get device frequency, it doesn't enable or disable clock,
+* SET_DIV : set clock by setting divisor only(clock must be enabled by CLK_ENABLE command),
+* SET_PLL : set clock by setting PLL only, no matter clock is enabled or not,
+* this cmd can be used before CLK_ENABLE cmd to avoid a extreme speed
+* to be enabled when clock enable.
+* SET_PLLDIV : set clock by setting PLL and divisor(clock must be enabled by CLK_ENABLE command).
+* dev : Target device ID to be set the clock.
+* unit : the unit of parameter "freq", 0 = Hz, 1 = KHz, 2 = MHz.
+* freq : frequency of the target to be set when cmd is "SET_XXX".
+*
+* return : return value is different depend on cmd type,
+* CLK_DISABLE : return internal count which means how many drivers still enable this clock,
+* retrun -1 if this device has no clock enable register.
+*
+* CLK_ENABLE : return internal count which means how many drivers enable this clock,
+* retrun -1 if this device has no clock enable register.
+*
+* GET_FREQ : return device frequency in Hz when clock is enabled,
+* return -1 when clock is disabled.
+*
+* SET_DIV : return the finally calculated frequency when clock is enabled,
+* return -1 when clock is disabled.
+*
+* SET_PLL : return the finally calculated frequency no matter clock is enabled or not.
+*
+* SET_PLLDIV : return the finally calculated frequency when clock is enabled,
+* return -1 when clock is disabled.
+* Caution :
+* 1. The final clock freq maybe an approximative value,
+* equal to or less than the setting freq.
+* 2. SET_DIV and SET_PLLDIV commands which would set divisor register must use CLK_ENABLE command
+* first to enable device clock.
+* 3. Due to default frequency may be extremely fast when clock is enabled. use SET_PLL command can
+* set the frequency into a reasonable value, but don't need to enable clock first.
+*/
+#define PMC_TABLE 1
+int auto_pll_divisor(enum dev_id dev, enum clk_cmd cmd, int unit, int freq)
+{
+ int last_freq, divisor, en_count;
+ /*unsigned int t1 = 0, t2 = 0, t3;*/
+ /*if (mutexInit == 23456789) {
+ mutexInit = 0;
+ mutex_init(&clk_cnt_lock);
+ }*/
+
+ switch (cmd) {
+ case CLK_DISABLE:
+ if (dev < 128) {
+ //en_count = disable_dev_clk(dev);
+ en_count = enable_dev_clk(dev, 0);
+ return en_count;
+ } else {
+ printk(KERN_INFO"device has not clock enable register");
+ return -1;
+ }
+ case CLK_ENABLE:
+ if (dev < 128) {
+ en_count = enable_dev_clk(dev, 1);
+ return en_count;
+ } else {
+ printk(KERN_INFO"device has not clock enable register");
+ return -1;
+ }
+ case GET_FREQ:
+ #ifdef PMC_TABLE
+ /*t1 = wmt_read_oscr();*/
+ last_freq = get_freq_t(dev, &divisor);
+ /*t2 = wmt_read_oscr() - t1;
+ t1 = wmt_read_oscr();*/
+ #else
+ last_freq = get_freq(dev, &divisor);
+ #endif
+ /*t3 = wmt_read_oscr() - t1;
+ printk("*******************GF t3=%d tt2=%d min=%d\n", t3, t2, last_freq - last_freq1);*/
+ return last_freq;
+ case SET_DIV:
+ divisor = 0;
+ #ifdef PMC_TABLE
+ /*t1 = wmt_read_oscr();*/
+ last_freq = set_divisor_t(dev, unit, freq, &divisor);
+ /*t2 = wmt_read_oscr() - t1;
+ t1 = wmt_read_oscr();*/
+ #else
+ last_freq = set_divisor(dev, unit, freq, &divisor);
+ #endif
+ /*t3 = wmt_read_oscr() - t1;
+ printk("*******************SD t3=%d tt2=%d min=%d\n", t3, t2, last_freq - last_freq1);*/
+ return last_freq;
+ case SET_PLL:
+ divisor = 0;
+ #ifdef PMC_TABLE
+ /*t1 = wmt_read_oscr();*/
+ last_freq = set_pll_speed_t(dev, unit, freq, &divisor, 1);
+ /*t2 = wmt_read_oscr() - t1;
+ t1 = wmt_read_oscr();*/
+ #else
+ last_freq = set_pll_speed(dev, unit, freq, &divisor, 1);
+ #endif
+ /*t3 = wmt_read_oscr() - t1;
+ printk("*******************SP t3=%d tt2=%d min=%d\n", t3, t2, last_freq - last_freq1);*/
+ return last_freq;
+ case SET_PLLDIV:
+ divisor = 0;
+ #ifdef PMC_TABLE
+ /*t1 = wmt_read_oscr();*/
+ last_freq = set_pll_divisor_t(dev, unit, freq, &divisor);
+ /*t2 = wmt_read_oscr() - t1;
+ t1 = wmt_read_oscr();*/
+ #else
+ last_freq = set_pll_divisor(dev, unit, freq, &divisor);
+ #endif
+ /*t3 = wmt_read_oscr() - t1;
+ printk("******************SPD t3=%d tt2=%d min=%d\n", t3, t2, last_freq - last_freq1);*/
+ return last_freq;
+ case GET_CPUTIMER:
+ last_freq = get_freq_timer(dev, &divisor);
+ return last_freq;
+ default:
+ printk(KERN_INFO"clock cmd unknow");
+ /*last_freq = get_freq(dev, &divisor);
+ last_freq = set_divisor(dev, unit, freq, &divisor);
+ last_freq = set_pll_speed(dev, unit, freq, &divisor, 1);
+ last_freq = set_pll_divisor(dev, unit, freq, &divisor);*/
+ return -1;
+ }
+}
+EXPORT_SYMBOL(auto_pll_divisor);
+
+/**
+* freq = src_freq * 2 * (DIVF+1)/((DIVR+1)*(2^DIVQ))
+*
+* dev : Target device ID to be set the clock.
+* DIVF : Feedback divider value.
+* DIVR : Reference divider value.
+* DIVQ : Output divider value.
+* dev_div : Divisor belongs to each device, 0 means not changed.
+* return : The final clock freq, in Hz, will be returned when success,
+* -1 means fail (waiting busy timeout).
+*
+* caution :
+* 1. src_freq/(DIVR+1) should great than or equal to 10,
+*/
+int manu_pll_divisor(enum dev_id dev, int DIVF, int DIVR, int DIVQ, int dev_div)
+{
+
+ unsigned int PLL, freq, pmc_clk_en, old_divisor, div;
+ int PLL_NO, div_addr_offs, j = 0, SD_MMC = 0;
+
+ if ((dev == DEV_SDMMC0)||(dev == DEV_SDMMC1)||(dev == DEV_SDMMC2))
+ SD_MMC = 1;
+
+ if (DIVF < 0 || DIVF > MAX_DF){
+ printk(KERN_INFO"DIVF is out of range 0 ~ %d", MAX_DF);
+ return -1;
+ }
+ if (DIVR < 0 || DIVR > MAX_DR){
+ printk(KERN_INFO"DIVR is out of range 0 ~ %d", MAX_DR);
+ return -1;
+ }
+ if (DIVQ < 0 || DIVQ > MAX_DQ){
+ printk(KERN_INFO"DIVQ is out of range 0 ~ %d", MAX_DQ);
+ return -1;
+ }
+ if ((1000/SRC_FREQ) > ((2*(DIVF+1))/(DIVR+1))) {
+ printk(KERN_INFO"((2*(DIVF+1))/(DIVR+1)) should great than (1000/SRC_FREQ)");
+ return -1;
+ }
+ if ((2000/SRC_FREQ) < ((2*(DIVF+1))/(DIVR+1))) {
+ printk(KERN_INFO"((2*(DIVF+1))/(DIVR+1)) should less than (2000/SRC_FREQ)");
+ return -1;
+ }
+
+ if (dev_div > ((SD_MMC == 1)?63:31)){
+ printk(KERN_INFO"divisor is out of range 0 ~ 31");
+ return -1;
+ }
+
+ PLL_NO = calc_pll_num(dev, &div_addr_offs);
+ if (PLL_NO == -1) {
+ printk(KERN_INFO"device not found");
+ return -1;
+ }
+ old_divisor = *(volatile unsigned char *)(PMC_BASE + div_addr_offs);
+
+ if (SD_MMC == 1 && (dev_div&32))
+ j = 1; /* sdmmc has a another divider = 64 */
+ div = dev_div&0x1F;
+ freq = (1000 * SRC_FREQ * 2 * (DIVF+1))/((DIVR+1)*(1<<DIVQ)*div*(j?128:1));
+ freq *= 1000;
+ //printk(KERN_INFO"DIVF%d, DIVR%d, DIVQ%d, dev_div%d, freq=%dkHz\n", DIVF, DIVR, DIVQ, dev_div, freq);
+
+ PLL = (DIVF<<16) + (DIVR<<8) + DIVQ;
+
+ /* if the clk of the device is not enable, then enable it */
+ if (dev < 128) {
+ pmc_clk_en = *(volatile unsigned int *)(PMC_CLK + 4*(dev/32));
+ if (!(pmc_clk_en & (1 << (dev - 32*(dev/32)))))
+ enable_dev_clk(dev, 1);
+ }
+
+ check_PLL_DIV_busy();
+ if (old_divisor < dev_div) {
+ *(volatile unsigned int *)(PMC_BASE + div_addr_offs)
+ = (j?32:0) + ((div == 32) ? 0 : div)/* + (div&1) ? (1<<8): 0*/;
+ check_PLL_DIV_busy();
+ }
+ *(volatile unsigned int *)(PMC_PLL + 4*PLL_NO) = PLL;
+ check_PLL_DIV_busy();
+ if (old_divisor > dev_div) {
+ *(volatile unsigned int *)(PMC_BASE + div_addr_offs)
+ = (j?32:0) + ((div == 32) ? 0 : div)/* + (div&1) ? (1<<8): 0*/;
+ check_PLL_DIV_busy();
+ }
+
+
+ //PLL = (j?32:0) + ((div == 32) ? 0 : div) /*+ (div&1) ? (1<<8): 0*/;
+ //printk(KERN_INFO"set divisor =0x%x, divider address=0x%x\n", PLL, (PMC_BASE + div_addr_offs));
+ return freq;
+}
+EXPORT_SYMBOL(manu_pll_divisor);
+
+
+unsigned int ftb[20] = {0xffffffff};
+int set_plla_divisor(struct plla_param *plla_env)
+{
+ int divisor = 0, ret = 0, i;
+ unsigned int plla_clk, arm_div, l2c_div, l2c_tag, l2c_data, axi_div;
+ unsigned int cpu_clk, index, /*old_arm_div,*/ nand_clk, tfreq, tb_index;
+ unsigned int drv_en, tbl_num, info, tmp;
+ int varlen = 512;
+ unsigned char buf[512] = {0};
+ char *ptr = NULL;
+
+ plla_clk = plla_env->plla_clk;
+ arm_div = plla_env->arm_div;
+ l2c_div = plla_env->l2c_div;
+ l2c_tag = plla_env->l2c_tag_div;
+ l2c_data = plla_env->l2c_data_div;
+ axi_div = plla_env->axi_div;
+ tb_index = plla_env->tb_index;
+
+ cpu_clk = get_freq_t(DEV_ARM, &divisor);
+ cpu_clk >>= 20;
+ //cpu_clk /= 1000000;
+ tfreq = plla_clk/arm_div;
+
+ info = *(volatile unsigned int *)(CPINFO);
+ if (ftb[0] == 0xffffffff) {
+ if ((info&0x8) == 0)
+ ret = wmt_getsyspara("wmt.cfadj.param", buf, &varlen);
+ else
+ ret = wmt_getsyspara("wmt.cflpadj.param", buf, &varlen);
+ if (ret) {
+ printk(KERN_INFO "Can not find uboot env wmt.cfadj.param\n");
+ ret = -ENODATA;
+ ftb[0] = 0;
+ goto no_adj;
+ }
+ sscanf(buf, "%x:%d:", &drv_en, &tbl_num);
+ if ((drv_en&1) == 0 || tbl_num == 0) {
+ ret = -ENODATA;
+ ftb[0] = 0;
+ goto no_adj;
+ }
+
+ ptr = buf;
+ if (tbl_num > 20)
+ tbl_num = 20;
+ fq_dbg("dvfs_adj_table:");
+ for (i = 0; i < tbl_num; i++) {
+ strsep(&ptr, "[");
+ sscanf(ptr, "%d][", &tmp);
+ ftb[i] = tmp;
+ fq_dbg("ftb[%d]=%d \n", i, ftb[i]);
+ }
+ fq_dbg("\n");
+ }
+ #ifdef DEBUG_PLLA
+ if (ftb[0] != 0)
+ tblpll = ftb[tb_index];
+ else
+ ret = 1;
+ //printk("tblpll = %d\n", tblpll);
+ #endif
+no_adj:
+ //printk("ret = %d\n", ret);
+ if (!ret) {
+ if (tfreq != tblpll) {
+ fr_rdn = (tfreq*15625)<<6;
+ tfreq = tblpll;
+ plla_clk = tfreq;
+ arm_div = 1;
+ } else
+ fr_rdn = 0;
+ } else {
+ #ifdef DEBUG_PLLA_FX
+ if (tfreq > (MAXPLL/1000000)) {
+ fr_rdn = tfreq*1000000;
+ tfreq = (MAXPLL/1000000);
+ plla_clk = tfreq;
+ arm_div = 1;
+ } else
+ #endif
+ fr_rdn = 0;
+ }
+
+ //printk("tfreq = %d\n", tfreq);
+ #if 0
+ if (cpu_clk > tfreq) {
+ //change cpu from faster to slower
+ old_arm_div = *(volatile unsigned int *)(PMC_BASE + 0x300);
+ index = set_pll_speed_t(DEV_ARM, 1, (plla_clk*1000)/old_arm_div, &divisor, 1);
+ if (index < 0)
+ return -1;
+
+ if (*(volatile unsigned char *)(PMC_BASE + 0x300) != arm_div) {
+ *(volatile unsigned int *)(PMC_BASE + 0x300) = arm_div;
+ check_PLL_DIV_busy();
+ }
+ if (*(volatile unsigned int *)(PMC_BASE + 0x30C) != l2c_div) {
+ *(volatile unsigned int *)(PMC_BASE + 0x30C) = l2c_div;
+ check_PLL_DIV_busy();
+ }
+ if (*(volatile unsigned int *)(PMC_BASE + 0x3F0) != l2c_tag) {
+ *(volatile unsigned int *)(PMC_BASE + 0x3F0) = l2c_tag;
+ check_PLL_DIV_busy();
+ }
+ if (*(volatile unsigned int *)(PMC_BASE + 0x3F4) != l2c_data) {
+ *(volatile unsigned int *)(PMC_BASE + 0x3F4) = l2c_data;
+ check_PLL_DIV_busy();
+ }
+ if (*(volatile unsigned int *)(PMC_BASE + 0x3B0) != axi_div) {
+ *(volatile unsigned int *)(PMC_BASE + 0x3B0) = axi_div;
+ check_PLL_DIV_busy();
+ }
+ } else
+ #endif
+ {
+ //change cpu from slower to faster
+ nand_clk = get_freq_t(DEV_NAND, &divisor);
+ //if ((nand_clk*divisor) > plla_clk)
+ *(volatile unsigned int *)(PMC_BASE + 0x300) = 2;
+ /*else
+ *(volatile unsigned int *)(PMC_BASE + 0x300) = arm_div;*/
+ check_PLL_DIV_busy();
+ if (*(volatile unsigned int *)(PMC_BASE + 0x30C) != l2c_div) {
+ *(volatile unsigned int *)(PMC_BASE + 0x30C) = l2c_div;
+ check_PLL_DIV_busy();
+ }
+ if (*(volatile unsigned int *)(PMC_BASE + 0x3F0) != l2c_tag) {
+ *(volatile unsigned int *)(PMC_BASE + 0x3F0) = l2c_tag;
+ check_PLL_DIV_busy();
+ }
+ if (*(volatile unsigned int *)(PMC_BASE + 0x3F4) != l2c_data) {
+ *(volatile unsigned int *)(PMC_BASE + 0x3F4) = l2c_data;
+ check_PLL_DIV_busy();
+ }
+ if (*(volatile unsigned int *)(PMC_BASE + 0x3B0) != axi_div) {
+ *(volatile unsigned int *)(PMC_BASE + 0x3B0) = axi_div;
+ check_PLL_DIV_busy();
+ }
+ //if ((nand_clk*divisor) > plla_clk) {
+ index = set_pll_speed_t(DEV_ARM, 1, (plla_clk*1000)/2, &divisor, 1);
+ if (index < 0)
+ return -1;
+ index = index*2;
+ *(volatile unsigned int *)(PMC_BASE + 0x300) = arm_div;
+ /*} else {
+ index = set_pll_speed_t(DEV_ARM, 1, (plla_clk*1000)/arm_div, &divisor, 0);
+ if (index < 0)
+ return -1;
+ }*/
+ }
+
+ return index;
+}
+EXPORT_SYMBOL(set_plla_divisor);
+
+int wm_pmc_set(enum dev_id dev, enum power_cmd cmd)
+{
+ int retval = -1;
+ unsigned int temp = 0, base = 0, mali_val = 0;
+ unsigned int mali_off, mali_l2c_off = 0x00130620/*, mali_gp_off = 0x00130624*/;
+ mali_off = mali_l2c_off;
+
+ base = 0xfe000000;
+ temp = REG32_VAL(base + 0x00110110);
+ temp = ((temp >> 10)&0xC0)|(temp&0x3F);
+
+ if ((cmd == DEV_PWRON)) {
+ if ((temp & 0xC0) == 0x80) {//8700/8720 can't be power on
+ retval = -1;
+ } else {
+ while ((REG32_VAL(base + mali_off)&0xF0)!= 0
+ && (REG32_VAL(base + mali_off)&0xF0)!= 0xF0)
+ ;
+
+ mali_val = REG32_VAL(base + mali_off);
+ if (!((mali_val&0xF0)==0xF0))
+ REG32_VAL(base + mali_off) |= 1;
+
+ while ((REG32_VAL(base + mali_off)&0xF0)!= 0
+ && (REG32_VAL(base + mali_off)&0xF0)!= 0xF0)
+ ;
+ retval = 0;
+ }
+ } else if (cmd == DEV_PWROFF) {
+ if ((temp & 0xC3) == 0xC0) {//8710B0 can't power off after power on
+ retval = -1;
+ } else {
+ while ((REG32_VAL(base + mali_off)&0xF0)!= 0
+ && (REG32_VAL(base + mali_off)&0xF0)!= 0xF0)
+ ;
+ mali_val = REG32_VAL(base + mali_off);
+ if ((mali_val&0xF0))
+ REG32_VAL(base + mali_off) &= ~1;
+ while ((REG32_VAL(base + mali_off)&0xF0)!= 0
+ && (REG32_VAL(base + mali_off)&0xF0)!= 0xF0)
+ ;
+ retval = 0;
+ }
+ } else if (cmd == DEV_PWRSTS) {
+ while ((REG32_VAL(base + mali_off)&0xF0)!= 0
+ && (REG32_VAL(base + mali_off)&0xF0)!= 0xF0)
+ ;
+ temp = REG32_VAL(base + mali_off);
+ if (temp & 0xF0)
+ retval = 1;
+ else
+ retval = 0;
+ }
+ return retval;
+}
+
+
+
+#define LOADER_ADDR 0xffff0000
+#define HIBERNATION_ENTER_EXIT_CODE_BASE_ADDR 0xFFFFFFC0
+#define DO_POWER_SET (HIBERNATION_ENTER_EXIT_CODE_BASE_ADDR + 0x2C)
+#define CP15_C1_XPbit 23
+/*
+ * Function:
+ * int wmt_power_dev(enum dev_id dev, enum power_cmd cmd)
+ * This function is used to control/get WMT SoC specific device power state.
+ *
+ * Parameter:
+ * The available dev_id is DEV_MALI cmd used to control/get device power state.
+ * The available power_cmd are
+ * - DEV_PWRON
+ * - DEV_PWROFF
+ * - DEV_PWRSTS
+ *
+ * Return:
+ * - As power_cmd are DEV_PWRON, DEV_PWROFF 0 indicates success.
+ * Negative value indicates failure as error code.
+ *
+ * - As power_cmd is DEV_PWRSTS
+ * 0 indicates the current device is power off.
+ * 1 indicates the current device is power on.
+ * Negative value indicates failure as error code.
+ */
+extern int spi_read_status(int chip);
+int wmt_power_dev(enum dev_id dev, enum power_cmd cmd)
+{
+#if 0
+ static unsigned int base = 0;
+ unsigned int exec_at = (unsigned int)-1, temp = 0, bootdev;
+ int (*theKernel_power)(int from, enum dev_id dev, enum power_cmd cmd);
+ int en_count, retval = 0, rc = 0;
+ unsigned long flags;
+ bootdev = GPIO_STRAP_STATUS_VAL;
+
+ /*printk(KERN_INFO"entry dev_id=%d cmd=%d, boot_strap=%x,\n",dev, cmd, GPIO_STRAP_STATUS_VAL);*/
+ /*enble SF clock*/
+ if((bootdev & 0x4040) == 0)
+ en_count = enable_dev_clk(DEV_SF); //SF boot
+ else if((bootdev & 0x4040) == 4)
+ en_count = enable_dev_clk(DEV_NAND);//NAND boot
+ else
+ en_count = enable_dev_clk(DEV_SDMMC0);//MMC boot
+ udelay(1);
+#ifdef CONFIG_MTD_WMT_SF
+ rc = spi_read_status(0);
+ if (rc)
+ printk("wr c0 wait status ret=%d\n", rc);
+#endif
+ /*rc = spi_read_status(1);
+ if (rc)
+ printk("wr c1 wait status ret=%d\n", rc);*/
+
+ rc = 0;
+ /*jump to loader api to do something*/
+ if (base == 0)
+ base = (unsigned int)ioremap/*_nocache*/(LOADER_ADDR, 0x10000);
+ exec_at = base + (DO_POWER_SET - LOADER_ADDR);
+ theKernel_power = (int (*)(int from, enum dev_id dev, enum power_cmd cmd))exec_at;
+ /*temp = *(volatile unsigned int *)(0xFE110110);
+ printk(KERN_INFO"entry exec_at=0x%x chip_id=0x%x, clock enable=0x%x\n", exec_at,
+ ((temp >> 10)&0xC0)|(temp&0x3F), *(volatile unsigned int *)(0xFE130250));*/
+ /*backup flags and disable irq*/
+ local_irq_save(flags);
+ /*enable subpage AP bits*/
+ asm volatile ("mrc p15, 0, %0, c1, c0, 0" : "=r" (temp));
+ //if (!(temp & (1<<CP15_C1_XPbit)))
+// printk(KERN_INFO"1 xp(23) bits =0x%x cp15c0=0x%x\n", temp&(1<<CP15_C1_XPbit), temp);
+ if (temp & (1<<CP15_C1_XPbit)) {
+ rc = 1;
+ temp &= ~(1<<CP15_C1_XPbit);
+ /*printk(KERN_INFO"2 xp(23) bits =0x%x \n", temp&(1<<CP15_C1_XPbit));*/
+ asm volatile ("mcr p15, 0, %0, c1, c0, 0" : : "r" (temp));
+ }
+ //retval = theKernel_power(4, DEV_MALI, cmd);
+ retval = wm_pmc_set(DEV_MALI, cmd);
+
+ if (rc == 1) {
+ /*disable subpage AP bits*/
+ asm volatile ("mrc p15, 0, %0, c1, c0, 0" : "=r" (temp));
+ /*printk(KERN_INFO"3 xp(23) bits =0x%x \n", temp&(1<<CP15_C1_XPbit));*/
+ temp |= (1<<CP15_C1_XPbit);
+ /*printk(KERN_INFO"4 xp(23) bits =0x%x \n", temp&(1<<CP15_C1_XPbit));*/
+ asm volatile ("mcr p15, 0, %0, c1, c0, 0" : : "r" (temp));
+ }
+ /*restore irq flags*/
+ local_irq_restore(flags);
+
+ /*iounmap((void *)base);*/
+ /*printk(KERN_INFO"entry base=0x%x exec_at=0x%x clock enable =0x%x\n",
+ base, exec_at, *(volatile unsigned int *)(0xFE130250));*/
+
+ /*disable SF clock*/
+ if((bootdev & 0x4040) == 0)
+ en_count = disable_dev_clk(DEV_SF); //SF boot
+ else if((bootdev & 0x4040) == 4)
+ en_count = disable_dev_clk(DEV_NAND);//NAND boot
+ else
+ en_count = disable_dev_clk(DEV_SDMMC0);//MMC boot
+
+ /*printk(KERN_INFO"exit!!ret = (%d)\n",retval);*/
+#endif
+ return 0;//retval;
+}
+EXPORT_SYMBOL(wmt_power_dev);
+
+/*struct pll_map pllmapAll[] = {
+{126, 0x00140003}, {126, 0x00290103}, {126, 0x00140102},
+{129, 0x002A0103},
+{132, 0x00150003}, {132, 0x002B0103}, {132, 0x00150102}, {132, 0x000A0101}, {132, 0x000A0002},
+{135, 0x002C0103},
+{138, 0x00160003}, {138, 0x002D0103}, {138, 0x00160102},
+{141, 0x002E0103},
+{144, 0x00170003}, {144, 0x002F0103}, {144, 0x00020000}, {144, 0x00170102}, {144, 0x000B0101}, {144, 0x00050100}, {144, 0x000B0002}, {144, 0x00050001},
+{147, 0x00300103},
+{150, 0x00180003}, {150, 0x00310103}, {150, 0x00180102},
+{153, 0x00320103},
+{156, 0x00190003}, {156, 0x00330103}, {156, 0x000C0101}, {156, 0x000C0002},
+{159, 0x00340103},
+{162, 0x001A0003}, {162, 0x00350103}, {162, 0x001A0102},
+{165, 0x00360103}, {156, 0x00190102},
+{168, 0x001B0003}, {168, 0x00370103}, {168, 0x001B0102}, {168, 0x000D0101}, {168, 0x00060100}, {168, 0x000D0002}, {168, 0x00060001},
+{171, 0x00380103},
+{174, 0x001C0003}, {174, 0x00390103}, {174, 0x001C0102},
+{177, 0x003A0103},
+{180, 0x001D0003}, {180, 0x003B0103}, {180, 0x001D0102}, {180, 0x000E0101}, {180, 0x000E0002},
+{183, 0x003C0103},
+{186, 0x001E0003}, {186, 0x001E0102}, {186, 0x003D0103},
+{189, 0x003E0103},
+{192, 0x001F0003}, {192, 0x00030000}, {192, 0x003F0103}, {192, 0x001F0102}, {192, 0x000F0101}, {192, 0x00070100}, {192, 0x000F0002}, {192, 0x00070001},
+{195, 0x00400103},
+{198, 0x00200003}, {198, 0x00200102},
+{198, 0x00410103},
+{201, 0x00420103},
+{204, 0x00210003}, {204, 0x00430103}, {204, 0x00210102}, {204, 0x00100101}, {204, 0x00100002},
+{207, 0x00440103},
+{210, 0x00220003}, {210, 0x00450103}, {210, 0x00220102},
+{213, 0x00460103},
+{216, 0x00230003}, {216, 0x00470103}, {216, 0x00230102}, {216, 0x00110101}, {216, 0x00080001}, {216, 0x00080100}, {216, 0x00110002},
+{219, 0x00480103},
+{222, 0x00240003}, {222, 0x00240102},
+{222, 0x00490103},
+{225, 0x004A0103},
+{228, 0x004B0103}, {228, 0x00250102}, {228, 0x00120101}, {228, 0x00250003}, {228, 0x00120002},
+{231, 0x004C0103},
+{234, 0x00260003}, {234, 0x00260102},
+{234, 0x004D0103},
+{237, 0x004E0103},
+{240, 0x00270003}, {240, 0x00270102}, {240, 0x004F0103}, {240, 0x00040000}, {240, 0x00130101}, {240, 0x00090001}, {240, 0x00090100}, {240, 0x00130002},
+{243, 0x00500103},
+{246, 0x00280003}, {246, 0x00280102},
+{246, 0x00510103},
+{249, 0x00520103},
+{252, 0x00290003}, {252, 0x00530103}, {252, 0x00290102}, {252, 0x00140002}, {252, 0x00140101},
+{258, 0x002A0102},
+{264, 0x00150002}, {264, 0x002B0102}, {264, 0x00150101}, {264, 0x000A0001}, {264, 0x000A0100},
+{270, 0x002C0102},
+{276, 0x00160002}, {276, 0x002D0102}, {276, 0x00160101},
+{282, 0x002E0102},
+{288, 0x00170002}, {288, 0x002F0102}, {288, 0x00050000}, {288, 0x000B0001}, {288, 0x00170101}, {288, 0x000B0100},
+{294, 0x00300102},
+{300, 0x00180002}, {300, 0x00310102}, {300, 0x00180101},
+{306, 0x00320102},
+{312, 0x00190002}, {312, 0x00330102}, {312, 0x000C0001}, {312, 0x00190101}, {312, 0x000C0100},
+{318, 0x00340102},
+{324, 0x001A0002}, {324, 0x00350102}, {324, 0x001A0101},
+{330, 0x00360102},
+{336, 0x001B0002}, {336, 0x00370102}, {336, 0x00060000}, {336, 0x000D0001}, {336, 0x001B0101}, {336, 0x000D0100},
+{342, 0x00380102},
+{348, 0x001C0002}, {348, 0x00390102}, {384, 0x00070000}, {348, 0x001C0101}, {384, 0x000F0100}, {384, 0x000F0001},
+{354, 0x003A0102},
+{360, 0x001D0002}, {360, 0x003B0102}, {360, 0x000E0001}, {360, 0x001D0101}, {360, 0x000E0100},
+{366, 0x003C0102},
+{372, 0x001E0002}, {372, 0x003D0102}, {372, 0x001E0101},
+{378, 0x003E0102},
+{384, 0x001F0002}, {384, 0x003F0102}, {384, 0x001F0101},
+{390, 0x00400102},
+{396, 0x00200002}, {396, 0x00410102}, {396, 0x00200101},
+{402, 0x00420102},
+{408, 0x00210002}, {408, 0x00430102}, {408, 0x00210101}, {408, 0x00100100}, {408, 0x00100001},
+{414, 0x00440102},
+{420, 0x00220002}, {420, 0x00450102}, {420, 0x00220101},
+{426, 0x00460102},
+{432, 0x00230002}, {432, 0x00470102}, {432, 0x00230101}, {432, 0x00080000}, {432, 0x00110001}, {432, 0x00110100},
+{438, 0x00480102}, {480, 0x00130001}, {480, 0x00130100}, {480, 0x00090000},
+{444, 0x00240002}, {444, 0x00490102}, {444, 0x00240101},
+{450, 0x004A0102},
+{456, 0x00250002}, {456, 0x004B0102}, {456, 0x00250101}, {456, 0x00120100}, {456, 0x00120001},
+{462, 0x004C0102},
+{468, 0x00260002}, {468, 0x004D0102}, {468, 0x00260101},
+{474, 0x004E0102},
+{480, 0x00270002}, {480, 0x004F0102}, {480, 0x00270101},
+{486, 0x00500102},
+{492, 0x00280002}, {492, 0x00510102}, {492, 0x00280101},
+{498, 0x00520102},
+{504, 0x00140001}, {504, 0x00290002}, {504, 0x00530102}, {504, 0x00290101}, {504, 0x00140100},
+{516, 0x002A0101},
+{528, 0x00150001}, {528, 0x002B0101}, {528, 0x00150100}, {528, 0x000A0000},
+{540, 0x002C0101},
+{552, 0x00160001}, {552, 0x002D0101}, {552, 0x00160100},
+{564, 0x002E0101},
+{576, 0x00170001}, {576, 0x002F0101}, {576, 0x00170100}, {576, 0x000B0000},
+{588, 0x00300101},
+{600, 0x00180001}, {600, 0x00310101}, {600, 0x00180100},
+{612, 0x00320101},
+{624, 0x00190001}, {624, 0x00330101}, {624, 0x000C0000}, {624, 0x00190100},
+{636, 0x00340101},
+{648, 0x001A0001}, {648, 0x00350101}, {648, 0x001A0100},
+{660, 0x00360101},
+{672, 0x001B0001}, {672, 0x00370101}, {672, 0x000D0000}, {672, 0x001B0100},
+{684, 0x00380101},
+{696, 0x001C0001}, {696, 0x00390101}, {696, 0x001C0100},
+{708, 0x003A0101},
+{720, 0x001D0001}, {720, 0x003B0101}, {720, 0x000E0000}, {720, 0x001D0100},
+{732, 0x003C0101},
+{744, 0x001E0001}, {744, 0x003D0101}, {744, 0x001E0100},
+{756, 0x003E0101},
+{768, 0x001F0001}, {768, 0x003F0101}, {768, 0x000F0000}, {768, 0x001F0100},
+{780, 0x00400101},
+{792, 0x00200001}, {792, 0x00410101}, {792, 0x00200100},
+{804, 0x00420101},
+{816, 0x00210001}, {816, 0x00430101}, {816, 0x00100000}, {816, 0x00210100},
+{828, 0x00440101},
+{840, 0x00220001}, {840, 0x00450101}, {840, 0x00220100},
+{852, 0x00460101},
+{864, 0x00230001}, {864, 0x00470101}, {864, 0x00230100}, {864, 0x00110000},
+{876, 0x00480101},
+{888, 0x00240001}, {888, 0x00490101}, {888, 0x00240100},
+{900, 0x004A0101},
+{912, 0x00250001}, {912, 0x004B0101}, {912, 0x00120000}, {912, 0x00250100},
+{924, 0x004C0101},
+{936, 0x004D0101}, {936, 0x00260100},
+{948, 0x004E0101},
+{960, 0x00270001}, {960, 0x004F0101}, {960, 0x00270100}, {960, 0x00130000},
+{972, 0x00500101},
+{984, 0x00280001}, {984, 0x00510101}, {984, 0x00280100},
+{936, 0x00260001}, {996, 0x00520101},
+{1008, 0x00290001}, {1008, 0x00530101}, {1008, 0x00290100}, {1008, 0x00140000},
+{1032, 0x002A0100},
+{1056, 0x00150000}, {1056, 0x002B0100},
+{1080, 0x002C0100},
+{1104, 0x00160000}, {1104, 0x002D0100},
+{1128, 0x002E0100},
+{1152, 0x00170000}, {1152, 0x002F0100},
+{1176, 0x00300100},
+{1200, 0x00180000}, {1200, 0x00310100},
+{1224, 0x00320100},
+{1248, 0x00190000}, {1248, 0x00330100},
+{1272, 0x00340100},
+{1296, 0x001A0000}, {1296, 0x00350100},
+{1320, 0x00360100},
+{1344, 0x001B0000}, {1344, 0x00370100},
+{1368, 0x00380100},
+{1392, 0x001C0000}, {1392, 0x00390100},
+{1416, 0x003A0100},
+{1440, 0x001D0000}, {1440, 0x003B0100},
+{1464, 0x003C0100},
+{1488, 0x001E0000}, {1488, 0x003D0100},
+{1512, 0x003E0100},
+{1536, 0x001F0000}, {1536, 0x003F0100},
+{1560, 0x00400100},
+{1584, 0x00200000}, {1584, 0x00410100},
+{1608, 0x00420100},
+{1632, 0x00210000}, {1632, 0x00430100},
+{1656, 0x00440100},
+{1680, 0x00220000}, {1680, 0x00450100},
+{1704, 0x00460100},
+{1728, 0x00230000}, {1728, 0x00470100},
+{1752, 0x00480100},
+{1776, 0x00240000}, {1776, 0x00490100},
+{1800, 0x004A0100},
+{1824, 0x004B0100}, {1824, 0x00250000},
+{1848, 0x004C0100},
+{1872, 0x00260000}, {1872, 0x004D0100},
+{1896, 0x004E0100},
+{1920, 0x00270000}, {1920, 0x004F0100},
+{1944, 0x00500100},
+{1968, 0x00280000}, {1968, 0x00510100},
+{1992, 0x00520100},
+{2016, 0x00290000}, {2016, 0x00530100}
+};*/
+void wmt_set_DIV(enum dev_id dev,int div)
+{
+ int PLL_NO, div_addr_offs;
+
+ PLL_NO = calc_pll_num(dev, &div_addr_offs);
+ check_PLL_DIV_busy();
+ if (dev == DEV_WMTNA)
+ *(volatile unsigned int *)(PMC_BASE + div_addr_offs) = (0x200 | ((div == 32) ? 0 : div));
+ else
+ *(volatile unsigned int *)(PMC_BASE + div_addr_offs)
+ = ((dev == DEV_SDTV)?0x10000:0) + ((div == 32) ? 0 : div);
+ check_PLL_DIV_busy();
+}
+
+extern int vpp_parse_param(char *buf, unsigned int *param,
+ int cnt, unsigned int hex_mask);
+
+#define WMT_VDD_CONFIG
+struct workqueue_struct *mmfreq_workqueue = 0;
+struct work_struct mmfreq_work;
+static int div_table[3][7];
+static int table_num;
+unsigned int mc5_08_default;
+unsigned int mc5_18_default;
+unsigned int mc5_20_default;
+
+void wmt_resume_mmfreq(void)
+{
+ int current_voltage = 0;
+
+ if (re) {
+ current_voltage = regulator_get_voltage(re);
+ regulator_set_voltage(re, current_voltage, current_voltage);
+ }
+ mmfreq_cur_num = ~0;
+}
+
+void wmt_suspend_mmfreq(void)
+{
+ if (!mmfreq_workqueue)
+ return;
+
+ flush_workqueue(mmfreq_workqueue);
+}
+
+void wmt_do_mmfreq(struct work_struct *ptr)
+{
+ static int init;
+
+ int num = mmfreq_num;
+ int dev_cnt;
+
+ wmt_clk_mutex_lock(1);
+ dev_cnt = dev_en_count[MMFREQ_VD];
+ wmt_clk_mutex_lock(0);
+
+
+// printk("%s %d --> %d,%d\n", __FUNCTION__, mmfreq_cur_num, num,dev_cnt);
+
+ if (init == 0) {
+#ifdef WMT_VDD_CONFIG
+ re = regulator_get(NULL, "wmt_vdd");
+#endif
+ init = 1;
+ }
+
+ if (dev_cnt)
+ return;
+
+ if (num > table_num)
+ return;
+
+ if (num == mmfreq_cur_num)
+ return;
+
+ if (mmfreq_debug) {
+#ifdef WMT_VDD_CONFIG
+ printk("mmfreq %d --> %d,re 0x%x\n",mmfreq_cur_num,num,(int)re);
+#endif
+ printk("vol %d,mali %d,vpp %d,vdu %d,vduna %d,cmn %d,cmnna %d\n",
+ div_table[num][0], div_table[num][1],
+ div_table[num][2], div_table[num][3],
+ div_table[num][4], div_table[num][5],
+ div_table[num][6]);
+ }
+#ifdef WMT_VDD_CONFIG
+ if (mmfreq_cur_num < num) { /* lo to hi */
+ regulator_set_voltage(re, div_table[num][0]*1000, div_table[num][0]*1000);
+ }
+#endif
+ wmt_set_DIV(DEV_MALI,div_table[num][1]);
+ wmt_set_DIV(DEV_VPP,div_table[num][2]);
+ wmt_set_DIV(DEV_WMTVDU,div_table[num][3]);
+ wmt_set_DIV(DEV_WMTNA,div_table[num][4]);
+ wmt_set_DIV(DEV_CNMVDU,div_table[num][5]);
+ wmt_set_DIV(DEV_CNMNA,div_table[num][6]);
+#ifdef WMT_VDD_CONFIG
+ if (mmfreq_cur_num > num) { /* hi to lo */
+ regulator_set_voltage(re, div_table[num][0]*1000, div_table[num][0]*1000);
+ }
+#endif
+ mmfreq_cur_num = num;
+ printk("vol %d,mali %d,vpp %d,vdu %d,vduna %d,cmn %d,cmnna %d,end wmt_do_mmfreq\n",
+ div_table[num][0], div_table[num][1],
+ div_table[num][2], div_table[num][3],
+ div_table[num][4], div_table[num][5],
+ div_table[num][6]);
+}
+
+void wmt_set_mmfreq(int num)
+{
+ (*(volatile unsigned int *)(MEMORY_CTRL_V4_CFG_BASE_ADDR + 0x08)) =
+ (num) ? 0x00f80000 : mc5_08_default;
+ (*(volatile unsigned int *)(MEMORY_CTRL_V4_CFG_BASE_ADDR + 0x18)) =
+ (num) ? 0x00fa0000 : mc5_18_default;
+ (*(volatile unsigned int *)(MEMORY_CTRL_V4_CFG_BASE_ADDR + 0x20)) =
+ (num) ? 0x00020505 : mc5_20_default;
+
+ if (!mmfreq_workqueue)
+ return;
+
+// printk("%s %d --> %d\n", __FUNCTION__, mmfreq_cur_num, num);
+ mmfreq_num = num;
+ if (mmfreq_cur_num == num)
+ return;
+
+ flush_workqueue(mmfreq_workqueue);
+ queue_work(mmfreq_workqueue, &mmfreq_work);
+}
+
+void wmt_enable_mmfreq(enum wmt_mmfreq_type type, int enable)
+{
+ wmt_clk_mutex_lock(1);
+ mmfreq_type_mask = (enable) ?
+ (mmfreq_type_mask | type) : (mmfreq_type_mask & ~type);
+ wmt_clk_mutex_lock(0);
+ wmt_set_mmfreq((mmfreq_type_mask) ? 1 : 0);
+}
+
+int wmt_mmfreq_init(void)
+{
+ char buf[100];
+ int varlen = 100;
+ int parm[21];
+ int i;
+ unsigned int info;
+
+ mc5_08_default =
+ (*(volatile unsigned int *)(MEMORY_CTRL_V4_CFG_BASE_ADDR + 0x08));
+ mc5_18_default =
+ (*(volatile unsigned int *)(MEMORY_CTRL_V4_CFG_BASE_ADDR + 0x18));
+ mc5_20_default =
+ (*(volatile unsigned int *)(MEMORY_CTRL_V4_CFG_BASE_ADDR + 0x20));
+
+ info = *(volatile unsigned int *)(CPINFO);
+ if (info & 0x8)
+ i = wmt_getsyspara("wmt.mmfreqlp.param", buf, &varlen);
+ else
+ i = wmt_getsyspara("wmt.mmfreq.param", buf, &varlen);
+
+ if (i)
+ return 0;
+
+ table_num = vpp_parse_param(buf, (unsigned int *)parm, 21, 0x1);
+ if (parm[0] & 0x1) {
+ mmfreq_debug = (parm[0] & 0x10) ? 1 : 0;
+#if 0
+ for (i = 0; i < table_num; i++ ) {
+ printk("%d:%d,",i,parm[i]);
+ }
+ printk("\n");
+#endif
+ table_num = (table_num - 3 + 1) / 9;
+ printk("mmfreq.parm en 0x%x,sr %d,num %d,%d\n",parm[0],parm[1],parm[2],table_num);
+ for (i=0; i<table_num; i++) {
+ div_table[i][0] = parm[9 * i + 4];
+ div_table[i][1] = parm[9 * i + 5];
+ div_table[i][2] = parm[9 * i + 6];
+ div_table[i][3] = parm[9 * i + 7];
+ div_table[i][4] = parm[9 * i + 8];
+ div_table[i][5] = parm[9 * i + 9];
+ div_table[i][6] = parm[9 * i + 10];
+ printk("vol %d,mali %d,vpp %d,vdu %d,vduna %d,cmn %d,cmnna %d\n",
+ div_table[i][0], div_table[i][1],
+ div_table[i][2], div_table[i][3],
+ div_table[i][4], div_table[i][5],
+ div_table[i][6]);
+ }
+ }
+ else {
+ table_num = 0;
+ printk("mmfreq disable\n");
+ }
+
+ if (table_num >= 2) {
+ mmfreq_workqueue = create_singlethread_workqueue("mmfreq_wq");
+ if (!mmfreq_workqueue)
+ return -1;
+ INIT_WORK(&mmfreq_work,wmt_do_mmfreq);
+ }
+ return 0;
+}
+module_init(wmt_mmfreq_init);
+