[POWERPC] Linkstation / kurobox support

Support for the Kurobox(HG)/LinkStation-I NAS systems by Buffalo
Technology, should be also applicable to the PPC TeraStation family.

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
This commit is contained in:
Guennadi Liakhovetski 2006-12-01 22:53:48 +01:00 committed by Paul Mackerras
parent 57933f8fbe
commit 04d76b937b
6 changed files with 2089 additions and 3 deletions

View file

@ -0,0 +1,148 @@
/*
* Device Tree Souce for Buffalo KuroboxHG
*
* Choose CONFIG_LINKSTATION to build a kernel for KuroboxHG, or use
* the default configuration linkstation_defconfig.
*
* Based on sandpoint.dts
*
* 2006 (c) G. Liakhovetski <g.liakhovetski@gmx.de>
*
* 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.
XXXX add flash parts, rtc, ??
build with: "dtc -f -I dts -O dtb -o kuroboxHG.dtb -V 16 kuroboxHG.dts"
*/
/ {
linux,phandle = <1000>;
model = "KuroboxHG";
compatible = "linkstation";
#address-cells = <1>;
#size-cells = <1>;
cpus {
linux,phandle = <2000>;
#cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
PowerPC,603e { /* Really 8241 */
linux,phandle = <2100>;
linux,boot-cpu;
device_type = "cpu";
reg = <0>;
clock-frequency = <fdad680>; /* Fixed by bootwrapper */
timebase-frequency = <1F04000>; /* Fixed by bootwrapper */
bus-frequency = <0>; /* From bootloader */
/* Following required by dtc but not used */
i-cache-line-size = <0>;
d-cache-line-size = <0>;
i-cache-size = <4000>;
d-cache-size = <4000>;
};
};
memory {
linux,phandle = <3000>;
device_type = "memory";
reg = <00000000 08000000>;
};
soc10x { /* AFAICT need to make soc for 8245's uarts to be defined */
linux,phandle = <4000>;
#address-cells = <1>;
#size-cells = <1>;
#interrupt-cells = <2>;
device_type = "soc";
compatible = "mpc10x";
store-gathering = <0>; /* 0 == off, !0 == on */
reg = <80000000 00100000>;
ranges = <80000000 80000000 70000000 /* pci mem space */
fc000000 fc000000 00100000 /* EUMB */
fe000000 fe000000 00c00000 /* pci i/o space */
fec00000 fec00000 00300000 /* pci cfg regs */
fef00000 fef00000 00100000>; /* pci iack */
i2c@80003000 {
linux,phandle = <4300>;
device_type = "i2c";
compatible = "fsl-i2c";
reg = <80003000 1000>;
interrupts = <5 2>;
interrupt-parent = <4400>;
};
serial@80004500 {
linux,phandle = <4511>;
device_type = "serial";
compatible = "ns16550";
reg = <80004500 8>;
clock-frequency = <7c044a8>;
current-speed = <2580>;
interrupts = <9 2>;
interrupt-parent = <4400>;
};
serial@80004600 {
linux,phandle = <4512>;
device_type = "serial";
compatible = "ns16550";
reg = <80004600 8>;
clock-frequency = <7c044a8>;
current-speed = <e100>;
interrupts = <a 0>;
interrupt-parent = <4400>;
};
pic@80040000 {
linux,phandle = <4400>;
#interrupt-cells = <2>;
#address-cells = <0>;
device_type = "open-pic";
compatible = "chrp,open-pic";
interrupt-controller;
reg = <80040000 40000>;
built-in;
};
pci@fec00000 {
linux,phandle = <4500>;
#address-cells = <3>;
#size-cells = <2>;
#interrupt-cells = <1>;
device_type = "pci";
compatible = "mpc10x-pci";
reg = <fec00000 400000>;
ranges = <01000000 0 0 fe000000 0 00c00000
02000000 0 80000000 80000000 0 70000000>;
bus-range = <0 ff>;
clock-frequency = <7f28155>;
interrupt-parent = <4400>;
interrupt-map-mask = <f800 0 0 7>;
interrupt-map = <
/* IDSEL 0x11 - IRQ0 ETH */
5800 0 0 1 4400 0 1
5800 0 0 2 4400 1 1
5800 0 0 3 4400 2 1
5800 0 0 4 4400 3 1
/* IDSEL 0x12 - IRQ1 IDE0 */
6000 0 0 1 4400 1 1
6000 0 0 2 4400 2 1
6000 0 0 3 4400 3 1
6000 0 0 4 4400 0 1
/* IDSEL 0x14 - IRQ3 USB2.0 */
7000 0 0 1 4400 3 1
7000 0 0 2 4400 3 1
7000 0 0 3 4400 3 1
7000 0 0 4 4400 3 1
>;
};
};
};

File diff suppressed because it is too large Load diff

View file

@ -74,6 +74,18 @@ config SANDPOINT
Select SANDPOINT if configuring for a Motorola Sandpoint X3
(any flavor).
config LINKSTATION
bool "Linkstation / Kurobox(HG) from Buffalo"
select MPIC
select FSL_SOC
select PPC_UDBG_16550 if SERIAL_8250
help
Select LINKSTATION if configuring for one of PPC- (MPC8241)
based NAS systems from Buffalo Technology. So far only
KuroboxHG has been tested. In the future classical Kurobox,
Linkstation-I HD-HLAN and HD-HGLAN versions, and PPC-based
Terastation systems should be supported too.
config MPC7448HPC2
bool "Freescale MPC7448HPC2(Taiga)"
select TSI108_BRIDGE
@ -196,7 +208,7 @@ config PPC_GEN550
depends on SANDPOINT || SPRUCE || PPLUS || \
PRPMC750 || PRPMC800 || LOPEC || \
(EV64260 && !SERIAL_MPSC) || CHESTNUT || RADSTONE_PPC7D || \
83xx
83xx || LINKSTATION
default y
config FORCE
@ -270,13 +282,13 @@ config EPIC_SERIAL_MODE
config MPC10X_BRIDGE
bool
depends on POWERPMC250 || LOPEC || SANDPOINT
depends on POWERPMC250 || LOPEC || SANDPOINT || LINKSTATION
select PPC_INDIRECT_PCI
default y
config MPC10X_OPENPIC
bool
depends on POWERPMC250 || LOPEC || SANDPOINT
depends on POWERPMC250 || LOPEC || SANDPOINT || LINKSTATION
default y
config MPC10X_STORE_GATHERING

View file

@ -2,3 +2,4 @@
# Makefile for the 6xx/7xx/7xxxx linux kernel.
#
obj-$(CONFIG_MPC7448HPC2) += mpc7448_hpc2.o
obj-$(CONFIG_LINKSTATION) += linkstation.o ls_uart.o

View file

@ -0,0 +1,211 @@
/*
* Board setup routines for the Buffalo Linkstation / Kurobox Platform.
*
* Copyright (C) 2006 G. Liakhovetski (g.liakhovetski@gmx.de)
*
* Based on sandpoint.c by Mark A. Greer
*
* 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/pci.h>
#include <linux/initrd.h>
#include <linux/root_dev.h>
#include <linux/mtd/physmap.h>
#include <asm/time.h>
#include <asm/prom.h>
#include <asm/mpic.h>
#include <asm/mpc10x.h>
#include <asm/pci-bridge.h>
static struct mtd_partition linkstation_physmap_partitions[] = {
{
.name = "mtd_firmimg",
.offset = 0x000000,
.size = 0x300000,
},
{
.name = "mtd_bootcode",
.offset = 0x300000,
.size = 0x070000,
},
{
.name = "mtd_status",
.offset = 0x370000,
.size = 0x010000,
},
{
.name = "mtd_conf",
.offset = 0x380000,
.size = 0x080000,
},
{
.name = "mtd_allflash",
.offset = 0x000000,
.size = 0x400000,
},
{
.name = "mtd_data",
.offset = 0x310000,
.size = 0x0f0000,
},
};
static int __init add_bridge(struct device_node *dev)
{
int len;
struct pci_controller *hose;
int *bus_range;
printk("Adding PCI host bridge %s\n", dev->full_name);
bus_range = (int *) get_property(dev, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int))
printk(KERN_WARNING "Can't get bus-range for %s, assume"
" bus 0\n", dev->full_name);
hose = pcibios_alloc_controller();
if (hose == NULL)
return -ENOMEM;
hose->first_busno = bus_range ? bus_range[0] : 0;
hose->last_busno = bus_range ? bus_range[1] : 0xff;
hose->arch_data = dev;
setup_indirect_pci(hose, 0xfec00000, 0xfee00000);
/* Interpret the "ranges" property */
/* This also maps the I/O region and sets isa_io/mem_base */
pci_process_bridge_OF_ranges(hose, dev, 1);
return 0;
}
static void __init linkstation_setup_arch(void)
{
struct device_node *np;
#ifdef CONFIG_MTD_PHYSMAP
physmap_set_partitions(linkstation_physmap_partitions,
ARRAY_SIZE(linkstation_physmap_partitions));
#endif
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start)
ROOT_DEV = Root_RAM0;
else
#endif
#ifdef CONFIG_ROOT_NFS
ROOT_DEV = Root_NFS;
#else
ROOT_DEV = Root_HDA1;
#endif
/* Lookup PCI host bridges */
for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
add_bridge(np);
printk(KERN_INFO "BUFFALO Network Attached Storage Series\n");
printk(KERN_INFO "(C) 2002-2005 BUFFALO INC.\n");
}
/*
* Interrupt setup and service. Interrrupts on the linkstation come
* from the four PCI slots plus onboard 8241 devices: I2C, DUART.
*/
static void __init linkstation_init_IRQ(void)
{
struct mpic *mpic;
struct device_node *dnp;
void *prop;
int size;
phys_addr_t paddr;
dnp = of_find_node_by_type(NULL, "open-pic");
if (dnp == NULL)
return;
prop = (struct device_node *)get_property(dnp, "reg", &size);
paddr = (phys_addr_t)of_translate_address(dnp, prop);
mpic = mpic_alloc(dnp, paddr, MPIC_PRIMARY | MPIC_WANTS_RESET, 4, 32, " EPIC ");
BUG_ON(mpic == NULL);
/* PCI IRQs */
mpic_assign_isu(mpic, 0, paddr + 0x10200);
/* I2C */
mpic_assign_isu(mpic, 1, paddr + 0x11000);
/* ttyS0, ttyS1 */
mpic_assign_isu(mpic, 2, paddr + 0x11100);
mpic_init(mpic);
}
extern void avr_uart_configure(void);
extern void avr_uart_send(const char);
static void linkstation_restart(char *cmd)
{
local_irq_disable();
/* Reset system via AVR */
avr_uart_configure();
/* Send reboot command */
avr_uart_send('C');
for(;;) /* Spin until reset happens */
avr_uart_send('G'); /* "kick" */
}
static void linkstation_power_off(void)
{
local_irq_disable();
/* Power down system via AVR */
avr_uart_configure();
/* send shutdown command */
avr_uart_send('E');
for(;;) /* Spin until power-off happens */
avr_uart_send('G'); /* "kick" */
/* NOTREACHED */
}
static void linkstation_halt(void)
{
linkstation_power_off();
/* NOTREACHED */
}
static void linkstation_show_cpuinfo(struct seq_file *m)
{
seq_printf(m, "vendor\t\t: Buffalo Technology\n");
seq_printf(m, "machine\t\t: Linkstation I/Kurobox(HG)\n");
}
static int __init linkstation_probe(void)
{
unsigned long root;
root = of_get_flat_dt_root();
if (!of_flat_dt_is_compatible(root, "linkstation"))
return 0;
return 1;
}
define_machine(linkstation){
.name = "Buffalo Linkstation",
.probe = linkstation_probe,
.setup_arch = linkstation_setup_arch,
.init_IRQ = linkstation_init_IRQ,
.show_cpuinfo = linkstation_show_cpuinfo,
.get_irq = mpic_get_irq,
.restart = linkstation_restart,
.power_off = linkstation_power_off,
.halt = linkstation_halt,
.calibrate_decr = generic_calibrate_decr,
};

View file

@ -0,0 +1,131 @@
#include <linux/workqueue.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/serial_reg.h>
#include <linux/serial_8250.h>
#include <asm/io.h>
#include <asm/mpc10x.h>
#include <asm/ppc_sys.h>
#include <asm/prom.h>
#include <asm/termbits.h>
static void __iomem *avr_addr;
static unsigned long avr_clock;
static struct work_struct wd_work;
static void wd_stop(void *unused)
{
const char string[] = "AAAAFFFFJJJJ>>>>VVVV>>>>ZZZZVVVVKKKK";
int i = 0, rescue = 8;
int len = strlen(string);
while (rescue--) {
int j;
char lsr = in_8(avr_addr + UART_LSR);
if (lsr & (UART_LSR_THRE | UART_LSR_TEMT)) {
for (j = 0; j < 16 && i < len; j++, i++)
out_8(avr_addr + UART_TX, string[i]);
if (i == len) {
/* Read "OK" back: 4ms for the last "KKKK"
plus a couple bytes back */
msleep(7);
printk("linkstation: disarming the AVR watchdog: ");
while (in_8(avr_addr + UART_LSR) & UART_LSR_DR)
printk("%c", in_8(avr_addr + UART_RX));
break;
}
}
msleep(17);
}
printk("\n");
}
#define AVR_QUOT(clock) ((clock) + 8 * 9600) / (16 * 9600)
void avr_uart_configure(void)
{
unsigned char cval = UART_LCR_WLEN8;
unsigned int quot = AVR_QUOT(avr_clock);
if (!avr_addr || !avr_clock)
return;
out_8(avr_addr + UART_LCR, cval); /* initialise UART */
out_8(avr_addr + UART_MCR, 0);
out_8(avr_addr + UART_IER, 0);
cval |= UART_LCR_STOP | UART_LCR_PARITY | UART_LCR_EPAR;
out_8(avr_addr + UART_LCR, cval); /* Set character format */
out_8(avr_addr + UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
out_8(avr_addr + UART_DLL, quot & 0xff); /* LS of divisor */
out_8(avr_addr + UART_DLM, quot >> 8); /* MS of divisor */
out_8(avr_addr + UART_LCR, cval); /* reset DLAB */
out_8(avr_addr + UART_FCR, UART_FCR_ENABLE_FIFO); /* enable FIFO */
}
void avr_uart_send(const char c)
{
if (!avr_addr || !avr_clock)
return;
out_8(avr_addr + UART_TX, c);
out_8(avr_addr + UART_TX, c);
out_8(avr_addr + UART_TX, c);
out_8(avr_addr + UART_TX, c);
}
static void __init ls_uart_init(void)
{
local_irq_disable();
#ifndef CONFIG_SERIAL_8250
out_8(avr_addr + UART_FCR, UART_FCR_ENABLE_FIFO); /* enable FIFO */
out_8(avr_addr + UART_FCR, UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); /* clear FIFOs */
out_8(avr_addr + UART_FCR, 0);
out_8(avr_addr + UART_IER, 0);
/* Clear up interrupts */
(void) in_8(avr_addr + UART_LSR);
(void) in_8(avr_addr + UART_RX);
(void) in_8(avr_addr + UART_IIR);
(void) in_8(avr_addr + UART_MSR);
#endif
avr_uart_configure();
local_irq_enable();
}
static int __init ls_uarts_init(void)
{
struct device_node *avr;
phys_addr_t phys_addr;
int len;
avr = of_find_node_by_path("/soc10x/serial@80004500");
if (!avr)
return -EINVAL;
avr_clock = *(u32*)get_property(avr, "clock-frequency", &len);
phys_addr = ((u32*)get_property(avr, "reg", &len))[0];
if (!avr_clock || !phys_addr)
return -EINVAL;
avr_addr = ioremap(phys_addr, 32);
if (!avr_addr)
return -EFAULT;
ls_uart_init();
INIT_WORK(&wd_work, wd_stop, NULL);
schedule_work(&wd_work);
return 0;
}
late_initcall(ls_uarts_init);