Commit 971d7fa0 authored by Andrei Konovalov's avatar Andrei Konovalov Committed by Linus Torvalds

[PATCH] ppc32: Xilinx ML300 board support (very basic)

Adds minimal Xilinx ML300 board support (enough to boot with ramdisk).  The
only peripheral devices supported are 16x50 compatible UARTs.
Signed-off-by: default avatarAndrei Konovalov <akonovalov@ru.mvista.com>
Acked-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: default avatarMatt Porter <mporter@kernel.crashing.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 9ee4f026
......@@ -78,7 +78,7 @@ config SERIAL_TEXT_DEBUG
config PPC_OCP
bool
depends on IBM_OCP || FSL_OCP
depends on IBM_OCP || FSL_OCP || XILINX_OCP
default y
endmenu
......@@ -749,32 +749,35 @@ embed_config(bd_t ** bdp)
static const unsigned long line_size = 32;
static const unsigned long congruence_classes = 256;
unsigned long addr;
u_char *cp;
int i;
unsigned long dccr;
bd_t *bd;
/*
* At one point, we were getting machine checks. Linux was not
* invalidating the data cache before it was enabled. The
* following code was added to do that. Soon after we had done
* that, we found the real reasons for the machine checks. I've
* run the kernel a few times with the following code
* temporarily removed without any apparent problems. However,
* I objdump'ed the kernel and boot code and found out that
* there were no other dccci's anywhere, so I put the code back
* in and have been reluctant to remove it. It seems safer to
* just leave it here.
*/
* Invalidate the data cache if the data cache is turned off.
* - The 405 core does not invalidate the data cache on power-up
* or reset but does turn off the data cache. We cannot assume
* that the cache contents are valid.
* - If the data cache is turned on this must have been done by
* a bootloader and we assume that the cache contents are
* valid.
*/
__asm__("mfdccr %0": "=r" (dccr));
if (dccr == 0) {
for (addr = 0;
addr < (congruence_classes * line_size); addr += line_size) {
addr < (congruence_classes * line_size);
addr += line_size) {
__asm__("dccci 0,%0": :"b"(addr));
}
}
bd = &bdinfo;
*bdp = bd;
bd->bi_memsize = XPAR_DDR_0_SIZE;
bd->bi_intfreq = XPAR_CORE_CLOCK_FREQ_HZ;
bd->bi_busfreq = XPAR_PLB_CLOCK_FREQ_HZ;
bd->bi_pci_busfreq = XPAR_PCI_0_CLOCK_FREQ_HZ;
timebase_period_ns = 1000000000 / bd->bi_tbfreq;
/* see bi_tbfreq definition in arch/ppc/platforms/4xx/xilinx_ml300.h */
}
#endif /* CONFIG_XILINX_ML300 */
......
......@@ -56,6 +56,11 @@ config WALNUT
help
This option enables support for the IBM PPC405GP evaluation board.
config XILINX_ML300
bool "Xilinx-ML300"
help
This option enables support for the Xilinx ML300 evaluation board.
endchoice
choice
......@@ -130,6 +135,11 @@ config IBM_OCP
depends on ASH || BUBINGA || CPCI405 || EBONY || EP405 || OCOTEA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || WALNUT
default y
config XILINX_OCP
bool
depends on XILINX_ML300
default y
config IBM_EMAC4
bool
depends on 440GX
......@@ -160,6 +170,11 @@ config 405GPR
depends on SYCAMORE
default y
config VIRTEX_II_PRO
bool
depends on XILINX_ML300
default y
config STB03xxx
bool
depends on REDWOOD_5 || REDWOOD_6
......@@ -167,7 +182,7 @@ config STB03xxx
config EMBEDDEDBOOT
bool
depends on EP405
depends on EP405 || XILINX_ML300
default y
config IBM_OPENBIOS
......
......@@ -12,6 +12,7 @@ obj-$(CONFIG_REDWOOD_5) += redwood5.o
obj-$(CONFIG_REDWOOD_6) += redwood6.o
obj-$(CONFIG_SYCAMORE) += sycamore.o
obj-$(CONFIG_WALNUT) += walnut.o
obj-$(CONFIG_XILINX_ML300) += xilinx_ml300.o
obj-$(CONFIG_405GP) += ibm405gp.o
obj-$(CONFIG_REDWOOD_5) += ibmstb4.o
......@@ -21,3 +22,4 @@ obj-$(CONFIG_440GP) += ibm440gp.o
obj-$(CONFIG_440GX) += ibm440gx.o
obj-$(CONFIG_405EP) += ibm405ep.o
obj-$(CONFIG_405GPR) += ibm405gpr.o
obj-$(CONFIG_VIRTEX_II_PRO) += virtex-ii_pro.o
/*
* arch/ppc/platforms/4xx/virtex-ii_pro.c
*
* Author: MontaVista Software, Inc.
* source@mvista.com
*
* 2002-2004 (c) MontaVista Software, Inc. 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/config.h>
#include <linux/init.h>
#include <asm/ocp.h>
#include "virtex-ii_pro.h"
/* Have OCP take care of the serial ports. */
struct ocp_def core_ocp[] = {
#ifdef XPAR_UARTNS550_0_BASEADDR
{ .vendor = OCP_VENDOR_XILINX,
.function = OCP_FUNC_16550,
.index = 0,
.paddr = XPAR_UARTNS550_0_BASEADDR,
.irq = XPAR_INTC_0_UARTNS550_0_VEC_ID,
.pm = OCP_CPM_NA
},
#ifdef XPAR_UARTNS550_1_BASEADDR
{ .vendor = OCP_VENDOR_XILINX,
.function = OCP_FUNC_16550,
.index = 1,
.paddr = XPAR_UARTNS550_1_BASEADDR,
.irq = XPAR_INTC_0_UARTNS550_1_VEC_ID,
.pm = OCP_CPM_NA
},
#ifdef XPAR_UARTNS550_2_BASEADDR
{ .vendor = OCP_VENDOR_XILINX,
.function = OCP_FUNC_16550,
.index = 2,
.paddr = XPAR_UARTNS550_2_BASEADDR,
.irq = XPAR_INTC_0_UARTNS550_2_VEC_ID,
.pm = OCP_CPM_NA
},
#ifdef XPAR_UARTNS550_3_BASEADDR
{ .vendor = OCP_VENDOR_XILINX,
.function = OCP_FUNC_16550,
.index = 3,
.paddr = XPAR_UARTNS550_3_BASEADDR,
.irq = XPAR_INTC_0_UARTNS550_3_VEC_ID,
.pm = OCP_CPM_NA
},
#ifdef XPAR_UARTNS550_4_BASEADDR
#error Edit this file to add more devices.
#endif /* 4 */
#endif /* 3 */
#endif /* 2 */
#endif /* 1 */
#endif /* 0 */
{ .vendor = OCP_VENDOR_INVALID
}
};
/*
* arch/ppc/platforms/4xx/virtex-ii_pro.h
*
* Include file that defines the Xilinx Virtex-II Pro processor
*
* Author: MontaVista Software, Inc.
* source@mvista.com
*
* 2002-2004 (c) MontaVista Software, Inc. 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.
*/
#ifdef __KERNEL__
#ifndef __ASM_VIRTEXIIPRO_H__
#define __ASM_VIRTEXIIPRO_H__
#include <linux/config.h>
#include <asm/xparameters.h>
/* serial defines */
#define RS_TABLE_SIZE 4 /* change this and add more devices below
if you have more then 4 16x50 UARTs */
#define BASE_BAUD (XPAR_UARTNS550_0_CLOCK_FREQ_HZ/16)
/* The serial ports in the Virtex-II Pro have each I/O byte in the
* LSByte of a word. This means that iomem_reg_shift needs to be 2 to
* change the byte offsets into word offsets. In addition the base
* addresses need to have 3 added to them to get to the LSByte.
*/
#define STD_UART_OP(num) \
{ 0, BASE_BAUD, 0, XPAR_INTC_0_UARTNS550_##num##_VEC_ID, \
ASYNC_BOOT_AUTOCONF, \
.iomem_base = (u8 *)XPAR_UARTNS550_##num##_BASEADDR + 3, \
.iomem_reg_shift = 2, \
.io_type = SERIAL_IO_MEM},
#if defined(XPAR_INTC_0_UARTNS550_0_VEC_ID)
#define ML300_UART0 STD_UART_OP(0)
#else
#define ML300_UART0
#endif
#if defined(XPAR_INTC_0_UARTNS550_1_VEC_ID)
#define ML300_UART1 STD_UART_OP(1)
#else
#define ML300_UART1
#endif
#if defined(XPAR_INTC_0_UARTNS550_2_VEC_ID)
#define ML300_UART2 STD_UART_OP(2)
#else
#define ML300_UART2
#endif
#if defined(XPAR_INTC_0_UARTNS550_3_VEC_ID)
#define ML300_UART3 STD_UART_OP(3)
#else
#define ML300_UART3
#endif
#if defined(XPAR_INTC_0_UARTNS550_4_VEC_ID)
#error Edit this file to add more devices.
#elif defined(XPAR_INTC_0_UARTNS550_3_VEC_ID)
#define NR_SER_PORTS 4
#elif defined(XPAR_INTC_0_UARTNS550_2_VEC_ID)
#define NR_SER_PORTS 3
#elif defined(XPAR_INTC_0_UARTNS550_1_VEC_ID)
#define NR_SER_PORTS 2
#elif defined(XPAR_INTC_0_UARTNS550_0_VEC_ID)
#define NR_SER_PORTS 1
#else
#define NR_SER_PORTS 0
#endif
#if defined(CONFIG_UART0_TTYS0)
#define SERIAL_PORT_DFNS \
ML300_UART0 \
ML300_UART1 \
ML300_UART2 \
ML300_UART3
#endif
#if defined(CONFIG_UART0_TTYS1)
#define SERIAL_PORT_DFNS \
ML300_UART1 \
ML300_UART0 \
ML300_UART2 \
ML300_UART3
#endif
#define DCRN_CPMFR_BASE 0
#include <asm/ibm405.h>
#endif /* __ASM_VIRTEXIIPRO_H__ */
#endif /* __KERNEL__ */
/*
* arch/ppc/platforms/4xx/xilinx_ml300.c
*
* Xilinx ML300 evaluation board initialization
*
* Author: MontaVista Software, Inc.
* source@mvista.com
*
* 2002-2004 (c) MontaVista Software, Inc. 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/config.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/serialP.h>
#include <asm/io.h>
#include <asm/machdep.h>
#include <asm/ocp.h>
#include <platforms/4xx/virtex-ii_pro.h> /* for NR_SER_PORTS */
/*
* As an overview of how the following functions (platform_init,
* ml300_map_io, ml300_setup_arch and ml300_init_IRQ) fit into the
* kernel startup procedure, here's a call tree:
*
* start_here arch/ppc/kernel/head_4xx.S
* early_init arch/ppc/kernel/setup.c
* machine_init arch/ppc/kernel/setup.c
* platform_init this file
* ppc4xx_init arch/ppc/syslib/ppc4xx_setup.c
* parse_bootinfo
* find_bootinfo
* "setup some default ppc_md pointers"
* MMU_init arch/ppc/mm/init.c
* *ppc_md.setup_io_mappings == ml300_map_io this file
* ppc4xx_map_io arch/ppc/syslib/ppc4xx_setup.c
* start_kernel init/main.c
* setup_arch arch/ppc/kernel/setup.c
* #if defined(CONFIG_KGDB)
* *ppc_md.kgdb_map_scc() == gen550_kgdb_map_scc
* #endif
* *ppc_md.setup_arch == ml300_setup_arch this file
* ppc4xx_setup_arch arch/ppc/syslib/ppc4xx_setup.c
* ppc4xx_find_bridges arch/ppc/syslib/ppc405_pci.c
* init_IRQ arch/ppc/kernel/irq.c
* *ppc_md.init_IRQ == ml300_init_IRQ this file
* ppc4xx_init_IRQ arch/ppc/syslib/ppc4xx_setup.c
* ppc4xx_pic_init arch/ppc/syslib/xilinx_pic.c
*/
#if defined(XPAR_POWER_0_POWERDOWN_BASEADDR)
static volatile unsigned *powerdown_base =
(volatile unsigned *) XPAR_POWER_0_POWERDOWN_BASEADDR;
static void
xilinx_power_off(void)
{
local_irq_disable();
out_be32(powerdown_base, XPAR_POWER_0_POWERDOWN_VALUE);
while (1) ;
}
#endif
void __init
ml300_map_io(void)
{
ppc4xx_map_io();
#if defined(XPAR_POWER_0_POWERDOWN_BASEADDR)
powerdown_base = ioremap((unsigned long) powerdown_base,
XPAR_POWER_0_POWERDOWN_HIGHADDR -
XPAR_POWER_0_POWERDOWN_BASEADDR + 1);
#endif
}
static void __init
ml300_early_serial_map(void)
{
#ifdef CONFIG_SERIAL_8250
struct serial_state old_ports[] = { SERIAL_PORT_DFNS };
struct uart_port port;
int i;
/* Setup ioremapped serial port access */
for (i = 0; i < ARRAY_SIZE(old_ports); i++ ) {
memset(&port, 0, sizeof(port));
port.membase = ioremap((phys_addr_t)(old_ports[i].iomem_base), 16);
port.irq = old_ports[i].irq;
port.uartclk = old_ports[i].baud_base * 16;
port.regshift = old_ports[i].iomem_reg_shift;
port.iotype = SERIAL_IO_MEM;
port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
port.line = i;
if (early_serial_setup(&port) != 0) {
printk("Early serial init of port %d failed\n", i);
}
}
#endif /* CONFIG_SERIAL_8250 */
}
void __init
ml300_setup_arch(void)
{
ppc4xx_setup_arch(); /* calls ppc4xx_find_bridges() */
ml300_early_serial_map();
/* Identify the system */
printk(KERN_INFO "Xilinx Virtex-II Pro port\n");
printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n");
}
/* Called after board_setup_irq from ppc4xx_init_IRQ(). */
void __init
ml300_init_irq(void)
{
unsigned int i;
ppc4xx_init_IRQ();
/*
* For PowerPC 405 cores the default value for NR_IRQS is 32.
* See include/asm-ppc/irq.h for details.
* This is just fine for ML300.
*/
#if (NR_IRQS != 32)
#error NR_IRQS must be 32 for ML300
#endif
for (i = 0; i < NR_IRQS; i++) {
if (XPAR_INTC_0_KIND_OF_INTR & (0x80000000 >> i))
irq_desc[i].status &= ~IRQ_LEVEL;
else
irq_desc[i].status |= IRQ_LEVEL;
}
}
void __init
platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7)
{
ppc4xx_init(r3, r4, r5, r6, r7);
ppc_md.setup_arch = ml300_setup_arch;
ppc_md.setup_io_mappings = ml300_map_io;
ppc_md.init_IRQ = ml300_init_irq;
#if defined(XPAR_POWER_0_POWERDOWN_BASEADDR)
ppc_md.power_off = xilinx_power_off;
#endif
#ifdef CONFIG_KGDB
ppc_md.early_serial_map = ml300_early_serial_map;
#endif
}
/*
* arch/ppc/platforms/4xx/xilinx_ml300.h
*
* Include file that defines the Xilinx ML300 evaluation board
*
* Author: MontaVista Software, Inc.
* source@mvista.com
*
* 2002-2004 (c) MontaVista Software, Inc. 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.
*/
#ifdef __KERNEL__
#ifndef __ASM_XILINX_ML300_H__
#define __ASM_XILINX_ML300_H__
/* ML300 has a Xilinx Virtex-II Pro processor */
#include <platforms/4xx/virtex-ii_pro.h>
#ifndef __ASSEMBLY__
#include <linux/types.h>
typedef struct board_info {
unsigned int bi_memsize; /* DRAM installed, in bytes */
unsigned char bi_enetaddr[6]; /* Local Ethernet MAC address */
unsigned int bi_intfreq; /* Processor speed, in Hz */
unsigned int bi_busfreq; /* PLB Bus speed, in Hz */
unsigned int bi_pci_busfreq; /* PCI Bus speed, in Hz */
} bd_t;
/* Some 4xx parts use a different timebase frequency from the internal clock.
*/
#define bi_tbfreq bi_intfreq
#endif /* !__ASSEMBLY__ */
/* We don't need anything mapped. Size of zero will accomplish that. */
#define PPC4xx_ONB_IO_PADDR 0u
#define PPC4xx_ONB_IO_VADDR 0u
#define PPC4xx_ONB_IO_SIZE 0u
#define PPC4xx_MACHINE_NAME "Xilinx ML300"
#endif /* __ASM_XILINX_ML300_H__ */
#endif /* __KERNEL__ */
This diff is collapsed.
......@@ -14,7 +14,12 @@ obj-$(CONFIG_44x) += ibm44x_common.o
obj-$(CONFIG_440GP) += ibm440gp_common.o
obj-$(CONFIG_440GX) += ibm440gx_common.o
ifeq ($(CONFIG_4xx),y)
obj-$(CONFIG_4xx) += ppc4xx_pic.o
ifeq ($(CONFIG_VIRTEX_II_PRO),y)
obj-$(CONFIG_40x) += xilinx_pic.o
else
obj-$(CONFIG_40x) += ppc4xx_pic.o
endif
obj-$(CONFIG_44x) += ppc4xx_pic.o
obj-$(CONFIG_40x) += ppc4xx_setup.o
obj-$(CONFIG_GEN_RTC) += todc_time.o
obj-$(CONFIG_PPC4xx_DMA) += ppc4xx_dma.o
......
/*
* arch/ppc/syslib/xilinx_pic.c
*
* Interrupt controller driver for Xilinx Virtex-II Pro.
*
* Author: MontaVista Software, Inc.
* source@mvista.com
*
* 2002-2004 (c) MontaVista Software, Inc. 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/init.h>
#include <linux/irq.h>
#include <asm/io.h>
#include <asm/xparameters.h>
#include <asm/ibm4xx.h>
/* No one else should require these constants, so define them locally here. */
#define ISR 0 /* Interrupt Status Register */
#define IPR 1 /* Interrupt Pending Register */
#define IER 2 /* Interrupt Enable Register */
#define IAR 3 /* Interrupt Acknowledge Register */
#define SIE 4 /* Set Interrupt Enable bits */
#define CIE 5 /* Clear Interrupt Enable bits */
#define IVR 6 /* Interrupt Vector Register */
#define MER 7 /* Master Enable Register */
#if XPAR_XINTC_USE_DCR == 0
static volatile u32 *intc;
#define intc_out_be32(addr, mask) out_be32((addr), (mask))
#define intc_in_be32(addr) in_be32((addr))
#else
#define intc XPAR_INTC_0_BASEADDR
#define intc_out_be32(addr, mask) mtdcr((addr), (mask))
#define intc_in_be32(addr) mfdcr((addr))
#endif
/* Global Variables */
struct hw_interrupt_type *ppc4xx_pic;
static void
xilinx_intc_enable(unsigned int irq)
{
unsigned long mask = (0x00000001 << (irq & 31));
pr_debug("enable: %d\n", irq);
intc_out_be32(intc + SIE, mask);
}
static void
xilinx_intc_disable(unsigned int irq)
{
unsigned long mask = (0x00000001 << (irq & 31));
pr_debug("disable: %d\n", irq);
intc_out_be32(intc + CIE, mask);
}
static void
xilinx_intc_disable_and_ack(unsigned int irq)
{
unsigned long mask = (0x00000001 << (irq & 31));
pr_debug("disable_and_ack: %d\n", irq);
intc_out_be32(intc + CIE, mask);
if (!(irq_desc[irq].status & IRQ_LEVEL))
intc_out_be32(intc + IAR, mask); /* ack edge triggered intr */
}
static void
xilinx_intc_end(unsigned int irq)
{
unsigned long mask = (0x00000001 << (irq & 31));
pr_debug("end: %d\n", irq);
if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
intc_out_be32(intc + SIE, mask);
/* ack level sensitive intr */
if (irq_desc[irq].status & IRQ_LEVEL)
intc_out_be32(intc + IAR, mask);
}
}
static struct hw_interrupt_type xilinx_intc = {
"Xilinx Interrupt Controller",
NULL,
NULL,
xilinx_intc_enable,
xilinx_intc_disable,
xilinx_intc_disable_and_ack,
xilinx_intc_end,
0
};
int
xilinx_pic_get_irq(struct pt_regs *regs)
{
int irq;
/*
* NOTE: This function is the one that needs to be improved in
* order to handle multiple interrupt controllers. It currently
* is hardcoded to check for interrupts only on the first INTC.
*/
irq = intc_in_be32(intc + IVR);
if (irq != -1)
irq = irq;
pr_debug("get_irq: %d\n", irq);
return (irq);
}
void __init
ppc4xx_pic_init(void)
{
#if XPAR_XINTC_USE_DCR == 0
intc = ioremap(XPAR_INTC_0_BASEADDR, 32);
printk(KERN_INFO "Xilinx INTC #0 at 0x%08lX mapped to 0x%08lX\n",
(unsigned long) XPAR_INTC_0_BASEADDR, (unsigned long) intc);
#else
printk(KERN_INFO "Xilinx INTC #0 at 0x%08lX (DCR)\n",
(unsigned long) XPAR_INTC_0_BASEADDR);
#endif
/*
* Disable all external interrupts until they are
* explicity requested.
*/
intc_out_be32(intc + IER, 0);
/* Acknowledge any pending interrupts just in case. */
intc_out_be32(intc + IAR, ~(u32) 0);
/* Turn on the Master Enable. */
intc_out_be32(intc + MER, 0x3UL);
ppc4xx_pic = &xilinx_intc;
ppc_md.get_irq = xilinx_pic_get_irq;
}
......@@ -59,6 +59,10 @@
#include <platforms/4xx/walnut.h>
#endif
#if defined(CONFIG_XILINX_ML300)
#include <platforms/4xx/xilinx_ml300.h>
#endif
#ifndef __ASSEMBLY__
#ifdef CONFIG_40x
......
/*
* include/asm-ppc/xparameters.h
*
* This file includes the correct xparameters.h for the CONFIG'ed board
*
* Author: MontaVista Software, Inc.
* source@mvista.com
*
* 2004 (c) MontaVista Software, Inc. 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/config.h>
#if defined(CONFIG_XILINX_ML300)
#include <platforms/4xx/xparameters/xparameters_ml300.h>
#endif
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