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