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