Commit 777f9beb authored by Lennert Buytenhek's avatar Lennert Buytenhek

[ARM] add Marvell Loki (88RC8480) SoC support

The Marvell Loki (88RC8480) is an ARM SoC based on a Feroceon CPU
core running at between 400 MHz and 1.0 GHz, and features a 64 bit
DDR controller, 512K of internal SRAM, two x4 PCI-Express ports,
two Gigabit Ethernet ports, two 4x SAS/SATA controllers, two UARTs,
two TWSI controllers, and IDMA/XOR engines.

This patch adds support for the Marvell LB88RC8480 Development
Board, enabling the use of the PCIe interfaces, the ethernet
interfaces, the TWSI interfaces and the UARTs.
Signed-off-by: default avatarLennert Buytenhek <buytenh@marvell.com>
parent 1219715d
......@@ -370,6 +370,14 @@ config ARCH_NS9XXX
<http://www.digi.com/products/microprocessors/index.jsp>
config ARCH_LOKI
bool "Marvell Loki (88RC8480)"
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
select PLAT_ORION
help
Support for the Marvell Loki (88RC8480) SoC.
config ARCH_MXC
bool "Freescale MXC/iMX-based"
select ARCH_MTD_XIP
......@@ -508,6 +516,8 @@ source "arch/arm/mach-ixp2000/Kconfig"
source "arch/arm/mach-ixp23xx/Kconfig"
source "arch/arm/mach-loki/Kconfig"
source "arch/arm/mach-pxa/Kconfig"
source "arch/arm/mach-sa1100/Kconfig"
......
......@@ -140,6 +140,7 @@ endif
machine-$(CONFIG_ARCH_MX3) := mx3
machine-$(CONFIG_ARCH_ORION5X) := orion5x
machine-$(CONFIG_ARCH_MSM7X00A) := msm
machine-$(CONFIG_ARCH_LOKI) := loki
ifeq ($(CONFIG_ARCH_EBSA110),y)
# This is what happens if you forget the IOCS16 line.
......
if ARCH_LOKI
menu "Marvell Loki (88RC8480) Implementations"
config MACH_LB88RC8480
bool "Marvell LB88RC8480 Development Board"
help
Say 'Y' here if you want your kernel to support the
Marvell LB88RC8480 Development Board.
endmenu
endif
obj-y += common.o addr-map.o irq.o
obj-$(CONFIG_MACH_LB88RC8480) += lb88rc8480-setup.o
zreladdr-y := 0x00008000
params_phys-y := 0x00000100
initrd_phys-y := 0x00800000
/*
* arch/arm/mach-loki/addr-map.c
*
* Address map functions for Marvell Loki (88RC8480) SoCs
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mbus.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include "common.h"
/*
* Generic Address Decode Windows bit settings
*/
#define TARGET_DDR 0
#define TARGET_DEV_BUS 1
#define TARGET_PCIE0 3
#define TARGET_PCIE1 4
#define ATTR_DEV_BOOT 0x0f
#define ATTR_DEV_CS2 0x1b
#define ATTR_DEV_CS1 0x1d
#define ATTR_DEV_CS0 0x1e
#define ATTR_PCIE_IO 0x51
#define ATTR_PCIE_MEM 0x59
/*
* Helpers to get DDR bank info
*/
#define DDR_SIZE_CS(n) DDR_REG(0x1500 + ((n) << 3))
#define DDR_BASE_CS(n) DDR_REG(0x1504 + ((n) << 3))
/*
* CPU Address Decode Windows registers
*/
#define CPU_WIN_CTRL(n) BRIDGE_REG(0x000 | ((n) << 4))
#define CPU_WIN_BASE(n) BRIDGE_REG(0x004 | ((n) << 4))
#define CPU_WIN_REMAP_LO(n) BRIDGE_REG(0x008 | ((n) << 4))
#define CPU_WIN_REMAP_HI(n) BRIDGE_REG(0x00c | ((n) << 4))
struct mbus_dram_target_info loki_mbus_dram_info;
static void __init setup_cpu_win(int win, u32 base, u32 size,
u8 target, u8 attr, int remap)
{
u32 ctrl;
base &= 0xffff0000;
ctrl = ((size - 1) & 0xffff0000) | (attr << 8) | (1 << 5) | target;
writel(base, CPU_WIN_BASE(win));
writel(ctrl, CPU_WIN_CTRL(win));
if (win < 2) {
if (remap < 0)
remap = base;
writel(remap & 0xffff0000, CPU_WIN_REMAP_LO(win));
writel(0, CPU_WIN_REMAP_HI(win));
}
}
void __init loki_setup_cpu_mbus(void)
{
int i;
int cs;
/*
* First, disable and clear windows.
*/
for (i = 0; i < 8; i++) {
writel(0, CPU_WIN_BASE(i));
writel(0, CPU_WIN_CTRL(i));
if (i < 2) {
writel(0, CPU_WIN_REMAP_LO(i));
writel(0, CPU_WIN_REMAP_HI(i));
}
}
/*
* Setup windows for PCIe IO+MEM space.
*/
setup_cpu_win(2, LOKI_PCIE0_MEM_PHYS_BASE, LOKI_PCIE0_MEM_SIZE,
TARGET_PCIE0, ATTR_PCIE_MEM, -1);
setup_cpu_win(3, LOKI_PCIE1_MEM_PHYS_BASE, LOKI_PCIE1_MEM_SIZE,
TARGET_PCIE1, ATTR_PCIE_MEM, -1);
/*
* Setup MBUS dram target info.
*/
loki_mbus_dram_info.mbus_dram_target_id = TARGET_DDR;
for (i = 0, cs = 0; i < 4; i++) {
u32 base = readl(DDR_BASE_CS(i));
u32 size = readl(DDR_SIZE_CS(i));
/*
* Chip select enabled?
*/
if (size & 1) {
struct mbus_dram_window *w;
w = &loki_mbus_dram_info.cs[cs++];
w->cs_index = i;
w->mbus_attr = 0xf & ~(1 << i);
w->base = base & 0xffff0000;
w->size = (size | 0x0000ffff) + 1;
}
}
loki_mbus_dram_info.num_cs = cs;
}
void __init loki_setup_dev_boot_win(u32 base, u32 size)
{
setup_cpu_win(4, base, size, TARGET_DEV_BUS, ATTR_DEV_BOOT, -1);
}
/*
* arch/arm/mach-loki/common.c
*
* Core functions for Marvell Loki (88RC8480) SoCs
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/serial_8250.h>
#include <linux/mbus.h>
#include <linux/mv643xx_eth.h>
#include <asm/page.h>
#include <asm/timex.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
#include <asm/arch/loki.h>
#include <asm/plat-orion/orion_nand.h>
#include <asm/plat-orion/time.h>
#include "common.h"
/*****************************************************************************
* I/O Address Mapping
****************************************************************************/
static struct map_desc loki_io_desc[] __initdata = {
{
.virtual = LOKI_REGS_VIRT_BASE,
.pfn = __phys_to_pfn(LOKI_REGS_PHYS_BASE),
.length = LOKI_REGS_SIZE,
.type = MT_DEVICE,
},
};
void __init loki_map_io(void)
{
iotable_init(loki_io_desc, ARRAY_SIZE(loki_io_desc));
}
/*****************************************************************************
* GE0
****************************************************************************/
struct mv643xx_eth_shared_platform_data loki_ge0_shared_data = {
.t_clk = LOKI_TCLK,
.dram = &loki_mbus_dram_info,
};
static struct resource loki_ge0_shared_resources[] = {
{
.name = "ge0 base",
.start = GE0_PHYS_BASE + 0x2000,
.end = GE0_PHYS_BASE + 0x3fff,
.flags = IORESOURCE_MEM,
},
};
static struct platform_device loki_ge0_shared = {
.name = MV643XX_ETH_SHARED_NAME,
.id = 0,
.dev = {
.platform_data = &loki_ge0_shared_data,
},
.num_resources = 1,
.resource = loki_ge0_shared_resources,
};
static struct resource loki_ge0_resources[] = {
{
.name = "ge0 irq",
.start = IRQ_LOKI_GBE_A_INT,
.end = IRQ_LOKI_GBE_A_INT,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device loki_ge0 = {
.name = MV643XX_ETH_NAME,
.id = 0,
.num_resources = 1,
.resource = loki_ge0_resources,
};
void __init loki_ge0_init(struct mv643xx_eth_platform_data *eth_data)
{
eth_data->shared = &loki_ge0_shared;
loki_ge0.dev.platform_data = eth_data;
writel(0x00079220, GE0_VIRT_BASE + 0x20b0);
platform_device_register(&loki_ge0_shared);
platform_device_register(&loki_ge0);
}
/*****************************************************************************
* GE1
****************************************************************************/
struct mv643xx_eth_shared_platform_data loki_ge1_shared_data = {
.t_clk = LOKI_TCLK,
.dram = &loki_mbus_dram_info,
};
static struct resource loki_ge1_shared_resources[] = {
{
.name = "ge1 base",
.start = GE1_PHYS_BASE + 0x2000,
.end = GE1_PHYS_BASE + 0x3fff,
.flags = IORESOURCE_MEM,
},
};
static struct platform_device loki_ge1_shared = {
.name = MV643XX_ETH_SHARED_NAME,
.id = 1,
.dev = {
.platform_data = &loki_ge1_shared_data,
},
.num_resources = 1,
.resource = loki_ge1_shared_resources,
};
static struct resource loki_ge1_resources[] = {
{
.name = "ge1 irq",
.start = IRQ_LOKI_GBE_B_INT,
.end = IRQ_LOKI_GBE_B_INT,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device loki_ge1 = {
.name = MV643XX_ETH_NAME,
.id = 1,
.num_resources = 1,
.resource = loki_ge1_resources,
};
void __init loki_ge1_init(struct mv643xx_eth_platform_data *eth_data)
{
eth_data->shared = &loki_ge1_shared;
loki_ge1.dev.platform_data = eth_data;
writel(0x00079220, GE1_VIRT_BASE + 0x20b0);
platform_device_register(&loki_ge1_shared);
platform_device_register(&loki_ge1);
}
/*****************************************************************************
* SAS/SATA
****************************************************************************/
static struct resource loki_sas_resources[] = {
{
.name = "mvsas0 mem",
.start = SAS0_PHYS_BASE,
.end = SAS0_PHYS_BASE + 0x01ff,
.flags = IORESOURCE_MEM,
}, {
.name = "mvsas0 irq",
.start = IRQ_LOKI_SAS_A,
.end = IRQ_LOKI_SAS_A,
.flags = IORESOURCE_IRQ,
}, {
.name = "mvsas1 mem",
.start = SAS1_PHYS_BASE,
.end = SAS1_PHYS_BASE + 0x01ff,
.flags = IORESOURCE_MEM,
}, {
.name = "mvsas1 irq",
.start = IRQ_LOKI_SAS_B,
.end = IRQ_LOKI_SAS_B,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device loki_sas = {
.name = "mvsas",
.id = 0,
.dev = {
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(loki_sas_resources),
.resource = loki_sas_resources,
};
void __init loki_sas_init(void)
{
writel(0x8300f707, DDR_REG(0x1424));
platform_device_register(&loki_sas);
}
/*****************************************************************************
* UART0
****************************************************************************/
static struct plat_serial8250_port loki_uart0_data[] = {
{
.mapbase = UART0_PHYS_BASE,
.membase = (char *)UART0_VIRT_BASE,
.irq = IRQ_LOKI_UART0,
.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
.iotype = UPIO_MEM,
.regshift = 2,
.uartclk = LOKI_TCLK,
}, {
},
};
static struct resource loki_uart0_resources[] = {
{
.start = UART0_PHYS_BASE,
.end = UART0_PHYS_BASE + 0xff,
.flags = IORESOURCE_MEM,
}, {
.start = IRQ_LOKI_UART0,
.end = IRQ_LOKI_UART0,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device loki_uart0 = {
.name = "serial8250",
.id = 0,
.dev = {
.platform_data = loki_uart0_data,
},
.resource = loki_uart0_resources,
.num_resources = ARRAY_SIZE(loki_uart0_resources),
};
void __init loki_uart0_init(void)
{
platform_device_register(&loki_uart0);
}
/*****************************************************************************
* UART1
****************************************************************************/
static struct plat_serial8250_port loki_uart1_data[] = {
{
.mapbase = UART1_PHYS_BASE,
.membase = (char *)UART1_VIRT_BASE,
.irq = IRQ_LOKI_UART1,
.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
.iotype = UPIO_MEM,
.regshift = 2,
.uartclk = LOKI_TCLK,
}, {
},
};
static struct resource loki_uart1_resources[] = {
{
.start = UART1_PHYS_BASE,
.end = UART1_PHYS_BASE + 0xff,
.flags = IORESOURCE_MEM,
}, {
.start = IRQ_LOKI_UART1,
.end = IRQ_LOKI_UART1,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device loki_uart1 = {
.name = "serial8250",
.id = 1,
.dev = {
.platform_data = loki_uart1_data,
},
.resource = loki_uart1_resources,
.num_resources = ARRAY_SIZE(loki_uart1_resources),
};
void __init loki_uart1_init(void)
{
platform_device_register(&loki_uart1);
}
/*****************************************************************************
* Time handling
****************************************************************************/
static void loki_timer_init(void)
{
orion_time_init(IRQ_LOKI_BRIDGE, LOKI_TCLK);
}
struct sys_timer loki_timer = {
.init = loki_timer_init,
};
/*****************************************************************************
* General
****************************************************************************/
void __init loki_init(void)
{
printk(KERN_INFO "Loki ID: 88RC8480. TCLK=%d.\n", LOKI_TCLK);
loki_setup_cpu_mbus();
}
/*
* arch/arm/mach-loki/common.h
*
* Core functions for Marvell Loki (88RC8480) SoCs
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#ifndef __ARCH_LOKI_COMMON_H
#define __ARCH_LOKI_COMMON_H
struct mv643xx_eth_platform_data;
/*
* Basic Loki init functions used early by machine-setup.
*/
void loki_map_io(void);
void loki_init(void);
void loki_init_irq(void);
extern struct mbus_dram_target_info loki_mbus_dram_info;
void loki_setup_cpu_mbus(void);
void loki_setup_dev_boot_win(u32 base, u32 size);
void loki_ge0_init(struct mv643xx_eth_platform_data *eth_data);
void loki_ge1_init(struct mv643xx_eth_platform_data *eth_data);
void loki_sas_init(void);
void loki_uart0_init(void);
void loki_uart1_init(void);
extern struct sys_timer loki_timer;
#endif
/*
* arch/arm/mach-loki/irq.c
*
* Marvell Loki (88RC8480) IRQ handling.
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <asm/io.h>
#include <asm/plat-orion/irq.h>
#include "common.h"
void __init loki_init_irq(void)
{
orion_irq_init(0, (void __iomem *)(IRQ_VIRT_BASE + IRQ_MASK_OFF));
}
/*
* arch/arm/mach-loki/lb88rc8480-setup.c
*
* Marvell LB88RC8480 Development Board Setup
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/irq.h>
#include <linux/mtd/physmap.h>
#include <linux/mtd/nand.h>
#include <linux/timer.h>
#include <linux/ata_platform.h>
#include <linux/mv643xx_eth.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/arch/loki.h>
#include "common.h"
#define LB88RC8480_FLASH_BOOT_CS_BASE 0xf8000000
#define LB88RC8480_FLASH_BOOT_CS_SIZE SZ_128M
#define LB88RC8480_NOR_BOOT_BASE 0xff000000
#define LB88RC8480_NOR_BOOT_SIZE SZ_16M
static struct mtd_partition lb88rc8480_boot_flash_parts[] = {
{
.name = "kernel",
.offset = 0,
.size = SZ_2M,
}, {
.name = "root-fs",
.offset = SZ_2M,
.size = (SZ_8M + SZ_4M + SZ_1M),
}, {
.name = "u-boot",
.offset = (SZ_8M + SZ_4M + SZ_2M + SZ_1M),
.size = SZ_1M,
},
};
static struct physmap_flash_data lb88rc8480_boot_flash_data = {
.parts = lb88rc8480_boot_flash_parts,
.nr_parts = ARRAY_SIZE(lb88rc8480_boot_flash_parts),
.width = 1, /* 8 bit bus width */
};
static struct resource lb88rc8480_boot_flash_resource = {
.flags = IORESOURCE_MEM,
.start = LB88RC8480_NOR_BOOT_BASE,
.end = LB88RC8480_NOR_BOOT_BASE + LB88RC8480_NOR_BOOT_SIZE - 1,
};
static struct platform_device lb88rc8480_boot_flash = {
.name = "physmap-flash",
.id = 0,
.dev = {
.platform_data = &lb88rc8480_boot_flash_data,
},
.num_resources = 1,
.resource = &lb88rc8480_boot_flash_resource,
};
static struct mv643xx_eth_platform_data lb88rc8480_ge0_data = {
.phy_addr = 1,
.mac_addr = { 0x00, 0x50, 0x43, 0x11, 0x22, 0x33 },
};
static void __init lb88rc8480_init(void)
{
/*
* Basic setup. Needs to be called early.