u-boot/arch/arm/mach-omap2/abb.c
Tom Rini d678a59d2d Revert "Merge patch series "arm: dts: am62-beagleplay: Fix Beagleplay Ethernet""
When bringing in the series 'arm: dts: am62-beagleplay: Fix Beagleplay
Ethernet"' I failed to notice that b4 noticed it was based on next and
so took that as the base commit and merged that part of next to master.

This reverts commit c8ffd1356d, reversing
changes made to 2ee6f3a5f7.

Reported-by: Jonas Karlman <jonas@kwiboo.se>
Signed-off-by: Tom Rini <trini@konsulko.com>
2024-05-19 08:16:36 -06:00

122 lines
3.5 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* Adaptive Body Bias programming sequence for OMAP family
*
* (C) Copyright 2013
* Texas Instruments, <www.ti.com>
*
* Andrii Tseglytskyi <andrii.tseglytskyi@ti.com>
*/
#include <common.h>
#include <asm/omap_common.h>
#include <asm/arch/clock.h>
#include <asm/io.h>
#include <asm/arch/sys_proto.h>
#include <linux/bitops.h>
__weak s8 abb_setup_ldovbb(u32 fuse, u32 ldovbb)
{
return -1;
}
static void abb_setup_timings(u32 setup)
{
u32 sys_rate, sr2_cnt, clk_cycles;
/*
* SR2_WTCNT_VALUE is the settling time for the ABB ldo after a
* transition and must be programmed with the correct time at boot.
* The value programmed into the register is the number of SYS_CLK
* clock cycles that match a given wall time profiled for the ldo.
* This value depends on:
* settling time of ldo in micro-seconds (varies per OMAP family),
* of clock cycles per SYS_CLK period (varies per OMAP family),
* the SYS_CLK frequency in MHz (varies per board)
* The formula is:
*
* ldo settling time (in micro-seconds)
* SR2_WTCNT_VALUE = ------------------------------------------
* (# system clock cycles) * (sys_clk period)
*
* Put another way:
*
* SR2_WTCNT_VALUE = settling time / (# SYS_CLK cycles / SYS_CLK rate))
*
* To avoid dividing by zero multiply both "# clock cycles" and
* "settling time" by 10 such that the final result is the one we want.
*/
/* calculate SR2_WTCNT_VALUE */
sys_rate = DIV_ROUND_CLOSEST(V_OSCK, 1000000);
clk_cycles = DIV_ROUND_CLOSEST(OMAP_ABB_CLOCK_CYCLES * 10, sys_rate);
sr2_cnt = DIV_ROUND_CLOSEST(OMAP_ABB_SETTLING_TIME * 10, clk_cycles);
setbits_le32(setup,
sr2_cnt << (ffs(OMAP_ABB_SETUP_SR2_WTCNT_VALUE_MASK) - 1));
}
void abb_setup(u32 fuse, u32 ldovbb, u32 setup, u32 control,
u32 txdone, u32 txdone_mask, u32 opp)
{
u32 abb_type_mask, opp_sel_mask;
/* sanity check */
if (!setup || !control || !txdone)
return;
/* setup ABB only in case of Fast or Slow OPP */
switch (opp) {
case OMAP_ABB_FAST_OPP:
abb_type_mask = OMAP_ABB_SETUP_ACTIVE_FBB_SEL_MASK;
opp_sel_mask = OMAP_ABB_CONTROL_FAST_OPP_SEL_MASK;
break;
case OMAP_ABB_SLOW_OPP:
abb_type_mask = OMAP_ABB_SETUP_ACTIVE_RBB_SEL_MASK;
opp_sel_mask = OMAP_ABB_CONTROL_SLOW_OPP_SEL_MASK;
break;
default:
return;
}
/*
* For some OMAP silicons additional setup for LDOVBB register is
* required. This is determined by data retrieved from corresponding
* OPP EFUSE register. Data, which is retrieved from EFUSE - is
* ABB enable/disable flag and VSET value, which must be copied
* to LDOVBB register. If function call fails - return quietly,
* it means no ABB is required for such silicon.
*
* For silicons, which don't require LDOVBB setup "fuse" and
* "ldovbb" offsets are not defined. ABB will be initialized in
* the common way for them.
*/
if (fuse && ldovbb) {
if (abb_setup_ldovbb(fuse, ldovbb))
return;
}
/* clear ABB registers */
writel(0, setup);
writel(0, control);
/* configure timings, based on oscillator value */
abb_setup_timings(setup);
/* clear pending interrupts before setup */
setbits_le32(txdone, txdone_mask);
/* select ABB type */
setbits_le32(setup, abb_type_mask | OMAP_ABB_SETUP_SR2EN_MASK);
/* initiate ABB ldo change */
setbits_le32(control, opp_sel_mask | OMAP_ABB_CONTROL_OPP_CHANGE_MASK);
/* wait until transition complete */
if (!wait_on_value(txdone_mask, txdone_mask, (void *)txdone, LDELAY))
puts("Error: ABB txdone is not set\n");
/* clear ABB tranxdone */
setbits_le32(txdone, txdone_mask);
}