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