xref: /openbmc/linux/arch/mips/generic/board-sead3.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
1*2874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
23f5f0a44SPaul Burton /*
33f5f0a44SPaul Burton  * Copyright (C) 2016 Imagination Technologies
4fb615d61SPaul Burton  * Author: Paul Burton <paul.burton@mips.com>
53f5f0a44SPaul Burton  */
63f5f0a44SPaul Burton 
73f5f0a44SPaul Burton #define pr_fmt(fmt) "sead3: " fmt
83f5f0a44SPaul Burton 
93f5f0a44SPaul Burton #include <linux/errno.h>
103f5f0a44SPaul Burton #include <linux/libfdt.h>
113f5f0a44SPaul Burton #include <linux/printk.h>
12f41d2430SPaul Burton #include <linux/sizes.h>
133f5f0a44SPaul Burton 
143f5f0a44SPaul Burton #include <asm/fw/fw.h>
153f5f0a44SPaul Burton #include <asm/io.h>
163f5f0a44SPaul Burton #include <asm/machine.h>
17571b7e69SPaul Burton #include <asm/yamon-dt.h>
183f5f0a44SPaul Burton 
193f5f0a44SPaul Burton #define SEAD_CONFIG			CKSEG1ADDR(0x1b100110)
203f5f0a44SPaul Burton #define SEAD_CONFIG_GIC_PRESENT		BIT(1)
213f5f0a44SPaul Burton 
223f5f0a44SPaul Burton #define MIPS_REVISION			CKSEG1ADDR(0x1fc00010)
233f5f0a44SPaul Burton #define MIPS_REVISION_MACHINE		(0xf << 4)
243f5f0a44SPaul Burton #define MIPS_REVISION_MACHINE_SEAD3	(0x4 << 4)
253f5f0a44SPaul Burton 
26f41d2430SPaul Burton /*
27f41d2430SPaul Burton  * Maximum 384MB RAM at physical address 0, preceding any I/O.
28f41d2430SPaul Burton  */
29f41d2430SPaul Burton static struct yamon_mem_region mem_regions[] __initdata = {
30f41d2430SPaul Burton 	/* start	size */
31f41d2430SPaul Burton 	{ 0,		SZ_256M + SZ_128M },
32f41d2430SPaul Burton 	{}
33f41d2430SPaul Burton };
34f41d2430SPaul Burton 
sead3_detect(void)353f5f0a44SPaul Burton static __init bool sead3_detect(void)
363f5f0a44SPaul Burton {
373f5f0a44SPaul Burton 	uint32_t rev;
383f5f0a44SPaul Burton 
393f5f0a44SPaul Burton 	rev = __raw_readl((void *)MIPS_REVISION);
403f5f0a44SPaul Burton 	return (rev & MIPS_REVISION_MACHINE) == MIPS_REVISION_MACHINE_SEAD3;
413f5f0a44SPaul Burton }
423f5f0a44SPaul Burton 
append_memory(void * fdt)43f41d2430SPaul Burton static __init int append_memory(void *fdt)
44f41d2430SPaul Burton {
45f41d2430SPaul Burton 	return yamon_dt_append_memory(fdt, mem_regions);
46f41d2430SPaul Burton }
47f41d2430SPaul Burton 
remove_gic(void * fdt)483f5f0a44SPaul Burton static __init int remove_gic(void *fdt)
493f5f0a44SPaul Burton {
503f5f0a44SPaul Burton 	const unsigned int cpu_ehci_int = 2;
513f5f0a44SPaul Burton 	const unsigned int cpu_uart_int = 4;
523f5f0a44SPaul Burton 	const unsigned int cpu_eth_int = 6;
533f5f0a44SPaul Burton 	int gic_off, cpu_off, uart_off, eth_off, ehci_off, err;
543f5f0a44SPaul Burton 	uint32_t cfg, cpu_phandle;
553f5f0a44SPaul Burton 
563f5f0a44SPaul Burton 	/* leave the GIC node intact if a GIC is present */
573f5f0a44SPaul Burton 	cfg = __raw_readl((uint32_t *)SEAD_CONFIG);
583f5f0a44SPaul Burton 	if (cfg & SEAD_CONFIG_GIC_PRESENT)
593f5f0a44SPaul Burton 		return 0;
603f5f0a44SPaul Burton 
613f5f0a44SPaul Burton 	gic_off = fdt_node_offset_by_compatible(fdt, -1, "mti,gic");
623f5f0a44SPaul Burton 	if (gic_off < 0) {
633f5f0a44SPaul Burton 		pr_err("unable to find DT GIC node: %d\n", gic_off);
643f5f0a44SPaul Burton 		return gic_off;
653f5f0a44SPaul Burton 	}
663f5f0a44SPaul Burton 
673f5f0a44SPaul Burton 	err = fdt_nop_node(fdt, gic_off);
683f5f0a44SPaul Burton 	if (err) {
693f5f0a44SPaul Burton 		pr_err("unable to nop GIC node\n");
703f5f0a44SPaul Burton 		return err;
713f5f0a44SPaul Burton 	}
723f5f0a44SPaul Burton 
733f5f0a44SPaul Burton 	cpu_off = fdt_node_offset_by_compatible(fdt, -1,
743f5f0a44SPaul Burton 			"mti,cpu-interrupt-controller");
753f5f0a44SPaul Burton 	if (cpu_off < 0) {
763f5f0a44SPaul Burton 		pr_err("unable to find CPU intc node: %d\n", cpu_off);
773f5f0a44SPaul Burton 		return cpu_off;
783f5f0a44SPaul Burton 	}
793f5f0a44SPaul Burton 
803f5f0a44SPaul Burton 	cpu_phandle = fdt_get_phandle(fdt, cpu_off);
813f5f0a44SPaul Burton 	if (!cpu_phandle) {
823f5f0a44SPaul Burton 		pr_err("unable to get CPU intc phandle\n");
833f5f0a44SPaul Burton 		return -EINVAL;
843f5f0a44SPaul Burton 	}
853f5f0a44SPaul Burton 
86fbdc674bSPaul Burton 	uart_off = fdt_node_offset_by_compatible(fdt, -1, "ns16550a");
87fbdc674bSPaul Burton 	while (uart_off >= 0) {
88fbdc674bSPaul Burton 		err = fdt_setprop_u32(fdt, uart_off, "interrupt-parent",
89fbdc674bSPaul Burton 				      cpu_phandle);
903f5f0a44SPaul Burton 		if (err) {
91fbdc674bSPaul Burton 			pr_warn("unable to set UART interrupt-parent: %d\n",
92fbdc674bSPaul Burton 				err);
933f5f0a44SPaul Burton 			return err;
943f5f0a44SPaul Burton 		}
953f5f0a44SPaul Burton 
963f5f0a44SPaul Burton 		err = fdt_setprop_u32(fdt, uart_off, "interrupts",
973f5f0a44SPaul Burton 				      cpu_uart_int);
983f5f0a44SPaul Burton 		if (err) {
993f5f0a44SPaul Burton 			pr_err("unable to set UART interrupts property: %d\n",
1003f5f0a44SPaul Burton 			       err);
1013f5f0a44SPaul Burton 			return err;
1023f5f0a44SPaul Burton 		}
1033f5f0a44SPaul Burton 
1043f5f0a44SPaul Burton 		uart_off = fdt_node_offset_by_compatible(fdt, uart_off,
1053f5f0a44SPaul Burton 							 "ns16550a");
1063f5f0a44SPaul Burton 	}
1073f5f0a44SPaul Burton 	if (uart_off != -FDT_ERR_NOTFOUND) {
1083f5f0a44SPaul Burton 		pr_err("error searching for UART DT node: %d\n", uart_off);
1093f5f0a44SPaul Burton 		return uart_off;
1103f5f0a44SPaul Burton 	}
1113f5f0a44SPaul Burton 
1123f5f0a44SPaul Burton 	eth_off = fdt_node_offset_by_compatible(fdt, -1, "smsc,lan9115");
1133f5f0a44SPaul Burton 	if (eth_off < 0) {
1143f5f0a44SPaul Burton 		pr_err("unable to find ethernet DT node: %d\n", eth_off);
1153f5f0a44SPaul Burton 		return eth_off;
1163f5f0a44SPaul Burton 	}
1173f5f0a44SPaul Burton 
118fbdc674bSPaul Burton 	err = fdt_setprop_u32(fdt, eth_off, "interrupt-parent", cpu_phandle);
119fbdc674bSPaul Burton 	if (err) {
120fbdc674bSPaul Burton 		pr_err("unable to set ethernet interrupt-parent: %d\n", err);
121fbdc674bSPaul Burton 		return err;
122fbdc674bSPaul Burton 	}
123fbdc674bSPaul Burton 
1243f5f0a44SPaul Burton 	err = fdt_setprop_u32(fdt, eth_off, "interrupts", cpu_eth_int);
1253f5f0a44SPaul Burton 	if (err) {
1263f5f0a44SPaul Burton 		pr_err("unable to set ethernet interrupts property: %d\n", err);
1273f5f0a44SPaul Burton 		return err;
1283f5f0a44SPaul Burton 	}
1293f5f0a44SPaul Burton 
1303f5f0a44SPaul Burton 	ehci_off = fdt_node_offset_by_compatible(fdt, -1, "generic-ehci");
1313f5f0a44SPaul Burton 	if (ehci_off < 0) {
1323f5f0a44SPaul Burton 		pr_err("unable to find EHCI DT node: %d\n", ehci_off);
1333f5f0a44SPaul Burton 		return ehci_off;
1343f5f0a44SPaul Burton 	}
1353f5f0a44SPaul Burton 
136fbdc674bSPaul Burton 	err = fdt_setprop_u32(fdt, ehci_off, "interrupt-parent", cpu_phandle);
137fbdc674bSPaul Burton 	if (err) {
138fbdc674bSPaul Burton 		pr_err("unable to set EHCI interrupt-parent: %d\n", err);
139fbdc674bSPaul Burton 		return err;
140fbdc674bSPaul Burton 	}
141fbdc674bSPaul Burton 
1423f5f0a44SPaul Burton 	err = fdt_setprop_u32(fdt, ehci_off, "interrupts", cpu_ehci_int);
1433f5f0a44SPaul Burton 	if (err) {
1443f5f0a44SPaul Burton 		pr_err("unable to set EHCI interrupts property: %d\n", err);
1453f5f0a44SPaul Burton 		return err;
1463f5f0a44SPaul Burton 	}
1473f5f0a44SPaul Burton 
1483f5f0a44SPaul Burton 	return 0;
1493f5f0a44SPaul Burton }
1503f5f0a44SPaul Burton 
151e889dfcaSPaul Burton static const struct mips_fdt_fixup sead3_fdt_fixups[] __initconst = {
152e889dfcaSPaul Burton 	{ yamon_dt_append_cmdline, "append command line" },
153e889dfcaSPaul Burton 	{ append_memory, "append memory" },
154e889dfcaSPaul Burton 	{ remove_gic, "remove GIC when not present" },
155e889dfcaSPaul Burton 	{ yamon_dt_serial_config, "append serial configuration" },
156e889dfcaSPaul Burton 	{ },
157e889dfcaSPaul Burton };
158e889dfcaSPaul Burton 
sead3_fixup_fdt(const void * fdt,const void * match_data)1593f5f0a44SPaul Burton static __init const void *sead3_fixup_fdt(const void *fdt,
1603f5f0a44SPaul Burton 					  const void *match_data)
1613f5f0a44SPaul Burton {
1623f5f0a44SPaul Burton 	static unsigned char fdt_buf[16 << 10] __initdata;
1633f5f0a44SPaul Burton 	int err;
1643f5f0a44SPaul Burton 
1653f5f0a44SPaul Burton 	if (fdt_check_header(fdt))
1663f5f0a44SPaul Burton 		panic("Corrupt DT");
1673f5f0a44SPaul Burton 
1683f5f0a44SPaul Burton 	/* if this isn't SEAD3, something went wrong */
1693f5f0a44SPaul Burton 	BUG_ON(fdt_node_check_compatible(fdt, 0, "mti,sead-3"));
1703f5f0a44SPaul Burton 
1713f5f0a44SPaul Burton 	fw_init_cmdline();
1723f5f0a44SPaul Burton 
173e889dfcaSPaul Burton 	err = apply_mips_fdt_fixups(fdt_buf, sizeof(fdt_buf),
174e889dfcaSPaul Burton 				    fdt, sead3_fdt_fixups);
1753f5f0a44SPaul Burton 	if (err)
176e889dfcaSPaul Burton 		panic("Unable to fixup FDT: %d", err);
1773f5f0a44SPaul Burton 
1783f5f0a44SPaul Burton 	return fdt_buf;
1793f5f0a44SPaul Burton }
1803f5f0a44SPaul Burton 
sead3_measure_hpt_freq(void)1813f5f0a44SPaul Burton static __init unsigned int sead3_measure_hpt_freq(void)
1823f5f0a44SPaul Burton {
1833f5f0a44SPaul Burton 	void __iomem *status_reg = (void __iomem *)0xbf000410;
1843f5f0a44SPaul Burton 	unsigned int freq, orig, tick = 0;
1853f5f0a44SPaul Burton 	unsigned long flags;
1863f5f0a44SPaul Burton 
1873f5f0a44SPaul Burton 	local_irq_save(flags);
1883f5f0a44SPaul Burton 
1893f5f0a44SPaul Burton 	orig = readl(status_reg) & 0x2;		      /* get original sample */
1903f5f0a44SPaul Burton 	/* wait for transition */
1913f5f0a44SPaul Burton 	while ((readl(status_reg) & 0x2) == orig)
1923f5f0a44SPaul Burton 		;
1933f5f0a44SPaul Burton 	orig = orig ^ 0x2;			      /* flip the bit */
1943f5f0a44SPaul Burton 
1953f5f0a44SPaul Burton 	write_c0_count(0);
1963f5f0a44SPaul Burton 
1973f5f0a44SPaul Burton 	/* wait 1 second (the sampling clock transitions every 10ms) */
1983f5f0a44SPaul Burton 	while (tick < 100) {
1993f5f0a44SPaul Burton 		/* wait for transition */
2003f5f0a44SPaul Burton 		while ((readl(status_reg) & 0x2) == orig)
2013f5f0a44SPaul Burton 			;
2023f5f0a44SPaul Burton 		orig = orig ^ 0x2;			      /* flip the bit */
2033f5f0a44SPaul Burton 		tick++;
2043f5f0a44SPaul Burton 	}
2053f5f0a44SPaul Burton 
2063f5f0a44SPaul Burton 	freq = read_c0_count();
2073f5f0a44SPaul Burton 
2083f5f0a44SPaul Burton 	local_irq_restore(flags);
2093f5f0a44SPaul Burton 
2103f5f0a44SPaul Burton 	return freq;
2113f5f0a44SPaul Burton }
2123f5f0a44SPaul Burton 
2133f5f0a44SPaul Burton extern char __dtb_sead3_begin[];
2143f5f0a44SPaul Burton 
2153f5f0a44SPaul Burton MIPS_MACHINE(sead3) = {
2163f5f0a44SPaul Burton 	.fdt = __dtb_sead3_begin,
2173f5f0a44SPaul Burton 	.detect = sead3_detect,
2183f5f0a44SPaul Burton 	.fixup_fdt = sead3_fixup_fdt,
2193f5f0a44SPaul Burton 	.measure_hpt_freq = sead3_measure_hpt_freq,
2203f5f0a44SPaul Burton };
221