162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * AmigaOne platform setup
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2008 Gerhard Pircher (gerhard_pircher@gmx.net)
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *   Based on original amigaone_setup.c source code
862306a36Sopenharmony_ci * Copyright 2003 by Hans-Joerg Frieden and Thomas Frieden
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/irqdomain.h>
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/of.h>
1462306a36Sopenharmony_ci#include <linux/of_address.h>
1562306a36Sopenharmony_ci#include <linux/seq_file.h>
1662306a36Sopenharmony_ci#include <generated/utsrelease.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <asm/machdep.h>
1962306a36Sopenharmony_ci#include <asm/cputable.h>
2062306a36Sopenharmony_ci#include <asm/pci-bridge.h>
2162306a36Sopenharmony_ci#include <asm/i8259.h>
2262306a36Sopenharmony_ci#include <asm/time.h>
2362306a36Sopenharmony_ci#include <asm/udbg.h>
2462306a36Sopenharmony_ci#include <asm/dma.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ciextern void __flush_disable_L1(void);
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_civoid amigaone_show_cpuinfo(struct seq_file *m)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	seq_printf(m, "vendor\t\t: Eyetech Ltd.\n");
3162306a36Sopenharmony_ci}
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistatic int __init amigaone_add_bridge(struct device_node *dev)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	const u32 *cfg_addr, *cfg_data;
3662306a36Sopenharmony_ci	int len;
3762306a36Sopenharmony_ci	const int *bus_range;
3862306a36Sopenharmony_ci	struct pci_controller *hose;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	printk(KERN_INFO "Adding PCI host bridge %pOF\n", dev);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	cfg_addr = of_get_address(dev, 0, NULL, NULL);
4362306a36Sopenharmony_ci	cfg_data = of_get_address(dev, 1, NULL, NULL);
4462306a36Sopenharmony_ci	if ((cfg_addr == NULL) || (cfg_data == NULL))
4562306a36Sopenharmony_ci		return -ENODEV;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	bus_range = of_get_property(dev, "bus-range", &len);
4862306a36Sopenharmony_ci	if ((bus_range == NULL) || (len < 2 * sizeof(int)))
4962306a36Sopenharmony_ci		printk(KERN_WARNING "Can't get bus-range for %pOF, assume"
5062306a36Sopenharmony_ci		       " bus 0\n", dev);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	hose = pcibios_alloc_controller(dev);
5362306a36Sopenharmony_ci	if (hose == NULL)
5462306a36Sopenharmony_ci		return -ENOMEM;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	hose->first_busno = bus_range ? bus_range[0] : 0;
5762306a36Sopenharmony_ci	hose->last_busno = bus_range ? bus_range[1] : 0xff;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	setup_indirect_pci(hose, cfg_addr[0], cfg_data[0], 0);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	/* Interpret the "ranges" property */
6262306a36Sopenharmony_ci	/* This also maps the I/O region and sets isa_io/mem_base */
6362306a36Sopenharmony_ci	pci_process_bridge_OF_ranges(hose, dev, 1);
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	return 0;
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_civoid __init amigaone_setup_arch(void)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	if (ppc_md.progress)
7162306a36Sopenharmony_ci		ppc_md.progress("Linux/PPC "UTS_RELEASE"\n", 0);
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic void __init amigaone_discover_phbs(void)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	struct device_node *np;
7762306a36Sopenharmony_ci	int phb = -ENODEV;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	/* Lookup PCI host bridges. */
8062306a36Sopenharmony_ci	for_each_compatible_node(np, "pci", "mai-logic,articia-s")
8162306a36Sopenharmony_ci		phb = amigaone_add_bridge(np);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	BUG_ON(phb != 0);
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_civoid __init amigaone_init_IRQ(void)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	struct device_node *pic, *np = NULL;
8962306a36Sopenharmony_ci	const unsigned long *prop = NULL;
9062306a36Sopenharmony_ci	unsigned long int_ack = 0;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	/* Search for ISA interrupt controller. */
9362306a36Sopenharmony_ci	pic = of_find_compatible_node(NULL, "interrupt-controller",
9462306a36Sopenharmony_ci	                              "pnpPNP,000");
9562306a36Sopenharmony_ci	BUG_ON(pic == NULL);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	/* Look for interrupt acknowledge address in the PCI root node. */
9862306a36Sopenharmony_ci	np = of_find_compatible_node(NULL, "pci", "mai-logic,articia-s");
9962306a36Sopenharmony_ci	if (np) {
10062306a36Sopenharmony_ci		prop = of_get_property(np, "8259-interrupt-acknowledge", NULL);
10162306a36Sopenharmony_ci		if (prop)
10262306a36Sopenharmony_ci			int_ack = prop[0];
10362306a36Sopenharmony_ci		of_node_put(np);
10462306a36Sopenharmony_ci	}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	if (int_ack == 0)
10762306a36Sopenharmony_ci		printk(KERN_WARNING "Cannot find PCI interrupt acknowledge"
10862306a36Sopenharmony_ci		       " address, polling\n");
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	i8259_init(pic, int_ack);
11162306a36Sopenharmony_ci	ppc_md.get_irq = i8259_irq;
11262306a36Sopenharmony_ci	irq_set_default_host(i8259_get_host());
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic int __init request_isa_regions(void)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	request_region(0x00, 0x20, "dma1");
11862306a36Sopenharmony_ci	request_region(0x40, 0x20, "timer");
11962306a36Sopenharmony_ci	request_region(0x80, 0x10, "dma page reg");
12062306a36Sopenharmony_ci	request_region(0xc0, 0x20, "dma2");
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	return 0;
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_cimachine_device_initcall(amigaone, request_isa_regions);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_civoid __noreturn amigaone_restart(char *cmd)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	local_irq_disable();
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	/* Flush and disable caches. */
13162306a36Sopenharmony_ci	__flush_disable_L1();
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci        /* Set SRR0 to the reset vector and turn on MSR_IP. */
13462306a36Sopenharmony_ci	mtspr(SPRN_SRR0, 0xfff00100);
13562306a36Sopenharmony_ci	mtspr(SPRN_SRR1, MSR_IP);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	/* Do an rfi to jump back to firmware. */
13862306a36Sopenharmony_ci	__asm__ __volatile__("rfi" : : : "memory");
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	/* Not reached. */
14162306a36Sopenharmony_ci	while (1);
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic int __init amigaone_probe(void)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	/*
14762306a36Sopenharmony_ci	 * Coherent memory access cause complete system lockup! Thus
14862306a36Sopenharmony_ci	 * disable this CPU feature, even if the CPU needs it.
14962306a36Sopenharmony_ci	 */
15062306a36Sopenharmony_ci	cur_cpu_spec->cpu_features &= ~CPU_FTR_NEED_COHERENT;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	DMA_MODE_READ = 0x44;
15362306a36Sopenharmony_ci	DMA_MODE_WRITE = 0x48;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	return 1;
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cidefine_machine(amigaone) {
15962306a36Sopenharmony_ci	.name			= "AmigaOne",
16062306a36Sopenharmony_ci	.compatible		= "eyetech,amigaone",
16162306a36Sopenharmony_ci	.probe			= amigaone_probe,
16262306a36Sopenharmony_ci	.setup_arch		= amigaone_setup_arch,
16362306a36Sopenharmony_ci	.discover_phbs		= amigaone_discover_phbs,
16462306a36Sopenharmony_ci	.show_cpuinfo		= amigaone_show_cpuinfo,
16562306a36Sopenharmony_ci	.init_IRQ		= amigaone_init_IRQ,
16662306a36Sopenharmony_ci	.restart		= amigaone_restart,
16762306a36Sopenharmony_ci	.progress		= udbg_progress,
16862306a36Sopenharmony_ci};
169