mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-08-20 08:58:52 +09:00
![Simon Glass](/assets/img/avatar_default.png)
This function can fail if the device tree runs out of space. Rather than silently booting with an incomplete device tree, allow the failure to be detected. Unfortunately this involves changing a lot of places in the code. I have not changed behvaiour to return an error where one is not currently returned, to avoid unexpected breakage. Eventually it would be nice to allow boards to register functions to be called to update the device tree. This would avoid all the many functions to do this. However it's not clear yet if this should be done using driver model or with a linker list. This work is left for later. Signed-off-by: Simon Glass <sjg@chromium.org> Acked-by: Anatolij Gustschin <agust@denx.de>
522 lines
13 KiB
C
522 lines
13 KiB
C
/*
|
|
* (C) Copyright 2008
|
|
* Stefan Roese, DENX Software Engineering, sr@denx.de.
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0+
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <asm/ppc440.h>
|
|
#include <libfdt.h>
|
|
#include <fdt_support.h>
|
|
#include <i2c.h>
|
|
#include <asm/processor.h>
|
|
#include <asm/io.h>
|
|
#include <asm/mmu.h>
|
|
#include <asm/4xx_pcie.h>
|
|
#include <asm/ppc4xx-gpio.h>
|
|
#include <asm/errno.h>
|
|
#include <usb.h>
|
|
|
|
extern flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
struct board_bcsr {
|
|
u8 board_id;
|
|
u8 cpld_rev;
|
|
u8 led_user;
|
|
u8 board_status;
|
|
u8 reset_ctrl;
|
|
u8 flash_ctrl;
|
|
u8 eth_ctrl;
|
|
u8 usb_ctrl;
|
|
u8 irq_ctrl;
|
|
};
|
|
|
|
#define BOARD_CANYONLANDS_PCIE 1
|
|
#define BOARD_CANYONLANDS_SATA 2
|
|
#define BOARD_GLACIER 3
|
|
#define BOARD_ARCHES 4
|
|
|
|
/*
|
|
* Override the default functions in arch/powerpc/cpu/ppc4xx/44x_spd_ddr2.c with
|
|
* board specific values.
|
|
*/
|
|
#if defined(CONFIG_ARCHES)
|
|
u32 ddr_wrdtr(u32 default_val) {
|
|
return (SDRAM_WRDTR_LLWP_1_CYC | SDRAM_WRDTR_WTR_0_DEG | 0x823);
|
|
}
|
|
#else
|
|
u32 ddr_wrdtr(u32 default_val) {
|
|
return (SDRAM_WRDTR_LLWP_1_CYC | SDRAM_WRDTR_WTR_180_DEG_ADV | 0x823);
|
|
}
|
|
|
|
u32 ddr_clktr(u32 default_val) {
|
|
return (SDRAM_CLKTR_CLKP_90_DEG_ADV);
|
|
}
|
|
#endif
|
|
|
|
#if defined(CONFIG_ARCHES)
|
|
/*
|
|
* FPGA read/write helper macros
|
|
*/
|
|
static inline int board_fpga_read(int offset)
|
|
{
|
|
int data;
|
|
|
|
data = in_8((void *)(CONFIG_SYS_FPGA_BASE + offset));
|
|
|
|
return data;
|
|
}
|
|
|
|
static inline void board_fpga_write(int offset, int data)
|
|
{
|
|
out_8((void *)(CONFIG_SYS_FPGA_BASE + offset), data);
|
|
}
|
|
|
|
/*
|
|
* CPLD read/write helper macros
|
|
*/
|
|
static inline int board_cpld_read(int offset)
|
|
{
|
|
int data;
|
|
|
|
out_8((void *)(CONFIG_SYS_CPLD_ADDR), offset);
|
|
data = in_8((void *)(CONFIG_SYS_CPLD_DATA));
|
|
|
|
return data;
|
|
}
|
|
|
|
static inline void board_cpld_write(int offset, int data)
|
|
{
|
|
out_8((void *)(CONFIG_SYS_CPLD_ADDR), offset);
|
|
out_8((void *)(CONFIG_SYS_CPLD_DATA), data);
|
|
}
|
|
#else
|
|
static int pvr_460ex(void)
|
|
{
|
|
u32 pvr = get_pvr();
|
|
|
|
if ((pvr == PVR_460EX_RA) || (pvr == PVR_460EX_SE_RA) ||
|
|
(pvr == PVR_460EX_RB))
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
#endif /* defined(CONFIG_ARCHES) */
|
|
|
|
int board_early_init_f(void)
|
|
{
|
|
#if !defined(CONFIG_ARCHES)
|
|
u32 sdr0_cust0;
|
|
struct board_bcsr *bcsr_data =
|
|
(struct board_bcsr *)CONFIG_SYS_BCSR_BASE;
|
|
|
|
#endif
|
|
|
|
/*
|
|
* Setup the interrupt controller polarities, triggers, etc.
|
|
*/
|
|
mtdcr(UIC0SR, 0xffffffff); /* clear all */
|
|
mtdcr(UIC0ER, 0x00000000); /* disable all */
|
|
mtdcr(UIC0CR, 0x00000005); /* ATI & UIC1 crit are critical */
|
|
mtdcr(UIC0PR, 0xffffffff); /* per ref-board manual */
|
|
mtdcr(UIC0TR, 0x00000000); /* per ref-board manual */
|
|
mtdcr(UIC0VR, 0x00000000); /* int31 highest, base=0x000 */
|
|
mtdcr(UIC0SR, 0xffffffff); /* clear all */
|
|
|
|
mtdcr(UIC1SR, 0xffffffff); /* clear all */
|
|
mtdcr(UIC1ER, 0x00000000); /* disable all */
|
|
mtdcr(UIC1CR, 0x00000000); /* all non-critical */
|
|
mtdcr(UIC1PR, 0xffffffff); /* per ref-board manual */
|
|
mtdcr(UIC1TR, 0x00000000); /* per ref-board manual */
|
|
mtdcr(UIC1VR, 0x00000000); /* int31 highest, base=0x000 */
|
|
mtdcr(UIC1SR, 0xffffffff); /* clear all */
|
|
|
|
mtdcr(UIC2SR, 0xffffffff); /* clear all */
|
|
mtdcr(UIC2ER, 0x00000000); /* disable all */
|
|
mtdcr(UIC2CR, 0x00000000); /* all non-critical */
|
|
mtdcr(UIC2PR, 0xffffffff); /* per ref-board manual */
|
|
mtdcr(UIC2TR, 0x00000000); /* per ref-board manual */
|
|
mtdcr(UIC2VR, 0x00000000); /* int31 highest, base=0x000 */
|
|
mtdcr(UIC2SR, 0xffffffff); /* clear all */
|
|
|
|
mtdcr(UIC3SR, 0xffffffff); /* clear all */
|
|
mtdcr(UIC3ER, 0x00000000); /* disable all */
|
|
mtdcr(UIC3CR, 0x00000000); /* all non-critical */
|
|
mtdcr(UIC3PR, 0xffffffff); /* per ref-board manual */
|
|
mtdcr(UIC3TR, 0x00000000); /* per ref-board manual */
|
|
mtdcr(UIC3VR, 0x00000000); /* int31 highest, base=0x000 */
|
|
mtdcr(UIC3SR, 0xffffffff); /* clear all */
|
|
|
|
#if !defined(CONFIG_ARCHES)
|
|
/* SDR Setting - enable NDFC */
|
|
mfsdr(SDR0_CUST0, sdr0_cust0);
|
|
sdr0_cust0 = SDR0_CUST0_MUX_NDFC_SEL |
|
|
SDR0_CUST0_NDFC_ENABLE |
|
|
SDR0_CUST0_NDFC_BW_8_BIT |
|
|
SDR0_CUST0_NDFC_ARE_MASK |
|
|
SDR0_CUST0_NDFC_BAC_ENCODE(3) |
|
|
(0x80000000 >> (28 + CONFIG_SYS_NAND_CS));
|
|
mtsdr(SDR0_CUST0, sdr0_cust0);
|
|
#endif
|
|
|
|
/*
|
|
* Configure PFC (Pin Function Control) registers
|
|
* UART0: 4 pins
|
|
*/
|
|
mtsdr(SDR0_PFC1, 0x00040000);
|
|
|
|
/* Enable PCI host functionality in SDR0_PCI0 */
|
|
mtsdr(SDR0_PCI0, 0xe0000000);
|
|
|
|
#if !defined(CONFIG_ARCHES)
|
|
/* Enable ethernet and take out of reset */
|
|
out_8(&bcsr_data->eth_ctrl, 0) ;
|
|
|
|
/* Remove NOR-FLASH, NAND-FLASH & EEPROM hardware write protection */
|
|
out_8(&bcsr_data->flash_ctrl, 0) ;
|
|
mtsdr(SDR0_SRST1, 0); /* Pull AHB out of reset default=1 */
|
|
|
|
/* Setup PLB4-AHB bridge based on the system address map */
|
|
mtdcr(AHB_TOP, 0x8000004B);
|
|
mtdcr(AHB_BOT, 0x8000004B);
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if defined(CONFIG_USB_OHCI_NEW) && defined(CONFIG_SYS_USB_OHCI_BOARD_INIT)
|
|
int board_usb_init(int index, enum usb_init_type init)
|
|
{
|
|
struct board_bcsr *bcsr_data =
|
|
(struct board_bcsr *)CONFIG_SYS_BCSR_BASE;
|
|
u8 val;
|
|
|
|
/* Enable USB host & USB-OTG */
|
|
val = in_8(&bcsr_data->usb_ctrl);
|
|
val &= ~(BCSR_USBCTRL_OTG_RST | BCSR_USBCTRL_HOST_RST);
|
|
out_8(&bcsr_data->usb_ctrl, val);
|
|
|
|
/*
|
|
* Configure USB-STP pins as alternate and not GPIO
|
|
* It seems to be neccessary to configure the STP pins as GPIO
|
|
* input at powerup (perhaps while USB reset is asserted). So
|
|
* we configure those pins to their "real" function now.
|
|
*/
|
|
gpio_config(16, GPIO_OUT, GPIO_ALT1, GPIO_OUT_1);
|
|
gpio_config(19, GPIO_OUT, GPIO_ALT1, GPIO_OUT_1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int usb_board_stop(void)
|
|
{
|
|
struct board_bcsr *bcsr_data =
|
|
(struct board_bcsr *)CONFIG_SYS_BCSR_BASE;
|
|
u8 val;
|
|
|
|
/* Disable USB host & USB-OTG */
|
|
val = in_8(&bcsr_data->usb_ctrl);
|
|
val |= (BCSR_USBCTRL_OTG_RST | BCSR_USBCTRL_HOST_RST);
|
|
out_8(&bcsr_data->usb_ctrl, val);
|
|
|
|
/* Reconfigure USB-STP pins as input */
|
|
gpio_config(16, GPIO_IN , GPIO_SEL, GPIO_OUT_0);
|
|
gpio_config(19, GPIO_IN , GPIO_SEL, GPIO_OUT_0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int board_usb_cleanup(int index, enum usb_init_type init)
|
|
{
|
|
return usb_board_stop();
|
|
}
|
|
#endif /* CONFIG_USB_OHCI_NEW && CONFIG_SYS_USB_OHCI_BOARD_INIT */
|
|
|
|
#if !defined(CONFIG_ARCHES)
|
|
static void canyonlands_sata_init(int board_type)
|
|
{
|
|
u32 reg;
|
|
|
|
if (board_type == BOARD_CANYONLANDS_SATA) {
|
|
/* Put SATA in reset */
|
|
SDR_WRITE(SDR0_SRST1, 0x00020001);
|
|
|
|
/* Set the phy for SATA, not PCI-E port 0 */
|
|
reg = SDR_READ(PESDR0_PHY_CTL_RST);
|
|
SDR_WRITE(PESDR0_PHY_CTL_RST, (reg & 0xeffffffc) | 0x00000001);
|
|
reg = SDR_READ(PESDR0_L0CLK);
|
|
SDR_WRITE(PESDR0_L0CLK, (reg & 0xfffffff8) | 0x00000007);
|
|
SDR_WRITE(PESDR0_L0CDRCTL, 0x00003111);
|
|
SDR_WRITE(PESDR0_L0DRV, 0x00000104);
|
|
|
|
/* Bring SATA out of reset */
|
|
SDR_WRITE(SDR0_SRST1, 0x00000000);
|
|
}
|
|
}
|
|
#endif /* !defined(CONFIG_ARCHES) */
|
|
|
|
int get_cpu_num(void)
|
|
{
|
|
int cpu = NA_OR_UNKNOWN_CPU;
|
|
|
|
#if defined(CONFIG_ARCHES)
|
|
int cpu_num;
|
|
|
|
cpu_num = board_fpga_read(0x3);
|
|
|
|
/* sanity check; assume cpu numbering starts and increments from 0 */
|
|
if ((cpu_num >= 0) && (cpu_num < CONFIG_BD_NUM_CPUS))
|
|
cpu = cpu_num;
|
|
#endif
|
|
|
|
return cpu;
|
|
}
|
|
|
|
#if !defined(CONFIG_ARCHES)
|
|
int checkboard(void)
|
|
{
|
|
struct board_bcsr *bcsr_data =
|
|
(struct board_bcsr *)CONFIG_SYS_BCSR_BASE;
|
|
char buf[64];
|
|
int i = getenv_f("serial#", buf, sizeof(buf));
|
|
|
|
if (pvr_460ex()) {
|
|
printf("Board: Canyonlands - AMCC PPC460EX Evaluation Board");
|
|
if (in_8(&bcsr_data->board_status) & BCSR_SELECT_PCIE)
|
|
gd->board_type = BOARD_CANYONLANDS_PCIE;
|
|
else
|
|
gd->board_type = BOARD_CANYONLANDS_SATA;
|
|
} else {
|
|
printf("Board: Glacier - AMCC PPC460GT Evaluation Board");
|
|
gd->board_type = BOARD_GLACIER;
|
|
}
|
|
|
|
switch (gd->board_type) {
|
|
case BOARD_CANYONLANDS_PCIE:
|
|
case BOARD_GLACIER:
|
|
puts(", 2*PCIe");
|
|
break;
|
|
|
|
case BOARD_CANYONLANDS_SATA:
|
|
puts(", 1*PCIe/1*SATA");
|
|
break;
|
|
}
|
|
|
|
printf(", Rev. %X", in_8(&bcsr_data->cpld_rev));
|
|
|
|
if (i > 0) {
|
|
puts(", serial# ");
|
|
puts(buf);
|
|
}
|
|
putc('\n');
|
|
|
|
canyonlands_sata_init(gd->board_type);
|
|
|
|
return (0);
|
|
}
|
|
|
|
#else /* defined(CONFIG_ARCHES) */
|
|
|
|
int checkboard(void)
|
|
{
|
|
char *s = getenv("serial#");
|
|
|
|
printf("Board: Arches - AMCC DUAL PPC460GT Reference Design\n");
|
|
printf(" Revision %02x.%02x ",
|
|
board_fpga_read(0x0), board_fpga_read(0x1));
|
|
|
|
gd->board_type = BOARD_ARCHES;
|
|
|
|
/* Only CPU0 has access to CPLD registers */
|
|
if (get_cpu_num() == 0) {
|
|
u8 cfg_sw = board_cpld_read(0x1);
|
|
printf("(FPGA=%02x, CPLD=%02x)\n",
|
|
board_fpga_read(0x2), board_cpld_read(0x0));
|
|
printf(" Configuration Switch %d%d%d%d\n",
|
|
((cfg_sw >> 3) & 0x01),
|
|
((cfg_sw >> 2) & 0x01),
|
|
((cfg_sw >> 1) & 0x01),
|
|
((cfg_sw >> 0) & 0x01));
|
|
} else
|
|
printf("(FPGA=%02x, CPLD=xx)\n", board_fpga_read(0x2));
|
|
|
|
|
|
if (s != NULL)
|
|
printf(" Serial# %s\n", s);
|
|
|
|
return 0;
|
|
}
|
|
#endif /* !defined(CONFIG_ARCHES) */
|
|
|
|
#if defined(CONFIG_PCI)
|
|
int board_pcie_first(void)
|
|
{
|
|
/*
|
|
* Canyonlands with SATA enabled has only one PCIe slot
|
|
* (2nd one).
|
|
*/
|
|
if (gd->board_type == BOARD_CANYONLANDS_SATA)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_PCI */
|
|
|
|
int board_early_init_r (void)
|
|
{
|
|
/*
|
|
* Canyonlands has 64MBytes of NOR FLASH (Spansion 29GL512), but the
|
|
* boot EBC mapping only supports a maximum of 16MBytes
|
|
* (4.ff00.0000 - 4.ffff.ffff).
|
|
* To solve this problem, the FLASH has to get remapped to another
|
|
* EBC address which accepts bigger regions:
|
|
*
|
|
* 0xfc00.0000 -> 4.cc00.0000
|
|
*/
|
|
|
|
/* Remap the NOR FLASH to 0xcc00.0000 ... 0xcfff.ffff */
|
|
mtebc(PB0CR, CONFIG_SYS_FLASH_BASE_PHYS_L | 0xda000);
|
|
|
|
/* Remove TLB entry of boot EBC mapping */
|
|
remove_tlb(CONFIG_SYS_BOOT_BASE_ADDR, 16 << 20);
|
|
|
|
/* Add TLB entry for 0xfc00.0000 -> 0x4.cc00.0000 */
|
|
program_tlb(CONFIG_SYS_FLASH_BASE_PHYS, CONFIG_SYS_FLASH_BASE, CONFIG_SYS_FLASH_SIZE,
|
|
TLB_WORD2_I_ENABLE);
|
|
|
|
/*
|
|
* Now accessing of the whole 64Mbytes of NOR FLASH at virtual address
|
|
* 0xfc00.0000 is possible
|
|
*/
|
|
|
|
/*
|
|
* Clear potential errors resulting from auto-calibration.
|
|
* If not done, then we could get an interrupt later on when
|
|
* exceptions are enabled.
|
|
*/
|
|
set_mcsr(get_mcsr());
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if !defined(CONFIG_ARCHES)
|
|
int misc_init_r(void)
|
|
{
|
|
u32 sdr0_srst1 = 0;
|
|
u32 eth_cfg;
|
|
u8 val;
|
|
|
|
/*
|
|
* Set EMAC mode/configuration (GMII, SGMII, RGMII...).
|
|
* This is board specific, so let's do it here.
|
|
*/
|
|
mfsdr(SDR0_ETH_CFG, eth_cfg);
|
|
/* disable SGMII mode */
|
|
eth_cfg &= ~(SDR0_ETH_CFG_SGMII2_ENABLE |
|
|
SDR0_ETH_CFG_SGMII1_ENABLE |
|
|
SDR0_ETH_CFG_SGMII0_ENABLE);
|
|
/* Set the for 2 RGMII mode */
|
|
/* GMC0 EMAC4_0, GMC0 EMAC4_1, RGMII Bridge 0 */
|
|
eth_cfg &= ~SDR0_ETH_CFG_GMC0_BRIDGE_SEL;
|
|
if (pvr_460ex())
|
|
eth_cfg |= SDR0_ETH_CFG_GMC1_BRIDGE_SEL;
|
|
else
|
|
eth_cfg &= ~SDR0_ETH_CFG_GMC1_BRIDGE_SEL;
|
|
mtsdr(SDR0_ETH_CFG, eth_cfg);
|
|
|
|
/*
|
|
* The AHB Bridge core is held in reset after power-on or reset
|
|
* so enable it now
|
|
*/
|
|
mfsdr(SDR0_SRST1, sdr0_srst1);
|
|
sdr0_srst1 &= ~SDR0_SRST1_AHB;
|
|
mtsdr(SDR0_SRST1, sdr0_srst1);
|
|
|
|
/*
|
|
* RTC/M41T62:
|
|
* Disable square wave output: Batterie will be drained
|
|
* quickly, when this output is not disabled
|
|
*/
|
|
val = i2c_reg_read(CONFIG_SYS_I2C_RTC_ADDR, 0xa);
|
|
val &= ~0x40;
|
|
i2c_reg_write(CONFIG_SYS_I2C_RTC_ADDR, 0xa, val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#else /* defined(CONFIG_ARCHES) */
|
|
|
|
int misc_init_r(void)
|
|
{
|
|
u32 eth_cfg = 0;
|
|
u32 eth_pll;
|
|
u32 reg;
|
|
|
|
/*
|
|
* Set EMAC mode/configuration (GMII, SGMII, RGMII...).
|
|
* This is board specific, so let's do it here.
|
|
*/
|
|
|
|
/* enable SGMII mode */
|
|
eth_cfg |= (SDR0_ETH_CFG_SGMII0_ENABLE |
|
|
SDR0_ETH_CFG_SGMII1_ENABLE |
|
|
SDR0_ETH_CFG_SGMII2_ENABLE);
|
|
|
|
/* Set EMAC for MDIO */
|
|
eth_cfg |= SDR0_ETH_CFG_MDIO_SEL_EMAC0;
|
|
|
|
/* bypass the TAHOE0/TAHOE1 cores for U-Boot */
|
|
eth_cfg |= (SDR0_ETH_CFG_TAHOE0_BYPASS | SDR0_ETH_CFG_TAHOE1_BYPASS);
|
|
|
|
mtsdr(SDR0_ETH_CFG, eth_cfg);
|
|
|
|
/* reset all SGMII interfaces */
|
|
mfsdr(SDR0_SRST1, reg);
|
|
reg |= (SDR0_SRST1_SGMII0 | SDR0_SRST1_SGMII1 | SDR0_SRST1_SGMII2);
|
|
mtsdr(SDR0_SRST1, reg);
|
|
mtsdr(SDR0_ETH_STS, 0xFFFFFFFF);
|
|
mtsdr(SDR0_SRST1, 0x00000000);
|
|
|
|
do {
|
|
mfsdr(SDR0_ETH_PLL, eth_pll);
|
|
} while (!(eth_pll & SDR0_ETH_PLL_PLLLOCK));
|
|
|
|
return 0;
|
|
}
|
|
#endif /* !defined(CONFIG_ARCHES) */
|
|
|
|
#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP)
|
|
extern int __ft_board_setup(void *blob, bd_t *bd);
|
|
|
|
int ft_board_setup(void *blob, bd_t *bd)
|
|
{
|
|
__ft_board_setup(blob, bd);
|
|
|
|
if (gd->board_type == BOARD_CANYONLANDS_SATA) {
|
|
/*
|
|
* When SATA is selected we need to disable the first PCIe
|
|
* node in the device tree, so that Linux doesn't initialize
|
|
* it.
|
|
*/
|
|
fdt_find_and_setprop(blob, "/plb/pciex@d00000000", "status",
|
|
"disabled", sizeof("disabled"), 1);
|
|
}
|
|
|
|
if (gd->board_type == BOARD_CANYONLANDS_PCIE) {
|
|
/*
|
|
* When PCIe is selected we need to disable the SATA
|
|
* node in the device tree, so that Linux doesn't initialize
|
|
* it.
|
|
*/
|
|
fdt_find_and_setprop(blob, "/plb/sata@bffd1000", "status",
|
|
"disabled", sizeof("disabled"), 1);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif /* defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP) */
|