提交 dbda2c65 编写于 作者: M Mike Frysinger

Blackfin: re-architect initcode

The single initcode function was growing unwieldy, so split it up the
distinct steps into their own function.  This should making digesting the
result much easier on people.
Signed-off-by: NMike Frysinger <vapier@gentoo.org>
上级 f5402d4c
......@@ -9,6 +9,8 @@
* Licensed under the GPL-2 or later.
*/
#define BFIN_IN_INITCODE
#include <config.h>
#include <asm/blackfin.h>
#include <asm/mach-common/bits/bootrom.h>
......@@ -17,7 +19,6 @@
#include <asm/mach-common/bits/pll.h>
#include <asm/mach-common/bits/uart.h>
#define BFIN_IN_INITCODE
#include "serial.h"
__attribute__((always_inline))
......@@ -213,6 +214,7 @@ static inline void serial_putc(char c)
# define CONFIG_HAS_VR 1
#endif
#if CONFIG_MEM_SIZE
#ifndef EBIU_RSTCTL
/* Blackfin with SDRAM */
#ifndef CONFIG_EBIU_SDBCTL_VAL
......@@ -245,6 +247,7 @@ static inline void serial_putc(char c)
# define CONFIG_EBIU_SDBCTL_VAL (CONFIG_EBCAW_VAL | CONFIG_EBSZ_VAL | EBE)
#endif
#endif
#endif
/* Conflicting Column Address Widths Causes SDRAM Errors:
* EB2CAW and EB3CAW must be the same
......@@ -255,28 +258,21 @@ static inline void serial_putc(char c)
# endif
#endif
BOOTROM_CALLED_FUNC_ATTR
void initcode(ADI_BOOT_DATA *bootstruct)
__attribute__((always_inline)) static inline void
program_early_devices(ADI_BOOT_DATA *bs, uint *sdivB, uint *divB, uint *vcoB)
{
ADI_BOOT_DATA bootstruct_scratch;
serial_putc('a');
/* Save the clock pieces that are used in baud rate calculation */
unsigned int sdivB, divB, vcoB;
serial_init();
if (BFIN_DEBUG_EARLY_SERIAL || CONFIG_BFIN_BOOT_MODE == BFIN_BOOT_UART) {
sdivB = bfin_read_PLL_DIV() & 0xf;
vcoB = (bfin_read_PLL_CTL() >> 9) & 0x3f;
divB = serial_early_get_div();
serial_putc('b');
*sdivB = bfin_read_PLL_DIV() & 0xf;
*vcoB = (bfin_read_PLL_CTL() >> 9) & 0x3f;
*divB = serial_early_get_div();
serial_putc('c');
}
serial_putc('A');
/* If the bootstruct is NULL, then it's because we're loading
* dynamically and not via LDR (bootrom). So set the struct to
* some scratch space.
*/
if (!bootstruct)
bootstruct = &bootstruct_scratch;
serial_putc('d');
#ifdef CONFIG_HW_WATCHDOG
# ifndef CONFIG_HW_WATCHDOG_TIMEOUT_INITCODE
......@@ -289,41 +285,69 @@ void initcode(ADI_BOOT_DATA *bootstruct)
* timeout, so don't clobber that.
*/
if (CONFIG_BFIN_BOOT_MODE != BFIN_BOOT_BYPASS) {
serial_putc('e');
bfin_write_WDOG_CNT(MSEC_TO_SCLK(CONFIG_HW_WATCHDOG_TIMEOUT_INITCODE));
bfin_write_WDOG_CTL(0);
serial_putc('f');
}
#endif
serial_putc('B');
serial_putc('g');
/* Blackfin bootroms use the SPI slow read opcode instead of the SPI
* fast read, so we need to slow down the SPI clock a lot more during
* boot. Once we switch over to u-boot's SPI flash driver, we'll
* increase the speed appropriately.
*/
if (CONFIG_BFIN_BOOT_MODE == BFIN_BOOT_SPI_MASTER) {
serial_putc('h');
if (BOOTROM_SUPPORTS_SPI_FAST_READ && CONFIG_SPI_BAUD_INITBLOCK < 4)
bs->dFlags |= BFLAG_FASTREAD;
bfin_write_SPI_BAUD(CONFIG_SPI_BAUD_INITBLOCK);
serial_putc('i');
}
serial_putc('j');
}
__attribute__((always_inline)) static inline bool
maybe_self_refresh(ADI_BOOT_DATA *bs)
{
serial_putc('a');
if (!CONFIG_MEM_SIZE)
return false;
/* If external memory is enabled, put it into self refresh first. */
bool put_into_srfs = false;
#ifdef EBIU_RSTCTL
if (bfin_read_EBIU_RSTCTL() & DDR_SRESET) {
serial_putc('b');
bfin_write_EBIU_RSTCTL(bfin_read_EBIU_RSTCTL() | SRREQ);
put_into_srfs = true;
return true;
}
#else
if (bfin_read_EBIU_SDBCTL() & EBE) {
serial_putc('b');
bfin_write_EBIU_SDGCTL(bfin_read_EBIU_SDGCTL() | SRFS);
put_into_srfs = true;
return true;
}
#endif
serial_putc('C');
serial_putc('c');
/* Blackfin bootroms use the SPI slow read opcode instead of the SPI
* fast read, so we need to slow down the SPI clock a lot more during
* boot. Once we switch over to u-boot's SPI flash driver, we'll
* increase the speed appropriately.
*/
if (CONFIG_BFIN_BOOT_MODE == BFIN_BOOT_SPI_MASTER) {
if (BOOTROM_SUPPORTS_SPI_FAST_READ && CONFIG_SPI_BAUD_INITBLOCK < 4)
bootstruct->dFlags |= BFLAG_FASTREAD;
bfin_write_SPI_BAUD(CONFIG_SPI_BAUD_INITBLOCK);
}
return false;
}
serial_putc('D');
__attribute__((always_inline)) static inline u16
program_clocks(ADI_BOOT_DATA *bs, bool put_into_srfs)
{
u16 vr_ctl;
serial_putc('a');
vr_ctl = bfin_read_VR_CTL();
serial_putc('b');
/* If we're entering self refresh, make sure it has happened. */
if (put_into_srfs)
......@@ -334,15 +358,14 @@ void initcode(ADI_BOOT_DATA *bootstruct)
#endif
continue;
serial_putc('E');
serial_putc('c');
/* With newer bootroms, we use the helper function to set up
* the memory controller. Older bootroms lacks such helpers
* so we do it ourselves.
*/
uint16_t vr_ctl = bfin_read_VR_CTL();
if (!ANOMALY_05000386) {
serial_putc('F');
serial_putc('d');
/* Always programming PLL_LOCKCNT avoids Anomaly 05000430 */
ADI_SYSCTRL_VALUES memory_settings;
......@@ -362,7 +385,9 @@ void initcode(ADI_BOOT_DATA *bootstruct)
#if ANOMALY_05000432
bfin_write_SIC_IWR1(0);
#endif
serial_putc('e');
bfrom_SysControl(actions, &memory_settings, NULL);
serial_putc('f');
#if ANOMALY_05000432
bfin_write_SIC_IWR1(-1);
#endif
......@@ -370,8 +395,9 @@ void initcode(ADI_BOOT_DATA *bootstruct)
bfin_write_SICA_IWR0(-1);
bfin_write_SICA_IWR1(-1);
#endif
serial_putc('g');
} else {
serial_putc('G');
serial_putc('h');
/* Disable all peripheral wakeups except for the PLL event. */
#ifdef SIC_IWR0
......@@ -387,38 +413,40 @@ void initcode(ADI_BOOT_DATA *bootstruct)
bfin_write_SIC_IWR(1);
#endif
serial_putc('H');
serial_putc('i');
/* Always programming PLL_LOCKCNT avoids Anomaly 05000430 */
bfin_write_PLL_LOCKCNT(CONFIG_PLL_LOCKCNT_VAL);
serial_putc('I');
serial_putc('j');
/* Only reprogram when needed to avoid triggering unnecessary
* PLL relock sequences.
*/
if (vr_ctl != CONFIG_VR_CTL_VAL) {
serial_putc('!');
serial_putc('?');
bfin_write_VR_CTL(CONFIG_VR_CTL_VAL);
asm("idle;");
serial_putc('!');
}
serial_putc('J');
serial_putc('k');
bfin_write_PLL_DIV(CONFIG_PLL_DIV_VAL);
serial_putc('K');
serial_putc('l');
/* Only reprogram when needed to avoid triggering unnecessary
* PLL relock sequences.
*/
if (ANOMALY_05000242 || bfin_read_PLL_CTL() != CONFIG_PLL_CTL_VAL) {
serial_putc('!');
serial_putc('?');
bfin_write_PLL_CTL(CONFIG_PLL_CTL_VAL);
asm("idle;");
serial_putc('!');
}
serial_putc('L');
serial_putc('m');
/* Restore all peripheral wakeups. */
#ifdef SIC_IWR0
......@@ -433,9 +461,19 @@ void initcode(ADI_BOOT_DATA *bootstruct)
#else
bfin_write_SIC_IWR(-1);
#endif
serial_putc('n');
}
serial_putc('M');
serial_putc('o');
return vr_ctl;
}
__attribute__((always_inline)) static inline void
update_serial_clocks(ADI_BOOT_DATA *bs, uint sdivB, uint divB, uint vcoB)
{
serial_putc('a');
/* Since we've changed the SCLK above, we may need to update
* the UART divisors (UART baud rates are based on SCLK).
......@@ -443,6 +481,7 @@ void initcode(ADI_BOOT_DATA *bootstruct)
* for dividing which means we'd generate a libgcc reference.
*/
if (CONFIG_BFIN_BOOT_MODE == BFIN_BOOT_UART) {
serial_putc('b');
unsigned int sdivR, vcoR;
sdivR = bfin_read_PLL_DIV() & 0xf;
vcoR = (bfin_read_PLL_CTL() >> 9) & 0x3f;
......@@ -452,20 +491,38 @@ void initcode(ADI_BOOT_DATA *bootstruct)
for (quotient = 0; dividend > 0; ++quotient)
dividend -= divisor;
serial_early_put_div(quotient - ANOMALY_05000230);
serial_putc('c');
}
serial_putc('N');
serial_putc('d');
}
__attribute__((always_inline)) static inline void
program_memory_controller(ADI_BOOT_DATA *bs, bool put_into_srfs)
{
serial_putc('a');
if (!CONFIG_MEM_SIZE)
return;
serial_putc('b');
/* Program the external memory controller before we come out of
* self-refresh. This only works with our SDRAM controller.
*/
#ifndef EBIU_RSTCTL
# ifdef CONFIG_EBIU_SDRRC_VAL
bfin_write_EBIU_SDRRC(CONFIG_EBIU_SDRRC_VAL);
# endif
# ifdef CONFIG_EBIU_SDBCTL_VAL
bfin_write_EBIU_SDBCTL(CONFIG_EBIU_SDBCTL_VAL);
# endif
# ifdef CONFIG_EBIU_SDGCTL_VAL
bfin_write_EBIU_SDGCTL(CONFIG_EBIU_SDGCTL_VAL);
# endif
#endif
serial_putc('O');
serial_putc('c');
/* Now that we've reprogrammed, take things out of self refresh. */
if (put_into_srfs)
......@@ -475,7 +532,7 @@ void initcode(ADI_BOOT_DATA *bootstruct)
bfin_write_EBIU_SDGCTL(bfin_read_EBIU_SDGCTL() & ~(SRFS));
#endif
serial_putc('P');
serial_putc('d');
/* Our DDR controller sucks and cannot be programmed while in
* self-refresh. So we have to pull it out before programming.
......@@ -494,7 +551,18 @@ void initcode(ADI_BOOT_DATA *bootstruct)
# endif
#endif
serial_putc('Q');
serial_putc('e');
}
__attribute__((always_inline)) static inline void
check_hibernation(ADI_BOOT_DATA *bs, u16 vr_ctl, bool put_into_srfs)
{
serial_putc('a');
if (!CONFIG_MEM_SIZE)
return;
serial_putc('b');
/* Are we coming out of hibernate (suspend to memory) ?
* The memory layout is:
......@@ -508,7 +576,7 @@ void initcode(ADI_BOOT_DATA *bootstruct)
uint32_t *hibernate_magic = 0;
__builtin_bfin_ssync(); /* make sure memory controller is done */
if (hibernate_magic[0] == 0xDEADBEEF) {
serial_putc('R');
serial_putc('c');
bfin_write_EVT15(hibernate_magic[1]);
bfin_write_IMASK(EVT_IVG15);
__asm__ __volatile__ (
......@@ -525,15 +593,24 @@ void initcode(ADI_BOOT_DATA *bootstruct)
: "p"(hibernate_magic), "d"(0x2000 /* jump.s 0 */)
);
}
serial_putc('d');
}
serial_putc('S');
serial_putc('e');
}
__attribute__((always_inline)) static inline void
program_async_controller(ADI_BOOT_DATA *bs)
{
serial_putc('a');
/* Program the async banks controller. */
bfin_write_EBIU_AMBCTL0(CONFIG_EBIU_AMBCTL0_VAL);
bfin_write_EBIU_AMBCTL1(CONFIG_EBIU_AMBCTL1_VAL);
bfin_write_EBIU_AMGCTL(CONFIG_EBIU_AMGCTL_VAL);
serial_putc('b');
#ifdef EBIU_MODE
/* Not all parts have these additional MMRs. */
bfin_write_EBIU_MBSCTL(CONFIG_EBIU_MBSCTL_VAL);
......@@ -541,9 +618,49 @@ void initcode(ADI_BOOT_DATA *bootstruct)
bfin_write_EBIU_FCTL(CONFIG_EBIU_FCTL_VAL);
#endif
serial_putc('T');
serial_putc('c');
}
BOOTROM_CALLED_FUNC_ATTR
void initcode(ADI_BOOT_DATA *bs)
{
ADI_BOOT_DATA bootstruct_scratch;
serial_init();
serial_putc('A');
/* If the bootstruct is NULL, then it's because we're loading
* dynamically and not via LDR (bootrom). So set the struct to
* some scratch space.
*/
if (!bs)
bs = &bootstruct_scratch;
serial_putc('B');
bool put_into_srfs = maybe_self_refresh(bs);
serial_putc('C');
uint sdivB, divB, vcoB;
program_early_devices(bs, &sdivB, &divB, &vcoB);
serial_putc('D');
u16 vr_ctl = program_clocks(bs, put_into_srfs);
serial_putc('E');
update_serial_clocks(bs, sdivB, divB, vcoB);
serial_putc('F');
program_memory_controller(bs, put_into_srfs);
serial_putc('G');
check_hibernation(bs, vr_ctl, put_into_srfs);
serial_putc('H');
program_async_controller(bs);
#ifdef CONFIG_BFIN_BOOTROM_USES_EVT1
serial_putc('I');
/* tell the bootrom where our entry point is */
if (CONFIG_BFIN_BOOT_MODE != BFIN_BOOT_BYPASS)
bfin_write_EVT1(CONFIG_SYS_MONITOR_BASE);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册