162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Board setup routines for the Buffalo Linkstation / Kurobox Platform.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) 2006 G. Liakhovetski (g.liakhovetski@gmx.de)
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Based on sandpoint.c by Mark A. Greer
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * This file is licensed under the terms of the GNU General Public License
962306a36Sopenharmony_ci * version 2.  This program is licensed "as is" without any warranty of
1062306a36Sopenharmony_ci * any kind, whether express or implied.
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/initrd.h>
1562306a36Sopenharmony_ci#include <linux/of_platform.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <asm/time.h>
1862306a36Sopenharmony_ci#include <asm/mpic.h>
1962306a36Sopenharmony_ci#include <asm/pci-bridge.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include "mpc10x.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic const struct of_device_id of_bus_ids[] __initconst = {
2462306a36Sopenharmony_ci	{ .type = "soc", },
2562306a36Sopenharmony_ci	{ .compatible = "simple-bus", },
2662306a36Sopenharmony_ci	{},
2762306a36Sopenharmony_ci};
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic int __init declare_of_platform_devices(void)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	of_platform_bus_probe(NULL, of_bus_ids, NULL);
3262306a36Sopenharmony_ci	return 0;
3362306a36Sopenharmony_ci}
3462306a36Sopenharmony_cimachine_device_initcall(linkstation, declare_of_platform_devices);
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic int __init linkstation_add_bridge(struct device_node *dev)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci#ifdef CONFIG_PCI
3962306a36Sopenharmony_ci	int len;
4062306a36Sopenharmony_ci	struct pci_controller *hose;
4162306a36Sopenharmony_ci	const int *bus_range;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	printk("Adding PCI host bridge %pOF\n", dev);
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	bus_range = of_get_property(dev, "bus-range", &len);
4662306a36Sopenharmony_ci	if (bus_range == NULL || len < 2 * sizeof(int))
4762306a36Sopenharmony_ci		printk(KERN_WARNING "Can't get bus-range for %pOF, assume"
4862306a36Sopenharmony_ci				" bus 0\n", dev);
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	hose = pcibios_alloc_controller(dev);
5162306a36Sopenharmony_ci	if (hose == NULL)
5262306a36Sopenharmony_ci		return -ENOMEM;
5362306a36Sopenharmony_ci	hose->first_busno = bus_range ? bus_range[0] : 0;
5462306a36Sopenharmony_ci	hose->last_busno = bus_range ? bus_range[1] : 0xff;
5562306a36Sopenharmony_ci	setup_indirect_pci(hose, 0xfec00000, 0xfee00000, 0);
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	/* Interpret the "ranges" property */
5862306a36Sopenharmony_ci	/* This also maps the I/O region and sets isa_io/mem_base */
5962306a36Sopenharmony_ci	pci_process_bridge_OF_ranges(hose, dev, 1);
6062306a36Sopenharmony_ci#endif
6162306a36Sopenharmony_ci	return 0;
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic void __init linkstation_setup_arch(void)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	printk(KERN_INFO "BUFFALO Network Attached Storage Series\n");
6762306a36Sopenharmony_ci	printk(KERN_INFO "(C) 2002-2005 BUFFALO INC.\n");
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic void __init linkstation_setup_pci(void)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	struct device_node *np;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	/* Lookup PCI host bridges */
7562306a36Sopenharmony_ci	for_each_compatible_node(np, "pci", "mpc10x-pci")
7662306a36Sopenharmony_ci		linkstation_add_bridge(np);
7762306a36Sopenharmony_ci}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci/*
8062306a36Sopenharmony_ci * Interrupt setup and service.  Interrupts on the linkstation come
8162306a36Sopenharmony_ci * from the four PCI slots plus onboard 8241 devices: I2C, DUART.
8262306a36Sopenharmony_ci */
8362306a36Sopenharmony_cistatic void __init linkstation_init_IRQ(void)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	struct mpic *mpic;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	mpic = mpic_alloc(NULL, 0, 0, 4, 0, " EPIC     ");
8862306a36Sopenharmony_ci	BUG_ON(mpic == NULL);
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	/* PCI IRQs */
9162306a36Sopenharmony_ci	mpic_assign_isu(mpic, 0, mpic->paddr + 0x10200);
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	/* I2C */
9462306a36Sopenharmony_ci	mpic_assign_isu(mpic, 1, mpic->paddr + 0x11000);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	/* ttyS0, ttyS1 */
9762306a36Sopenharmony_ci	mpic_assign_isu(mpic, 2, mpic->paddr + 0x11100);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	mpic_init(mpic);
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic void __noreturn linkstation_restart(char *cmd)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	local_irq_disable();
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	/* Reset system via AVR */
10762306a36Sopenharmony_ci	avr_uart_configure();
10862306a36Sopenharmony_ci	/* Send reboot command */
10962306a36Sopenharmony_ci	avr_uart_send('C');
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	for(;;)  /* Spin until reset happens */
11262306a36Sopenharmony_ci		avr_uart_send('G');	/* "kick" */
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic void __noreturn linkstation_power_off(void)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	local_irq_disable();
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	/* Power down system via AVR */
12062306a36Sopenharmony_ci	avr_uart_configure();
12162306a36Sopenharmony_ci	/* send shutdown command */
12262306a36Sopenharmony_ci	avr_uart_send('E');
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	for(;;)  /* Spin until power-off happens */
12562306a36Sopenharmony_ci		avr_uart_send('G');	/* "kick" */
12662306a36Sopenharmony_ci	/* NOTREACHED */
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic void __noreturn linkstation_halt(void)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	linkstation_power_off();
13262306a36Sopenharmony_ci	/* NOTREACHED */
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic void linkstation_show_cpuinfo(struct seq_file *m)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	seq_printf(m, "vendor\t\t: Buffalo Technology\n");
13862306a36Sopenharmony_ci	seq_printf(m, "machine\t\t: Linkstation I/Kurobox(HG)\n");
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistatic int __init linkstation_probe(void)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	pm_power_off = linkstation_power_off;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	return 1;
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cidefine_machine(linkstation){
14962306a36Sopenharmony_ci	.name 			= "Buffalo Linkstation",
15062306a36Sopenharmony_ci	.compatible		= "linkstation",
15162306a36Sopenharmony_ci	.probe 			= linkstation_probe,
15262306a36Sopenharmony_ci	.setup_arch 		= linkstation_setup_arch,
15362306a36Sopenharmony_ci	.discover_phbs		= linkstation_setup_pci,
15462306a36Sopenharmony_ci	.init_IRQ 		= linkstation_init_IRQ,
15562306a36Sopenharmony_ci	.show_cpuinfo 		= linkstation_show_cpuinfo,
15662306a36Sopenharmony_ci	.get_irq 		= mpic_get_irq,
15762306a36Sopenharmony_ci	.restart 		= linkstation_restart,
15862306a36Sopenharmony_ci	.halt	 		= linkstation_halt,
15962306a36Sopenharmony_ci};
160