]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/cpu/armv7/omap-common/abb.c
Add GPL-2.0+ SPDX-License-Identifier to source files
[karo-tx-uboot.git] / arch / arm / cpu / armv7 / omap-common / abb.c
1 /*
2  * Adaptive Body Bias programming sequence for OMAP family
3  *
4  * (C) Copyright 2013
5  * Texas Instruments, <www.ti.com>
6  *
7  * Andrii Tseglytskyi <andrii.tseglytskyi@ti.com>
8  *
9  * SPDX-License-Identifier:     GPL-2.0+
10  */
11
12 #include <common.h>
13 #include <asm/omap_common.h>
14 #include <asm/io.h>
15 #include <asm/arch/sys_proto.h>
16
17 __weak s8 abb_setup_ldovbb(u32 fuse, u32 ldovbb)
18 {
19         return -1;
20 }
21
22 static void abb_setup_timings(u32 setup)
23 {
24         u32 sys_rate, sr2_cnt, clk_cycles;
25
26         /*
27          * SR2_WTCNT_VALUE is the settling time for the ABB ldo after a
28          * transition and must be programmed with the correct time at boot.
29          * The value programmed into the register is the number of SYS_CLK
30          * clock cycles that match a given wall time profiled for the ldo.
31          * This value depends on:
32          * settling time of ldo in micro-seconds (varies per OMAP family),
33          * of clock cycles per SYS_CLK period (varies per OMAP family),
34          * the SYS_CLK frequency in MHz (varies per board)
35          * The formula is:
36          *
37          *                     ldo settling time (in micro-seconds)
38          * SR2_WTCNT_VALUE = ------------------------------------------
39          *                  (# system clock cycles) * (sys_clk period)
40          *
41          * Put another way:
42          *
43          * SR2_WTCNT_VALUE = settling time / (# SYS_CLK cycles / SYS_CLK rate))
44          *
45          * To avoid dividing by zero multiply both "# clock cycles" and
46          * "settling time" by 10 such that the final result is the one we want.
47          */
48
49         /* calculate SR2_WTCNT_VALUE */
50         sys_rate = DIV_ROUND(V_OSCK, 1000000);
51         clk_cycles = DIV_ROUND(OMAP_ABB_CLOCK_CYCLES * 10, sys_rate);
52         sr2_cnt = DIV_ROUND(OMAP_ABB_SETTLING_TIME * 10, clk_cycles);
53
54         setbits_le32(setup,
55                      sr2_cnt << (ffs(OMAP_ABB_SETUP_SR2_WTCNT_VALUE_MASK) - 1));
56 }
57
58 void abb_setup(u32 fuse, u32 ldovbb, u32 setup, u32 control,
59                u32 txdone, u32 txdone_mask, u32 opp)
60 {
61         u32 abb_type_mask, opp_sel_mask;
62
63         /* sanity check */
64         if (!setup || !control || !txdone)
65                 return;
66
67         /* setup ABB only in case of Fast or Slow OPP */
68         switch (opp) {
69         case OMAP_ABB_FAST_OPP:
70                 abb_type_mask = OMAP_ABB_SETUP_ACTIVE_FBB_SEL_MASK;
71                 opp_sel_mask = OMAP_ABB_CONTROL_FAST_OPP_SEL_MASK;
72                 break;
73         case OMAP_ABB_SLOW_OPP:
74                 abb_type_mask = OMAP_ABB_SETUP_ACTIVE_RBB_SEL_MASK;
75                 opp_sel_mask = OMAP_ABB_CONTROL_SLOW_OPP_SEL_MASK;
76                 break;
77         default:
78                return;
79         }
80
81         /*
82          * For some OMAP silicons additional setup for LDOVBB register is
83          * required. This is determined by data retrieved from corresponding
84          * OPP EFUSE register. Data, which is retrieved from EFUSE - is
85          * ABB enable/disable flag and VSET value, which must be copied
86          * to LDOVBB register. If function call fails - return quietly,
87          * it means no ABB is required for such silicon.
88          *
89          * For silicons, which don't require LDOVBB setup "fuse" and
90          * "ldovbb" offsets are not defined. ABB will be initialized in
91          * the common way for them.
92          */
93         if (fuse && ldovbb) {
94                 if (abb_setup_ldovbb(fuse, ldovbb))
95                         return;
96         }
97
98         /* clear ABB registers */
99         writel(0, setup);
100         writel(0, control);
101
102         /* configure timings, based on oscillator value */
103         abb_setup_timings(setup);
104
105         /* clear pending interrupts before setup */
106         setbits_le32(txdone, txdone_mask);
107
108         /* select ABB type */
109         setbits_le32(setup, abb_type_mask | OMAP_ABB_SETUP_SR2EN_MASK);
110
111         /* initiate ABB ldo change */
112         setbits_le32(control, opp_sel_mask | OMAP_ABB_CONTROL_OPP_CHANGE_MASK);
113
114         /* wait until transition complete */
115         if (!wait_on_value(txdone_mask, txdone_mask, (void *)txdone, LDELAY))
116                 puts("Error: ABB txdone is not set\n");
117
118         /* clear ABB tranxdone */
119         setbits_le32(txdone, txdone_mask);
120 }