1 /* 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 * 9 * SPDX-License-Identifier: GPL-2.0+ 10 */ 11 12 #include <common.h> 13 #include <asm/omap_common.h> 14 #include <asm/arch/clock.h> 15 #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 23 static 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_CLOSEST(V_OSCK, 1000000); 52 clk_cycles = DIV_ROUND_CLOSEST(OMAP_ABB_CLOCK_CYCLES * 10, sys_rate); 53 sr2_cnt = DIV_ROUND_CLOSEST(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 59 void 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 } 122