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/bmips | |
download | ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.tar.gz ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.zip |
Initial commit: OpenHarmony-v4.0-ReleaseOpenHarmony-v4.0-Release
Diffstat (limited to 'arch/mips/bmips')
-rw-r--r-- | arch/mips/bmips/Kconfig | 83 | ||||
-rw-r--r-- | arch/mips/bmips/Makefile | 2 | ||||
-rw-r--r-- | arch/mips/bmips/Platform | 6 | ||||
-rw-r--r-- | arch/mips/bmips/dma.c | 123 | ||||
-rw-r--r-- | arch/mips/bmips/irq.c | 42 | ||||
-rw-r--r-- | arch/mips/bmips/setup.c | 204 |
6 files changed, 460 insertions, 0 deletions
diff --git a/arch/mips/bmips/Kconfig b/arch/mips/bmips/Kconfig new file mode 100644 index 000000000..63dfc6950 --- /dev/null +++ b/arch/mips/bmips/Kconfig | |||
@@ -0,0 +1,83 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | ||
2 | if BMIPS_GENERIC | ||
3 | |||
4 | choice | ||
5 | prompt "Built-in device tree" | ||
6 | help | ||
7 | Legacy bootloaders do not pass a DTB pointer to the kernel, so | ||
8 | if a "wrapper" is not being used, the kernel will need to include | ||
9 | a device tree that matches the target board. | ||
10 | |||
11 | The builtin DTB will only be used if the firmware does not supply | ||
12 | a valid DTB. | ||
13 | |||
14 | config DT_NONE | ||
15 | bool "None" | ||
16 | |||
17 | config DT_BCM93384WVG | ||
18 | bool "BCM93384WVG Zephyr CPU" | ||
19 | select BUILTIN_DTB | ||
20 | |||
21 | config DT_BCM93384WVG_VIPER | ||
22 | bool "BCM93384WVG Viper CPU (EXPERIMENTAL)" | ||
23 | select BUILTIN_DTB | ||
24 | |||
25 | config DT_BCM96368MVWG | ||
26 | bool "BCM96368MVWG" | ||
27 | select BUILTIN_DTB | ||
28 | |||
29 | config DT_BCM9EJTAGPRB | ||
30 | bool "BCM9EJTAGPRB" | ||
31 | select BUILTIN_DTB | ||
32 | |||
33 | config DT_BCM97125CBMB | ||
34 | bool "BCM97125CBMB" | ||
35 | select BUILTIN_DTB | ||
36 | |||
37 | config DT_BCM97346DBSMB | ||
38 | bool "BCM97346DBSMB" | ||
39 | select BUILTIN_DTB | ||
40 | |||
41 | config DT_BCM97358SVMB | ||
42 | bool "BCM97358SVMB" | ||
43 | select BUILTIN_DTB | ||
44 | |||
45 | config DT_BCM97360SVMB | ||
46 | bool "BCM97360SVMB" | ||
47 | select BUILTIN_DTB | ||
48 | |||
49 | config DT_BCM97362SVMB | ||
50 | bool "BCM97362SVMB" | ||
51 | select BUILTIN_DTB | ||
52 | |||
53 | config DT_BCM97420C | ||
54 | bool "BCM97420C" | ||
55 | select BUILTIN_DTB | ||
56 | |||
57 | config DT_BCM97425SVMB | ||
58 | bool "BCM97425SVMB" | ||
59 | select BUILTIN_DTB | ||
60 | |||
61 | config DT_BCM97435SVMB | ||
62 | bool "BCM97435SVMB" | ||
63 | select BUILTIN_DTB | ||
64 | |||
65 | config DT_COMTREND_VR3032U | ||
66 | bool "Comtrend VR-3032u" | ||
67 | select BUILTIN_DTB | ||
68 | |||
69 | config DT_NETGEAR_CVG834G | ||
70 | bool "NETGEAR CVG834G" | ||
71 | select BUILTIN_DTB | ||
72 | |||
73 | config DT_SFR_NEUFBOX4_SERCOMM | ||
74 | bool "SFR Neufbox 4 (Sercomm)" | ||
75 | select BUILTIN_DTB | ||
76 | |||
77 | config DT_SFR_NEUFBOX6_SERCOMM | ||
78 | bool "SFR Neufbox 6 (Sercomm)" | ||
79 | select BUILTIN_DTB | ||
80 | |||
81 | endchoice | ||
82 | |||
83 | endif | ||
diff --git a/arch/mips/bmips/Makefile b/arch/mips/bmips/Makefile new file mode 100644 index 000000000..1165bf2ef --- /dev/null +++ b/arch/mips/bmips/Makefile | |||
@@ -0,0 +1,2 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0-only | ||
2 | obj-y += setup.o irq.o dma.o | ||
diff --git a/arch/mips/bmips/Platform b/arch/mips/bmips/Platform new file mode 100644 index 000000000..1434ea31c --- /dev/null +++ b/arch/mips/bmips/Platform | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Broadcom Generic BMIPS kernel | ||
3 | # | ||
4 | cflags-$(CONFIG_BMIPS_GENERIC) += \ | ||
5 | -I$(srctree)/arch/mips/include/asm/mach-bmips/ | ||
6 | load-$(CONFIG_BMIPS_GENERIC) := 0xffffffff80010000 | ||
diff --git a/arch/mips/bmips/dma.c b/arch/mips/bmips/dma.c new file mode 100644 index 000000000..49061b870 --- /dev/null +++ b/arch/mips/bmips/dma.c | |||
@@ -0,0 +1,123 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2014 Kevin Cernekee <cernekee@gmail.com> | ||
7 | */ | ||
8 | |||
9 | #define pr_fmt(fmt) "bmips-dma: " fmt | ||
10 | |||
11 | #include <linux/device.h> | ||
12 | #include <linux/dma-direction.h> | ||
13 | #include <linux/dma-mapping.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/of.h> | ||
17 | #include <linux/printk.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/types.h> | ||
20 | #include <asm/bmips.h> | ||
21 | |||
22 | /* | ||
23 | * BCM338x has configurable address translation windows which allow the | ||
24 | * peripherals' DMA addresses to be different from the Zephyr-visible | ||
25 | * physical addresses. e.g. usb_dma_addr = zephyr_pa ^ 0x08000000 | ||
26 | * | ||
27 | * If the "brcm,ubus" node has a "dma-ranges" property we will enable this | ||
28 | * translation globally using the provided information. This implements a | ||
29 | * very limited subset of "dma-ranges" support and it will probably be | ||
30 | * replaced by a more generic version later. | ||
31 | */ | ||
32 | |||
33 | struct bmips_dma_range { | ||
34 | u32 child_addr; | ||
35 | u32 parent_addr; | ||
36 | u32 size; | ||
37 | }; | ||
38 | |||
39 | static struct bmips_dma_range *bmips_dma_ranges; | ||
40 | |||
41 | #define FLUSH_RAC 0x100 | ||
42 | |||
43 | dma_addr_t phys_to_dma(struct device *dev, phys_addr_t pa) | ||
44 | { | ||
45 | struct bmips_dma_range *r; | ||
46 | |||
47 | for (r = bmips_dma_ranges; r && r->size; r++) { | ||
48 | if (pa >= r->child_addr && | ||
49 | pa < (r->child_addr + r->size)) | ||
50 | return pa - r->child_addr + r->parent_addr; | ||
51 | } | ||
52 | return pa; | ||
53 | } | ||
54 | |||
55 | phys_addr_t dma_to_phys(struct device *dev, dma_addr_t dma_addr) | ||
56 | { | ||
57 | struct bmips_dma_range *r; | ||
58 | |||
59 | for (r = bmips_dma_ranges; r && r->size; r++) { | ||
60 | if (dma_addr >= r->parent_addr && | ||
61 | dma_addr < (r->parent_addr + r->size)) | ||
62 | return dma_addr - r->parent_addr + r->child_addr; | ||
63 | } | ||
64 | return dma_addr; | ||
65 | } | ||
66 | |||
67 | void arch_sync_dma_for_cpu_all(void) | ||
68 | { | ||
69 | void __iomem *cbr = BMIPS_GET_CBR(); | ||
70 | u32 cfg; | ||
71 | |||
72 | if (boot_cpu_type() != CPU_BMIPS3300 && | ||
73 | boot_cpu_type() != CPU_BMIPS4350 && | ||
74 | boot_cpu_type() != CPU_BMIPS4380) | ||
75 | return; | ||
76 | |||
77 | /* Flush stale data out of the readahead cache */ | ||
78 | cfg = __raw_readl(cbr + BMIPS_RAC_CONFIG); | ||
79 | __raw_writel(cfg | 0x100, cbr + BMIPS_RAC_CONFIG); | ||
80 | __raw_readl(cbr + BMIPS_RAC_CONFIG); | ||
81 | } | ||
82 | |||
83 | static int __init bmips_init_dma_ranges(void) | ||
84 | { | ||
85 | struct device_node *np = | ||
86 | of_find_compatible_node(NULL, NULL, "brcm,ubus"); | ||
87 | const __be32 *data; | ||
88 | struct bmips_dma_range *r; | ||
89 | int len; | ||
90 | |||
91 | if (!np) | ||
92 | return 0; | ||
93 | |||
94 | data = of_get_property(np, "dma-ranges", &len); | ||
95 | if (!data) | ||
96 | goto out_good; | ||
97 | |||
98 | len /= sizeof(*data) * 3; | ||
99 | if (!len) | ||
100 | goto out_bad; | ||
101 | |||
102 | /* add a dummy (zero) entry at the end as a sentinel */ | ||
103 | bmips_dma_ranges = kcalloc(len + 1, sizeof(struct bmips_dma_range), | ||
104 | GFP_KERNEL); | ||
105 | if (!bmips_dma_ranges) | ||
106 | goto out_bad; | ||
107 | |||
108 | for (r = bmips_dma_ranges; len; len--, r++) { | ||
109 | r->child_addr = be32_to_cpup(data++); | ||
110 | r->parent_addr = be32_to_cpup(data++); | ||
111 | r->size = be32_to_cpup(data++); | ||
112 | } | ||
113 | |||
114 | out_good: | ||
115 | of_node_put(np); | ||
116 | return 0; | ||
117 | |||
118 | out_bad: | ||
119 | pr_err("error parsing dma-ranges property\n"); | ||
120 | of_node_put(np); | ||
121 | return -EINVAL; | ||
122 | } | ||
123 | arch_initcall(bmips_init_dma_ranges); | ||
diff --git a/arch/mips/bmips/irq.c b/arch/mips/bmips/irq.c new file mode 100644 index 000000000..c4daa590b --- /dev/null +++ b/arch/mips/bmips/irq.c | |||
@@ -0,0 +1,42 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-only | ||
2 | /* | ||
3 | * | ||
4 | * Copyright (C) 2014 Broadcom Corporation | ||
5 | * Author: Kevin Cernekee <cernekee@gmail.com> | ||
6 | */ | ||
7 | |||
8 | #include <linux/of.h> | ||
9 | #include <linux/irqchip.h> | ||
10 | |||
11 | #include <asm/bmips.h> | ||
12 | #include <asm/irq.h> | ||
13 | #include <asm/irq_cpu.h> | ||
14 | #include <asm/time.h> | ||
15 | |||
16 | static const struct of_device_id smp_intc_dt_match[] = { | ||
17 | { .compatible = "brcm,bcm7038-l1-intc" }, | ||
18 | { .compatible = "brcm,bcm6345-l1-intc" }, | ||
19 | {} | ||
20 | }; | ||
21 | |||
22 | unsigned int get_c0_compare_int(void) | ||
23 | { | ||
24 | return CP0_LEGACY_COMPARE_IRQ; | ||
25 | } | ||
26 | |||
27 | void __init arch_init_irq(void) | ||
28 | { | ||
29 | struct device_node *dn; | ||
30 | |||
31 | /* Only these controllers support SMP IRQ affinity */ | ||
32 | dn = of_find_matching_node(NULL, smp_intc_dt_match); | ||
33 | if (dn) | ||
34 | of_node_put(dn); | ||
35 | else | ||
36 | bmips_tp1_irqs = 0; | ||
37 | |||
38 | irqchip_init(); | ||
39 | } | ||
40 | |||
41 | IRQCHIP_DECLARE(mips_cpu_intc, "mti,cpu-interrupt-controller", | ||
42 | mips_cpu_irq_of_init); | ||
diff --git a/arch/mips/bmips/setup.c b/arch/mips/bmips/setup.c new file mode 100644 index 000000000..1b06b25ae --- /dev/null +++ b/arch/mips/bmips/setup.c | |||
@@ -0,0 +1,204 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> | ||
7 | * Copyright (C) 2014 Kevin Cernekee <cernekee@gmail.com> | ||
8 | */ | ||
9 | |||
10 | #include <linux/init.h> | ||
11 | #include <linux/bitops.h> | ||
12 | #include <linux/memblock.h> | ||
13 | #include <linux/ioport.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/of.h> | ||
17 | #include <linux/of_clk.h> | ||
18 | #include <linux/of_fdt.h> | ||
19 | #include <linux/of_platform.h> | ||
20 | #include <linux/libfdt.h> | ||
21 | #include <linux/smp.h> | ||
22 | #include <asm/addrspace.h> | ||
23 | #include <asm/bmips.h> | ||
24 | #include <asm/bootinfo.h> | ||
25 | #include <asm/cpu-type.h> | ||
26 | #include <asm/mipsregs.h> | ||
27 | #include <asm/prom.h> | ||
28 | #include <asm/smp-ops.h> | ||
29 | #include <asm/time.h> | ||
30 | #include <asm/traps.h> | ||
31 | |||
32 | #define RELO_NORMAL_VEC BIT(18) | ||
33 | |||
34 | #define REG_BCM6328_OTP ((void __iomem *)CKSEG1ADDR(0x1000062c)) | ||
35 | #define BCM6328_TP1_DISABLED BIT(9) | ||
36 | |||
37 | static const unsigned long kbase = VMLINUX_LOAD_ADDRESS & 0xfff00000; | ||
38 | |||
39 | struct bmips_quirk { | ||
40 | const char *compatible; | ||
41 | void (*quirk_fn)(void); | ||
42 | }; | ||
43 | |||
44 | static void kbase_setup(void) | ||
45 | { | ||
46 | __raw_writel(kbase | RELO_NORMAL_VEC, | ||
47 | BMIPS_GET_CBR() + BMIPS_RELO_VECTOR_CONTROL_1); | ||
48 | ebase = kbase; | ||
49 | } | ||
50 | |||
51 | static void bcm3384_viper_quirks(void) | ||
52 | { | ||
53 | /* | ||
54 | * Some experimental CM boxes are set up to let CM own the Viper TP0 | ||
55 | * and let Linux own TP1. This requires moving the kernel | ||
56 | * load address to a non-conflicting region (e.g. via | ||
57 | * CONFIG_PHYSICAL_START) and supplying an alternate DTB. | ||
58 | * If we detect this condition, we need to move the MIPS exception | ||
59 | * vectors up to an area that we own. | ||
60 | * | ||
61 | * This is distinct from the OTHER special case mentioned in | ||
62 | * smp-bmips.c (boot on TP1, but enable SMP, then TP0 becomes our | ||
63 | * logical CPU#1). For the Viper TP1 case, SMP is off limits. | ||
64 | * | ||
65 | * Also note that many BMIPS435x CPUs do not have a | ||
66 | * BMIPS_RELO_VECTOR_CONTROL_1 register, so it isn't safe to just | ||
67 | * write VMLINUX_LOAD_ADDRESS into that register on every SoC. | ||
68 | */ | ||
69 | board_ebase_setup = &kbase_setup; | ||
70 | bmips_smp_enabled = 0; | ||
71 | } | ||
72 | |||
73 | static void bcm63xx_fixup_cpu1(void) | ||
74 | { | ||
75 | /* | ||
76 | * The bootloader has set up the CPU1 reset vector at | ||
77 | * 0xa000_0200. | ||
78 | * This conflicts with the special interrupt vector (IV). | ||
79 | * The bootloader has also set up CPU1 to respond to the wrong | ||
80 | * IPI interrupt. | ||
81 | * Here we will start up CPU1 in the background and ask it to | ||
82 | * reconfigure itself then go back to sleep. | ||
83 | */ | ||
84 | memcpy((void *)0xa0000200, &bmips_smp_movevec, 0x20); | ||
85 | __sync(); | ||
86 | set_c0_cause(C_SW0); | ||
87 | cpumask_set_cpu(1, &bmips_booted_mask); | ||
88 | } | ||
89 | |||
90 | static void bcm6328_quirks(void) | ||
91 | { | ||
92 | /* Check CPU1 status in OTP (it is usually disabled) */ | ||
93 | if (__raw_readl(REG_BCM6328_OTP) & BCM6328_TP1_DISABLED) | ||
94 | bmips_smp_enabled = 0; | ||
95 | else | ||
96 | bcm63xx_fixup_cpu1(); | ||
97 | } | ||
98 | |||
99 | static void bcm6358_quirks(void) | ||
100 | { | ||
101 | /* | ||
102 | * BCM3368/BCM6358 need special handling for their shared TLB, so | ||
103 | * disable SMP for now | ||
104 | */ | ||
105 | bmips_smp_enabled = 0; | ||
106 | } | ||
107 | |||
108 | static void bcm6368_quirks(void) | ||
109 | { | ||
110 | bcm63xx_fixup_cpu1(); | ||
111 | } | ||
112 | |||
113 | static const struct bmips_quirk bmips_quirk_list[] = { | ||
114 | { "brcm,bcm3368", &bcm6358_quirks }, | ||
115 | { "brcm,bcm3384-viper", &bcm3384_viper_quirks }, | ||
116 | { "brcm,bcm33843-viper", &bcm3384_viper_quirks }, | ||
117 | { "brcm,bcm6328", &bcm6328_quirks }, | ||
118 | { "brcm,bcm6358", &bcm6358_quirks }, | ||
119 | { "brcm,bcm6362", &bcm6368_quirks }, | ||
120 | { "brcm,bcm6368", &bcm6368_quirks }, | ||
121 | { "brcm,bcm63168", &bcm6368_quirks }, | ||
122 | { "brcm,bcm63268", &bcm6368_quirks }, | ||
123 | { }, | ||
124 | }; | ||
125 | |||
126 | void __init prom_init(void) | ||
127 | { | ||
128 | bmips_cpu_setup(); | ||
129 | register_bmips_smp_ops(); | ||
130 | } | ||
131 | |||
132 | void __init prom_free_prom_memory(void) | ||
133 | { | ||
134 | } | ||
135 | |||
136 | const char *get_system_type(void) | ||
137 | { | ||
138 | return "Generic BMIPS kernel"; | ||
139 | } | ||
140 | |||
141 | void __init plat_time_init(void) | ||
142 | { | ||
143 | struct device_node *np; | ||
144 | u32 freq; | ||
145 | |||
146 | np = of_find_node_by_name(NULL, "cpus"); | ||
147 | if (!np) | ||
148 | panic("missing 'cpus' DT node"); | ||
149 | if (of_property_read_u32(np, "mips-hpt-frequency", &freq) < 0) | ||
150 | panic("missing 'mips-hpt-frequency' property"); | ||
151 | of_node_put(np); | ||
152 | |||
153 | mips_hpt_frequency = freq; | ||
154 | } | ||
155 | |||
156 | void __init plat_mem_setup(void) | ||
157 | { | ||
158 | void *dtb; | ||
159 | const struct bmips_quirk *q; | ||
160 | |||
161 | set_io_port_base(0); | ||
162 | ioport_resource.start = 0; | ||
163 | ioport_resource.end = ~0; | ||
164 | |||
165 | /* intended to somewhat resemble ARM; see Documentation/arm/booting.rst */ | ||
166 | if (fw_arg0 == 0 && fw_arg1 == 0xffffffff) | ||
167 | dtb = phys_to_virt(fw_arg2); | ||
168 | else if (fw_passed_dtb) /* UHI interface or appended dtb */ | ||
169 | dtb = (void *)fw_passed_dtb; | ||
170 | else if (&__dtb_start != &__dtb_end) | ||
171 | dtb = (void *)__dtb_start; | ||
172 | else | ||
173 | panic("no dtb found"); | ||
174 | |||
175 | __dt_setup_arch(dtb); | ||
176 | |||
177 | for (q = bmips_quirk_list; q->quirk_fn; q++) { | ||
178 | if (of_flat_dt_is_compatible(of_get_flat_dt_root(), | ||
179 | q->compatible)) { | ||
180 | q->quirk_fn(); | ||
181 | } | ||
182 | } | ||
183 | } | ||
184 | |||
185 | void __init device_tree_init(void) | ||
186 | { | ||
187 | struct device_node *np; | ||
188 | |||
189 | unflatten_and_copy_device_tree(); | ||
190 | |||
191 | /* Disable SMP boot unless both CPUs are listed in DT and !disabled */ | ||
192 | np = of_find_node_by_name(NULL, "cpus"); | ||
193 | if (np && of_get_available_child_count(np) <= 1) | ||
194 | bmips_smp_enabled = 0; | ||
195 | of_node_put(np); | ||
196 | } | ||
197 | |||
198 | static int __init plat_dev_init(void) | ||
199 | { | ||
200 | of_clk_init(NULL); | ||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | device_initcall(plat_dev_init); | ||