aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/generic
diff options
context:
space:
mode:
authorWe-unite <3205135446@qq.com>2025-03-08 22:04:20 +0800
committerWe-unite <3205135446@qq.com>2025-03-08 22:04:20 +0800
commita07bb8fd1299070229f0e8f3dcb57ffd5ef9870a (patch)
tree84f21bd0bf7071bc5fc7dd989e77d7ceb5476682 /arch/mips/generic
downloadohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.tar.gz
ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.zip
Initial commit: OpenHarmony-v4.0-ReleaseOpenHarmony-v4.0-Release
Diffstat (limited to 'arch/mips/generic')
-rw-r--r--arch/mips/generic/Kconfig92
-rw-r--r--arch/mips/generic/Makefile15
-rw-r--r--arch/mips/generic/Platform23
-rw-r--r--arch/mips/generic/board-boston.its.S22
-rw-r--r--arch/mips/generic/board-ingenic.c120
-rw-r--r--arch/mips/generic/board-ni169445.its.S22
-rw-r--r--arch/mips/generic/board-ocelot.c78
-rw-r--r--arch/mips/generic/board-ocelot.its.S40
-rw-r--r--arch/mips/generic/board-ranchu.c89
-rw-r--r--arch/mips/generic/board-sead3.c220
-rw-r--r--arch/mips/generic/board-xilfpga.its.S22
-rw-r--r--arch/mips/generic/init.c208
-rw-r--r--arch/mips/generic/irq.c61
-rw-r--r--arch/mips/generic/proc.c30
-rw-r--r--arch/mips/generic/vmlinux.its.S32
-rw-r--r--arch/mips/generic/yamon-dt.c232
16 files changed, 1306 insertions, 0 deletions
diff --git a/arch/mips/generic/Kconfig b/arch/mips/generic/Kconfig
new file mode 100644
index 000000000..55d9aed7c
--- /dev/null
+++ b/arch/mips/generic/Kconfig
@@ -0,0 +1,92 @@
1# SPDX-License-Identifier: GPL-2.0
2if MIPS_GENERIC_KERNEL
3
4config LEGACY_BOARDS
5 bool
6 help
7 Select this from your board if the board must use a legacy, non-UHI,
8 boot protocol. This will cause the kernel to scan through the list of
9 supported machines calling their detect functions in turn if the
10 kernel is booted without being provided with an FDT via the UHI
11 boot protocol.
12
13config YAMON_DT_SHIM
14 bool
15 help
16 Select this from your board if the board uses the YAMON bootloader
17 and you wish to include code which helps translate various
18 YAMON-provided environment variables into a device tree properties.
19
20comment "Legacy (non-UHI/non-FIT) Boards"
21
22config LEGACY_BOARD_SEAD3
23 bool "Support MIPS SEAD-3 boards"
24 select LEGACY_BOARDS
25 select YAMON_DT_SHIM
26 help
27 Enable this to include support for booting on MIPS SEAD-3 FPGA-based
28 development boards, which boot using a legacy boot protocol.
29
30comment "MSCC Ocelot doesn't work with SEAD3 enabled"
31 depends on LEGACY_BOARD_SEAD3
32
33config LEGACY_BOARD_OCELOT
34 bool "Support MSCC Ocelot boards"
35 depends on LEGACY_BOARD_SEAD3=n
36 select LEGACY_BOARDS
37 select MSCC_OCELOT
38 select SYS_HAS_EARLY_PRINTK
39 select USE_GENERIC_EARLY_PRINTK_8250
40
41config MSCC_OCELOT
42 bool
43 select GPIOLIB
44 select MSCC_OCELOT_IRQ
45
46comment "FIT/UHI Boards"
47
48config FIT_IMAGE_FDT_BOSTON
49 bool "Include FDT for MIPS Boston boards"
50 help
51 Enable this to include the FDT for the MIPS Boston development board
52 from Imagination Technologies in the FIT kernel image. You should
53 enable this if you wish to boot on a MIPS Boston board, as it is
54 expected by the bootloader.
55
56config FIT_IMAGE_FDT_NI169445
57 bool "Include FDT for NI 169445"
58 help
59 Enable this to include the FDT for the 169445 platform from
60 National Instruments in the FIT kernel image.
61
62config FIT_IMAGE_FDT_XILFPGA
63 bool "Include FDT for Xilfpga"
64 help
65 Enable this to include the FDT for the MIPSfpga platform
66 from Imagination Technologies in the FIT kernel image.
67
68config FIT_IMAGE_FDT_OCELOT
69 bool "Include FDT for Microsemi Ocelot development platforms"
70 select MSCC_OCELOT
71 help
72 Enable this to include the FDT for the Ocelot development platforms
73 from Microsemi in the FIT kernel image.
74 This requires u-boot on the platform.
75
76config BOARD_INGENIC
77 bool "Support boards based on Ingenic SoCs"
78 select MACH_INGENIC_GENERIC
79 help
80 Enable support for boards based on Ingenic SoCs.
81
82config VIRT_BOARD_RANCHU
83 bool "Support Ranchu platform for Android emulator"
84 help
85 This enables support for the platform used by Android emulator.
86
87 Ranchu platform consists of a set of virtual devices. This platform
88 enables emulation of variety of virtual configurations while using
89 Android emulator. Android emulator is based on Qemu, and contains
90 the support for the same set of virtual devices.
91
92endif
diff --git a/arch/mips/generic/Makefile b/arch/mips/generic/Makefile
new file mode 100644
index 000000000..e37a59bae
--- /dev/null
+++ b/arch/mips/generic/Makefile
@@ -0,0 +1,15 @@
1# SPDX-License-Identifier: GPL-2.0-or-later
2#
3# Copyright (C) 2016 Imagination Technologies
4# Author: Paul Burton <paul.burton@mips.com>
5#
6
7obj-y += init.o
8obj-y += irq.o
9obj-y += proc.o
10
11obj-$(CONFIG_YAMON_DT_SHIM) += yamon-dt.o
12obj-$(CONFIG_LEGACY_BOARD_SEAD3) += board-sead3.o
13obj-$(CONFIG_LEGACY_BOARD_OCELOT) += board-ocelot.o
14obj-$(CONFIG_MACH_INGENIC) += board-ingenic.o
15obj-$(CONFIG_VIRT_BOARD_RANCHU) += board-ranchu.o
diff --git a/arch/mips/generic/Platform b/arch/mips/generic/Platform
new file mode 100644
index 000000000..f8ef2f9d1
--- /dev/null
+++ b/arch/mips/generic/Platform
@@ -0,0 +1,23 @@
1#
2# Copyright (C) 2016 Imagination Technologies
3# Author: Paul Burton <paul.burton@mips.com>
4#
5# This program is free software; you can redistribute it and/or modify it
6# under the terms of the GNU General Public License as published by the
7# Free Software Foundation; either version 2 of the License, or (at your
8# option) any later version.
9#
10
11# Note: order matters, keep the asm/mach-generic include last.
12cflags-$(CONFIG_MACH_INGENIC_SOC) += -I$(srctree)/arch/mips/include/asm/mach-ingenic
13cflags-$(CONFIG_MIPS_GENERIC) += -I$(srctree)/arch/mips/include/asm/mach-generic
14
15load-$(CONFIG_MIPS_GENERIC) += 0xffffffff80100000
16zload-$(CONFIG_MIPS_GENERIC) += 0xffffffff81000000
17all-$(CONFIG_MIPS_GENERIC) := vmlinux.gz.itb
18
19its-y := vmlinux.its.S
20its-$(CONFIG_FIT_IMAGE_FDT_BOSTON) += board-boston.its.S
21its-$(CONFIG_FIT_IMAGE_FDT_NI169445) += board-ni169445.its.S
22its-$(CONFIG_FIT_IMAGE_FDT_OCELOT) += board-ocelot.its.S
23its-$(CONFIG_FIT_IMAGE_FDT_XILFPGA) += board-xilfpga.its.S
diff --git a/arch/mips/generic/board-boston.its.S b/arch/mips/generic/board-boston.its.S
new file mode 100644
index 000000000..c45ad2759
--- /dev/null
+++ b/arch/mips/generic/board-boston.its.S
@@ -0,0 +1,22 @@
1/ {
2 images {
3 fdt-boston {
4 description = "img,boston Device Tree";
5 data = /incbin/("boot/dts/img/boston.dtb");
6 type = "flat_dt";
7 arch = "mips";
8 compression = "none";
9 hash {
10 algo = "sha1";
11 };
12 };
13 };
14
15 configurations {
16 conf-boston {
17 description = "Boston Linux kernel";
18 kernel = "kernel";
19 fdt = "fdt-boston";
20 };
21 };
22};
diff --git a/arch/mips/generic/board-ingenic.c b/arch/mips/generic/board-ingenic.c
new file mode 100644
index 000000000..0cec0bea1
--- /dev/null
+++ b/arch/mips/generic/board-ingenic.c
@@ -0,0 +1,120 @@
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Support for Ingenic SoCs
4 *
5 * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
6 * Copyright (C) 2011, Maarten ter Huurne <maarten@treewalker.org>
7 * Copyright (C) 2020 Paul Cercueil <paul@crapouillou.net>
8 */
9
10#include <linux/of_address.h>
11#include <linux/of_fdt.h>
12#include <linux/pm.h>
13#include <linux/sizes.h>
14#include <linux/suspend.h>
15#include <linux/types.h>
16
17#include <asm/bootinfo.h>
18#include <asm/machine.h>
19#include <asm/reboot.h>
20
21static __init char *ingenic_get_system_type(unsigned long machtype)
22{
23 switch (machtype) {
24 case MACH_INGENIC_X2000E:
25 return "X2000E";
26 case MACH_INGENIC_X2000:
27 return "X2000";
28 case MACH_INGENIC_X1830:
29 return "X1830";
30 case MACH_INGENIC_X1000E:
31 return "X1000E";
32 case MACH_INGENIC_X1000:
33 return "X1000";
34 case MACH_INGENIC_JZ4780:
35 return "JZ4780";
36 case MACH_INGENIC_JZ4775:
37 return "JZ4775";
38 case MACH_INGENIC_JZ4770:
39 return "JZ4770";
40 case MACH_INGENIC_JZ4725B:
41 return "JZ4725B";
42 default:
43 return "JZ4740";
44 }
45}
46
47static __init const void *ingenic_fixup_fdt(const void *fdt, const void *match_data)
48{
49 /*
50 * Old devicetree files for the qi,lb60 board did not have a /memory
51 * node. Hardcode the memory info here.
52 */
53 if (!fdt_node_check_compatible(fdt, 0, "qi,lb60") &&
54 fdt_path_offset(fdt, "/memory") < 0)
55 early_init_dt_add_memory_arch(0, SZ_32M);
56
57 mips_machtype = (unsigned long)match_data;
58 system_type = ingenic_get_system_type(mips_machtype);
59
60 return fdt;
61}
62
63static const struct of_device_id ingenic_of_match[] __initconst = {
64 { .compatible = "ingenic,jz4740", .data = (void *)MACH_INGENIC_JZ4740 },
65 { .compatible = "ingenic,jz4725b", .data = (void *)MACH_INGENIC_JZ4725B },
66 { .compatible = "ingenic,jz4770", .data = (void *)MACH_INGENIC_JZ4770 },
67 { .compatible = "ingenic,jz4775", .data = (void *)MACH_INGENIC_JZ4775 },
68 { .compatible = "ingenic,jz4780", .data = (void *)MACH_INGENIC_JZ4780 },
69 { .compatible = "ingenic,x1000", .data = (void *)MACH_INGENIC_X1000 },
70 { .compatible = "ingenic,x1000e", .data = (void *)MACH_INGENIC_X1000E },
71 { .compatible = "ingenic,x1830", .data = (void *)MACH_INGENIC_X1830 },
72 { .compatible = "ingenic,x2000", .data = (void *)MACH_INGENIC_X2000 },
73 { .compatible = "ingenic,x2000e", .data = (void *)MACH_INGENIC_X2000E },
74 {}
75};
76
77MIPS_MACHINE(ingenic) = {
78 .matches = ingenic_of_match,
79 .fixup_fdt = ingenic_fixup_fdt,
80};
81
82static void ingenic_wait_instr(void)
83{
84 __asm__(".set push;\n"
85 ".set mips3;\n"
86 "wait;\n"
87 ".set pop;\n"
88 );
89}
90
91static void ingenic_halt(void)
92{
93 for (;;)
94 ingenic_wait_instr();
95}
96
97static int __maybe_unused ingenic_pm_enter(suspend_state_t state)
98{
99 ingenic_wait_instr();
100
101 return 0;
102}
103
104static const struct platform_suspend_ops ingenic_pm_ops __maybe_unused = {
105 .valid = suspend_valid_only_mem,
106 .enter = ingenic_pm_enter,
107};
108
109static int __init ingenic_pm_init(void)
110{
111 if (boot_cpu_type() == CPU_XBURST) {
112 if (IS_ENABLED(CONFIG_PM_SLEEP))
113 suspend_set_ops(&ingenic_pm_ops);
114 _machine_halt = ingenic_halt;
115 }
116
117 return 0;
118
119}
120late_initcall(ingenic_pm_init);
diff --git a/arch/mips/generic/board-ni169445.its.S b/arch/mips/generic/board-ni169445.its.S
new file mode 100644
index 000000000..0a2e8f7a8
--- /dev/null
+++ b/arch/mips/generic/board-ni169445.its.S
@@ -0,0 +1,22 @@
1/ {
2 images {
3 fdt-ni169445 {
4 description = "NI 169445 device tree";
5 data = /incbin/("boot/dts/ni/169445.dtb");
6 type = "flat_dt";
7 arch = "mips";
8 compression = "none";
9 hash {
10 algo = "sha1";
11 };
12 };
13 };
14
15 configurations {
16 conf-ni169445 {
17 description = "NI 169445 Linux Kernel";
18 kernel = "kernel";
19 fdt = "fdt-ni169445";
20 };
21 };
22};
diff --git a/arch/mips/generic/board-ocelot.c b/arch/mips/generic/board-ocelot.c
new file mode 100644
index 000000000..c238e9519
--- /dev/null
+++ b/arch/mips/generic/board-ocelot.c
@@ -0,0 +1,78 @@
1// SPDX-License-Identifier: (GPL-2.0 OR MIT)
2/*
3 * Microsemi MIPS SoC support
4 *
5 * Copyright (c) 2017 Microsemi Corporation
6 */
7#include <asm/machine.h>
8#include <asm/prom.h>
9
10#define DEVCPU_GCB_CHIP_REGS_CHIP_ID 0x71070000
11#define CHIP_ID_PART_ID GENMASK(27, 12)
12
13#define OCELOT_PART_ID (0x7514 << 12)
14
15#define UART_UART 0x70100000
16
17static __init bool ocelot_detect(void)
18{
19 u32 rev;
20 int idx;
21
22 /* Look for the TLB entry set up by redboot before trying to use it */
23 write_c0_entryhi(DEVCPU_GCB_CHIP_REGS_CHIP_ID);
24 mtc0_tlbw_hazard();
25 tlb_probe();
26 tlb_probe_hazard();
27 idx = read_c0_index();
28 if (idx < 0)
29 return 0;
30
31 /* A TLB entry exists, lets assume its usable and check the CHIP ID */
32 rev = __raw_readl((void __iomem *)DEVCPU_GCB_CHIP_REGS_CHIP_ID);
33
34 if ((rev & CHIP_ID_PART_ID) != OCELOT_PART_ID)
35 return 0;
36
37 /* Copy command line from bootloader early for Initrd detection */
38 if (fw_arg0 < 10 && (fw_arg1 & 0xFFF00000) == 0x80000000) {
39 unsigned int prom_argc = fw_arg0;
40 const char **prom_argv = (const char **)fw_arg1;
41
42 if (prom_argc > 1 && strlen(prom_argv[1]) > 0)
43 /* ignore all built-in args if any f/w args given */
44 strcpy(arcs_cmdline, prom_argv[1]);
45 }
46
47 return 1;
48}
49
50static void __init ocelot_earlyprintk_init(void)
51{
52 void __iomem *uart_base;
53
54 uart_base = ioremap(UART_UART, 0x20);
55 setup_8250_early_printk_port((unsigned long)uart_base, 2, 50000);
56}
57
58static void __init ocelot_late_init(void)
59{
60 ocelot_earlyprintk_init();
61}
62
63static __init const void *ocelot_fixup_fdt(const void *fdt,
64 const void *match_data)
65{
66 /* This has to be done so late because ioremap needs to work */
67 late_time_init = ocelot_late_init;
68
69 return fdt;
70}
71
72extern char __dtb_ocelot_pcb123_begin[];
73
74MIPS_MACHINE(ocelot) = {
75 .fdt = __dtb_ocelot_pcb123_begin,
76 .fixup_fdt = ocelot_fixup_fdt,
77 .detect = ocelot_detect,
78};
diff --git a/arch/mips/generic/board-ocelot.its.S b/arch/mips/generic/board-ocelot.its.S
new file mode 100644
index 000000000..8c7e3a1b6
--- /dev/null
+++ b/arch/mips/generic/board-ocelot.its.S
@@ -0,0 +1,40 @@
1/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
2/ {
3 images {
4 fdt-ocelot_pcb123 {
5 description = "MSCC Ocelot PCB123 Device Tree";
6 data = /incbin/("boot/dts/mscc/ocelot_pcb123.dtb");
7 type = "flat_dt";
8 arch = "mips";
9 compression = "none";
10 hash {
11 algo = "sha1";
12 };
13 };
14
15 fdt-ocelot_pcb120 {
16 description = "MSCC Ocelot PCB120 Device Tree";
17 data = /incbin/("boot/dts/mscc/ocelot_pcb120.dtb");
18 type = "flat_dt";
19 arch = "mips";
20 compression = "none";
21 hash {
22 algo = "sha1";
23 };
24 };
25 };
26
27 configurations {
28 conf-ocelot_pcb123 {
29 description = "Ocelot Linux kernel";
30 kernel = "kernel";
31 fdt = "fdt-ocelot_pcb123";
32 };
33
34 conf-ocelot_pcb120 {
35 description = "Ocelot Linux kernel";
36 kernel = "kernel";
37 fdt = "fdt-ocelot_pcb120";
38 };
39 };
40};
diff --git a/arch/mips/generic/board-ranchu.c b/arch/mips/generic/board-ranchu.c
new file mode 100644
index 000000000..a89aaad59
--- /dev/null
+++ b/arch/mips/generic/board-ranchu.c
@@ -0,0 +1,89 @@
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Support code for virtual Ranchu board for MIPS.
4 *
5 * Author: Miodrag Dinic <miodrag.dinic@mips.com>
6 */
7
8#include <linux/of_address.h>
9#include <linux/types.h>
10
11#include <asm/machine.h>
12#include <asm/mipsregs.h>
13#include <asm/time.h>
14
15#define GOLDFISH_TIMER_LOW 0x00
16#define GOLDFISH_TIMER_HIGH 0x04
17
18static __init u64 read_rtc_time(void __iomem *base)
19{
20 u32 time_low;
21 u32 time_high;
22
23 /*
24 * Reading the low address latches the high value
25 * as well so there is no fear that we may read
26 * inaccurate high value.
27 */
28 time_low = readl(base + GOLDFISH_TIMER_LOW);
29 time_high = readl(base + GOLDFISH_TIMER_HIGH);
30
31 return ((u64)time_high << 32) | time_low;
32}
33
34static __init unsigned int ranchu_measure_hpt_freq(void)
35{
36 u64 rtc_start, rtc_current, rtc_delta;
37 unsigned int start, count;
38 struct device_node *np;
39 void __iomem *rtc_base;
40
41 np = of_find_compatible_node(NULL, NULL, "google,goldfish-rtc");
42 if (!np)
43 panic("%s(): Failed to find 'google,goldfish-rtc' dt node!",
44 __func__);
45
46 rtc_base = of_iomap(np, 0);
47 if (!rtc_base)
48 panic("%s(): Failed to ioremap Goldfish RTC base!", __func__);
49
50 /*
51 * Poll the nanosecond resolution RTC for one
52 * second to calibrate the CPU frequency.
53 */
54 rtc_start = read_rtc_time(rtc_base);
55 start = read_c0_count();
56
57 do {
58 rtc_current = read_rtc_time(rtc_base);
59 rtc_delta = rtc_current - rtc_start;
60 } while (rtc_delta < NSEC_PER_SEC);
61
62 count = read_c0_count() - start;
63
64 /*
65 * Make sure the frequency will be a round number.
66 * Without this correction, the returned value may vary
67 * between subsequent emulation executions.
68 *
69 * TODO: Set this value using device tree.
70 */
71 count += 5000;
72 count -= count % 10000;
73
74 iounmap(rtc_base);
75
76 return count;
77}
78
79static const struct of_device_id ranchu_of_match[] __initconst = {
80 {
81 .compatible = "mti,ranchu",
82 },
83 {}
84};
85
86MIPS_MACHINE(ranchu) = {
87 .matches = ranchu_of_match,
88 .measure_hpt_freq = ranchu_measure_hpt_freq,
89};
diff --git a/arch/mips/generic/board-sead3.c b/arch/mips/generic/board-sead3.c
new file mode 100644
index 000000000..748ef4228
--- /dev/null
+++ b/arch/mips/generic/board-sead3.c
@@ -0,0 +1,220 @@
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2016 Imagination Technologies
4 * Author: Paul Burton <paul.burton@mips.com>
5 */
6
7#define pr_fmt(fmt) "sead3: " fmt
8
9#include <linux/errno.h>
10#include <linux/libfdt.h>
11#include <linux/printk.h>
12#include <linux/sizes.h>
13
14#include <asm/fw/fw.h>
15#include <asm/io.h>
16#include <asm/machine.h>
17#include <asm/yamon-dt.h>
18
19#define SEAD_CONFIG CKSEG1ADDR(0x1b100110)
20#define SEAD_CONFIG_GIC_PRESENT BIT(1)
21
22#define MIPS_REVISION CKSEG1ADDR(0x1fc00010)
23#define MIPS_REVISION_MACHINE (0xf << 4)
24#define MIPS_REVISION_MACHINE_SEAD3 (0x4 << 4)
25
26/*
27 * Maximum 384MB RAM at physical address 0, preceding any I/O.
28 */
29static struct yamon_mem_region mem_regions[] __initdata = {
30 /* start size */
31 { 0, SZ_256M + SZ_128M },
32 {}
33};
34
35static __init bool sead3_detect(void)
36{
37 uint32_t rev;
38
39 rev = __raw_readl((void *)MIPS_REVISION);
40 return (rev & MIPS_REVISION_MACHINE) == MIPS_REVISION_MACHINE_SEAD3;
41}
42
43static __init int append_memory(void *fdt)
44{
45 return yamon_dt_append_memory(fdt, mem_regions);
46}
47
48static __init int remove_gic(void *fdt)
49{
50 const unsigned int cpu_ehci_int = 2;
51 const unsigned int cpu_uart_int = 4;
52 const unsigned int cpu_eth_int = 6;
53 int gic_off, cpu_off, uart_off, eth_off, ehci_off, err;
54 uint32_t cfg, cpu_phandle;
55
56 /* leave the GIC node intact if a GIC is present */
57 cfg = __raw_readl((uint32_t *)SEAD_CONFIG);
58 if (cfg & SEAD_CONFIG_GIC_PRESENT)
59 return 0;
60
61 gic_off = fdt_node_offset_by_compatible(fdt, -1, "mti,gic");
62 if (gic_off < 0) {
63 pr_err("unable to find DT GIC node: %d\n", gic_off);
64 return gic_off;
65 }
66
67 err = fdt_nop_node(fdt, gic_off);
68 if (err) {
69 pr_err("unable to nop GIC node\n");
70 return err;
71 }
72
73 cpu_off = fdt_node_offset_by_compatible(fdt, -1,
74 "mti,cpu-interrupt-controller");
75 if (cpu_off < 0) {
76 pr_err("unable to find CPU intc node: %d\n", cpu_off);
77 return cpu_off;
78 }
79
80 cpu_phandle = fdt_get_phandle(fdt, cpu_off);
81 if (!cpu_phandle) {
82 pr_err("unable to get CPU intc phandle\n");
83 return -EINVAL;
84 }
85
86 uart_off = fdt_node_offset_by_compatible(fdt, -1, "ns16550a");
87 while (uart_off >= 0) {
88 err = fdt_setprop_u32(fdt, uart_off, "interrupt-parent",
89 cpu_phandle);
90 if (err) {
91 pr_warn("unable to set UART interrupt-parent: %d\n",
92 err);
93 return err;
94 }
95
96 err = fdt_setprop_u32(fdt, uart_off, "interrupts",
97 cpu_uart_int);
98 if (err) {
99 pr_err("unable to set UART interrupts property: %d\n",
100 err);
101 return err;
102 }
103
104 uart_off = fdt_node_offset_by_compatible(fdt, uart_off,
105 "ns16550a");
106 }
107 if (uart_off != -FDT_ERR_NOTFOUND) {
108 pr_err("error searching for UART DT node: %d\n", uart_off);
109 return uart_off;
110 }
111
112 eth_off = fdt_node_offset_by_compatible(fdt, -1, "smsc,lan9115");
113 if (eth_off < 0) {
114 pr_err("unable to find ethernet DT node: %d\n", eth_off);
115 return eth_off;
116 }
117
118 err = fdt_setprop_u32(fdt, eth_off, "interrupt-parent", cpu_phandle);
119 if (err) {
120 pr_err("unable to set ethernet interrupt-parent: %d\n", err);
121 return err;
122 }
123
124 err = fdt_setprop_u32(fdt, eth_off, "interrupts", cpu_eth_int);
125 if (err) {
126 pr_err("unable to set ethernet interrupts property: %d\n", err);
127 return err;
128 }
129
130 ehci_off = fdt_node_offset_by_compatible(fdt, -1, "generic-ehci");
131 if (ehci_off < 0) {
132 pr_err("unable to find EHCI DT node: %d\n", ehci_off);
133 return ehci_off;
134 }
135
136 err = fdt_setprop_u32(fdt, ehci_off, "interrupt-parent", cpu_phandle);
137 if (err) {
138 pr_err("unable to set EHCI interrupt-parent: %d\n", err);
139 return err;
140 }
141
142 err = fdt_setprop_u32(fdt, ehci_off, "interrupts", cpu_ehci_int);
143 if (err) {
144 pr_err("unable to set EHCI interrupts property: %d\n", err);
145 return err;
146 }
147
148 return 0;
149}
150
151static const struct mips_fdt_fixup sead3_fdt_fixups[] __initconst = {
152 { yamon_dt_append_cmdline, "append command line" },
153 { append_memory, "append memory" },
154 { remove_gic, "remove GIC when not present" },
155 { yamon_dt_serial_config, "append serial configuration" },
156 { },
157};
158
159static __init const void *sead3_fixup_fdt(const void *fdt,
160 const void *match_data)
161{
162 static unsigned char fdt_buf[16 << 10] __initdata;
163 int err;
164
165 if (fdt_check_header(fdt))
166 panic("Corrupt DT");
167
168 /* if this isn't SEAD3, something went wrong */
169 BUG_ON(fdt_node_check_compatible(fdt, 0, "mti,sead-3"));
170
171 fw_init_cmdline();
172
173 err = apply_mips_fdt_fixups(fdt_buf, sizeof(fdt_buf),
174 fdt, sead3_fdt_fixups);
175 if (err)
176 panic("Unable to fixup FDT: %d", err);
177
178 return fdt_buf;
179}
180
181static __init unsigned int sead3_measure_hpt_freq(void)
182{
183 void __iomem *status_reg = (void __iomem *)0xbf000410;
184 unsigned int freq, orig, tick = 0;
185 unsigned long flags;
186
187 local_irq_save(flags);
188
189 orig = readl(status_reg) & 0x2; /* get original sample */
190 /* wait for transition */
191 while ((readl(status_reg) & 0x2) == orig)
192 ;
193 orig = orig ^ 0x2; /* flip the bit */
194
195 write_c0_count(0);
196
197 /* wait 1 second (the sampling clock transitions every 10ms) */
198 while (tick < 100) {
199 /* wait for transition */
200 while ((readl(status_reg) & 0x2) == orig)
201 ;
202 orig = orig ^ 0x2; /* flip the bit */
203 tick++;
204 }
205
206 freq = read_c0_count();
207
208 local_irq_restore(flags);
209
210 return freq;
211}
212
213extern char __dtb_sead3_begin[];
214
215MIPS_MACHINE(sead3) = {
216 .fdt = __dtb_sead3_begin,
217 .detect = sead3_detect,
218 .fixup_fdt = sead3_fixup_fdt,
219 .measure_hpt_freq = sead3_measure_hpt_freq,
220};
diff --git a/arch/mips/generic/board-xilfpga.its.S b/arch/mips/generic/board-xilfpga.its.S
new file mode 100644
index 000000000..08c1e900e
--- /dev/null
+++ b/arch/mips/generic/board-xilfpga.its.S
@@ -0,0 +1,22 @@
1/ {
2 images {
3 fdt-xilfpga {
4 description = "MIPSfpga (xilfpga) Device Tree";
5 data = /incbin/("boot/dts/xilfpga/nexys4ddr.dtb");
6 type = "flat_dt";
7 arch = "mips";
8 compression = "none";
9 hash {
10 algo = "sha1";
11 };
12 };
13 };
14
15 configurations {
16 conf-xilfpga {
17 description = "MIPSfpga Linux kernel";
18 kernel = "kernel";
19 fdt = "fdt-xilfpga";
20 };
21 };
22};
diff --git a/arch/mips/generic/init.c b/arch/mips/generic/init.c
new file mode 100644
index 000000000..66a19337d
--- /dev/null
+++ b/arch/mips/generic/init.c
@@ -0,0 +1,208 @@
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2016 Imagination Technologies
4 * Author: Paul Burton <paul.burton@mips.com>
5 */
6
7#include <linux/clk.h>
8#include <linux/clocksource.h>
9#include <linux/init.h>
10#include <linux/irqchip.h>
11#include <linux/of_clk.h>
12#include <linux/of_fdt.h>
13
14#include <asm/bootinfo.h>
15#include <asm/fw/fw.h>
16#include <asm/irq_cpu.h>
17#include <asm/machine.h>
18#include <asm/mips-cps.h>
19#include <asm/prom.h>
20#include <asm/smp-ops.h>
21#include <asm/time.h>
22
23static __initconst const void *fdt;
24static __initconst const struct mips_machine *mach;
25static __initconst const void *mach_match_data;
26
27void __init prom_init(void)
28{
29 plat_get_fdt();
30 BUG_ON(!fdt);
31}
32
33void __init *plat_get_fdt(void)
34{
35 const struct mips_machine *check_mach;
36 const struct of_device_id *match;
37
38 if (fdt)
39 /* Already set up */
40 return (void *)fdt;
41
42 if (fw_passed_dtb && !fdt_check_header((void *)fw_passed_dtb)) {
43 /*
44 * We have been provided with the appropriate device tree for
45 * the board. Make use of it & search for any machine struct
46 * based upon the root compatible string.
47 */
48 fdt = (void *)fw_passed_dtb;
49
50 for_each_mips_machine(check_mach) {
51 match = mips_machine_is_compatible(check_mach, fdt);
52 if (match) {
53 mach = check_mach;
54 mach_match_data = match->data;
55 break;
56 }
57 }
58 } else if (IS_ENABLED(CONFIG_LEGACY_BOARDS)) {
59 /*
60 * We weren't booted using the UHI boot protocol, but do
61 * support some number of boards with legacy boot protocols.
62 * Attempt to find the right one.
63 */
64 for_each_mips_machine(check_mach) {
65 if (!check_mach->detect)
66 continue;
67
68 if (!check_mach->detect())
69 continue;
70
71 mach = check_mach;
72 }
73
74 /*
75 * If we don't recognise the machine then we can't continue, so
76 * die here.
77 */
78 BUG_ON(!mach);
79
80 /* Retrieve the machine's FDT */
81 fdt = mach->fdt;
82 }
83 return (void *)fdt;
84}
85
86#ifdef CONFIG_RELOCATABLE
87
88void __init plat_fdt_relocated(void *new_location)
89{
90 /*
91 * reset fdt as the cached value would point to the location
92 * before relocations happened and update the location argument
93 * if it was passed using UHI
94 */
95 fdt = NULL;
96
97 if (fw_arg0 == -2)
98 fw_arg1 = (unsigned long)new_location;
99}
100
101#endif /* CONFIG_RELOCATABLE */
102
103void __init plat_mem_setup(void)
104{
105 if (mach && mach->fixup_fdt)
106 fdt = mach->fixup_fdt(fdt, mach_match_data);
107
108 fw_init_cmdline();
109 __dt_setup_arch((void *)fdt);
110}
111
112void __init device_tree_init(void)
113{
114 int err;
115
116 unflatten_and_copy_device_tree();
117 mips_cpc_probe();
118
119 err = register_cps_smp_ops();
120 if (err)
121 err = register_up_smp_ops();
122}
123
124int __init apply_mips_fdt_fixups(void *fdt_out, size_t fdt_out_size,
125 const void *fdt_in,
126 const struct mips_fdt_fixup *fixups)
127{
128 int err;
129
130 err = fdt_open_into(fdt_in, fdt_out, fdt_out_size);
131 if (err) {
132 pr_err("Failed to open FDT\n");
133 return err;
134 }
135
136 for (; fixups->apply; fixups++) {
137 err = fixups->apply(fdt_out);
138 if (err) {
139 pr_err("Failed to apply FDT fixup \"%s\"\n",
140 fixups->description);
141 return err;
142 }
143 }
144
145 err = fdt_pack(fdt_out);
146 if (err)
147 pr_err("Failed to pack FDT\n");
148 return err;
149}
150
151void __init plat_time_init(void)
152{
153 struct device_node *np;
154 struct clk *clk;
155
156 of_clk_init(NULL);
157
158 if (!cpu_has_counter) {
159 mips_hpt_frequency = 0;
160 } else if (mach && mach->measure_hpt_freq) {
161 mips_hpt_frequency = mach->measure_hpt_freq();
162 } else {
163 np = of_get_cpu_node(0, NULL);
164 if (!np) {
165 pr_err("Failed to get CPU node\n");
166 return;
167 }
168
169 clk = of_clk_get(np, 0);
170 if (IS_ERR(clk)) {
171 pr_err("Failed to get CPU clock: %ld\n", PTR_ERR(clk));
172 return;
173 }
174
175 mips_hpt_frequency = clk_get_rate(clk);
176 clk_put(clk);
177
178 switch (boot_cpu_type()) {
179 case CPU_20KC:
180 case CPU_25KF:
181 /* The counter runs at the CPU clock rate */
182 break;
183 default:
184 /* The counter runs at half the CPU clock rate */
185 mips_hpt_frequency /= 2;
186 break;
187 }
188 }
189
190 timer_probe();
191}
192
193void __init arch_init_irq(void)
194{
195 struct device_node *intc_node;
196
197 intc_node = of_find_compatible_node(NULL, NULL,
198 "mti,cpu-interrupt-controller");
199 if (!cpu_has_veic && !intc_node)
200 mips_cpu_irq_init();
201 of_node_put(intc_node);
202
203 irqchip_init();
204}
205
206void __init prom_free_prom_memory(void)
207{
208}
diff --git a/arch/mips/generic/irq.c b/arch/mips/generic/irq.c
new file mode 100644
index 000000000..933119262
--- /dev/null
+++ b/arch/mips/generic/irq.c
@@ -0,0 +1,61 @@
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2016 Imagination Technologies
4 * Author: Paul Burton <paul.burton@mips.com>
5 */
6
7#include <linux/clk.h>
8#include <linux/clk-provider.h>
9#include <linux/clocksource.h>
10#include <linux/init.h>
11#include <linux/types.h>
12
13#include <asm/irq.h>
14#include <asm/mips-cps.h>
15#include <asm/time.h>
16
17int get_c0_fdc_int(void)
18{
19 int mips_cpu_fdc_irq;
20
21 if (mips_gic_present())
22 mips_cpu_fdc_irq = gic_get_c0_fdc_int();
23 else if (cpu_has_veic)
24 panic("Unimplemented!");
25 else if (cp0_fdc_irq >= 0)
26 mips_cpu_fdc_irq = MIPS_CPU_IRQ_BASE + cp0_fdc_irq;
27 else
28 mips_cpu_fdc_irq = -1;
29
30 return mips_cpu_fdc_irq;
31}
32
33int get_c0_perfcount_int(void)
34{
35 int mips_cpu_perf_irq;
36
37 if (mips_gic_present())
38 mips_cpu_perf_irq = gic_get_c0_perfcount_int();
39 else if (cpu_has_veic)
40 panic("Unimplemented!");
41 else if (cp0_perfcount_irq >= 0)
42 mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
43 else
44 mips_cpu_perf_irq = -1;
45
46 return mips_cpu_perf_irq;
47}
48
49unsigned int get_c0_compare_int(void)
50{
51 int mips_cpu_timer_irq;
52
53 if (mips_gic_present())
54 mips_cpu_timer_irq = gic_get_c0_compare_int();
55 else if (cpu_has_veic)
56 panic("Unimplemented!");
57 else
58 mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq;
59
60 return mips_cpu_timer_irq;
61}
diff --git a/arch/mips/generic/proc.c b/arch/mips/generic/proc.c
new file mode 100644
index 000000000..cce2fde21
--- /dev/null
+++ b/arch/mips/generic/proc.c
@@ -0,0 +1,30 @@
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2016 Imagination Technologies
4 * Author: Paul Burton <paul.burton@mips.com>
5 */
6
7#include <linux/of.h>
8
9#include <asm/bootinfo.h>
10
11char *system_type;
12
13const char *get_system_type(void)
14{
15 const char *str;
16 int err;
17
18 if (system_type)
19 return system_type;
20
21 err = of_property_read_string(of_root, "model", &str);
22 if (!err)
23 return str;
24
25 err = of_property_read_string_index(of_root, "compatible", 0, &str);
26 if (!err)
27 return str;
28
29 return "Unknown";
30}
diff --git a/arch/mips/generic/vmlinux.its.S b/arch/mips/generic/vmlinux.its.S
new file mode 100644
index 000000000..3e2546765
--- /dev/null
+++ b/arch/mips/generic/vmlinux.its.S
@@ -0,0 +1,32 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/dts-v1/;
3
4/ {
5 description = KERNEL_NAME;
6 #address-cells = <ADDR_CELLS>;
7
8 images {
9 kernel {
10 description = KERNEL_NAME;
11 data = /incbin/(VMLINUX_BINARY);
12 type = "kernel";
13 arch = "mips";
14 os = "linux";
15 compression = VMLINUX_COMPRESSION;
16 load = /bits/ ADDR_BITS <VMLINUX_LOAD_ADDRESS>;
17 entry = /bits/ ADDR_BITS <VMLINUX_ENTRY_ADDRESS>;
18 hash {
19 algo = "sha1";
20 };
21 };
22 };
23
24 configurations {
25 default = "conf-default";
26
27 conf-default {
28 description = "Generic Linux kernel";
29 kernel = "kernel";
30 };
31 };
32};
diff --git a/arch/mips/generic/yamon-dt.c b/arch/mips/generic/yamon-dt.c
new file mode 100644
index 000000000..a07a5edbc
--- /dev/null
+++ b/arch/mips/generic/yamon-dt.c
@@ -0,0 +1,232 @@
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2016 Imagination Technologies
4 * Author: Paul Burton <paul.burton@mips.com>
5 */
6
7#define pr_fmt(fmt) "yamon-dt: " fmt
8
9#include <linux/bug.h>
10#include <linux/errno.h>
11#include <linux/kernel.h>
12#include <linux/libfdt.h>
13#include <linux/printk.h>
14
15#include <asm/fw/fw.h>
16#include <asm/yamon-dt.h>
17
18#define MAX_MEM_ARRAY_ENTRIES 2
19
20__init int yamon_dt_append_cmdline(void *fdt)
21{
22 int err, chosen_off;
23
24 /* find or add chosen node */
25 chosen_off = fdt_path_offset(fdt, "/chosen");
26 if (chosen_off == -FDT_ERR_NOTFOUND)
27 chosen_off = fdt_add_subnode(fdt, 0, "chosen");
28 if (chosen_off < 0) {
29 pr_err("Unable to find or add DT chosen node: %d\n",
30 chosen_off);
31 return chosen_off;
32 }
33
34 err = fdt_setprop_string(fdt, chosen_off, "bootargs", fw_getcmdline());
35 if (err) {
36 pr_err("Unable to set bootargs property: %d\n", err);
37 return err;
38 }
39
40 return 0;
41}
42
43static unsigned int __init gen_fdt_mem_array(
44 const struct yamon_mem_region *regions,
45 __be32 *mem_array,
46 unsigned int max_entries,
47 unsigned long memsize)
48{
49 const struct yamon_mem_region *mr;
50 unsigned long size;
51 unsigned int entries = 0;
52
53 for (mr = regions; mr->size && memsize; ++mr) {
54 if (entries >= max_entries) {
55 pr_warn("Number of regions exceeds max %u\n",
56 max_entries);
57 break;
58 }
59
60 /* How much of the remaining RAM fits in the next region? */
61 size = min_t(unsigned long, memsize, mr->size);
62 memsize -= size;
63
64 /* Emit a memory region */
65 *(mem_array++) = cpu_to_be32(mr->start);
66 *(mem_array++) = cpu_to_be32(size);
67 ++entries;
68
69 /* Discard the next mr->discard bytes */
70 memsize -= min_t(unsigned long, memsize, mr->discard);
71 }
72 return entries;
73}
74
75__init int yamon_dt_append_memory(void *fdt,
76 const struct yamon_mem_region *regions)
77{
78 unsigned long phys_memsize = 0, memsize;
79 __be32 mem_array[2 * MAX_MEM_ARRAY_ENTRIES];
80 unsigned int mem_entries;
81 int i, err, mem_off;
82 char *var, param_name[10], *var_names[] = {
83 "ememsize", "memsize",
84 };
85
86 /* find memory size from the bootloader environment */
87 for (i = 0; i < ARRAY_SIZE(var_names); i++) {
88 var = fw_getenv(var_names[i]);
89 if (!var)
90 continue;
91
92 err = kstrtoul(var, 0, &phys_memsize);
93 if (!err)
94 break;
95
96 pr_warn("Failed to read the '%s' env variable '%s'\n",
97 var_names[i], var);
98 }
99
100 if (!phys_memsize) {
101 pr_warn("The bootloader didn't provide memsize: defaulting to 32MB\n");
102 phys_memsize = 32 << 20;
103 }
104
105 /* default to using all available RAM */
106 memsize = phys_memsize;
107
108 /* allow the user to override the usable memory */
109 for (i = 0; i < ARRAY_SIZE(var_names); i++) {
110 snprintf(param_name, sizeof(param_name), "%s=", var_names[i]);
111 var = strstr(arcs_cmdline, param_name);
112 if (!var)
113 continue;
114
115 memsize = memparse(var + strlen(param_name), NULL);
116 }
117
118 /* if the user says there's more RAM than we thought, believe them */
119 phys_memsize = max_t(unsigned long, phys_memsize, memsize);
120
121 /* find or add a memory node */
122 mem_off = fdt_path_offset(fdt, "/memory");
123 if (mem_off == -FDT_ERR_NOTFOUND)
124 mem_off = fdt_add_subnode(fdt, 0, "memory");
125 if (mem_off < 0) {
126 pr_err("Unable to find or add memory DT node: %d\n", mem_off);
127 return mem_off;
128 }
129
130 err = fdt_setprop_string(fdt, mem_off, "device_type", "memory");
131 if (err) {
132 pr_err("Unable to set memory node device_type: %d\n", err);
133 return err;
134 }
135
136 mem_entries = gen_fdt_mem_array(regions, mem_array,
137 MAX_MEM_ARRAY_ENTRIES, phys_memsize);
138 err = fdt_setprop(fdt, mem_off, "reg",
139 mem_array, mem_entries * 2 * sizeof(mem_array[0]));
140 if (err) {
141 pr_err("Unable to set memory regs property: %d\n", err);
142 return err;
143 }
144
145 mem_entries = gen_fdt_mem_array(regions, mem_array,
146 MAX_MEM_ARRAY_ENTRIES, memsize);
147 err = fdt_setprop(fdt, mem_off, "linux,usable-memory",
148 mem_array, mem_entries * 2 * sizeof(mem_array[0]));
149 if (err) {
150 pr_err("Unable to set linux,usable-memory property: %d\n", err);
151 return err;
152 }
153
154 return 0;
155}
156
157__init int yamon_dt_serial_config(void *fdt)
158{
159 const char *yamontty, *mode_var;
160 char mode_var_name[9], path[20], parity;
161 unsigned int uart, baud, stop_bits;
162 bool hw_flow;
163 int chosen_off, err;
164
165 yamontty = fw_getenv("yamontty");
166 if (!yamontty || !strcmp(yamontty, "tty0")) {
167 uart = 0;
168 } else if (!strcmp(yamontty, "tty1")) {
169 uart = 1;
170 } else {
171 pr_warn("yamontty environment variable '%s' invalid\n",
172 yamontty);
173 uart = 0;
174 }
175
176 baud = stop_bits = 0;
177 parity = 0;
178 hw_flow = false;
179
180 snprintf(mode_var_name, sizeof(mode_var_name), "modetty%u", uart);
181 mode_var = fw_getenv(mode_var_name);
182 if (mode_var) {
183 while (mode_var[0] >= '0' && mode_var[0] <= '9') {
184 baud *= 10;
185 baud += mode_var[0] - '0';
186 mode_var++;
187 }
188 if (mode_var[0] == ',')
189 mode_var++;
190 if (mode_var[0])
191 parity = mode_var[0];
192 if (mode_var[0] == ',')
193 mode_var++;
194 if (mode_var[0])
195 stop_bits = mode_var[0] - '0';
196 if (mode_var[0] == ',')
197 mode_var++;
198 if (!strcmp(mode_var, "hw"))
199 hw_flow = true;
200 }
201
202 if (!baud)
203 baud = 38400;
204
205 if (parity != 'e' && parity != 'n' && parity != 'o')
206 parity = 'n';
207
208 if (stop_bits != 7 && stop_bits != 8)
209 stop_bits = 8;
210
211 WARN_ON(snprintf(path, sizeof(path), "serial%u:%u%c%u%s",
212 uart, baud, parity, stop_bits,
213 hw_flow ? "r" : "") >= sizeof(path));
214
215 /* find or add chosen node */
216 chosen_off = fdt_path_offset(fdt, "/chosen");
217 if (chosen_off == -FDT_ERR_NOTFOUND)
218 chosen_off = fdt_add_subnode(fdt, 0, "chosen");
219 if (chosen_off < 0) {
220 pr_err("Unable to find or add DT chosen node: %d\n",
221 chosen_off);
222 return chosen_off;
223 }
224
225 err = fdt_setprop_string(fdt, chosen_off, "stdout-path", path);
226 if (err) {
227 pr_err("Unable to set stdout-path property: %d\n", err);
228 return err;
229 }
230
231 return 0;
232}