uboot/arch/arm/mach-omap2/abb.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   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
  11#include <common.h>
  12#include <asm/omap_common.h>
  13#include <asm/arch/clock.h>
  14#include <asm/io.h>
  15#include <asm/arch/sys_proto.h>
  16#include <linux/bitops.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_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
  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}
 122