Commit 61974038 authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Josh Boyer

[POWERPC] 4xx: EP405 boards support for arch/powerpc

Brings EP405 support to arch/powerpc. The IRQ routing for the CPLD
comes from a device-tree property, PCI is working to the point where
I can see the video card, USB device, and south bridge.

This should work with both EP405 and EP405PC.

I've not totally figured out how IRQs are wired on this hardware
though, thus at this stage, expect only USB interrupts working,
pretty much the same as what arch/ppc did.

Also, the flash, nvram, rtc and temp control still have to be wired.
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarJosh Boyer <jwboyer@linux.vnet.ibm.com>
parent 9dae8afd
...@@ -179,13 +179,16 @@ void ibm40x_dbcr_reset(void) ...@@ -179,13 +179,16 @@ void ibm40x_dbcr_reset(void)
#define EMAC_RESET 0x20000000 #define EMAC_RESET 0x20000000
void ibm4xx_quiesce_eth(u32 *emac0, u32 *emac1) void ibm4xx_quiesce_eth(u32 *emac0, u32 *emac1)
{ {
/* Quiesce the MAL and EMAC(s) since PIBS/OpenBIOS don't do this for us */ /* Quiesce the MAL and EMAC(s) since PIBS/OpenBIOS don't
* do this for us
*/
if (emac0) if (emac0)
*emac0 = EMAC_RESET; *emac0 = EMAC_RESET;
if (emac1) if (emac1)
*emac1 = EMAC_RESET; *emac1 = EMAC_RESET;
mtdcr(DCRN_MAL0_CFG, MAL_RESET); mtdcr(DCRN_MAL0_CFG, MAL_RESET);
while (mfdcr(DCRN_MAL0_CFG) & MAL_RESET) {};
} }
/* Read 4xx EBC bus bridge registers to get mappings of the peripheral /* Read 4xx EBC bus bridge registers to get mappings of the peripheral
...@@ -298,3 +301,53 @@ void ibm440ep_fixup_clocks(unsigned int sysclk, unsigned int ser_clk) ...@@ -298,3 +301,53 @@ void ibm440ep_fixup_clocks(unsigned int sysclk, unsigned int ser_clk)
dt_fixup_clock("/plb/opb/serial@ef600500", uart0); dt_fixup_clock("/plb/opb/serial@ef600500", uart0);
dt_fixup_clock("/plb/opb/serial@ef600600", uart0); dt_fixup_clock("/plb/opb/serial@ef600600", uart0);
} }
void ibm405gp_fixup_clocks(unsigned int sysclk, unsigned int ser_clk)
{
u32 pllmr = mfdcr(DCRN_CPC0_PLLMR);
u32 cpc0_cr0 = mfdcr(DCRN_405_CPC0_CR0);
u32 cpc0_cr1 = mfdcr(DCRN_405_CPC0_CR1);
u32 cpu, plb, opb, ebc, tb, uart0, uart1, m;
u32 fwdv, fbdv, cbdv, opdv, epdv, udiv;
fwdv = (8 - ((pllmr & 0xe0000000) >> 29));
fbdv = (pllmr & 0x1e000000) >> 25;
cbdv = ((pllmr & 0x00060000) >> 17) + 1;
opdv = ((pllmr & 0x00018000) >> 15) + 1;
epdv = ((pllmr & 0x00001800) >> 13) + 2;
udiv = ((cpc0_cr0 & 0x3e) >> 1) + 1;
m = fwdv * fbdv * cbdv;
cpu = sysclk * m / fwdv;
plb = cpu / cbdv;
opb = plb / opdv;
ebc = plb / epdv;
if (cpc0_cr0 & 0x80) {
/* uart0 uses the external clock */
uart0 = ser_clk;
} else {
uart0 = cpu / udiv;
}
if (cpc0_cr0 & 0x40) {
/* uart1 uses the external clock */
uart1 = ser_clk;
} else {
uart1 = cpu / udiv;
}
/* setup the timebase clock to tick at the cpu frequency */
cpc0_cr1 = cpc0_cr1 & ~0x00800000;
mtdcr(DCRN_405_CPC0_CR1, cpc0_cr1);
tb = cpu;
dt_fixup_cpu_clocks(cpu, tb, 0);
dt_fixup_clock("/plb", plb);
dt_fixup_clock("/plb/opb", opb);
dt_fixup_clock("/plb/ebc", ebc);
dt_fixup_clock("/plb/opb/serial@ef600300", uart0);
dt_fixup_clock("/plb/opb/serial@ef600400", uart1);
}
...@@ -18,5 +18,6 @@ void ibm40x_dbcr_reset(void); ...@@ -18,5 +18,6 @@ void ibm40x_dbcr_reset(void);
void ibm4xx_quiesce_eth(u32 *emac0, u32 *emac1); void ibm4xx_quiesce_eth(u32 *emac0, u32 *emac1);
void ibm4xx_fixup_ebc_ranges(const char *ebc); void ibm4xx_fixup_ebc_ranges(const char *ebc);
void ibm440ep_fixup_clocks(unsigned int sysclk, unsigned int ser_clk); void ibm440ep_fixup_clocks(unsigned int sysclk, unsigned int ser_clk);
void ibm405gp_fixup_clocks(unsigned int sysclk, unsigned int ser_clk);
#endif /* _POWERPC_BOOT_4XX_H_ */ #endif /* _POWERPC_BOOT_4XX_H_ */
...@@ -58,7 +58,7 @@ src-plat := of.c cuboot-52xx.c cuboot-83xx.c cuboot-85xx.c holly.c \ ...@@ -58,7 +58,7 @@ src-plat := of.c cuboot-52xx.c cuboot-83xx.c cuboot-85xx.c holly.c \
cuboot-ebony.c treeboot-ebony.c prpmc2800.c \ cuboot-ebony.c treeboot-ebony.c prpmc2800.c \
ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c \ ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c \
cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c cuboot-bamboo.c \ cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c cuboot-bamboo.c \
fixed-head.S ep88xc.c cuboot-hpc2.c fixed-head.S ep88xc.c cuboot-hpc2.c ep405.c
src-boot := $(src-wlib) $(src-plat) empty.c src-boot := $(src-wlib) $(src-plat) empty.c
src-boot := $(addprefix $(obj)/, $(src-boot)) src-boot := $(addprefix $(obj)/, $(src-boot))
...@@ -189,6 +189,7 @@ image-$(CONFIG_DEFAULT_UIMAGE) += uImage ...@@ -189,6 +189,7 @@ image-$(CONFIG_DEFAULT_UIMAGE) += uImage
ifneq ($(CONFIG_DEVICE_TREE),"") ifneq ($(CONFIG_DEVICE_TREE),"")
image-$(CONFIG_PPC_8xx) += cuImage.8xx image-$(CONFIG_PPC_8xx) += cuImage.8xx
image-$(CONFIG_PPC_EP88XC) += zImage.ep88xc image-$(CONFIG_PPC_EP88XC) += zImage.ep88xc
image-$(CONFIG_EP405) += zImage.ep405
image-$(CONFIG_8260) += cuImage.pq2 image-$(CONFIG_8260) += cuImage.pq2
image-$(CONFIG_PPC_MPC52xx) += cuImage.52xx image-$(CONFIG_PPC_MPC52xx) += cuImage.52xx
image-$(CONFIG_PPC_83xx) += cuImage.83xx image-$(CONFIG_PPC_83xx) += cuImage.83xx
......
/*
* Device Tree Source for EP405
*
* Copyright 2007 IBM Corp.
* Benjamin Herrenschmidt <benh@kernel.crashing.org>
*
* 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.
*/
/ {
#address-cells = <1>;
#size-cells = <1>;
model = "ep405";
compatible = "ep405";
dcr-parent = <&/cpus/PowerPC,405GP@0>;
cpus {
#address-cells = <1>;
#size-cells = <0>;
PowerPC,405GP@0 {
device_type = "cpu";
reg = <0>;
clock-frequency = <bebc200>; /* Filled in by zImage */
timebase-frequency = <0>; /* Filled in by zImage */
i-cache-line-size = <20>;
d-cache-line-size = <20>;
i-cache-size = <4000>;
d-cache-size = <4000>;
dcr-controller;
dcr-access-method = "native";
};
};
memory {
device_type = "memory";
reg = <0 0>; /* Filled in by zImage */
};
UIC0: interrupt-controller {
compatible = "ibm,uic";
interrupt-controller;
cell-index = <0>;
dcr-reg = <0c0 9>;
#address-cells = <0>;
#size-cells = <0>;
#interrupt-cells = <2>;
};
plb {
compatible = "ibm,plb3";
#address-cells = <1>;
#size-cells = <1>;
ranges;
clock-frequency = <0>; /* Filled in by zImage */
SDRAM0: memory-controller {
compatible = "ibm,sdram-405gp";
dcr-reg = <010 2>;
};
MAL: mcmal {
compatible = "ibm,mcmal-405gp", "ibm,mcmal";
dcr-reg = <180 62>;
num-tx-chans = <1>;
num-rx-chans = <1>;
interrupt-parent = <&UIC0>;
interrupts = <
b 4 /* TXEOB */
c 4 /* RXEOB */
a 4 /* SERR */
d 4 /* TXDE */
e 4 /* RXDE */>;
};
POB0: opb {
compatible = "ibm,opb-405gp", "ibm,opb";
#address-cells = <1>;
#size-cells = <1>;
ranges = <ef600000 ef600000 a00000>;
dcr-reg = <0a0 5>;
clock-frequency = <0>; /* Filled in by zImage */
UART0: serial@ef600300 {
device_type = "serial";
compatible = "ns16550";
reg = <ef600300 8>;
virtual-reg = <ef600300>;
clock-frequency = <0>; /* Filled in by zImage */
current-speed = <2580>;
interrupt-parent = <&UIC0>;
interrupts = <0 4>;
};
UART1: serial@ef600400 {
device_type = "serial";
compatible = "ns16550";
reg = <ef600400 8>;
virtual-reg = <ef600400>;
clock-frequency = <0>; /* Filled in by zImage */
current-speed = <2580>;
interrupt-parent = <&UIC0>;
interrupts = <1 4>;
};
IIC: i2c@ef600500 {
compatible = "ibm,iic-405gp", "ibm,iic";
reg = <ef600500 11>;
interrupt-parent = <&UIC0>;
interrupts = <2 4>;
};
GPIO: gpio@ef600700 {
compatible = "ibm,gpio-405gp";
reg = <ef600700 20>;
};
EMAC: ethernet@ef600800 {
linux,network-index = <0>;
device_type = "network";
compatible = "ibm,emac-405gp", "ibm,emac";
interrupt-parent = <&UIC0>;
interrupts = <
f 4 /* Ethernet */
9 4 /* Ethernet Wake Up */>;
local-mac-address = [000000000000]; /* Filled in by zImage */
reg = <ef600800 70>;
mal-device = <&MAL>;
mal-tx-channel = <0>;
mal-rx-channel = <0>;
cell-index = <0>;
max-frame-size = <5dc>;
rx-fifo-size = <1000>;
tx-fifo-size = <800>;
phy-mode = "rmii";
phy-map = <00000000>;
};
};
EBC0: ebc {
compatible = "ibm,ebc-405gp", "ibm,ebc";
dcr-reg = <012 2>;
#address-cells = <2>;
#size-cells = <1>;
/* The ranges property is supplied by the bootwrapper
* and is based on the firmware's configuration of the
* EBC bridge
*/
clock-frequency = <0>; /* Filled in by zImage */
/* NVRAM and RTC */
nvrtc@4,200000 {
compatible = "ds1742";
reg = <4 200000 0>; /* size fixed up by zImage */
};
/* "BCSR" CPLD contains a PCI irq controller */
bcsr@4,0 {
compatible = "ep405-bcsr";
reg = <4 0 10>;
interrupt-controller;
/* Routing table */
irq-routing = [ 00 /* SYSERR */
01 /* STTM */
01 /* RTC */
01 /* FENET */
02 /* NB PCIIRQ mux ? */
03 /* SB Winbond 8259 ? */
04 /* Serial Ring */
05 /* USB (ep405pc) */
06 /* XIRQ 0 */
06 /* XIRQ 1 */
06 /* XIRQ 2 */
06 /* XIRQ 3 */
06 /* XIRQ 4 */
06 /* XIRQ 5 */
06 /* XIRQ 6 */
07]; /* Reserved */
};
};
PCI0: pci@ec000000 {
device_type = "pci";
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
compatible = "ibm,plb405gp-pci", "ibm,plb-pci";
primary;
reg = <eec00000 8 /* Config space access */
eed80000 4 /* IACK */
eed80000 4 /* Special cycle */
ef480000 40>; /* Internal registers */
/* Outbound ranges, one memory and one IO,
* later cannot be changed. Chip supports a second
* IO range but we don't use it for now
*/
ranges = <02000000 0 80000000 80000000 0 20000000
01000000 0 00000000 e8000000 0 00010000>;
/* Inbound 2GB range starting at 0 */
dma-ranges = <42000000 0 0 0 0 80000000>;
/* That's all I know about IRQs on that thing ... */
interrupt-map-mask = <f800 0 0 0>;
interrupt-map = <
/* USB */
7000 0 0 0 &UIC0 1e 8 /* IRQ5 */
>;
};
};
chosen {
linux,stdout-path = "/plb/opb/serial@ef600300";
};
};
/*
* Embedded Planet EP405 with PlanetCore firmware
*
* (c) Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp,\
*
* Based on ep88xc.c by
*
* Scott Wood <scottwood@freescale.com>
*
* Copyright (c) 2007 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*/
#include "ops.h"
#include "stdio.h"
#include "planetcore.h"
#include "dcr.h"
#include "4xx.h"
#include "io.h"
static char *table;
static u64 mem_size;
static void platform_fixups(void)
{
u64 val;
void *nvrtc;
dt_fixup_memory(0, mem_size);
planetcore_set_mac_addrs(table);
if (!planetcore_get_decimal(table, PLANETCORE_KEY_CRYSTAL_HZ, &val)) {
printf("No PlanetCore crystal frequency key.\r\n");
return;
}
ibm405gp_fixup_clocks(val, 0xa8c000);
ibm4xx_quiesce_eth((u32 *)0xef600800, NULL);
ibm4xx_fixup_ebc_ranges("/plb/ebc");
if (!planetcore_get_decimal(table, PLANETCORE_KEY_KB_NVRAM, &val)) {
printf("No PlanetCore NVRAM size key.\r\n");
return;
}
nvrtc = finddevice("/plb/ebc/nvrtc@4,200000");
if (nvrtc != NULL) {
u32 reg[3] = { 4, 0x200000, 0};
getprop(nvrtc, "reg", reg, 3);
reg[2] = (val << 10) & 0xffffffff;
setprop(nvrtc, "reg", reg, 3);
}
}
void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7)
{
table = (char *)r3;
planetcore_prepare_table(table);
if (!planetcore_get_decimal(table, PLANETCORE_KEY_MB_RAM, &mem_size))
return;
mem_size *= 1024 * 1024;
simple_alloc_init(_end, mem_size - (unsigned long)_end, 32, 64);
fdt_init(_dtb_start);
planetcore_set_stdout_path(table);
serial_console_init();
platform_ops.fixups = platform_fixups;
}
...@@ -20,55 +20,6 @@ ...@@ -20,55 +20,6 @@
BSS_STACK(4096); BSS_STACK(4096);
void ibm405gp_fixup_clocks(unsigned int sysclk, unsigned int ser_clk)
{
u32 pllmr = mfdcr(DCRN_CPC0_PLLMR);
u32 cpc0_cr0 = mfdcr(DCRN_405_CPC0_CR0);
u32 cpc0_cr1 = mfdcr(DCRN_405_CPC0_CR1);
u32 cpu, plb, opb, ebc, tb, uart0, uart1, m;
u32 fwdv, fbdv, cbdv, opdv, epdv, udiv;
fwdv = (8 - ((pllmr & 0xe0000000) >> 29));
fbdv = (pllmr & 0x1e000000) >> 25;
cbdv = ((pllmr & 0x00060000) >> 17) + 1;
opdv = ((pllmr & 0x00018000) >> 15) + 1;
epdv = ((pllmr & 0x00001800) >> 13) + 2;
udiv = ((cpc0_cr0 & 0x3e) >> 1) + 1;
m = fwdv * fbdv * cbdv;
cpu = sysclk * m / fwdv;
plb = cpu / cbdv;
opb = plb / opdv;
ebc = plb / epdv;
if (cpc0_cr0 & 0x80) {
/* uart0 uses the external clock */
uart0 = ser_clk;
} else {
uart0 = cpu / udiv;
}
if (cpc0_cr0 & 0x40) {
/* uart1 uses the external clock */
uart1 = ser_clk;
} else {
uart1 = cpu / udiv;
}
/* setup the timebase clock to tick at the cpu frequency */
cpc0_cr1 = cpc0_cr1 & ~0x00800000;
mtdcr(DCRN_405_CPC0_CR1, cpc0_cr1);
tb = cpu;
dt_fixup_cpu_clocks(cpu, tb, 0);
dt_fixup_clock("/plb", plb);
dt_fixup_clock("/plb/opb", opb);
dt_fixup_clock("/plb/ebc", ebc);
dt_fixup_clock("/plb/opb/serial@ef600300", uart0);
dt_fixup_clock("/plb/opb/serial@ef600400", uart1);
}
static void walnut_flashsel_fixup(void) static void walnut_flashsel_fixup(void)
{ {
void *devp, *sram; void *devp, *sram;
......
...@@ -168,7 +168,7 @@ ps3) ...@@ -168,7 +168,7 @@ ps3)
ksection=.kernel:vmlinux.bin ksection=.kernel:vmlinux.bin
isection=.kernel:initrd isection=.kernel:initrd
;; ;;
ep88xc) ep88xc|ep405)
platformo="$object/fixed-head.o $object/$platform.o" platformo="$object/fixed-head.o $object/$platform.o"
binary=y binary=y
;; ;;
......
This diff is collapsed.
...@@ -14,20 +14,14 @@ ...@@ -14,20 +14,14 @@
# help # help
# This option enables support for the CPCI405 board. # This option enables support for the CPCI405 board.
#config EP405 config EP405
# bool "EP405/EP405PC" bool "EP405/EP405PC"
# depends on 40x depends on 40x
# default n default n
# select 405GP select 405GP
# help select PCI
# This option enables support for the EP405/EP405PC boards. help
This option enables support for the EP405/EP405PC boards.
#config EP405PC
# bool "EP405PC Support"
# depends on EP405
# default y
# help
# This option enables support for the extra features of the EP405PC board.
config KILAUEA config KILAUEA
bool "Kilauea" bool "Kilauea"
......
obj-$(CONFIG_KILAUEA) += kilauea.o obj-$(CONFIG_KILAUEA) += kilauea.o
obj-$(CONFIG_WALNUT) += walnut.o obj-$(CONFIG_WALNUT) += walnut.o
obj-$(CONFIG_XILINX_VIRTEX_GENERIC_BOARD) += virtex.o obj-$(CONFIG_XILINX_VIRTEX_GENERIC_BOARD) += virtex.o
obj-$(CONFIG_EP405) += ep405.o
/*
* Architecture- / platform-specific boot-time initialization code for
* IBM PowerPC 4xx based boards. Adapted from original
* code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek
* <dan@net4x.com>.
*
* Copyright(c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
*
* Rewritten and ported to the merged powerpc tree:
* Copyright 2007 IBM Corporation
* Josh Boyer <jwboyer@linux.vnet.ibm.com>
*
* Adapted to EP405 by Ben. Herrenschmidt <benh@kernel.crashing.org>
*
* TODO: Wire up the PCI IRQ mux and the southbridge interrupts
*
* 2002 (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/of_platform.h>
#include <asm/machdep.h>
#include <asm/prom.h>
#include <asm/udbg.h>
#include <asm/time.h>
#include <asm/uic.h>
#include <asm/pci-bridge.h>
static struct device_node *bcsr_node;
static void __iomem *bcsr_regs;
/* BCSR registers */
#define BCSR_ID 0
#define BCSR_PCI_CTRL 1
#define BCSR_FLASH_NV_POR_CTRL 2
#define BCSR_FENET_UART_CTRL 3
#define BCSR_PCI_IRQ 4
#define BCSR_XIRQ_SELECT 5
#define BCSR_XIRQ_ROUTING 6
#define BCSR_XIRQ_STATUS 7
#define BCSR_XIRQ_STATUS2 8
#define BCSR_SW_STAT_LED_CTRL 9
#define BCSR_GPIO_IRQ_PAR_CTRL 10
/* there's more, can't be bothered typing them tho */
static struct of_device_id ep405_of_bus[] = {
{ .compatible = "ibm,plb3", },
{ .compatible = "ibm,opb", },
{ .compatible = "ibm,ebc", },
{},
};
static int __init ep405_device_probe(void)
{
if (!machine_is(ep405))
return 0;
of_platform_bus_probe(NULL, ep405_of_bus, NULL);
return 0;
}
device_initcall(ep405_device_probe);
static void __init ep405_init_bcsr(void)
{
const u8 *irq_routing;
int i;
/* Find the bloody thing & map it */
bcsr_node = of_find_compatible_node(NULL, NULL, "ep405-bcsr");
if (bcsr_node == NULL) {
printk(KERN_ERR "EP405 BCSR not found !\n");
return;
}
bcsr_regs = of_iomap(bcsr_node, 0);
if (bcsr_regs == NULL) {
printk(KERN_ERR "EP405 BCSR failed to map !\n");
return;
}
/* Get the irq-routing property and apply the routing to the CPLD */
irq_routing = of_get_property(bcsr_node, "irq-routing", NULL);
if (irq_routing == NULL)
return;
for (i = 0; i < 16; i++) {
u8 irq = irq_routing[i];
out_8(bcsr_regs + BCSR_XIRQ_SELECT, i);
out_8(bcsr_regs + BCSR_XIRQ_ROUTING, irq);
}
in_8(bcsr_regs + BCSR_XIRQ_SELECT);
mb();
out_8(bcsr_regs + BCSR_GPIO_IRQ_PAR_CTRL, 0xfe);
}
static void __init ep405_setup_arch(void)
{
/* Find & init the BCSR CPLD */
ep405_init_bcsr();
}
static int __init ep405_probe(void)
{
unsigned long root = of_get_flat_dt_root();
if (!of_flat_dt_is_compatible(root, "ep405"))
return 0;
return 1;
}
define_machine(ep405) {
.name = "EP405",
.probe = ep405_probe,
.setup_arch = ep405_setup_arch,
.progress = udbg_progress,
.init_IRQ = uic_init_tree,
.get_irq = uic_get_irq,
.calibrate_decr = generic_calibrate_decr,
};
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