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