Commit 9942ae92 authored by Alexander Potashev's avatar Alexander Potashev

RT77744. lpc4350: Support booting from 16-bit external NOR flash

 * The Boot ROM bootloader loads only the first 32KBytes of U-Boot image
from the external 16-bit NOR flash. We make U-Boot load the remaining
contents of the image.
 * Put all function and data used for bootstrapping in the beginning
of the U-Boot image in sections `.lpc18xx_image_top_text` and
`.lpc18xx_image_top_data`.
 * Configure the boot pins to determine the boot source if the relevant
fields in the One-Time Programmable memory are not set.
 * Configure the remaining EMC pins before reading the whole U-Boot
image. The Boot ROM bootloader forgets to configure some EMC pins.
 * Reload the U-Boot image from NOR flash only when boot source is
`EMC 16-bit`.
parent 74cfefd6
......@@ -238,12 +238,6 @@ struct lpc_emc_regs {
DECLARE_GLOBAL_DATA_PTR;
/*
* Pin settings for EMC pins
*/
#define LPC18XX_IOMUX_EMC_CONFIG(func) \
(LPC18XX_IOMUX_CONFIG(func, 0, 1, 1, 1, 1))
/*
* Pin configuration table for Hitex LPC4350 Eval.
*
......@@ -448,6 +442,208 @@ static void iomux_init(void)
hitex_lpc4350_iomux, ARRAY_SIZE(hitex_lpc4350_iomux));
}
#ifdef CONFIG_LPC18XX_NORFLASH_BOOTSTRAP_WORKAROUND
extern char _mem_nvm_base;
extern char _mem_nvm_size;
/*
* OTP (One-Time Programmable) memory area map
*/
struct lpc18xx_otp_area {
u32 part_id; /* Part ID */
u32 rsv0;
u32 uniq_id; /* Unique ID */
u32 rsv1;
u32 key0[4]; /* AES key 0 */
u32 key1[4]; /* AES key 1 */
u32 ctrl; /* Customer control data */
u32 usb_id; /* USB ID */
u32 user1; /* General purpose OTP memory */
u32 user2; /* General purpose OTP memory */
};
/*
* OTP memory base
*/
#define LPC18XX_OTP_BASE 0x40045000
#define LPC18XX_OTP ((volatile struct lpc18xx_otp_area *) \
LPC18XX_OTP_BASE)
/*
* Customer control data
*/
/* Boot source selection in OTP */
#define LPC18XX_OTP_CTRL_BOOTSRC_BITS 25
#define LPC18XX_OTP_CTRL_BOOTSRC_MSK (0xF << LPC18XX_OTP_CTRL_BOOTSRC_BITS)
/*
* GPIO (GPIO ports) register map
*/
struct lpc18xx_gpio_regs {
u8 pbyte[256]; /* GPIO port byte pin registers */
u32 rsv0[960];
u32 pword[256]; /* GPIO port word pin registers */
u32 rsv1[768];
u32 dir[8]; /* GPIO port direction registers */
u32 rsv2[24];
u32 mask[8]; /* GPIO port mask registers */
u32 rsv3[24];
u32 pin[8]; /* GPIO port pin registers */
u32 rsv4[24];
u32 mpin[8]; /* GPIO masked port pin registers */
u32 rsv5[24];
u32 set[8]; /* GPIO port set registers */
u32 rsv6[24];
u32 clr[8]; /* GPIO port clear registers */
u32 rsv7[24];
u32 not[8]; /* GPIO port toggle registers */
};
/*
* GPIO registers base
*/
#define LPC18XX_GPIO_BASE 0x400F4000
#define LPC18XX_GPIO ((volatile struct lpc18xx_gpio_regs *) \
LPC18XX_GPIO_BASE)
#define LPC18XX_GPIO_B(port,pin) (LPC18XX_GPIO->pbyte[32*(port) + (pin)])
/*
* Configuration of boot pins as GPIO inputs
*/
static const struct lpc18xx_pin_config
__attribute__((section(".lpc18xx_image_top_data")))
hitex_lpc4350_iomux_boot_pins[] = {
/* P1.1 = GPIO0[8] - BOOT1 */
{{0x1, 1}, LPC18XX_IOMUX_GPIO_IN(0)},
/* P1.2 = GPIO0[9] - BOOT2 */
{{0x1, 2}, LPC18XX_IOMUX_GPIO_IN(0)},
/* P2.8 = GPIO5[7] - BOOT3 */
{{0x2, 8}, LPC18XX_IOMUX_GPIO_IN(4)},
/* P2.9 = GPIO1[10] - BOOT4 */
{{0x2, 9}, LPC18XX_IOMUX_GPIO_IN(0)},
};
/*
* List of values returned by lpc18xx_get_boot_source()
*/
#define LPC18XX_BOOTSRC_USART0 0
#define LPC18XX_BOOTSRC_SPIFI 1
#define LPC18XX_BOOTSRC_EMC_8BIT 2
#define LPC18XX_BOOTSRC_EMC_16BIT 3
#define LPC18XX_BOOTSRC_EMC_32BIT 4
#define LPC18XX_BOOTSRC_USB0 5
#define LPC18XX_BOOTSRC_USB1 6
#define LPC18XX_BOOTSRC_SPI 7
#define LPC18XX_BOOTSRC_USART3 8
/*
* Return identifier of the boot source used (from OTP or status of boot pins)
*/
static int __attribute__((section(".lpc18xx_image_top_text")))
lpc18xx_get_boot_source(void)
{
int rv;
/*
* Try to find boot source selector in OTP
*/
rv = (LPC18XX_OTP->ctrl & LPC18XX_OTP_CTRL_BOOTSRC_MSK) >>
LPC18XX_OTP_CTRL_BOOTSRC_BITS;
if (rv > 0) {
rv--;
goto out;
}
/*
* Check status of boot pins
*
* The pins need to be configured for GPIOs before reading their
* statuses. The directions of GPIOs are set to inputs by default, no
* need to reconfigure directions therefore.
*/
lpc18xx_pin_config_table(
hitex_lpc4350_iomux_boot_pins,
ARRAY_SIZE(hitex_lpc4350_iomux_boot_pins));
rv = (LPC18XX_GPIO_B(0, 8) << 0) |
(LPC18XX_GPIO_B(0, 9) << 1) |
(LPC18XX_GPIO_B(5, 7) << 2) |
(LPC18XX_GPIO_B(1, 10) << 3);
out:
return rv;
}
/*
* Configure enough pins to access the first 128KBytes of the 16-bit NOR flash
*/
static const struct lpc18xx_pin_config
__attribute__((section(".lpc18xx_image_top_data")))
hitex_lpc4350_iomux_boot_norflash[] = {
/*
* Reconfigure the boot pins, because we turned them into GPIO inputs
*/
/* P1.1 = A6 - SDRAM,NOR */
{{0x1, 1}, LPC18XX_IOMUX_EMC_CONFIG(2)},
/* P1.2 = A7 - SDRAM,NOR */
{{0x1, 2}, LPC18XX_IOMUX_EMC_CONFIG(2)},
/* P2.8 = A8 - SDRAM,NOR */
{{0x2, 8}, LPC18XX_IOMUX_EMC_CONFIG(3)},
/* P2.9 = A0 - SDRAM */
{{0x2, 9}, LPC18XX_IOMUX_EMC_CONFIG(3)},
/*
* Configure the EMC pins required to access the first 128KBytes
* of NOR flash. The Boot ROM of LPC4350 forgets to configure these
* pins.
*/
/* P6.8 = A14 */
{{0x6, 8}, LPC18XX_IOMUX_EMC_CONFIG(1)},
/* P6.7 = A15 */
{{0x6, 7}, LPC18XX_IOMUX_EMC_CONFIG(1)},
/* PD.16 = A16 */
{{0xD, 16}, LPC18XX_IOMUX_EMC_CONFIG(2)},
};
static void __attribute__((section(".lpc18xx_image_top_text")))
norflash_bootstrap_iomux_init(void)
{
lpc18xx_pin_config_table(
hitex_lpc4350_iomux_boot_norflash,
ARRAY_SIZE(hitex_lpc4350_iomux_boot_norflash));
}
/*
* This function will be called very early on U-Boot initialization to reload
* the whole U-Boot image from NOR flash if we use bootloading from NOR flash.
*/
void __attribute__((section(".lpc18xx_image_top_text")))
lpc18xx_bootstrap_from_norflash(void)
{
char *src, *dest, *src_end;
/*
* Check if we boot from NOR flash
*/
if (lpc18xx_get_boot_source() == LPC18XX_BOOTSRC_EMC_16BIT) {
/*
* Configure remaining pins required for NOR flash
*/
norflash_bootstrap_iomux_init();
/*
* Copy U-Boot image from NOR flash to internal SRAM
*/
dest = &_mem_nvm_base;
src = (void *)(CONFIG_SYS_FLASH_BANK1_BASE +
CONFIG_LPC18XX_NORFLASH_IMAGE_OFFSET);
src_end = src + (u32)&_mem_nvm_size;
for (; src < src_end; src++, dest++)
*dest = *src;
}
}
#endif /* CONFIG_LPC18XX_NORFLASH_BOOTSTRAP_WORKAROUND */
/*
* Early hardware init.
*/
......
......@@ -38,7 +38,11 @@ void wdt_strobe(void)
/*
* Disable the WDT.
*/
void wdt_disable(void)
void
#ifdef CONFIG_LPC18XX_NORFLASH_BOOTSTRAP_WORKAROUND
__attribute__((section(".lpc18xx_image_top_text")))
#endif
wdt_disable(void)
{
/*
* TBD
......@@ -50,7 +54,11 @@ void wdt_disable(void)
/*
* Enable the WDT.
*/
void wdt_enable(void)
void
#ifdef CONFIG_LPC18XX_NORFLASH_BOOTSTRAP_WORKAROUND
__attribute__((section(".lpc18xx_image_top_text")))
#endif
wdt_enable(void)
{
/*
* TBD
......
......@@ -17,9 +17,14 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <config.h>
#include <string.h>
#include "wdt.h"
#ifdef CONFIG_LPC18XX_NORFLASH_BOOTSTRAP_WORKAROUND
#include <asm/arch/lpc18xx_gpio.h>
#endif
/*
* FIXME: move to the appropriate header
*/
......@@ -46,6 +51,10 @@ void default_isr(void);
extern void start_armboot(void);
#ifdef CONFIG_LPC18XX_NORFLASH_BOOTSTRAP_WORKAROUND
extern void lpc18xx_norflash_bootstrap_iomux_init(void);
#endif
/*
* Control IRQs
*/
......@@ -81,10 +90,23 @@ unsigned int vectors[] __attribute__((section(".vectors"))) = {
[2 ... 165] = (unsigned int)&default_isr
};
#ifdef CONFIG_LPC18XX_NORFLASH_BOOTSTRAP_WORKAROUND
/*
* This function will be called very early on U-Boot initialization to reload
* the whole U-Boot image from NOR flash if we use bootloading from NOR flash.
*/
void __attribute__((section(".lpc18xx_image_top_text")))
lpc18xx_bootstrap_from_norflash(void);
#endif /* CONFIG_LPC18XX_NORFLASH_BOOTSTRAP_WORKAROUND */
/*
* Reset entry point
*/
void _start(void)
void
#ifdef CONFIG_LPC18XX_NORFLASH_BOOTSTRAP_WORKAROUND
__attribute__((section(".lpc18xx_image_top_text")))
#endif
_start(void)
{
/*
* Depending on the config parameter, enable or disable the WDT.
......@@ -100,6 +122,15 @@ void _start(void)
*/
__disable_irq();
#ifdef CONFIG_LPC18XX_NORFLASH_BOOTSTRAP_WORKAROUND
/*
* Reload the whole U-Boot image from NOR flash.
* The Boot ROM on LPC4350 parts cannot load more than 32KBytes
* from NOR flash when booting.
*/
lpc18xx_bootstrap_from_norflash();
#endif /* CONFIG_LPC18XX_NORFLASH_BOOTSTRAP_WORKAROUND */
/*
* Copy data and initialize BSS
* This is in lieu of the U-boot "conventional" relocation
......@@ -133,7 +164,12 @@ void _start(void)
/*
* Default exception handler
*/
void __attribute__((naked, noreturn)) default_isr(void);
void __attribute__((naked, noreturn))
#ifdef CONFIG_LPC18XX_NORFLASH_BOOTSTRAP_WORKAROUND
__attribute__((section(".lpc18xx_image_top_text")))
#endif
default_isr(void);
void default_isr(void)
{
/*
......
......@@ -53,6 +53,16 @@ SECTIONS
KEEP(*(.kinetis_flash_conf))
} >NVM
/*
* Store contents of these two sections in the beginning of the U-Boot
* image to ensure they are loaded by the Boot ROM of the LPC4350 MCU.
*/
.lpc18xx_image_top :
{
*(.lpc18xx_image_top_text)
*(.lpc18xx_image_top_data)
} >NVM
.text :
{
*(.text)
......
......@@ -87,7 +87,11 @@ static inline int lpc18xx_validate_pin(const struct lpc18xx_iomux_dsc *dsc)
* Configure the specified MCU pin.
* Returns 0 on success, -EINVAL otherwise.
*/
int lpc18xx_pin_config(const struct lpc18xx_iomux_dsc *dsc, u32 regval)
int
#ifdef CONFIG_LPC18XX_NORFLASH_BOOTSTRAP_WORKAROUND
__attribute__((section(".lpc18xx_image_top_text")))
#endif
lpc18xx_pin_config(const struct lpc18xx_iomux_dsc *dsc, u32 regval)
{
int rv;
......@@ -102,8 +106,12 @@ int lpc18xx_pin_config(const struct lpc18xx_iomux_dsc *dsc, u32 regval)
* Configure a set of MCU pins using the given configuration table.
* Returns 0 on success.
*/
int lpc18xx_pin_config_table(
const struct lpc18xx_pin_config *table, unsigned int len)
int
#ifdef CONFIG_LPC18XX_NORFLASH_BOOTSTRAP_WORKAROUND
__attribute__((section(".lpc18xx_image_top_text")))
#endif
lpc18xx_pin_config_table(
const struct lpc18xx_pin_config *table, unsigned int len)
{
unsigned int i;
int rv;
......
......@@ -22,6 +22,8 @@
#ifndef _LPC18XX_IOMUX_H_
#define _LPC18XX_IOMUX_H_
#include <asm/types.h>
/*
* Bits and bit groups inside the SCU_SFS registers
*/
......@@ -57,6 +59,17 @@
* TBD: similar macros for other pin types
*/
/*
* Pin settings for EMC pins
*/
#define LPC18XX_IOMUX_EMC_CONFIG(func) \
(LPC18XX_IOMUX_CONFIG(func, 0, 1, 1, 1, 1))
/*
* Pin settings for GPIO input pins
*/
#define LPC18XX_IOMUX_GPIO_IN(func) \
(LPC18XX_IOMUX_CONFIG(func, 0, 1, 0, 1, 0))
/*
* IOMUX pin descriptor
*/
......
......@@ -190,6 +190,14 @@
#define CONFIG_INFERNO 1
#define CONFIG_ENV_OVERWRITE 1
/*
* Support booting U-Boot from NOR flash
*/
/* U-Boot will reload itself from flash to be sure the whole image is in SRAM */
#define CONFIG_LPC18XX_NORFLASH_BOOTSTRAP_WORKAROUND
/* The image contents go immediately after the 16-byte header */
#define CONFIG_LPC18XX_NORFLASH_IMAGE_OFFSET 16
/*
* Serial console configuration
*/
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment