rk3026: i2s add several attempts to double confirm i2s frac effect
[firefly-linux-kernel-4.4.55.git] / arch / arm / mach-rk3026 / dvfs.c
1 /* arch/arm/mach-rk3026/dvfs.c\r
2  *\r
3  * Copyright (C) 2012 ROCKCHIP, Inc.\r
4  *\r
5  * This software is licensed under the terms of the GNU General Public\r
6  * License version 2, as published by the Free Software Foundation, and\r
7  * may be copied, distributed, and modified under those terms.\r
8  *\r
9  * This program is distributed in the hope that it will be useful,\r
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
12  * GNU General Public License for more details.\r
13  *\r
14  */\r
15 \r
16 #include <linux/kernel.h>\r
17 #include <linux/err.h>\r
18 #include <linux/spinlock.h>\r
19 #include <linux/list.h>\r
20 #include <linux/slab.h>\r
21 #include <linux/clk.h>\r
22 #include <linux/cpufreq.h>\r
23 #include <mach/dvfs.h>\r
24 #include <mach/clock.h>\r
25 #include <linux/regulator/consumer.h>\r
26 #include <linux/delay.h>\r
27 #include <linux/io.h>\r
28 #include <linux/hrtimer.h>\r
29 #include <plat/efuse.h>\r
30 \r
31 static int rk_dvfs_clk_notifier_event(struct notifier_block *this,\r
32                 unsigned long event, void *ptr)\r
33 {\r
34         struct clk_notifier_data *noti_info;\r
35         struct clk *clk;\r
36         struct clk_node *dvfs_clk;\r
37         noti_info = (struct clk_notifier_data *)ptr;\r
38         clk = noti_info->clk;\r
39         dvfs_clk = clk->dvfs_info;\r
40 \r
41         switch (event) {\r
42                 case CLK_PRE_RATE_CHANGE:\r
43                         DVFS_DBG("%s CLK_PRE_RATE_CHANGE\n", __func__);\r
44                         break;\r
45                 case CLK_POST_RATE_CHANGE:\r
46                         DVFS_DBG("%s CLK_POST_RATE_CHANGE\n", __func__);\r
47                         break;\r
48                 case CLK_ABORT_RATE_CHANGE:\r
49                         DVFS_DBG("%s CLK_ABORT_RATE_CHANGE\n", __func__);\r
50                         break;\r
51                 case CLK_PRE_ENABLE:\r
52                         DVFS_DBG("%s CLK_PRE_ENABLE\n", __func__);\r
53                         break;\r
54                 case CLK_POST_ENABLE:\r
55                         DVFS_DBG("%s CLK_POST_ENABLE\n", __func__);\r
56                         break;\r
57                 case CLK_ABORT_ENABLE:\r
58                         DVFS_DBG("%s CLK_ABORT_ENABLE\n", __func__);\r
59                         break;\r
60                 case CLK_PRE_DISABLE:\r
61                         DVFS_DBG("%s CLK_PRE_DISABLE\n", __func__);\r
62                         break;\r
63                 case CLK_POST_DISABLE:\r
64                         DVFS_DBG("%s CLK_POST_DISABLE\n", __func__);\r
65                         dvfs_clk->set_freq = 0;\r
66                         break;\r
67                 case CLK_ABORT_DISABLE:\r
68                         DVFS_DBG("%s CLK_ABORT_DISABLE\n", __func__);\r
69 \r
70                         break;\r
71                 default:\r
72                         break;\r
73         }\r
74         return 0;\r
75 }\r
76 \r
77 static struct notifier_block rk_dvfs_clk_notifier = {\r
78         .notifier_call = rk_dvfs_clk_notifier_event,\r
79 };\r
80 struct lkg_maxvolt {\r
81         int leakage_level;\r
82         unsigned int maxvolt;\r
83 };\r
84 #if 0\r
85 #if 0\r
86 /* avdd_com & vdd_arm separate circuit */\r
87 static struct lkg_maxvolt lkg_volt_table[] = {\r
88         {.leakage_level = 1,    .maxvolt = 1350 * 1000},\r
89         {.leakage_level = 3,    .maxvolt = 1275 * 1000},\r
90         {.leakage_level = 15,   .maxvolt = 1200 * 1000},\r
91 };\r
92 #else\r
93 /* avdd_com & vdd_arm short circuit */\r
94 static struct lkg_maxvolt lkg_volt_table[] = {\r
95         {.leakage_level = 3,    .maxvolt = 1350 * 1000},\r
96         {.leakage_level = 15,   .maxvolt = 1250 * 1000},\r
97 };\r
98 #endif\r
99 static int leakage_level = 0;\r
100 #define MHZ     (1000 * 1000)\r
101 #define KHZ     (1000)\r
102 // Delayline bound for nandc = 148.5MHz, Varm = Vlog = 1.00V\r
103 #define HIGH_DELAYLINE  125\r
104 #define LOW_DELAYLINE   125\r
105 static u8 rk30_get_avs_val(void);\r
106 void dvfs_adjust_table_lmtvolt(struct clk *clk, struct cpufreq_frequency_table *table)\r
107 {\r
108         int i = 0;\r
109         unsigned int maxvolt = 0;\r
110         if (IS_ERR_OR_NULL(clk) || IS_ERR_OR_NULL(table)) {\r
111                 DVFS_ERR("%s: clk error OR table error\n", __func__);\r
112                 return ;\r
113         }\r
114 \r
115         leakage_level = rk_leakage_val();\r
116         printk("DVFS MSG: %s: %s get leakage_level = %d\n", clk->name, __func__, leakage_level);\r
117         if (leakage_level == 0) {\r
118 \r
119                 /*\r
120                  * This is for delayline auto scale voltage, \r
121                  * FIXME: HIGH_DELAYLINE / LOW_DELAYLINE value maybe redefined under\r
122                  * Varm = Vlog = 1.00V.\r
123                  * Warning: this value is frequency/voltage sensitive, care\r
124                  * about Freq nandc/Volt log.\r
125                  *\r
126                  */\r
127 \r
128                 unsigned long delayline_val = 0;\r
129                 unsigned long high_delayline = 0, low_delayline = 0;\r
130                 unsigned long rate_nandc = 0;\r
131                 rate_nandc = clk_get_rate(clk_get(NULL, "nandc")) / KHZ;\r
132                 printk("Get nandc rate = %lu KHz\n", rate_nandc);\r
133                 high_delayline = HIGH_DELAYLINE * 148500 / rate_nandc;\r
134                 low_delayline = LOW_DELAYLINE * 148500 / rate_nandc;\r
135                 delayline_val = rk30_get_avs_val();\r
136                 printk("This chip no leakage msg, use delayline instead, val = %lu.(HDL=%lu, LDL=%lu)\n",\r
137                                 delayline_val, high_delayline, low_delayline);\r
138 \r
139                 if (delayline_val >= high_delayline) {\r
140                         leakage_level = 4;      //same as leakage_level > 4\r
141 \r
142                 } else if (delayline_val <= low_delayline) {\r
143                         leakage_level = 1;\r
144                         printk("Delayline TOO LOW, high voltage request\n");\r
145 \r
146                 } else\r
147                         leakage_level = 2;      //same as leakage_level = 3\r
148         }\r
149 \r
150         for (i = 0; i < ARRAY_SIZE(lkg_volt_table); i++) {\r
151                 if (leakage_level <= lkg_volt_table[i].leakage_level) {\r
152                         maxvolt = lkg_volt_table[i].maxvolt;\r
153                         break;\r
154                 }\r
155         }\r
156 \r
157         for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {\r
158                 if (table[i].index > maxvolt) {\r
159                         printk("\t\tadjust table freq=%d KHz, index=%d mV", table[i].frequency, table[i].index);\r
160                         table[i].index = maxvolt;\r
161                         printk(" to index=%d mV\n", table[i].index);\r
162                 }\r
163         }\r
164 }\r
165 #endif\r
166 \r
167 //static struct clk_node *dvfs_clk_cpu;\r
168 static struct vd_node vd_core;\r
169 int dvfs_target(struct clk *clk, unsigned long rate_hz)\r
170 {\r
171         struct clk_node *dvfs_clk;\r
172         int volt_new = 0, clk_volt_store = 0;\r
173         struct cpufreq_frequency_table clk_fv;\r
174         int ret = 0;\r
175         unsigned long rate_new, rate_old;\r
176 \r
177         if (!clk) {\r
178                 DVFS_ERR("%s is not a clk\n", __func__);\r
179                 return -1;\r
180         }\r
181         dvfs_clk = clk_get_dvfs_info(clk);\r
182         DVFS_DBG("enter %s: clk(%s) rate = %lu Hz\n", __func__, dvfs_clk->name, rate_hz);\r
183 \r
184         if (!dvfs_clk || dvfs_clk->vd == NULL || IS_ERR_OR_NULL(dvfs_clk->vd->regulator)) {\r
185                 DVFS_ERR("dvfs(%s) is not register regulator\n", dvfs_clk->name);\r
186                 return -1;\r
187         }\r
188 \r
189         if (dvfs_clk->vd->volt_set_flag == DVFS_SET_VOLT_FAILURE) {\r
190                 /* It means the last time set voltage error */\r
191                 ret = dvfs_reset_volt(dvfs_clk->vd);\r
192                 if (ret < 0) {\r
193                         return -1;\r
194                 }\r
195         }\r
196 \r
197         /* Check limit rate */\r
198         if (rate_hz < dvfs_clk->min_rate) {\r
199                 rate_hz = dvfs_clk->min_rate;\r
200         } else if (rate_hz > dvfs_clk->max_rate) {\r
201                 rate_hz = dvfs_clk->max_rate;\r
202         }\r
203 \r
204         /* need round rate */\r
205         rate_old = clk_get_rate(clk);\r
206         rate_new = clk_round_rate_nolock(clk, rate_hz);\r
207         if(rate_new == rate_old)\r
208                 return 0;\r
209 \r
210         DVFS_DBG("dvfs(%s) round rate (%lu)(rount %lu) old (%lu)\n",\r
211                         dvfs_clk->name, rate_hz, rate_new, rate_old);\r
212 \r
213         /* find the clk corresponding voltage */\r
214         if (0 != dvfs_clk_get_ref_volt(dvfs_clk, rate_new / 1000, &clk_fv)) {\r
215                 DVFS_ERR("dvfs(%s) rate %luhz is larger,not support\n", dvfs_clk->name, rate_hz);\r
216                 return -1;\r
217         }\r
218         clk_volt_store = dvfs_clk->set_volt;\r
219         dvfs_clk->set_volt = clk_fv.index;\r
220         volt_new = dvfs_vd_get_newvolt_byclk(dvfs_clk);\r
221         DVFS_DBG("%s,%s,new rate=%lu(was=%lu),new volt=%lu,(was=%d)\n",__FUNCTION__,dvfs_clk->name,rate_new,\r
222                         rate_old,volt_new,dvfs_clk->vd->cur_volt);\r
223 \r
224         /* if up the rate */\r
225         if (rate_new > rate_old) {\r
226                 ret = dvfs_scale_volt_direct(dvfs_clk->vd, volt_new);\r
227                 if (ret < 0)\r
228                         goto fail_roll_back;\r
229         }\r
230 \r
231         /* scale rate */\r
232         if (dvfs_clk->clk_dvfs_target) {\r
233                 ret = dvfs_clk->clk_dvfs_target(clk, rate_new, clk_set_rate_locked);\r
234         } else {\r
235                 ret = clk_set_rate_locked(clk, rate_new);\r
236         }\r
237 \r
238         if (ret < 0) {\r
239                 DVFS_ERR("%s set rate err\n", __func__);\r
240                 goto fail_roll_back;\r
241         }\r
242         dvfs_clk->set_freq = rate_new / 1000;\r
243 \r
244         DVFS_DBG("dvfs %s set rate %lu ok\n", dvfs_clk->name, clk_get_rate(clk));\r
245 \r
246         /* if down the rate */\r
247         if (rate_new < rate_old) {\r
248                 ret = dvfs_scale_volt_direct(dvfs_clk->vd, volt_new);\r
249                 if (ret < 0)\r
250                         goto out;\r
251         }\r
252 \r
253         return ret;\r
254 fail_roll_back:\r
255         dvfs_clk->set_volt = clk_volt_store;\r
256 out:\r
257         return -1;\r
258 }\r
259 \r
260 \r
261 /*****************************init**************************/\r
262 /**\r
263  * rate must be raising sequence\r
264  */\r
265 static struct cpufreq_frequency_table cpu_dvfs_table[] = {\r
266         // {.frequency  = 48 * DVFS_KHZ, .index = 920*DVFS_MV},\r
267         // {.frequency  = 126 * DVFS_KHZ, .index        = 970 * DVFS_MV},\r
268         // {.frequency  = 252 * DVFS_KHZ, .index        = 1040 * DVFS_MV},\r
269         // {.frequency  = 504 * DVFS_KHZ, .index        = 1050 * DVFS_MV},\r
270         {.frequency     = 816 * DVFS_KHZ, .index        = 1050 * DVFS_MV},\r
271         // {.frequency  = 1008 * DVFS_KHZ, .index       = 1100 * DVFS_MV},\r
272         {.frequency     = CPUFREQ_TABLE_END},\r
273 };\r
274 \r
275 static struct cpufreq_frequency_table ddr_dvfs_table[] = {\r
276         // {.frequency = 100 * DVFS_KHZ, .index = 1100 * DVFS_MV},\r
277         {.frequency = 200 * DVFS_KHZ, .index = 1000 * DVFS_MV},\r
278         {.frequency = 300 * DVFS_KHZ, .index = 1050 * DVFS_MV},\r
279         {.frequency = 400 * DVFS_KHZ, .index = 1100 * DVFS_MV},\r
280         {.frequency = 500 * DVFS_KHZ, .index = 1150 * DVFS_MV},\r
281         {.frequency = 600 * DVFS_KHZ, .index = 1200 * DVFS_MV},\r
282         {.frequency = CPUFREQ_TABLE_END},\r
283 };\r
284 \r
285 static struct cpufreq_frequency_table gpu_dvfs_table[] = {\r
286         {.frequency = 90 * DVFS_KHZ, .index = 1100 * DVFS_MV},\r
287         {.frequency = 180 * DVFS_KHZ, .index = 1150 * DVFS_MV},\r
288         {.frequency = 300 * DVFS_KHZ, .index = 1100 * DVFS_MV},\r
289         {.frequency = 400 * DVFS_KHZ, .index = 1150 * DVFS_MV},\r
290         {.frequency = 500 * DVFS_KHZ, .index = 1200 * DVFS_MV},\r
291         {.frequency = CPUFREQ_TABLE_END},\r
292 };\r
293 #if 0\r
294 static struct cpufreq_frequency_table peri_aclk_dvfs_table[] = {\r
295         {.frequency = 100 * DVFS_KHZ, .index = 1000 * DVFS_MV},\r
296         {.frequency = 200 * DVFS_KHZ, .index = 1050 * DVFS_MV},\r
297         {.frequency = 300 * DVFS_KHZ, .index = 1070 * DVFS_MV},\r
298         {.frequency = 500 * DVFS_KHZ, .index = 1100 * DVFS_MV},\r
299         {.frequency = CPUFREQ_TABLE_END},\r
300 };\r
301 #endif\r
302 static struct cpufreq_frequency_table vpu_dvfs_table[] = {\r
303         {.frequency = 266 * DVFS_KHZ, .index = 1100 * DVFS_MV},\r
304         {.frequency = 300 * DVFS_KHZ, .index = 1100 * DVFS_MV},\r
305         {.frequency = 400 * DVFS_KHZ, .index = 1200 * DVFS_MV},\r
306         {.frequency = CPUFREQ_TABLE_END},\r
307 };\r
308 \r
309 static struct cpufreq_frequency_table dep_cpu2core_table[] = {\r
310         // {.frequency = 252 * DVFS_KHZ, .index    = 1025 * DVFS_MV},\r
311         // {.frequency = 504 * DVFS_KHZ, .index    = 1025 * DVFS_MV},\r
312         {.frequency = 816 * DVFS_KHZ, .index    = 1050 * DVFS_MV},//logic 1.050V\r
313         // {.frequency = 1008 * DVFS_KHZ,.index    = 1050 * DVFS_MV},\r
314         // {.frequency = 1200 * DVFS_KHZ,.index    = 1050 * DVFS_MV},\r
315         // {.frequency = 1272 * DVFS_KHZ,.index    = 1050 * DVFS_MV},//logic 1.050V\r
316         // {.frequency = 1416 * DVFS_KHZ,.index    = 1100 * DVFS_MV},//logic 1.100V\r
317         // {.frequency = 1512 * DVFS_KHZ,.index    = 1125 * DVFS_MV},//logic 1.125V\r
318         // {.frequency = 1608 * DVFS_KHZ,.index    = 1175 * DVFS_MV},//logic 1.175V\r
319         {.frequency     = CPUFREQ_TABLE_END},\r
320 };\r
321 \r
322 static struct vd_node vd_cpu = {\r
323         .name           = "vd_cpu",\r
324         .regulator_name = "vdd_cpu",\r
325         .volt_set_flag  = DVFS_SET_VOLT_FAILURE,\r
326         .vd_dvfs_target = dvfs_target,\r
327 };\r
328 \r
329 static struct vd_node vd_core = {\r
330         .name           = "vd_core",\r
331         .regulator_name = "vdd_core",\r
332         .volt_set_flag  = DVFS_SET_VOLT_FAILURE,\r
333         .vd_dvfs_target = dvfs_target,\r
334 };\r
335 \r
336 static struct vd_node vd_rtc = {\r
337         .name           = "vd_rtc",\r
338         .regulator_name = "vdd_rtc",\r
339         .volt_set_flag  = DVFS_SET_VOLT_FAILURE,\r
340         .vd_dvfs_target = NULL,\r
341 };\r
342 \r
343 static struct vd_node *rk30_vds[] = {&vd_cpu, &vd_core, &vd_rtc};\r
344 \r
345 static struct pd_node pd_a9_0 = {\r
346         .name                   = "pd_a9_0",\r
347         .vd                     = &vd_cpu,\r
348 };\r
349 static struct pd_node pd_a9_1 = {\r
350         .name                   = "pd_a9_1",\r
351         .vd                     = &vd_cpu,\r
352 };\r
353 static struct pd_node pd_debug = {\r
354         .name                   = "pd_debug",\r
355         .vd                     = &vd_cpu,\r
356 };\r
357 static struct pd_node pd_scu = {\r
358         .name                   = "pd_scu",\r
359         .vd                     = &vd_cpu,\r
360 };\r
361 static struct pd_node pd_video = {\r
362         .name                   = "pd_video",\r
363         .vd                     = &vd_core,\r
364 };\r
365 static struct pd_node pd_vio = {\r
366         .name                   = "pd_vio",\r
367         .vd                     = &vd_core,\r
368 };\r
369 static struct pd_node pd_gpu = {\r
370         .name                   = "pd_gpu",\r
371         .vd                     = &vd_core,\r
372 };\r
373 static struct pd_node pd_peri = {\r
374         .name                   = "pd_peri",\r
375         .vd                     = &vd_core,\r
376 };\r
377 static struct pd_node pd_cpu = {\r
378         .name                   = "pd_cpu",\r
379         .vd                     = &vd_core,\r
380 };\r
381 static struct pd_node pd_alive = {\r
382         .name                   = "pd_alive",\r
383         .vd                     = &vd_core,\r
384 };\r
385 static struct pd_node pd_rtc = {\r
386         .name                   = "pd_rtc",\r
387         .vd                     = &vd_rtc,\r
388 };\r
389 #define LOOKUP_PD(_ppd) \\r
390 {       \\r
391         .pd     = _ppd, \\r
392 }\r
393 static struct pd_node_lookup rk30_pds[] = {\r
394         LOOKUP_PD(&pd_a9_0),\r
395         LOOKUP_PD(&pd_a9_1),\r
396         LOOKUP_PD(&pd_debug),\r
397         LOOKUP_PD(&pd_scu),\r
398         LOOKUP_PD(&pd_video),\r
399         LOOKUP_PD(&pd_vio),\r
400         LOOKUP_PD(&pd_gpu),\r
401         LOOKUP_PD(&pd_peri),\r
402         LOOKUP_PD(&pd_cpu),\r
403         LOOKUP_PD(&pd_alive),\r
404         LOOKUP_PD(&pd_rtc),\r
405 };\r
406 \r
407 #define CLK_PDS(_ppd) \\r
408 {       \\r
409         .pd     = _ppd, \\r
410 }\r
411 \r
412 static struct pds_list cpu_pds[] = {\r
413         CLK_PDS(&pd_a9_0),\r
414         CLK_PDS(&pd_a9_1),\r
415         CLK_PDS(NULL),\r
416 };\r
417 \r
418 static struct pds_list ddr_pds[] = {\r
419         CLK_PDS(&pd_cpu),\r
420         CLK_PDS(NULL),\r
421 };\r
422 \r
423 static struct pds_list gpu_pds[] = {\r
424         CLK_PDS(&pd_gpu),\r
425         CLK_PDS(NULL),\r
426 };\r
427 #if 0\r
428 static struct pds_list aclk_periph_pds[] = {\r
429         CLK_PDS(&pd_peri),\r
430         CLK_PDS(NULL),\r
431 };\r
432 #endif\r
433 static struct pds_list aclk_vepu_pds[] = {\r
434         CLK_PDS(&pd_video),\r
435         CLK_PDS(NULL),\r
436 };\r
437 \r
438 #define RK_CLKS(_clk_name, _ppds, _dvfs_table, _dvfs_nb) \\r
439 { \\r
440         .name   = _clk_name, \\r
441         .pds = _ppds,\\r
442         .dvfs_table = _dvfs_table,      \\r
443         .dvfs_nb        = _dvfs_nb,     \\r
444 }\r
445 \r
446 static struct clk_node rk30_clks[] = {\r
447         RK_CLKS("cpu", cpu_pds, cpu_dvfs_table, &rk_dvfs_clk_notifier),\r
448         RK_CLKS("ddr", ddr_pds, ddr_dvfs_table, &rk_dvfs_clk_notifier),\r
449         RK_CLKS("gpu", gpu_pds, gpu_dvfs_table, &rk_dvfs_clk_notifier),\r
450         RK_CLKS("aclk_vepu", aclk_vepu_pds, vpu_dvfs_table, &rk_dvfs_clk_notifier),\r
451         //RK_CLKS("aclk_periph", aclk_periph_pds, peri_aclk_dvfs_table, &rk_dvfs_clk_notifier),\r
452 };\r
453 \r
454 #define RK_DEPPENDS(_clk_name, _pvd, _dep_table) \\r
455 { \\r
456         .clk_name       = _clk_name, \\r
457         .dep_vd         = _pvd,\\r
458         .dep_table      = _dep_table,   \\r
459 }\r
460 \r
461 static struct depend_lookup rk30_depends[] = {\r
462         RK_DEPPENDS("cpu", &vd_core, dep_cpu2core_table),\r
463         //RK_DEPPENDS("gpu", &vd_cpu, NULL),\r
464         //RK_DEPPENDS("gpu", &vd_cpu, NULL),\r
465 };\r
466 \r
467 \r
468 static struct avs_ctr_st rk292x_avs_ctr;\r
469 \r
470 int rk292x_dvfs_init(void)\r
471 {\r
472         int i = 0;\r
473         for (i = 0; i < ARRAY_SIZE(rk30_vds); i++) {\r
474                 rk_regist_vd(rk30_vds[i]);\r
475         }\r
476         for (i = 0; i < ARRAY_SIZE(rk30_pds); i++) {\r
477                 rk_regist_pd(&rk30_pds[i]);\r
478         }\r
479         for (i = 0; i < ARRAY_SIZE(rk30_clks); i++) {\r
480                 rk_regist_clk(&rk30_clks[i]);\r
481         }\r
482         for (i = 0; i < ARRAY_SIZE(rk30_depends); i++) {\r
483                 rk_regist_depends(&rk30_depends[i]);\r
484         }\r
485         //dvfs_clk_cpu = dvfs_get_dvfs_clk_byname("cpu");\r
486         avs_board_init(&rk292x_avs_ctr);\r
487         return 0;\r
488 }\r
489 \r
490 /******************************rk292x avs**************************************************/\r
491 \r
492 static void __iomem *rk292x_nandc_base;\r
493 #define nandc_readl(offset)     readl_relaxed(rk292x_nandc_base + offset)\r
494 #define nandc_writel(v, offset) do { writel_relaxed(v, rk292x_nandc_base + offset); dsb(); } while (0)\r
495 static u8 rk292x_get_avs_val(void)\r
496 {\r
497         u32 nanc_save_reg[4];\r
498         unsigned long flags;\r
499         u32 paramet = 0;\r
500         u32 count = 100;\r
501         if(rk292x_nandc_base == NULL)   \r
502                 return 0;\r
503         preempt_disable();\r
504         local_irq_save(flags);\r
505 \r
506         nanc_save_reg[0] = nandc_readl(0);\r
507         nanc_save_reg[1] = nandc_readl(0x130);\r
508         nanc_save_reg[2] = nandc_readl(0x134);\r
509         nanc_save_reg[3] = nandc_readl(0x158);\r
510 \r
511         nandc_writel(nanc_save_reg[0] | 0x1 << 14, 0);\r
512         nandc_writel(0x5, 0x130);\r
513 \r
514         /* Just break lock status */\r
515         nandc_writel(0x1, 0x158);\r
516         nandc_writel(0x7, 0x158);\r
517         nandc_writel(0x21, 0x134);\r
518 \r
519         while(count--) {\r
520                 paramet = nandc_readl(0x138);\r
521                 if((paramet & 0x1))\r
522                         break;\r
523                 udelay(1);\r
524         };\r
525         paramet = (paramet >> 1) & 0xff;\r
526         nandc_writel(nanc_save_reg[0], 0);\r
527         nandc_writel(nanc_save_reg[1], 0x130);\r
528         nandc_writel(nanc_save_reg[2], 0x134);\r
529         nandc_writel(nanc_save_reg[3], 0x158);\r
530 \r
531         local_irq_restore(flags);\r
532         preempt_enable();\r
533         return (u8)paramet;\r
534 \r
535 }\r
536 \r
537 void rk292x_avs_init(void)\r
538 {\r
539         rk292x_nandc_base = ioremap(RK2928_NANDC_PHYS, RK2928_NANDC_SIZE);\r
540         //avs_init_val_get(0,1150000,"board_init");\r
541 }\r
542 \r
543 static struct avs_ctr_st rk292x_avs_ctr = {\r
544         .avs_init               =rk292x_avs_init,\r
545         .avs_get_val    = rk292x_get_avs_val,\r
546 };\r