Andrii Tseglytskyi | 28095da | 2013-05-20 22:42:08 +0000 | [diff] [blame] | 1 | /* |
| 2 | * |
| 3 | * 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> |
| 9 | * |
| 10 | * See file CREDITS for list of people who contributed to this |
| 11 | * project. |
| 12 | * |
| 13 | * This program is free software; you can redistribute it and/or |
| 14 | * modify it under the terms of the GNU General Public License as |
| 15 | * published by the Free Software Foundation; either version 2 of |
| 16 | * the License, or (at your option) any later version. |
| 17 | * |
| 18 | * This program is distributed in the hope that it will be useful, |
| 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 21 | * GNU General Public License for more details. |
| 22 | * |
| 23 | * You should have received a copy of the GNU General Public License |
| 24 | * along with this program; if not, write to the Free Software |
| 25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
| 26 | * MA 02111-1307 USA |
| 27 | */ |
| 28 | |
| 29 | #include <common.h> |
| 30 | #include <asm/omap_common.h> |
| 31 | #include <asm/io.h> |
| 32 | #include <asm/arch/sys_proto.h> |
| 33 | |
| 34 | __weak s8 abb_setup_ldovbb(u32 fuse, u32 ldovbb) |
| 35 | { |
| 36 | return -1; |
| 37 | } |
| 38 | |
| 39 | static void abb_setup_timings(u32 setup) |
| 40 | { |
| 41 | u32 sys_rate, sr2_cnt, clk_cycles; |
| 42 | |
| 43 | /* |
| 44 | * SR2_WTCNT_VALUE is the settling time for the ABB ldo after a |
| 45 | * transition and must be programmed with the correct time at boot. |
| 46 | * The value programmed into the register is the number of SYS_CLK |
| 47 | * clock cycles that match a given wall time profiled for the ldo. |
| 48 | * This value depends on: |
| 49 | * settling time of ldo in micro-seconds (varies per OMAP family), |
| 50 | * of clock cycles per SYS_CLK period (varies per OMAP family), |
| 51 | * the SYS_CLK frequency in MHz (varies per board) |
| 52 | * The formula is: |
| 53 | * |
| 54 | * ldo settling time (in micro-seconds) |
| 55 | * SR2_WTCNT_VALUE = ------------------------------------------ |
| 56 | * (# system clock cycles) * (sys_clk period) |
| 57 | * |
| 58 | * Put another way: |
| 59 | * |
| 60 | * SR2_WTCNT_VALUE = settling time / (# SYS_CLK cycles / SYS_CLK rate)) |
| 61 | * |
| 62 | * To avoid dividing by zero multiply both "# clock cycles" and |
| 63 | * "settling time" by 10 such that the final result is the one we want. |
| 64 | */ |
| 65 | |
| 66 | /* calculate SR2_WTCNT_VALUE */ |
| 67 | sys_rate = DIV_ROUND(V_OSCK, 1000000); |
| 68 | clk_cycles = DIV_ROUND(OMAP_ABB_CLOCK_CYCLES * 10, sys_rate); |
| 69 | sr2_cnt = DIV_ROUND(OMAP_ABB_SETTLING_TIME * 10, clk_cycles); |
| 70 | |
| 71 | setbits_le32(setup, |
| 72 | sr2_cnt << (ffs(OMAP_ABB_SETUP_SR2_WTCNT_VALUE_MASK) - 1)); |
| 73 | } |
| 74 | |
| 75 | void abb_setup(u32 fuse, u32 ldovbb, u32 setup, u32 control, |
| 76 | u32 txdone, u32 txdone_mask, u32 opp) |
| 77 | { |
| 78 | u32 abb_type_mask, opp_sel_mask; |
| 79 | |
| 80 | /* sanity check */ |
| 81 | if (!setup || !control || !txdone) |
| 82 | return; |
| 83 | |
| 84 | /* setup ABB only in case of Fast or Slow OPP */ |
| 85 | switch (opp) { |
| 86 | case OMAP_ABB_FAST_OPP: |
| 87 | abb_type_mask = OMAP_ABB_SETUP_ACTIVE_FBB_SEL_MASK; |
| 88 | opp_sel_mask = OMAP_ABB_CONTROL_FAST_OPP_SEL_MASK; |
| 89 | break; |
| 90 | case OMAP_ABB_SLOW_OPP: |
| 91 | abb_type_mask = OMAP_ABB_SETUP_ACTIVE_RBB_SEL_MASK; |
| 92 | opp_sel_mask = OMAP_ABB_CONTROL_SLOW_OPP_SEL_MASK; |
| 93 | break; |
| 94 | default: |
| 95 | return; |
| 96 | } |
| 97 | |
| 98 | /* |
| 99 | * For some OMAP silicons additional setup for LDOVBB register is |
| 100 | * required. This is determined by data retrieved from corresponding |
| 101 | * OPP EFUSE register. Data, which is retrieved from EFUSE - is |
| 102 | * ABB enable/disable flag and VSET value, which must be copied |
| 103 | * to LDOVBB register. If function call fails - return quietly, |
| 104 | * it means no ABB is required for such silicon. |
| 105 | * |
| 106 | * For silicons, which don't require LDOVBB setup "fuse" and |
| 107 | * "ldovbb" offsets are not defined. ABB will be initialized in |
| 108 | * the common way for them. |
| 109 | */ |
| 110 | if (fuse && ldovbb) { |
| 111 | if (abb_setup_ldovbb(fuse, ldovbb)) |
| 112 | return; |
| 113 | } |
| 114 | |
| 115 | /* clear ABB registers */ |
| 116 | writel(0, setup); |
| 117 | writel(0, control); |
| 118 | |
| 119 | /* configure timings, based on oscillator value */ |
| 120 | abb_setup_timings(setup); |
| 121 | |
| 122 | /* clear pending interrupts before setup */ |
| 123 | setbits_le32(txdone, txdone_mask); |
| 124 | |
| 125 | /* select ABB type */ |
| 126 | setbits_le32(setup, abb_type_mask | OMAP_ABB_SETUP_SR2EN_MASK); |
| 127 | |
| 128 | /* initiate ABB ldo change */ |
| 129 | setbits_le32(control, opp_sel_mask | OMAP_ABB_CONTROL_OPP_CHANGE_MASK); |
| 130 | |
| 131 | /* wait until transition complete */ |
| 132 | if (!wait_on_value(txdone_mask, txdone_mask, (void *)txdone, LDELAY)) |
| 133 | puts("Error: ABB txdone is not set\n"); |
| 134 | |
| 135 | /* clear ABB tranxdone */ |
| 136 | setbits_le32(txdone, txdone_mask); |
| 137 | } |