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