u-boot/arch/arm/cpu/arm926ejs/orion5x/cpu.c
Albert Aribaud 4e4479a892 Orion5x: bugfix: window size (mis)calculation
Fix orion5x_winctrl_calcsize() off-by-1 bug which caused mapping
windows to be cut by half. This afected all windows including NOR
flash (causing half the flash to be unaccessible) but DRAM was and
still is fine as its size is determined otherwise.

Signed-off-by: Albert Aribaud <albert.aribaud@free.fr>
2010-08-26 14:05:19 +05:30

278 lines
7.6 KiB
C

/*
* Copyright (C) 2010 Albert ARIBAUD <albert.aribaud@free.fr>
*
* Based on original Kirkwood support which is
* (C) Copyright 2009
* Marvell Semiconductor <www.marvell.com>
* Written-by: Prafulla Wadaskar <prafulla@marvell.com>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include <common.h>
#include <netdev.h>
#include <asm/cache.h>
#include <u-boot/md5.h>
#include <asm/arch/orion5x.h>
#include <hush.h>
#define BUFLEN 16
void reset_cpu(unsigned long ignored)
{
struct orion5x_cpu_registers *cpureg =
(struct orion5x_cpu_registers *)ORION5X_CPU_REG_BASE;
writel(readl(&cpureg->rstoutn_mask) | (1 << 2),
&cpureg->rstoutn_mask);
writel(readl(&cpureg->sys_soft_rst) | 1,
&cpureg->sys_soft_rst);
while (1)
;
}
/*
* Window Size
* Used with the Base register to set the address window size and location.
* Must be programmed from LSB to MSB as sequence of ones followed by
* sequence of zeros. The number of ones specifies the size of the window in
* 64 KByte granularity (e.g., a value of 0x00FF specifies 256 = 16 MByte).
* NOTE: A value of 0x0 specifies 64-KByte size.
*/
unsigned int orion5x_winctrl_calcsize(unsigned int sizeval)
{
int i;
unsigned int j = 0;
u32 val = sizeval >> 1;
for (i = 0; val >= 0x10000; i++) {
j |= (1 << i);
val = val >> 1;
}
return 0x0000ffff & j;
}
/*
* orion5x_config_adr_windows - Configure address Windows
*
* There are 8 address windows supported by Orion5x Soc to addess different
* devices. Each window can be configured for size, BAR and remap addr
* Below configuration is standard for most of the cases
*
* If remap function not used, remap_lo must be set as base
*
* Reference Documentation:
* Mbus-L to Mbus Bridge Registers Configuration.
* (Sec 25.1 and 25.3 of Datasheet)
*/
int orion5x_config_adr_windows(void)
{
struct orion5x_win_registers *winregs =
(struct orion5x_win_registers *)ORION5X_CPU_WIN_BASE;
/* Window 0: PCIE MEM address space */
writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_SZ_PCIE_MEM,
ORION5X_TARGET_PCIE, ORION5X_ATTR_PCIE_MEM,
ORION5X_WIN_ENABLE), &winregs[0].ctrl);
writel(ORION5X_ADR_PCIE_MEM, &winregs[0].base);
writel(ORION5X_ADR_PCIE_MEM_REMAP_LO, &winregs[0].remap_lo);
writel(ORION5X_ADR_PCIE_MEM_REMAP_HI, &winregs[0].remap_hi);
/* Window 1: PCIE IO address space */
writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_SZ_PCIE_IO,
ORION5X_TARGET_PCIE, ORION5X_ATTR_PCIE_IO,
ORION5X_WIN_ENABLE), &winregs[1].ctrl);
writel(ORION5X_ADR_PCIE_IO, &winregs[1].base);
writel(ORION5X_ADR_PCIE_IO_REMAP_LO, &winregs[1].remap_lo);
writel(ORION5X_ADR_PCIE_IO_REMAP_HI, &winregs[1].remap_hi);
/* Window 2: PCI MEM address space */
writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_SZ_PCI_MEM,
ORION5X_TARGET_PCI, ORION5X_ATTR_PCI_MEM,
ORION5X_WIN_ENABLE), &winregs[2].ctrl);
writel(ORION5X_ADR_PCI_MEM, &winregs[2].base);
/* Window 3: PCI IO address space */
writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_SZ_PCI_IO,
ORION5X_TARGET_PCI, ORION5X_ATTR_PCI_IO,
ORION5X_WIN_ENABLE), &winregs[3].ctrl);
writel(ORION5X_ADR_PCI_IO, &winregs[3].base);
/* Window 4: DEV_CS0 address space */
writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_SZ_DEV_CS0,
ORION5X_TARGET_DEVICE, ORION5X_ATTR_DEV_CS0,
ORION5X_WIN_ENABLE), &winregs[4].ctrl);
writel(ORION5X_ADR_DEV_CS0, &winregs[4].base);
/* Window 5: DEV_CS1 address space */
writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_SZ_DEV_CS1,
ORION5X_TARGET_DEVICE, ORION5X_ATTR_DEV_CS1,
ORION5X_WIN_ENABLE), &winregs[5].ctrl);
writel(ORION5X_ADR_DEV_CS1, &winregs[5].base);
/* Window 6: DEV_CS2 address space */
writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_SZ_DEV_CS2,
ORION5X_TARGET_DEVICE, ORION5X_ATTR_DEV_CS2,
ORION5X_WIN_ENABLE), &winregs[6].ctrl);
writel(ORION5X_ADR_DEV_CS2, &winregs[6].base);
/* Window 7: BOOT Memory address space */
writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_SZ_BOOTROM,
ORION5X_TARGET_DEVICE, ORION5X_ATTR_BOOTROM,
ORION5X_WIN_ENABLE), &winregs[7].ctrl);
writel(ORION5X_ADR_BOOTROM, &winregs[7].base);
return 0;
}
/*
* Orion5x identification is done through PCIE space.
*/
u32 orion5x_device_id(void)
{
return readl(PCIE_DEV_ID_OFF) >> 16;
}
u32 orion5x_device_rev(void)
{
return readl(PCIE_DEV_REV_OFF) & 0xff;
}
#if defined(CONFIG_DISPLAY_CPUINFO)
/* Display device and revision IDs.
* This function must cover all known device/revision
* combinations, not only the one for which u-boot is
* compiled; this way, one can identify actual HW in
* case of a mismatch.
*/
int print_cpuinfo(void)
{
char dev_str[] = "0x0000";
char rev_str[] = "0x00";
char *dev_name = NULL;
char *rev_name = NULL;
u32 dev = orion5x_device_id();
u32 rev = orion5x_device_rev();
if (dev == MV88F5181_DEV_ID) {
dev_name = "MV88F5181";
if (rev == MV88F5181_REV_B1)
rev_name = "B1";
else if (rev == MV88F5181L_REV_A1) {
dev_name = "MV88F5181L";
rev_name = "A1";
} else if (rev == MV88F5181L_REV_A0) {
dev_name = "MV88F5181L";
rev_name = "A0";
}
} else if (dev == MV88F5182_DEV_ID) {
dev_name = "MV88F5182";
if (rev == MV88F5182_REV_A2)
rev_name = "A2";
} else if (dev == MV88F5281_DEV_ID) {
dev_name = "MV88F5281";
if (rev == MV88F5281_REV_D2)
rev_name = "D2";
else if (rev == MV88F5281_REV_D1)
rev_name = "D1";
else if (rev == MV88F5281_REV_D0)
rev_name = "D0";
} else if (dev == MV88F6183_DEV_ID) {
dev_name = "MV88F6183";
if (rev == MV88F6183_REV_B0)
rev_name = "B0";
}
if (dev_name == NULL) {
sprintf(dev_str, "0x%04x", dev);
dev_name = dev_str;
}
if (rev_name == NULL) {
sprintf(rev_str, "0x%02x", rev);
rev_name = rev_str;
}
printf("SoC: Orion5x %s-%s\n", dev_name, rev_name);
return 0;
}
#endif /* CONFIG_DISPLAY_CPUINFO */
#ifdef CONFIG_ARCH_CPU_INIT
int arch_cpu_init(void)
{
/* Enable and invalidate L2 cache in write through mode */
invalidate_l2_cache();
orion5x_config_adr_windows();
return 0;
}
#endif /* CONFIG_ARCH_CPU_INIT */
/*
* SOC specific misc init
*/
#if defined(CONFIG_ARCH_MISC_INIT)
int arch_misc_init(void)
{
u32 temp;
/*CPU streaming & write allocate */
temp = readfr_extra_feature_reg();
temp &= ~(1 << 28); /* disable wr alloc */
writefr_extra_feature_reg(temp);
temp = readfr_extra_feature_reg();
temp &= ~(1 << 29); /* streaming disabled */
writefr_extra_feature_reg(temp);
/* L2Cache settings */
temp = readfr_extra_feature_reg();
/* Disable L2C pre fetch - Set bit 24 */
temp |= (1 << 24);
/* enable L2C - Set bit 22 */
temp |= (1 << 22);
writefr_extra_feature_reg(temp);
icache_enable();
/* Change reset vector to address 0x0 */
temp = get_cr();
set_cr(temp & ~CR_V);
/* Set CPIOs and MPPs - values provided by board
include file */
writel(ORION5X_MPP0_7, ORION5X_MPP_BASE+0x00);
writel(ORION5X_MPP8_15, ORION5X_MPP_BASE+0x04);
writel(ORION5X_MPP16_23, ORION5X_MPP_BASE+0x50);
writel(ORION5X_GPIO_OUT_ENABLE, ORION5X_GPIO_BASE+0x04);
return 0;
}
#endif /* CONFIG_ARCH_MISC_INIT */
#ifdef CONFIG_MVGBE
int cpu_eth_init(bd_t *bis)
{
mvgbe_initialize(bis);
return 0;
}
#endif