]>
Commit | Line | Data |
---|---|---|
4d0df9c1 | 1 | /* |
4d0df9c1 AT |
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 | * | |
1a459660 | 9 | * SPDX-License-Identifier: GPL-2.0+ |
4d0df9c1 AT |
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 | } |