tizen 2.4 release
[kernel/u-boot-tm1.git] / arch / arm / cpu / armv7 / sc8830 / dcdc_cal.c
1 #include <common.h>
2 #include <asm/io.h>
3 #include <asm/arch/adc_drvapi.h>
4 #include <asm/arch/adi_hal_internal.h>
5 #include <asm/arch/sprd_reg.h>
6
7 //#define DEBUG
8
9 #ifdef DEBUG
10 #undef debug
11 #define debug(format, arg...) printf("\t" format, ## arg)
12 #define debug2(format, arg...) printf("\t\t" format, ## arg)
13 #else
14 #undef debug
15 #define debug(format, arg...)
16 #define debug2(format, arg...)
17 #endif
18 #define debug0(format, arg...)
19
20 /* abs() handles unsigned and signed longs, ints, shorts and chars.  For all input types abs()
21  * returns a signed long.
22  * abs() should not be used for 64-bit types (s64, u64, long long) - use abs64() for those.*/
23 #define abs(x) ({                                                                       \
24                                 long ret;                                                       \
25                                 if (sizeof(x) == sizeof(long)) {                \
26                                         long __x = (x);                         \
27                                         ret = (__x < 0) ? -__x : __x;           \
28                                 } else {                                                        \
29                                         int __x = (x);                                  \
30                                         ret = (__x < 0) ? -__x : __x;           \
31                                 }                                                               \
32                                 ret;                                                            \
33                         })
34
35
36 #undef ffs
37 #undef fls
38
39 /* On ARMv5 and above those functions can be implemented around the clz instruction for
40  * much better code efficiency.         */
41
42 static inline int fls(int x)
43 {
44         int ret;
45
46         asm("clz\t%0, %1": "=r"(ret):"r"(x));
47         ret = 32 - ret;
48         return ret;
49 }
50
51 #define __fls(x) (fls(x) - 1)
52 #define ffs(x) ({ unsigned long __t = (x); fls(__t & -__t); })
53 #define __ffs(x) (ffs(x) - 1)
54 #define ffz(x) __ffs( ~(x) )
55
56 #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
57
58 #define MEASURE_TIMES                           (15)
59
60 #define ADC_DROP_CNT    ( DIV_ROUND(MEASURE_TIMES, 5) )
61 static int __average(int a[], int N)
62 {
63         int i, sum = 0;
64         for (i = 0; i < N; i++)
65                 sum += a[i];
66         return DIV_ROUND(sum, N);
67 }
68
69 static void bubble_sort(int a[], int N)
70 {
71         int i, j, t;
72         for (i = 0; i < N - 1; i++) {
73                 for (j = i + 1; j < N; j++) {
74                         if (a[i] > a[j]) {
75                                 t = a[i];
76                                 a[i] = a[j];
77                                 a[j] = t;
78                         }
79                 }
80         }
81 }
82
83 static int sci_adc_request(int channel)
84 {
85         int i;
86         int results[MEASURE_TIMES];
87
88         if (-1 == ADC_GetValues(channel, ADC_SCALE_3V, MEASURE_TIMES, results)) {
89                 return 0;
90         }
91
92         bubble_sort(results, MEASURE_TIMES);
93
94         /* dump results */
95         for (i = 0; i < MEASURE_TIMES; i++) {
96                 printf("%d ", results[i]);
97         }
98         printf("\n");
99
100         return results[MEASURE_TIMES / 2];
101 }
102
103 #define RATIO(_n_, _d_) (_n_ << 16 | _d_)
104
105 static int sci_adc_ratio(int channel, int mux)
106 {
107         switch (channel) {
108                 case 5://vbat
109                         return RATIO(7, 29);
110                 case 13://dcdcarm
111                 case 14://dcdccore
112                         return RATIO(4, 5);
113                 case 15://dcdcmem
114                         return RATIO(3, 5);
115                 case 16://dcdcgen
116                         return RATIO(4, 9);
117                 case 18://dcdcwrf
118                         return RATIO(1, 3);
119                 case 21://ldo_mux0
120                         return RATIO(1, 3);
121                 case 22://ldo_mux1
122                         if ((mux & 0xFFFF) == BIT(5))
123                                 return RATIO(1, 3);
124                         else
125                                 return RATIO(1, 2);
126                 case 23://ldo_mux2
127                         return RATIO(1, 3);
128                 default:
129                         return RATIO(1, 1);
130         }
131         return RATIO(1, 1);
132 }
133
134 static u32 bat_numerators, bat_denominators = 0;
135 extern uint16_t sprdbat_auxadc2vbatvol (uint16_t adcvalue);
136
137 static int sci_adc_vol_request(int channel, int mux)
138 {
139         int adc_res;
140         adc_res = sci_adc_request(channel);
141         if (adc_res) {
142                 u32 res, chan_numerators, chan_denominators;
143                 res = (u32) sci_adc_ratio(channel, mux);
144                 chan_numerators = res >> 16;
145                 chan_denominators = res & 0xffff;
146                 return sprdbat_auxadc2vbatvol(adc_res)
147                     * (bat_numerators * chan_denominators)
148                     / (bat_denominators * chan_numerators);
149         }
150         return 0;
151 }
152
153 /* Simple shorthand for a section definition */
154 #ifndef __section
155 # define __section(S) __attribute__ ((__section__(#S)))
156 #endif
157
158 #define __init0 __section(.rodata.regu.init0)
159 #define __init1 __section(.rodata.regu.init1)
160 #define __init2 __section(.rodata.regu.init2)
161
162 static const u32 __init0 __init_begin = 0xeeeebbbb;
163 static const u32 __init2 __init_end = 0xddddeeee;
164
165 struct regulator_regs {
166         int typ;
167         u32 pd_set, pd_set_bit;
168         /* at new feature, some LDOs had only set, no rst bits.
169          * and DCDCs voltage and trimming controller is the same register */
170         u32 pd_rst, pd_rst_bit;
171         u32 slp_ctl, slp_ctl_bit;
172         u32 vol_trm, vol_trm_bits;
173         u32 cal_ctl, cal_ctl_bits;
174         u32 vol_def;
175         u32 vol_ctl, vol_ctl_bits;
176         u32 vol_sel_cnt, vol_sel[];
177 };
178
179 struct regulator_desc {
180         int id;
181         const char *name;
182         const struct regulator_regs *regs;
183 };
184
185 #define REGU_VERIFY_DLY (1000)  /*ms */
186 #define SCI_REGU_REG(VDD, TYP, PD_SET, SET_BIT, PD_RST, RST_BIT, SLP_CTL, SLP_CTL_BIT, \
187                      VOL_TRM, VOL_TRM_BITS, CAL_CTL, CAL_CTL_BITS, VOL_DEF,     \
188                      VOL_CTL, VOL_CTL_BITS, VOL_SEL_CNT, ...)                                   \
189         static const struct regulator_regs REGS_##VDD = {                                               \
190                 .typ = TYP,                                                     \
191                 .pd_set = PD_SET,                                       \
192                 .pd_set_bit = SET_BIT,                                  \
193                 .pd_rst = PD_RST,                                               \
194                 .pd_rst_bit = RST_BIT,                                  \
195                 .slp_ctl = SLP_CTL,                                             \
196                 .slp_ctl_bit = SLP_CTL_BIT,                             \
197                 .vol_trm = VOL_TRM,                                     \
198                 .vol_trm_bits = VOL_TRM_BITS,                   \
199                 .cal_ctl = CAL_CTL,                                     \
200                 .cal_ctl_bits = CAL_CTL_BITS,                   \
201                 .vol_def = VOL_DEF,                                     \
202                 .vol_ctl = VOL_CTL,                                     \
203                 .vol_ctl_bits = VOL_CTL_BITS,                   \
204                 .vol_sel_cnt = VOL_SEL_CNT,                     \
205                 .vol_sel = {__VA_ARGS__},                               \
206         };                                                                              \
207         struct regulator_desc __init1 DESC_##VDD = {    \
208                 .id = -1,                                                               \
209                 .name = #VDD,                                           \
210                 .regs = &REGS_##VDD,                                    \
211         };                                                                              \
212
213
214 #include <asm/arch/chip_x35/sprd_reg_regulator_map.h>
215
216
217 typedef struct dcdc_cali_tag
218 {
219         char name[32];
220         int     cali_vol;                                                               /* ctl_vol - to_vol */
221 } dcdc_cali_t;
222
223 #define CALI_VOL_ADDR                                           0x1F00
224 #define CALI_VOL_ADDR_NUM                                       8
225
226 static dcdc_cali_t* get_cali_addr()
227 {
228         dcdc_cali_t *p = (dcdc_cali_t *)CALI_VOL_ADDR;
229         u32 i = 0;
230
231         while ((*(u32 *)p != 0) && (i < 4))
232         {
233                 p++;
234                 i++;
235         }
236
237         if (i >= 4)
238                 return (dcdc_cali_t*)0;
239         else
240                 return p;
241 }
242
243 /* standard dcdc ops*/
244 static int __dcdc_is_orig(struct regulator_desc *desc)
245 {
246         if (0 == strcmp(desc->name, "vddmem") || 0 == strcmp(desc->name, "vddwrf"))
247                 if (ANA_REG_GET(ANA_REG_GLB_CHIP_ID_LOW) & 0xff) /* BA CHIP */
248                         return 0;
249         return 1;
250 }
251
252 static int dcdc_get_trimming_step(struct regulator_desc *desc, int to_vol)
253 {
254         /* FIXME: vddmem step 200/32mV */
255         if (0 == strcmp(desc->name, "vddmem") || 0 == strcmp(desc->name, "vddwrf"))
256         {
257                 return 1000 * 200 / 32; /*uV */
258         }
259         return 1000 * 100 / 32; /*uV */
260 }
261
262 static int __match_dcdc_vol(struct regulator_desc *desc, u32 vol)
263 {
264         int i, j = -1;
265         int ds, min_ds = 100;   /* mV, the max range of small voltage */
266         const struct regulator_regs *regs = desc->regs;
267
268         for (i = 0; i < regs->vol_sel_cnt; i++) {
269                 ds = vol - regs->vol_sel[i];
270                 if (ds >= 0 && ds < min_ds) {
271                         min_ds = ds;
272                         j = i;
273                 }
274         }
275
276         if (j < 0 && !__dcdc_is_orig(desc)) {
277                 for (i = 0; i < regs->vol_sel_cnt; i++) {
278                         ds = abs(vol - regs->vol_sel[i]);
279                         if (ds < min_ds) {
280                                 min_ds = ds;
281                                 j = i;
282                         }
283                 }
284         }
285
286         return j;
287 }
288
289 static int dcdc_get_voltage(struct regulator_desc *desc)
290 {
291         const struct regulator_regs *regs = desc->regs;
292         u32 mv;
293         int cal = 0;            /* uV */
294         int i, shft = __ffs(regs->vol_ctl_bits);
295
296         i = (ANA_REG_GET(regs->vol_ctl) & regs->vol_ctl_bits) >> shft;
297         mv = regs->vol_sel[i];
298
299         cal = (ANA_REG_GET(regs->vol_trm) & regs->vol_trm_bits) >> __ffs(regs->vol_trm_bits);
300         if (!__dcdc_is_orig(desc)) {
301                 cal -= 0x10;
302         }
303         cal *= dcdc_get_trimming_step(desc, 0); /*uV */
304
305         debug0("%s %d +%dmv\n", desc->name, mv, cal / 1000);
306         return mv + cal / 1000;
307 }
308
309 static int dcdc_set_voltage(struct regulator_desc *desc, int min_mV, int max_mV)
310 {
311         const struct regulator_regs *regs = desc->regs;
312         int i, mv = min_mV;
313
314         /* found the closely vol ctrl bits */
315         i = __match_dcdc_vol(desc, mv);
316         if (i < 0) {
317                 debug2("%s: %s failed to match voltage: %d\n",__func__,desc->name,mv);
318                 return -1;
319         }
320
321         /* dcdc calibration control bits (default 0) small adjust voltage: 100/32mv ~= 3.125mv */
322         {
323                 int shft = __ffs(regs->vol_ctl_bits);
324                 int j = (mv - (int)regs->vol_sel[i]) * 1000 / dcdc_get_trimming_step(desc, mv);
325
326                 if (!__dcdc_is_orig(desc))
327                         j += 0x10;
328
329                 debug2("regu_dcdc %p (%s) %d = %d %+dmv (trim=%d);\n", regs, desc->name,
330                            mv, regs->vol_sel[i], mv - regs->vol_sel[i], j);
331
332                 if (j >= 0 && j < 32)
333                         ANA_REG_MSK_OR(regs->vol_ctl, j | (i << shft),
334                                 regs->vol_trm_bits | regs->vol_ctl_bits);
335         }
336         return 0;
337 }
338
339 static int dcdc_set_trimming(struct regulator_desc *desc, int def_vol, int to_vol, int adc_vol)
340 {
341         dcdc_cali_t *p = NULL;
342         int acc_vol = dcdc_get_trimming_step(desc, to_vol) / 1000;
343
344         /*FIXME: no need division?
345         int ctl_vol = DIV_ROUND_UP(def_vol * to_vol * 1000, adc_vol) + acc_vol; */
346         int ctl_vol = (def_vol - (adc_vol - to_vol)) + acc_vol;
347
348         p = get_cali_addr();
349         if (p != 0) {
350                 strcpy(p->name, desc->name);
351                 p->cali_vol = ctl_vol - to_vol;
352         }
353
354         return dcdc_set_voltage(desc, ctl_vol, ctl_vol);
355 }
356
357 static int ldo_get_voltage(struct regulator_desc *desc)
358 {
359         const struct regulator_regs *regs = desc->regs;
360         u32 vol;
361
362         if (regs->vol_trm && regs->vol_sel_cnt == 2) {
363                 int shft = __ffs(regs->vol_trm_bits);
364                 u32 trim =
365                     (ANA_REG_GET(regs->vol_trm) & regs->vol_trm_bits) >> shft;
366                 vol = regs->vol_sel[0] * 1000 + trim * regs->vol_sel[1];
367                 vol /= 1000;
368                 debug0("%s voltage %dmv\n", desc->name, vol);
369                 return vol;
370         }
371
372         return -1;
373 }
374
375 /* ldo trimming step about 0.625%, range 90% ~ 109.375%. that all maps as follow.
376
377         0x1F :  +9.375 : 109.375
378         0x1E :  +8.750 : 108.750
379         0x1D :  +8.125 : 108.125
380         0x1C :  +7.500 : 107.500
381         0x1B :  +6.875 : 106.875
382         0x1A :  +6.250 : 106.250
383         0x19 :  +5.625 : 105.625
384         0x18 :  +5.000 : 105.000
385         0x17 :  +4.375 : 104.375
386         0x16 :  +3.750 : 103.750
387         0x15 :  +3.125 : 103.125
388         0x14 :  +2.500 : 102.500
389         0x13 :  +1.875 : 101.875
390         0x12 :  +1.250 : 101.250
391         0x11 :  +0.625 : 100.625
392         0x10 :  +0.000 : 100.000
393         0x0F :  -0.625 : 99.375
394         0x0E :  -1.250 : 98.750
395         0x0D :  -1.875 : 98.125
396         0x0C :  -2.500 : 97.500
397         0x0B :  -3.125 : 96.875
398         0x0A :  -3.750 : 96.250
399         0x09 :  -4.375 : 95.625
400         0x08 :  -5.000 : 95.000
401         0x07 :  -5.625 : 94.375
402         0x06 :  -6.250 : 93.750
403         0x05 :  -6.875 : 93.125
404         0x04 :  -7.500 : 92.500
405         0x03 :  -8.125 : 91.875
406         0x02 :  -8.750 : 91.250
407         0x01 :  -9.375 : 90.625
408         0x00 : -10.000 : 90.000
409 */
410 static int ldo_set_trimming(struct regulator_desc *desc, int def_vol, int to_vol, int adc_vol)
411 {
412         const struct regulator_regs *regs = desc->regs;
413         int ret = -1;
414
415         if (regs->vol_trm) {
416                 /* assert 5 valid trim bits, R = V_IDEAL / V_ADCIN - 1 */
417                 u32 trim = DIV_ROUND_UP((to_vol * 100 - adc_vol * 90) * 32, (adc_vol * 20));
418                 if (trim > BIT(5) - 1)
419                         goto exit;
420                 debug2("regu %p (%s) trimming %d = %d %+d%%, got [%02X]\n",
421                         regs, desc->name, to_vol, adc_vol, (trim * 20 / 32 - 10), trim);
422
423                 ANA_REG_MSK_OR(regs->vol_trm,
424                                                 trim << __ffs(regs->vol_trm_bits),
425                                                 regs->vol_trm_bits);
426                 ret = 0;
427         }
428
429 exit:
430         return ret;
431 }
432
433 static int dcdc_get_trimming_vol(struct regulator_desc *desc)
434 {
435         int shft, trm_vol = 0;
436         int tmpVal;
437
438         shft = __ffs(desc->regs->vol_trm_bits);
439         tmpVal = (ANA_REG_GET(desc->regs->vol_trm) & desc->regs->vol_trm_bits) >> shft;
440
441         if (!__dcdc_is_orig(desc))
442                 tmpVal -= 0x10;
443
444         trm_vol = tmpVal * (dcdc_get_trimming_step(desc, trm_vol))/1000;
445
446         return trm_vol;
447 }
448
449 static int DCDC_Cal_One(struct regulator_desc *desc, int is_cal)
450 {
451         const struct regulator_regs *regs = desc->regs;
452         int def_vol = 0, to_vol = 0;
453         int adc_vol = 0, cal_vol = 0;
454         int ret = -1, adc_chan = regs->cal_ctl_bits >> 16;
455         u16 ldo_cal_sel = regs->cal_ctl_bits & 0xFFFF;
456
457         if (!adc_chan || !regs->vol_def)
458                 return -1;
459
460         if (ldo_cal_sel)
461                 ANA_REG_OR(regs->cal_ctl, ldo_cal_sel);
462
463         {
464                 u16 tmpVal;
465                 tmpVal = (ANA_REG_GET(regs->vol_ctl) & regs->vol_ctl_bits) >> __ffs(regs->vol_ctl_bits);
466                 if (regs->typ == 2)
467                         def_vol = to_vol = (int)regs->vol_sel[tmpVal] + dcdc_get_trimming_vol(desc);
468                 else if (regs->typ == 0)
469                         def_vol = to_vol = regs->vol_sel[tmpVal];
470         }
471
472         adc_vol = sci_adc_vol_request(adc_chan, ldo_cal_sel);
473         if (adc_vol <= 0) {
474                 debug("%s default %dmv, maybe not enable\n", desc->name, def_vol);
475                 goto exit;
476         }
477
478         cal_vol = abs(adc_vol - to_vol);
479         debug("%s default %dmv, from %dmv to %dmv, bias %c%d.%03d%%\n",
480               desc->name, def_vol, adc_vol, to_vol,
481               (adc_vol > to_vol) ? '+' : '-',
482               cal_vol * 100 / to_vol, cal_vol * 100 * 1000 / to_vol % 1000);
483
484         if (!def_vol || !to_vol || adc_vol <= 0)
485                 goto exit;
486
487         if (abs(adc_vol - def_vol) >= def_vol / 10)     /* adjust limit 10% */
488                 goto exit;
489         else if (cal_vol < to_vol / 100) {      /* bias 1% */
490                 goto exit;
491         }
492         else if (is_cal) {
493                 if (regs->typ == 2/*VDD_TYP_DCDC*/)
494                         ret = dcdc_set_trimming(desc, def_vol, to_vol, adc_vol);
495                 else if (regs->typ == 0/*VDD_TYP_LDO*/)
496                         ret = ldo_set_trimming(desc, def_vol, to_vol, adc_vol);
497         }
498
499 exit:
500         if (ldo_cal_sel)
501                 ANA_REG_BIC(regs->cal_ctl, ldo_cal_sel);
502
503         return 0;
504 }
505
506 int SC2713S_DCDC_Cal_ArmCore(void);
507 int DCDC_Cal_ArmCore(void)
508 {
509         u16 regVal;
510         u32 res;
511         struct regulator_desc *desc = NULL;
512         struct regulator_desc *desc_end = NULL;
513
514         printf("%s\n", __FUNCTION__);
515
516 #ifdef CONFIG_ADIE_SC2713S
517         if((sci_get_adie_chip_id() & ~0xFFF)== 0x2713C000)
518                 return SC2713S_DCDC_Cal_ArmCore();
519 #endif
520
521         /* mem arm core bits are [11:9]*/
522         regVal = ANA_REG_GET(ANA_REG_GLB_LDO_DCDC_PD_RTCCLR);
523         regVal |= BIT(11) | BIT(10) | BIT(9);
524         ANA_REG_SET(ANA_REG_GLB_LDO_DCDC_PD_RTCCLR, regVal);
525
526         /* enable sim0, sim2. */
527         regVal = ANA_REG_GET(ANA_REG_GLB_LDO_PD_CTRL);
528         regVal &= ~(BIT(2) | BIT(4));
529         ANA_REG_SET(ANA_REG_GLB_LDO_PD_CTRL, regVal);
530
531         /* FIXME: Update CHGMNG_AdcvalueToVoltage table before setup vbat ratio. */
532         /*ADC_CHANNEL_VBAT is 5*/
533         res = (u32) sci_adc_ratio(5, 0);
534         bat_numerators = res >> 16;
535         bat_denominators = res & 0xffff;
536
537         /* initialize 4 struct free */
538         memset((u8 *)CALI_VOL_ADDR , 0x00, (sizeof(dcdc_cali_t) * (CALI_VOL_ADDR_NUM)));
539
540         /* TODO: calibrate all DCDCs */
541         desc = (struct regulator_desc *)(&__init_begin + 1);
542
543         printf("%p (%x) -- %p -- %p (%x)\n", &__init_begin, __init_begin,
544                 desc, &__init_end, __init_end);
545
546         while (desc < (struct regulator_desc *)&__init_end) {
547                 if ((0 == strcmp("vddmem", desc->name))
548                         || (0 == strcmp("vddarm", desc->name))
549                         || (0 == strcmp("vddcore", desc->name))
550                         || (0 == strcmp("vddsim0", desc->name))
551                         || (0 == strcmp("vddsim2", desc->name))) {
552
553                         printf("\nCalibrate %s ...\n", desc->name);
554                         DCDC_Cal_One(desc, 1);
555                 }
556
557                 desc++;
558         }
559
560         /* wait a moment for LDOs ready */
561         udelay(200 * 1000);
562
563         /* TODO: verify all DCDCs */
564         desc = (struct regulator_desc *)(&__init_begin + 1);
565
566         while (desc < (struct regulator_desc *)&__init_end) {
567                 if ((0 == strcmp("vddmem", desc->name))
568                         || (0 == strcmp("vddarm", desc->name))
569                         || (0 == strcmp("vddcore", desc->name))
570                         || (0 == strcmp("vddsim0", desc->name))
571                         || (0 == strcmp("vddsim2", desc->name))) {
572
573                         printf("\nVerify %s ...\n", desc->name);
574                         DCDC_Cal_One(desc, 0);
575                 }
576
577                 desc++;
578         }
579
580         /* disable sim0, sim2. */
581         regVal |= (BIT(2) | BIT(4));
582         ANA_REG_SET(ANA_REG_GLB_LDO_PD_CTRL, regVal);
583
584         return 0;
585 }
586