diff options
author | 2025-03-08 22:04:20 +0800 | |
---|---|---|
committer | 2025-03-08 22:04:20 +0800 | |
commit | a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a (patch) | |
tree | 84f21bd0bf7071bc5fc7dd989e77d7ceb5476682 /arch/mips/generic | |
download | ohosKernel-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/Kconfig | 92 | ||||
-rw-r--r-- | arch/mips/generic/Makefile | 15 | ||||
-rw-r--r-- | arch/mips/generic/Platform | 23 | ||||
-rw-r--r-- | arch/mips/generic/board-boston.its.S | 22 | ||||
-rw-r--r-- | arch/mips/generic/board-ingenic.c | 120 | ||||
-rw-r--r-- | arch/mips/generic/board-ni169445.its.S | 22 | ||||
-rw-r--r-- | arch/mips/generic/board-ocelot.c | 78 | ||||
-rw-r--r-- | arch/mips/generic/board-ocelot.its.S | 40 | ||||
-rw-r--r-- | arch/mips/generic/board-ranchu.c | 89 | ||||
-rw-r--r-- | arch/mips/generic/board-sead3.c | 220 | ||||
-rw-r--r-- | arch/mips/generic/board-xilfpga.its.S | 22 | ||||
-rw-r--r-- | arch/mips/generic/init.c | 208 | ||||
-rw-r--r-- | arch/mips/generic/irq.c | 61 | ||||
-rw-r--r-- | arch/mips/generic/proc.c | 30 | ||||
-rw-r--r-- | arch/mips/generic/vmlinux.its.S | 32 | ||||
-rw-r--r-- | arch/mips/generic/yamon-dt.c | 232 |
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 | ||
2 | if MIPS_GENERIC_KERNEL | ||
3 | |||
4 | config 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 | |||
13 | config 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 | |||
20 | comment "Legacy (non-UHI/non-FIT) Boards" | ||
21 | |||
22 | config 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 | |||
30 | comment "MSCC Ocelot doesn't work with SEAD3 enabled" | ||
31 | depends on LEGACY_BOARD_SEAD3 | ||
32 | |||
33 | config 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 | |||
41 | config MSCC_OCELOT | ||
42 | bool | ||
43 | select GPIOLIB | ||
44 | select MSCC_OCELOT_IRQ | ||
45 | |||
46 | comment "FIT/UHI Boards" | ||
47 | |||
48 | config 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 | |||
56 | config 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 | |||
62 | config 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 | |||
68 | config 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 | |||
76 | config 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 | |||
82 | config 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 | |||
92 | endif | ||
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 | |||
7 | obj-y += init.o | ||
8 | obj-y += irq.o | ||
9 | obj-y += proc.o | ||
10 | |||
11 | obj-$(CONFIG_YAMON_DT_SHIM) += yamon-dt.o | ||
12 | obj-$(CONFIG_LEGACY_BOARD_SEAD3) += board-sead3.o | ||
13 | obj-$(CONFIG_LEGACY_BOARD_OCELOT) += board-ocelot.o | ||
14 | obj-$(CONFIG_MACH_INGENIC) += board-ingenic.o | ||
15 | obj-$(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. | ||
12 | cflags-$(CONFIG_MACH_INGENIC_SOC) += -I$(srctree)/arch/mips/include/asm/mach-ingenic | ||
13 | cflags-$(CONFIG_MIPS_GENERIC) += -I$(srctree)/arch/mips/include/asm/mach-generic | ||
14 | |||
15 | load-$(CONFIG_MIPS_GENERIC) += 0xffffffff80100000 | ||
16 | zload-$(CONFIG_MIPS_GENERIC) += 0xffffffff81000000 | ||
17 | all-$(CONFIG_MIPS_GENERIC) := vmlinux.gz.itb | ||
18 | |||
19 | its-y := vmlinux.its.S | ||
20 | its-$(CONFIG_FIT_IMAGE_FDT_BOSTON) += board-boston.its.S | ||
21 | its-$(CONFIG_FIT_IMAGE_FDT_NI169445) += board-ni169445.its.S | ||
22 | its-$(CONFIG_FIT_IMAGE_FDT_OCELOT) += board-ocelot.its.S | ||
23 | its-$(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 | |||
21 | static __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 | |||
47 | static __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 | |||
63 | static 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 | |||
77 | MIPS_MACHINE(ingenic) = { | ||
78 | .matches = ingenic_of_match, | ||
79 | .fixup_fdt = ingenic_fixup_fdt, | ||
80 | }; | ||
81 | |||
82 | static 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 | |||
91 | static void ingenic_halt(void) | ||
92 | { | ||
93 | for (;;) | ||
94 | ingenic_wait_instr(); | ||
95 | } | ||
96 | |||
97 | static int __maybe_unused ingenic_pm_enter(suspend_state_t state) | ||
98 | { | ||
99 | ingenic_wait_instr(); | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static const struct platform_suspend_ops ingenic_pm_ops __maybe_unused = { | ||
105 | .valid = suspend_valid_only_mem, | ||
106 | .enter = ingenic_pm_enter, | ||
107 | }; | ||
108 | |||
109 | static 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 | } | ||
120 | late_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 | |||
17 | static __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 | |||
50 | static 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 | |||
58 | static void __init ocelot_late_init(void) | ||
59 | { | ||
60 | ocelot_earlyprintk_init(); | ||
61 | } | ||
62 | |||
63 | static __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 | |||
72 | extern char __dtb_ocelot_pcb123_begin[]; | ||
73 | |||
74 | MIPS_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 | |||
18 | static __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 | |||
34 | static __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 | |||
79 | static const struct of_device_id ranchu_of_match[] __initconst = { | ||
80 | { | ||
81 | .compatible = "mti,ranchu", | ||
82 | }, | ||
83 | {} | ||
84 | }; | ||
85 | |||
86 | MIPS_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 | */ | ||
29 | static struct yamon_mem_region mem_regions[] __initdata = { | ||
30 | /* start size */ | ||
31 | { 0, SZ_256M + SZ_128M }, | ||
32 | {} | ||
33 | }; | ||
34 | |||
35 | static __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 | |||
43 | static __init int append_memory(void *fdt) | ||
44 | { | ||
45 | return yamon_dt_append_memory(fdt, mem_regions); | ||
46 | } | ||
47 | |||
48 | static __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 | |||
151 | static 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 | |||
159 | static __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 | |||
181 | static __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 | |||
213 | extern char __dtb_sead3_begin[]; | ||
214 | |||
215 | MIPS_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 | |||
23 | static __initconst const void *fdt; | ||
24 | static __initconst const struct mips_machine *mach; | ||
25 | static __initconst const void *mach_match_data; | ||
26 | |||
27 | void __init prom_init(void) | ||
28 | { | ||
29 | plat_get_fdt(); | ||
30 | BUG_ON(!fdt); | ||
31 | } | ||
32 | |||
33 | void __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 | |||
88 | void __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 | |||
103 | void __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 | |||
112 | void __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 | |||
124 | int __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 | |||
151 | void __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 | |||
193 | void __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 | |||
206 | void __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 | |||
17 | int 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 | |||
33 | int 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 | |||
49 | unsigned 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 | |||
11 | char *system_type; | ||
12 | |||
13 | const 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 | |||
43 | static 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 | } | ||