blob: ce33d2fe129744a06d0822eec6e2473d1d1b6e88 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Andrii Tseglytskyi28095da2013-05-20 22:42:08 +00002/*
Andrii Tseglytskyi28095da2013-05-20 22:42:08 +00003 * Adaptive Body Bias programming sequence for OMAP family
4 *
5 * (C) Copyright 2013
6 * Texas Instruments, <www.ti.com>
7 *
8 * Andrii Tseglytskyi <andrii.tseglytskyi@ti.com>
Andrii Tseglytskyi28095da2013-05-20 22:42:08 +00009 */
10
Andrii Tseglytskyi28095da2013-05-20 22:42:08 +000011#include <asm/omap_common.h>
Nikita Kiryanovba827452013-12-08 14:29:19 +020012#include <asm/arch/clock.h>
Andrii Tseglytskyi28095da2013-05-20 22:42:08 +000013#include <asm/io.h>
14#include <asm/arch/sys_proto.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060015#include <linux/bitops.h>
Andrii Tseglytskyi28095da2013-05-20 22:42:08 +000016
17__weak s8 abb_setup_ldovbb(u32 fuse, u32 ldovbb)
18{
19 return -1;
20}
21
22static 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 */
Masahiro Yamadaeff8e682014-11-07 03:03:26 +090050 sys_rate = DIV_ROUND_CLOSEST(V_OSCK, 1000000);
51 clk_cycles = DIV_ROUND_CLOSEST(OMAP_ABB_CLOCK_CYCLES * 10, sys_rate);
52 sr2_cnt = DIV_ROUND_CLOSEST(OMAP_ABB_SETTLING_TIME * 10, clk_cycles);
Andrii Tseglytskyi28095da2013-05-20 22:42:08 +000053
54 setbits_le32(setup,
55 sr2_cnt << (ffs(OMAP_ABB_SETUP_SR2_WTCNT_VALUE_MASK) - 1));
56}
57
58void 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}