diff options
Diffstat (limited to 'arch/mips/loongson')
-rw-r--r-- | arch/mips/loongson/Kconfig | 47 | ||||
-rw-r--r-- | arch/mips/loongson/Makefile | 6 | ||||
-rw-r--r-- | arch/mips/loongson/Platform | 1 | ||||
-rw-r--r-- | arch/mips/loongson/common/Makefile | 5 | ||||
-rw-r--r-- | arch/mips/loongson/common/dma-swiotlb.c | 136 | ||||
-rw-r--r-- | arch/mips/loongson/common/env.c | 67 | ||||
-rw-r--r-- | arch/mips/loongson/common/init.c | 11 | ||||
-rw-r--r-- | arch/mips/loongson/common/machtype.c | 4 | ||||
-rw-r--r-- | arch/mips/loongson/common/mem.c | 42 | ||||
-rw-r--r-- | arch/mips/loongson/common/pci.c | 6 | ||||
-rw-r--r-- | arch/mips/loongson/common/reset.c | 21 | ||||
-rw-r--r-- | arch/mips/loongson/common/serial.c | 26 | ||||
-rw-r--r-- | arch/mips/loongson/common/setup.c | 8 | ||||
-rw-r--r-- | arch/mips/loongson/common/uart_base.c | 9 | ||||
-rw-r--r-- | arch/mips/loongson/loongson-3/Makefile | 6 | ||||
-rw-r--r-- | arch/mips/loongson/loongson-3/irq.c | 126 | ||||
-rw-r--r-- | arch/mips/loongson/loongson-3/smp.c | 443 | ||||
-rw-r--r-- | arch/mips/loongson/loongson-3/smp.h | 29 |
18 files changed, 958 insertions, 35 deletions
diff --git a/arch/mips/loongson/Kconfig b/arch/mips/loongson/Kconfig index 263beb9322a8..7397be226a06 100644 --- a/arch/mips/loongson/Kconfig +++ b/arch/mips/loongson/Kconfig | |||
@@ -59,6 +59,36 @@ config LEMOTE_MACH2F | |||
59 | 59 | ||
60 | These family machines include fuloong2f mini PC, yeeloong2f notebook, | 60 | These family machines include fuloong2f mini PC, yeeloong2f notebook, |
61 | LingLoong allinone PC and so forth. | 61 | LingLoong allinone PC and so forth. |
62 | |||
63 | config LEMOTE_MACH3A | ||
64 | bool "Lemote Loongson 3A family machines" | ||
65 | select ARCH_SPARSEMEM_ENABLE | ||
66 | select GENERIC_ISA_DMA_SUPPORT_BROKEN | ||
67 | select GENERIC_HARDIRQS_NO__DO_IRQ | ||
68 | select BOOT_ELF32 | ||
69 | select BOARD_SCACHE | ||
70 | select CSRC_R4K | ||
71 | select CEVT_R4K | ||
72 | select CPU_HAS_WB | ||
73 | select HW_HAS_PCI | ||
74 | select ISA | ||
75 | select HT_PCI | ||
76 | select I8259 | ||
77 | select IRQ_CPU | ||
78 | select NR_CPUS_DEFAULT_4 | ||
79 | select SYS_HAS_CPU_LOONGSON3 | ||
80 | select SYS_HAS_EARLY_PRINTK | ||
81 | select SYS_SUPPORTS_SMP | ||
82 | select SYS_SUPPORTS_HOTPLUG_CPU | ||
83 | select SYS_SUPPORTS_64BIT_KERNEL | ||
84 | select SYS_SUPPORTS_HIGHMEM | ||
85 | select SYS_SUPPORTS_LITTLE_ENDIAN | ||
86 | select LOONGSON_MC146818 | ||
87 | select ZONE_DMA32 | ||
88 | select LEFI_FIRMWARE_INTERFACE | ||
89 | help | ||
90 | Lemote Loongson 3A family machines utilize the 3A revision of | ||
91 | Loongson processor and RS780/SBX00 chipset. | ||
62 | endchoice | 92 | endchoice |
63 | 93 | ||
64 | config CS5536 | 94 | config CS5536 |
@@ -86,8 +116,25 @@ config LOONGSON_UART_BASE | |||
86 | default y | 116 | default y |
87 | depends on EARLY_PRINTK || SERIAL_8250 | 117 | depends on EARLY_PRINTK || SERIAL_8250 |
88 | 118 | ||
119 | config IOMMU_HELPER | ||
120 | bool | ||
121 | |||
122 | config NEED_SG_DMA_LENGTH | ||
123 | bool | ||
124 | |||
125 | config SWIOTLB | ||
126 | bool "Soft IOMMU Support for All-Memory DMA" | ||
127 | default y | ||
128 | depends on CPU_LOONGSON3 | ||
129 | select IOMMU_HELPER | ||
130 | select NEED_SG_DMA_LENGTH | ||
131 | select NEED_DMA_MAP_STATE | ||
132 | |||
89 | config LOONGSON_MC146818 | 133 | config LOONGSON_MC146818 |
90 | bool | 134 | bool |
91 | default n | 135 | default n |
92 | 136 | ||
137 | config LEFI_FIRMWARE_INTERFACE | ||
138 | bool | ||
139 | |||
93 | endif # MACH_LOONGSON | 140 | endif # MACH_LOONGSON |
diff --git a/arch/mips/loongson/Makefile b/arch/mips/loongson/Makefile index 0dc0055754cd..7429994e7604 100644 --- a/arch/mips/loongson/Makefile +++ b/arch/mips/loongson/Makefile | |||
@@ -15,3 +15,9 @@ obj-$(CONFIG_LEMOTE_FULOONG2E) += fuloong-2e/ | |||
15 | # | 15 | # |
16 | 16 | ||
17 | obj-$(CONFIG_LEMOTE_MACH2F) += lemote-2f/ | 17 | obj-$(CONFIG_LEMOTE_MACH2F) += lemote-2f/ |
18 | |||
19 | # | ||
20 | # All Loongson-3 family machines | ||
21 | # | ||
22 | |||
23 | obj-$(CONFIG_CPU_LOONGSON3) += loongson-3/ | ||
diff --git a/arch/mips/loongson/Platform b/arch/mips/loongson/Platform index 29692e5433b1..6205372b6c2d 100644 --- a/arch/mips/loongson/Platform +++ b/arch/mips/loongson/Platform | |||
@@ -30,3 +30,4 @@ platform-$(CONFIG_MACH_LOONGSON) += loongson/ | |||
30 | cflags-$(CONFIG_MACH_LOONGSON) += -I$(srctree)/arch/mips/include/asm/mach-loongson -mno-branch-likely | 30 | cflags-$(CONFIG_MACH_LOONGSON) += -I$(srctree)/arch/mips/include/asm/mach-loongson -mno-branch-likely |
31 | load-$(CONFIG_LEMOTE_FULOONG2E) += 0xffffffff80100000 | 31 | load-$(CONFIG_LEMOTE_FULOONG2E) += 0xffffffff80100000 |
32 | load-$(CONFIG_LEMOTE_MACH2F) += 0xffffffff80200000 | 32 | load-$(CONFIG_LEMOTE_MACH2F) += 0xffffffff80200000 |
33 | load-$(CONFIG_CPU_LOONGSON3) += 0xffffffff80200000 | ||
diff --git a/arch/mips/loongson/common/Makefile b/arch/mips/loongson/common/Makefile index 9e4484ccbb03..0bb9cc9dc621 100644 --- a/arch/mips/loongson/common/Makefile +++ b/arch/mips/loongson/common/Makefile | |||
@@ -26,3 +26,8 @@ obj-$(CONFIG_CS5536) += cs5536/ | |||
26 | # | 26 | # |
27 | 27 | ||
28 | obj-$(CONFIG_LOONGSON_SUSPEND) += pm.o | 28 | obj-$(CONFIG_LOONGSON_SUSPEND) += pm.o |
29 | |||
30 | # | ||
31 | # Big Memory (SWIOTLB) Support | ||
32 | # | ||
33 | obj-$(CONFIG_SWIOTLB) += dma-swiotlb.o | ||
diff --git a/arch/mips/loongson/common/dma-swiotlb.c b/arch/mips/loongson/common/dma-swiotlb.c new file mode 100644 index 000000000000..c2be01f91575 --- /dev/null +++ b/arch/mips/loongson/common/dma-swiotlb.c | |||
@@ -0,0 +1,136 @@ | |||
1 | #include <linux/mm.h> | ||
2 | #include <linux/init.h> | ||
3 | #include <linux/dma-mapping.h> | ||
4 | #include <linux/scatterlist.h> | ||
5 | #include <linux/swiotlb.h> | ||
6 | #include <linux/bootmem.h> | ||
7 | |||
8 | #include <asm/bootinfo.h> | ||
9 | #include <boot_param.h> | ||
10 | #include <dma-coherence.h> | ||
11 | |||
12 | static void *loongson_dma_alloc_coherent(struct device *dev, size_t size, | ||
13 | dma_addr_t *dma_handle, gfp_t gfp, struct dma_attrs *attrs) | ||
14 | { | ||
15 | void *ret; | ||
16 | |||
17 | if (dma_alloc_from_coherent(dev, size, dma_handle, &ret)) | ||
18 | return ret; | ||
19 | |||
20 | /* ignore region specifiers */ | ||
21 | gfp &= ~(__GFP_DMA | __GFP_DMA32 | __GFP_HIGHMEM); | ||
22 | |||
23 | #ifdef CONFIG_ISA | ||
24 | if (dev == NULL) | ||
25 | gfp |= __GFP_DMA; | ||
26 | else | ||
27 | #endif | ||
28 | #ifdef CONFIG_ZONE_DMA | ||
29 | if (dev->coherent_dma_mask < DMA_BIT_MASK(32)) | ||
30 | gfp |= __GFP_DMA; | ||
31 | else | ||
32 | #endif | ||
33 | #ifdef CONFIG_ZONE_DMA32 | ||
34 | if (dev->coherent_dma_mask < DMA_BIT_MASK(40)) | ||
35 | gfp |= __GFP_DMA32; | ||
36 | else | ||
37 | #endif | ||
38 | ; | ||
39 | gfp |= __GFP_NORETRY; | ||
40 | |||
41 | ret = swiotlb_alloc_coherent(dev, size, dma_handle, gfp); | ||
42 | mb(); | ||
43 | return ret; | ||
44 | } | ||
45 | |||
46 | static void loongson_dma_free_coherent(struct device *dev, size_t size, | ||
47 | void *vaddr, dma_addr_t dma_handle, struct dma_attrs *attrs) | ||
48 | { | ||
49 | int order = get_order(size); | ||
50 | |||
51 | if (dma_release_from_coherent(dev, order, vaddr)) | ||
52 | return; | ||
53 | |||
54 | swiotlb_free_coherent(dev, size, vaddr, dma_handle); | ||
55 | } | ||
56 | |||
57 | static dma_addr_t loongson_dma_map_page(struct device *dev, struct page *page, | ||
58 | unsigned long offset, size_t size, | ||
59 | enum dma_data_direction dir, | ||
60 | struct dma_attrs *attrs) | ||
61 | { | ||
62 | dma_addr_t daddr = swiotlb_map_page(dev, page, offset, size, | ||
63 | dir, attrs); | ||
64 | mb(); | ||
65 | return daddr; | ||
66 | } | ||
67 | |||
68 | static int loongson_dma_map_sg(struct device *dev, struct scatterlist *sg, | ||
69 | int nents, enum dma_data_direction dir, | ||
70 | struct dma_attrs *attrs) | ||
71 | { | ||
72 | int r = swiotlb_map_sg_attrs(dev, sg, nents, dir, NULL); | ||
73 | mb(); | ||
74 | |||
75 | return r; | ||
76 | } | ||
77 | |||
78 | static void loongson_dma_sync_single_for_device(struct device *dev, | ||
79 | dma_addr_t dma_handle, size_t size, | ||
80 | enum dma_data_direction dir) | ||
81 | { | ||
82 | swiotlb_sync_single_for_device(dev, dma_handle, size, dir); | ||
83 | mb(); | ||
84 | } | ||
85 | |||
86 | static void loongson_dma_sync_sg_for_device(struct device *dev, | ||
87 | struct scatterlist *sg, int nents, | ||
88 | enum dma_data_direction dir) | ||
89 | { | ||
90 | swiotlb_sync_sg_for_device(dev, sg, nents, dir); | ||
91 | mb(); | ||
92 | } | ||
93 | |||
94 | static int loongson_dma_set_mask(struct device *dev, u64 mask) | ||
95 | { | ||
96 | if (mask > DMA_BIT_MASK(loongson_sysconf.dma_mask_bits)) { | ||
97 | *dev->dma_mask = DMA_BIT_MASK(loongson_sysconf.dma_mask_bits); | ||
98 | return -EIO; | ||
99 | } | ||
100 | |||
101 | *dev->dma_mask = mask; | ||
102 | |||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) | ||
107 | { | ||
108 | return paddr; | ||
109 | } | ||
110 | |||
111 | phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr) | ||
112 | { | ||
113 | return daddr; | ||
114 | } | ||
115 | |||
116 | static struct dma_map_ops loongson_dma_map_ops = { | ||
117 | .alloc = loongson_dma_alloc_coherent, | ||
118 | .free = loongson_dma_free_coherent, | ||
119 | .map_page = loongson_dma_map_page, | ||
120 | .unmap_page = swiotlb_unmap_page, | ||
121 | .map_sg = loongson_dma_map_sg, | ||
122 | .unmap_sg = swiotlb_unmap_sg_attrs, | ||
123 | .sync_single_for_cpu = swiotlb_sync_single_for_cpu, | ||
124 | .sync_single_for_device = loongson_dma_sync_single_for_device, | ||
125 | .sync_sg_for_cpu = swiotlb_sync_sg_for_cpu, | ||
126 | .sync_sg_for_device = loongson_dma_sync_sg_for_device, | ||
127 | .mapping_error = swiotlb_dma_mapping_error, | ||
128 | .dma_supported = swiotlb_dma_supported, | ||
129 | .set_dma_mask = loongson_dma_set_mask | ||
130 | }; | ||
131 | |||
132 | void __init plat_swiotlb_setup(void) | ||
133 | { | ||
134 | swiotlb_init(1); | ||
135 | mips_dma_map_ops = &loongson_dma_map_ops; | ||
136 | } | ||
diff --git a/arch/mips/loongson/common/env.c b/arch/mips/loongson/common/env.c index 0a18fcf2d372..0c543eae49bf 100644 --- a/arch/mips/loongson/common/env.c +++ b/arch/mips/loongson/common/env.c | |||
@@ -18,29 +18,30 @@ | |||
18 | * option) any later version. | 18 | * option) any later version. |
19 | */ | 19 | */ |
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | |||
22 | #include <asm/bootinfo.h> | 21 | #include <asm/bootinfo.h> |
23 | |||
24 | #include <loongson.h> | 22 | #include <loongson.h> |
23 | #include <boot_param.h> | ||
25 | 24 | ||
26 | unsigned long cpu_clock_freq; | 25 | u32 cpu_clock_freq; |
27 | EXPORT_SYMBOL(cpu_clock_freq); | 26 | EXPORT_SYMBOL(cpu_clock_freq); |
28 | unsigned long memsize, highmemsize; | 27 | struct efi_memory_map_loongson *loongson_memmap; |
28 | struct loongson_system_configuration loongson_sysconf; | ||
29 | 29 | ||
30 | #define parse_even_earlier(res, option, p) \ | 30 | #define parse_even_earlier(res, option, p) \ |
31 | do { \ | 31 | do { \ |
32 | unsigned int tmp __maybe_unused; \ | 32 | unsigned int tmp __maybe_unused; \ |
33 | \ | 33 | \ |
34 | if (strncmp(option, (char *)p, strlen(option)) == 0) \ | 34 | if (strncmp(option, (char *)p, strlen(option)) == 0) \ |
35 | tmp = strict_strtol((char *)p + strlen(option"="), 10, &res); \ | 35 | tmp = kstrtou32((char *)p + strlen(option"="), 10, &res); \ |
36 | } while (0) | 36 | } while (0) |
37 | 37 | ||
38 | void __init prom_init_env(void) | 38 | void __init prom_init_env(void) |
39 | { | 39 | { |
40 | /* pmon passes arguments in 32bit pointers */ | 40 | /* pmon passes arguments in 32bit pointers */ |
41 | int *_prom_envp; | ||
42 | unsigned long bus_clock; | ||
43 | unsigned int processor_id; | 41 | unsigned int processor_id; |
42 | |||
43 | #ifndef CONFIG_LEFI_FIRMWARE_INTERFACE | ||
44 | int *_prom_envp; | ||
44 | long l; | 45 | long l; |
45 | 46 | ||
46 | /* firmware arguments are initialized in head.S */ | 47 | /* firmware arguments are initialized in head.S */ |
@@ -48,7 +49,6 @@ void __init prom_init_env(void) | |||
48 | 49 | ||
49 | l = (long)*_prom_envp; | 50 | l = (long)*_prom_envp; |
50 | while (l != 0) { | 51 | while (l != 0) { |
51 | parse_even_earlier(bus_clock, "busclock", l); | ||
52 | parse_even_earlier(cpu_clock_freq, "cpuclock", l); | 52 | parse_even_earlier(cpu_clock_freq, "cpuclock", l); |
53 | parse_even_earlier(memsize, "memsize", l); | 53 | parse_even_earlier(memsize, "memsize", l); |
54 | parse_even_earlier(highmemsize, "highmemsize", l); | 54 | parse_even_earlier(highmemsize, "highmemsize", l); |
@@ -57,8 +57,48 @@ void __init prom_init_env(void) | |||
57 | } | 57 | } |
58 | if (memsize == 0) | 58 | if (memsize == 0) |
59 | memsize = 256; | 59 | memsize = 256; |
60 | if (bus_clock == 0) | 60 | pr_info("memsize=%u, highmemsize=%u\n", memsize, highmemsize); |
61 | bus_clock = 66000000; | 61 | #else |
62 | struct boot_params *boot_p; | ||
63 | struct loongson_params *loongson_p; | ||
64 | struct efi_cpuinfo_loongson *ecpu; | ||
65 | struct irq_source_routing_table *eirq_source; | ||
66 | |||
67 | /* firmware arguments are initialized in head.S */ | ||
68 | boot_p = (struct boot_params *)fw_arg2; | ||
69 | loongson_p = &(boot_p->efi.smbios.lp); | ||
70 | |||
71 | ecpu = (struct efi_cpuinfo_loongson *) | ||
72 | ((u64)loongson_p + loongson_p->cpu_offset); | ||
73 | eirq_source = (struct irq_source_routing_table *) | ||
74 | ((u64)loongson_p + loongson_p->irq_offset); | ||
75 | loongson_memmap = (struct efi_memory_map_loongson *) | ||
76 | ((u64)loongson_p + loongson_p->memory_offset); | ||
77 | |||
78 | cpu_clock_freq = ecpu->cpu_clock_freq; | ||
79 | loongson_sysconf.cputype = ecpu->cputype; | ||
80 | loongson_sysconf.nr_cpus = ecpu->nr_cpus; | ||
81 | if (ecpu->nr_cpus > NR_CPUS || ecpu->nr_cpus == 0) | ||
82 | loongson_sysconf.nr_cpus = NR_CPUS; | ||
83 | |||
84 | loongson_sysconf.pci_mem_start_addr = eirq_source->pci_mem_start_addr; | ||
85 | loongson_sysconf.pci_mem_end_addr = eirq_source->pci_mem_end_addr; | ||
86 | loongson_sysconf.pci_io_base = eirq_source->pci_io_start_addr; | ||
87 | loongson_sysconf.dma_mask_bits = eirq_source->dma_mask_bits; | ||
88 | if (loongson_sysconf.dma_mask_bits < 32 || | ||
89 | loongson_sysconf.dma_mask_bits > 64) | ||
90 | loongson_sysconf.dma_mask_bits = 32; | ||
91 | |||
92 | loongson_sysconf.restart_addr = boot_p->reset_system.ResetWarm; | ||
93 | loongson_sysconf.poweroff_addr = boot_p->reset_system.Shutdown; | ||
94 | loongson_sysconf.suspend_addr = boot_p->reset_system.DoSuspend; | ||
95 | |||
96 | loongson_sysconf.ht_control_base = 0x90000EFDFB000000; | ||
97 | loongson_sysconf.vgabios_addr = boot_p->efi.smbios.vga_bios; | ||
98 | pr_debug("Shutdown Addr: %llx, Restart Addr: %llx, VBIOS Addr: %llx\n", | ||
99 | loongson_sysconf.poweroff_addr, loongson_sysconf.restart_addr, | ||
100 | loongson_sysconf.vgabios_addr); | ||
101 | #endif | ||
62 | if (cpu_clock_freq == 0) { | 102 | if (cpu_clock_freq == 0) { |
63 | processor_id = (¤t_cpu_data)->processor_id; | 103 | processor_id = (¤t_cpu_data)->processor_id; |
64 | switch (processor_id & PRID_REV_MASK) { | 104 | switch (processor_id & PRID_REV_MASK) { |
@@ -68,12 +108,13 @@ void __init prom_init_env(void) | |||
68 | case PRID_REV_LOONGSON2F: | 108 | case PRID_REV_LOONGSON2F: |
69 | cpu_clock_freq = 797000000; | 109 | cpu_clock_freq = 797000000; |
70 | break; | 110 | break; |
111 | case PRID_REV_LOONGSON3A: | ||
112 | cpu_clock_freq = 900000000; | ||
113 | break; | ||
71 | default: | 114 | default: |
72 | cpu_clock_freq = 100000000; | 115 | cpu_clock_freq = 100000000; |
73 | break; | 116 | break; |
74 | } | 117 | } |
75 | } | 118 | } |
76 | 119 | pr_info("CpuClock = %u\n", cpu_clock_freq); | |
77 | pr_info("busclock=%ld, cpuclock=%ld, memsize=%ld, highmemsize=%ld\n", | ||
78 | bus_clock, cpu_clock_freq, memsize, highmemsize); | ||
79 | } | 120 | } |
diff --git a/arch/mips/loongson/common/init.c b/arch/mips/loongson/common/init.c index ae7af1fd5d59..f37fe5413b73 100644 --- a/arch/mips/loongson/common/init.c +++ b/arch/mips/loongson/common/init.c | |||
@@ -9,6 +9,7 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/bootmem.h> | 11 | #include <linux/bootmem.h> |
12 | #include <asm/smp-ops.h> | ||
12 | 13 | ||
13 | #include <loongson.h> | 14 | #include <loongson.h> |
14 | 15 | ||
@@ -17,10 +18,6 @@ unsigned long __maybe_unused _loongson_addrwincfg_base; | |||
17 | 18 | ||
18 | void __init prom_init(void) | 19 | void __init prom_init(void) |
19 | { | 20 | { |
20 | /* init base address of io space */ | ||
21 | set_io_port_base((unsigned long) | ||
22 | ioremap(LOONGSON_PCIIO_BASE, LOONGSON_PCIIO_SIZE)); | ||
23 | |||
24 | #ifdef CONFIG_CPU_SUPPORTS_ADDRWINCFG | 21 | #ifdef CONFIG_CPU_SUPPORTS_ADDRWINCFG |
25 | _loongson_addrwincfg_base = (unsigned long) | 22 | _loongson_addrwincfg_base = (unsigned long) |
26 | ioremap(LOONGSON_ADDRWINCFG_BASE, LOONGSON_ADDRWINCFG_SIZE); | 23 | ioremap(LOONGSON_ADDRWINCFG_BASE, LOONGSON_ADDRWINCFG_SIZE); |
@@ -28,10 +25,16 @@ void __init prom_init(void) | |||
28 | 25 | ||
29 | prom_init_cmdline(); | 26 | prom_init_cmdline(); |
30 | prom_init_env(); | 27 | prom_init_env(); |
28 | |||
29 | /* init base address of io space */ | ||
30 | set_io_port_base((unsigned long) | ||
31 | ioremap(LOONGSON_PCIIO_BASE, LOONGSON_PCIIO_SIZE)); | ||
32 | |||
31 | prom_init_memory(); | 33 | prom_init_memory(); |
32 | 34 | ||
33 | /*init the uart base address */ | 35 | /*init the uart base address */ |
34 | prom_init_uart_base(); | 36 | prom_init_uart_base(); |
37 | register_smp_ops(&loongson3_smp_ops); | ||
35 | } | 38 | } |
36 | 39 | ||
37 | void __init prom_free_prom_memory(void) | 40 | void __init prom_free_prom_memory(void) |
diff --git a/arch/mips/loongson/common/machtype.c b/arch/mips/loongson/common/machtype.c index 4becd4f9ef2e..1a4797984b8d 100644 --- a/arch/mips/loongson/common/machtype.c +++ b/arch/mips/loongson/common/machtype.c | |||
@@ -27,6 +27,10 @@ static const char *system_types[] = { | |||
27 | [MACH_DEXXON_GDIUM2F10] "dexxon-gdium-2f", | 27 | [MACH_DEXXON_GDIUM2F10] "dexxon-gdium-2f", |
28 | [MACH_LEMOTE_NAS] "lemote-nas-2f", | 28 | [MACH_LEMOTE_NAS] "lemote-nas-2f", |
29 | [MACH_LEMOTE_LL2F] "lemote-lynloong-2f", | 29 | [MACH_LEMOTE_LL2F] "lemote-lynloong-2f", |
30 | [MACH_LEMOTE_A1004] "lemote-3a-notebook-a1004", | ||
31 | [MACH_LEMOTE_A1101] "lemote-3a-itx-a1101", | ||
32 | [MACH_LEMOTE_A1201] "lemote-2gq-notebook-a1201", | ||
33 | [MACH_LEMOTE_A1205] "lemote-2gq-aio-a1205", | ||
30 | [MACH_LOONGSON_END] NULL, | 34 | [MACH_LOONGSON_END] NULL, |
31 | }; | 35 | }; |
32 | 36 | ||
diff --git a/arch/mips/loongson/common/mem.c b/arch/mips/loongson/common/mem.c index 8626a42f5b94..b01d52473da8 100644 --- a/arch/mips/loongson/common/mem.c +++ b/arch/mips/loongson/common/mem.c | |||
@@ -11,9 +11,14 @@ | |||
11 | #include <asm/bootinfo.h> | 11 | #include <asm/bootinfo.h> |
12 | 12 | ||
13 | #include <loongson.h> | 13 | #include <loongson.h> |
14 | #include <boot_param.h> | ||
14 | #include <mem.h> | 15 | #include <mem.h> |
15 | #include <pci.h> | 16 | #include <pci.h> |
16 | 17 | ||
18 | #ifndef CONFIG_LEFI_FIRMWARE_INTERFACE | ||
19 | |||
20 | u32 memsize, highmemsize; | ||
21 | |||
17 | void __init prom_init_memory(void) | 22 | void __init prom_init_memory(void) |
18 | { | 23 | { |
19 | add_memory_region(0x0, (memsize << 20), BOOT_MEM_RAM); | 24 | add_memory_region(0x0, (memsize << 20), BOOT_MEM_RAM); |
@@ -49,6 +54,43 @@ void __init prom_init_memory(void) | |||
49 | #endif /* !CONFIG_64BIT */ | 54 | #endif /* !CONFIG_64BIT */ |
50 | } | 55 | } |
51 | 56 | ||
57 | #else /* CONFIG_LEFI_FIRMWARE_INTERFACE */ | ||
58 | |||
59 | void __init prom_init_memory(void) | ||
60 | { | ||
61 | int i; | ||
62 | u32 node_id; | ||
63 | u32 mem_type; | ||
64 | |||
65 | /* parse memory information */ | ||
66 | for (i = 0; i < loongson_memmap->nr_map; i++) { | ||
67 | node_id = loongson_memmap->map[i].node_id; | ||
68 | mem_type = loongson_memmap->map[i].mem_type; | ||
69 | |||
70 | if (node_id == 0) { | ||
71 | switch (mem_type) { | ||
72 | case SYSTEM_RAM_LOW: | ||
73 | add_memory_region(loongson_memmap->map[i].mem_start, | ||
74 | (u64)loongson_memmap->map[i].mem_size << 20, | ||
75 | BOOT_MEM_RAM); | ||
76 | break; | ||
77 | case SYSTEM_RAM_HIGH: | ||
78 | add_memory_region(loongson_memmap->map[i].mem_start, | ||
79 | (u64)loongson_memmap->map[i].mem_size << 20, | ||
80 | BOOT_MEM_RAM); | ||
81 | break; | ||
82 | case MEM_RESERVED: | ||
83 | add_memory_region(loongson_memmap->map[i].mem_start, | ||
84 | (u64)loongson_memmap->map[i].mem_size << 20, | ||
85 | BOOT_MEM_RESERVED); | ||
86 | break; | ||
87 | } | ||
88 | } | ||
89 | } | ||
90 | } | ||
91 | |||
92 | #endif /* CONFIG_LEFI_FIRMWARE_INTERFACE */ | ||
93 | |||
52 | /* override of arch/mips/mm/cache.c: __uncached_access */ | 94 | /* override of arch/mips/mm/cache.c: __uncached_access */ |
53 | int __uncached_access(struct file *file, unsigned long addr) | 95 | int __uncached_access(struct file *file, unsigned long addr) |
54 | { | 96 | { |
diff --git a/arch/mips/loongson/common/pci.c b/arch/mips/loongson/common/pci.c index fa7784459721..003ab4e618b3 100644 --- a/arch/mips/loongson/common/pci.c +++ b/arch/mips/loongson/common/pci.c | |||
@@ -11,6 +11,7 @@ | |||
11 | 11 | ||
12 | #include <pci.h> | 12 | #include <pci.h> |
13 | #include <loongson.h> | 13 | #include <loongson.h> |
14 | #include <boot_param.h> | ||
14 | 15 | ||
15 | static struct resource loongson_pci_mem_resource = { | 16 | static struct resource loongson_pci_mem_resource = { |
16 | .name = "pci memory space", | 17 | .name = "pci memory space", |
@@ -82,7 +83,10 @@ static int __init pcibios_init(void) | |||
82 | setup_pcimap(); | 83 | setup_pcimap(); |
83 | 84 | ||
84 | loongson_pci_controller.io_map_base = mips_io_port_base; | 85 | loongson_pci_controller.io_map_base = mips_io_port_base; |
85 | 86 | #ifdef CONFIG_LEFI_FIRMWARE_INTERFACE | |
87 | loongson_pci_mem_resource.start = loongson_sysconf.pci_mem_start_addr; | ||
88 | loongson_pci_mem_resource.end = loongson_sysconf.pci_mem_end_addr; | ||
89 | #endif | ||
86 | register_pci_controller(&loongson_pci_controller); | 90 | register_pci_controller(&loongson_pci_controller); |
87 | 91 | ||
88 | return 0; | 92 | return 0; |
diff --git a/arch/mips/loongson/common/reset.c b/arch/mips/loongson/common/reset.c index 65bfbb5d06f4..a60715e11306 100644 --- a/arch/mips/loongson/common/reset.c +++ b/arch/mips/loongson/common/reset.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <asm/reboot.h> | 16 | #include <asm/reboot.h> |
17 | 17 | ||
18 | #include <loongson.h> | 18 | #include <loongson.h> |
19 | #include <boot_param.h> | ||
19 | 20 | ||
20 | static inline void loongson_reboot(void) | 21 | static inline void loongson_reboot(void) |
21 | { | 22 | { |
@@ -37,17 +38,37 @@ static inline void loongson_reboot(void) | |||
37 | 38 | ||
38 | static void loongson_restart(char *command) | 39 | static void loongson_restart(char *command) |
39 | { | 40 | { |
41 | #ifndef CONFIG_LEFI_FIRMWARE_INTERFACE | ||
40 | /* do preparation for reboot */ | 42 | /* do preparation for reboot */ |
41 | mach_prepare_reboot(); | 43 | mach_prepare_reboot(); |
42 | 44 | ||
43 | /* reboot via jumping to boot base address */ | 45 | /* reboot via jumping to boot base address */ |
44 | loongson_reboot(); | 46 | loongson_reboot(); |
47 | #else | ||
48 | void (*fw_restart)(void) = (void *)loongson_sysconf.restart_addr; | ||
49 | |||
50 | fw_restart(); | ||
51 | while (1) { | ||
52 | if (cpu_wait) | ||
53 | cpu_wait(); | ||
54 | } | ||
55 | #endif | ||
45 | } | 56 | } |
46 | 57 | ||
47 | static void loongson_poweroff(void) | 58 | static void loongson_poweroff(void) |
48 | { | 59 | { |
60 | #ifndef CONFIG_LEFI_FIRMWARE_INTERFACE | ||
49 | mach_prepare_shutdown(); | 61 | mach_prepare_shutdown(); |
50 | unreachable(); | 62 | unreachable(); |
63 | #else | ||
64 | void (*fw_poweroff)(void) = (void *)loongson_sysconf.poweroff_addr; | ||
65 | |||
66 | fw_poweroff(); | ||
67 | while (1) { | ||
68 | if (cpu_wait) | ||
69 | cpu_wait(); | ||
70 | } | ||
71 | #endif | ||
51 | } | 72 | } |
52 | 73 | ||
53 | static void loongson_halt(void) | 74 | static void loongson_halt(void) |
diff --git a/arch/mips/loongson/common/serial.c b/arch/mips/loongson/common/serial.c index 5f2b78ae97cc..bd2b7095b6dc 100644 --- a/arch/mips/loongson/common/serial.c +++ b/arch/mips/loongson/common/serial.c | |||
@@ -19,19 +19,19 @@ | |||
19 | #include <loongson.h> | 19 | #include <loongson.h> |
20 | #include <machine.h> | 20 | #include <machine.h> |
21 | 21 | ||
22 | #define PORT(int) \ | 22 | #define PORT(int, clk) \ |
23 | { \ | 23 | { \ |
24 | .irq = int, \ | 24 | .irq = int, \ |
25 | .uartclk = 1843200, \ | 25 | .uartclk = clk, \ |
26 | .iotype = UPIO_PORT, \ | 26 | .iotype = UPIO_PORT, \ |
27 | .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, \ | 27 | .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, \ |
28 | .regshift = 0, \ | 28 | .regshift = 0, \ |
29 | } | 29 | } |
30 | 30 | ||
31 | #define PORT_M(int) \ | 31 | #define PORT_M(int, clk) \ |
32 | { \ | 32 | { \ |
33 | .irq = MIPS_CPU_IRQ_BASE + (int), \ | 33 | .irq = MIPS_CPU_IRQ_BASE + (int), \ |
34 | .uartclk = 3686400, \ | 34 | .uartclk = clk, \ |
35 | .iotype = UPIO_MEM, \ | 35 | .iotype = UPIO_MEM, \ |
36 | .membase = (void __iomem *)NULL, \ | 36 | .membase = (void __iomem *)NULL, \ |
37 | .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, \ | 37 | .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, \ |
@@ -40,13 +40,17 @@ | |||
40 | 40 | ||
41 | static struct plat_serial8250_port uart8250_data[][2] = { | 41 | static struct plat_serial8250_port uart8250_data[][2] = { |
42 | [MACH_LOONGSON_UNKNOWN] {}, | 42 | [MACH_LOONGSON_UNKNOWN] {}, |
43 | [MACH_LEMOTE_FL2E] {PORT(4), {} }, | 43 | [MACH_LEMOTE_FL2E] {PORT(4, 1843200), {} }, |
44 | [MACH_LEMOTE_FL2F] {PORT(3), {} }, | 44 | [MACH_LEMOTE_FL2F] {PORT(3, 1843200), {} }, |
45 | [MACH_LEMOTE_ML2F7] {PORT_M(3), {} }, | 45 | [MACH_LEMOTE_ML2F7] {PORT_M(3, 3686400), {} }, |
46 | [MACH_LEMOTE_YL2F89] {PORT_M(3), {} }, | 46 | [MACH_LEMOTE_YL2F89] {PORT_M(3, 3686400), {} }, |
47 | [MACH_DEXXON_GDIUM2F10] {PORT_M(3), {} }, | 47 | [MACH_DEXXON_GDIUM2F10] {PORT_M(3, 3686400), {} }, |
48 | [MACH_LEMOTE_NAS] {PORT_M(3), {} }, | 48 | [MACH_LEMOTE_NAS] {PORT_M(3, 3686400), {} }, |
49 | [MACH_LEMOTE_LL2F] {PORT(3), {} }, | 49 | [MACH_LEMOTE_LL2F] {PORT(3, 1843200), {} }, |
50 | [MACH_LEMOTE_A1004] {PORT_M(2, 33177600), {} }, | ||
51 | [MACH_LEMOTE_A1101] {PORT_M(2, 25000000), {} }, | ||
52 | [MACH_LEMOTE_A1201] {PORT_M(2, 25000000), {} }, | ||
53 | [MACH_LEMOTE_A1205] {PORT_M(2, 25000000), {} }, | ||
50 | [MACH_LOONGSON_END] {}, | 54 | [MACH_LOONGSON_END] {}, |
51 | }; | 55 | }; |
52 | 56 | ||
diff --git a/arch/mips/loongson/common/setup.c b/arch/mips/loongson/common/setup.c index 8223f8acfd59..bb4ac922e47a 100644 --- a/arch/mips/loongson/common/setup.c +++ b/arch/mips/loongson/common/setup.c | |||
@@ -18,9 +18,6 @@ | |||
18 | #include <linux/screen_info.h> | 18 | #include <linux/screen_info.h> |
19 | #endif | 19 | #endif |
20 | 20 | ||
21 | void (*__wbflush)(void); | ||
22 | EXPORT_SYMBOL(__wbflush); | ||
23 | |||
24 | static void wbflush_loongson(void) | 21 | static void wbflush_loongson(void) |
25 | { | 22 | { |
26 | asm(".set\tpush\n\t" | 23 | asm(".set\tpush\n\t" |
@@ -32,10 +29,11 @@ static void wbflush_loongson(void) | |||
32 | ".set mips0\n\t"); | 29 | ".set mips0\n\t"); |
33 | } | 30 | } |
34 | 31 | ||
32 | void (*__wbflush)(void) = wbflush_loongson; | ||
33 | EXPORT_SYMBOL(__wbflush); | ||
34 | |||
35 | void __init plat_mem_setup(void) | 35 | void __init plat_mem_setup(void) |
36 | { | 36 | { |
37 | __wbflush = wbflush_loongson; | ||
38 | |||
39 | #ifdef CONFIG_VT | 37 | #ifdef CONFIG_VT |
40 | #if defined(CONFIG_VGA_CONSOLE) | 38 | #if defined(CONFIG_VGA_CONSOLE) |
41 | conswitchp = &vga_con; | 39 | conswitchp = &vga_con; |
diff --git a/arch/mips/loongson/common/uart_base.c b/arch/mips/loongson/common/uart_base.c index e192ad021edc..1e1eeea73fde 100644 --- a/arch/mips/loongson/common/uart_base.c +++ b/arch/mips/loongson/common/uart_base.c | |||
@@ -35,9 +35,16 @@ void prom_init_loongson_uart_base(void) | |||
35 | case MACH_DEXXON_GDIUM2F10: | 35 | case MACH_DEXXON_GDIUM2F10: |
36 | case MACH_LEMOTE_NAS: | 36 | case MACH_LEMOTE_NAS: |
37 | default: | 37 | default: |
38 | /* The CPU provided serial port */ | 38 | /* The CPU provided serial port (LPC) */ |
39 | loongson_uart_base = LOONGSON_LIO1_BASE + 0x3f8; | 39 | loongson_uart_base = LOONGSON_LIO1_BASE + 0x3f8; |
40 | break; | 40 | break; |
41 | case MACH_LEMOTE_A1004: | ||
42 | case MACH_LEMOTE_A1101: | ||
43 | case MACH_LEMOTE_A1201: | ||
44 | case MACH_LEMOTE_A1205: | ||
45 | /* The CPU provided serial port (CPU) */ | ||
46 | loongson_uart_base = LOONGSON_REG_BASE + 0x1e0; | ||
47 | break; | ||
41 | } | 48 | } |
42 | 49 | ||
43 | _loongson_uart_base = | 50 | _loongson_uart_base = |
diff --git a/arch/mips/loongson/loongson-3/Makefile b/arch/mips/loongson/loongson-3/Makefile new file mode 100644 index 000000000000..70152b252ddc --- /dev/null +++ b/arch/mips/loongson/loongson-3/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Makefile for Loongson-3 family machines | ||
3 | # | ||
4 | obj-y += irq.o | ||
5 | |||
6 | obj-$(CONFIG_SMP) += smp.o | ||
diff --git a/arch/mips/loongson/loongson-3/irq.c b/arch/mips/loongson/loongson-3/irq.c new file mode 100644 index 000000000000..f240828181ff --- /dev/null +++ b/arch/mips/loongson/loongson-3/irq.c | |||
@@ -0,0 +1,126 @@ | |||
1 | #include <loongson.h> | ||
2 | #include <irq.h> | ||
3 | #include <linux/interrupt.h> | ||
4 | #include <linux/module.h> | ||
5 | |||
6 | #include <asm/irq_cpu.h> | ||
7 | #include <asm/i8259.h> | ||
8 | #include <asm/mipsregs.h> | ||
9 | |||
10 | unsigned int ht_irq[] = {1, 3, 4, 5, 6, 7, 8, 12, 14, 15}; | ||
11 | |||
12 | static void ht_irqdispatch(void) | ||
13 | { | ||
14 | unsigned int i, irq; | ||
15 | |||
16 | irq = LOONGSON_HT1_INT_VECTOR(0); | ||
17 | LOONGSON_HT1_INT_VECTOR(0) = irq; /* Acknowledge the IRQs */ | ||
18 | |||
19 | for (i = 0; i < ARRAY_SIZE(ht_irq); i++) { | ||
20 | if (irq & (0x1 << ht_irq[i])) | ||
21 | do_IRQ(ht_irq[i]); | ||
22 | } | ||
23 | } | ||
24 | |||
25 | void mach_irq_dispatch(unsigned int pending) | ||
26 | { | ||
27 | if (pending & CAUSEF_IP7) | ||
28 | do_IRQ(LOONGSON_TIMER_IRQ); | ||
29 | #if defined(CONFIG_SMP) | ||
30 | else if (pending & CAUSEF_IP6) | ||
31 | loongson3_ipi_interrupt(NULL); | ||
32 | #endif | ||
33 | else if (pending & CAUSEF_IP3) | ||
34 | ht_irqdispatch(); | ||
35 | else if (pending & CAUSEF_IP2) | ||
36 | do_IRQ(LOONGSON_UART_IRQ); | ||
37 | else { | ||
38 | pr_err("%s : spurious interrupt\n", __func__); | ||
39 | spurious_interrupt(); | ||
40 | } | ||
41 | } | ||
42 | |||
43 | static struct irqaction cascade_irqaction = { | ||
44 | .handler = no_action, | ||
45 | .name = "cascade", | ||
46 | }; | ||
47 | |||
48 | static inline void mask_loongson_irq(struct irq_data *d) | ||
49 | { | ||
50 | clear_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE)); | ||
51 | irq_disable_hazard(); | ||
52 | |||
53 | /* Workaround: UART IRQ may deliver to any core */ | ||
54 | if (d->irq == LOONGSON_UART_IRQ) { | ||
55 | int cpu = smp_processor_id(); | ||
56 | |||
57 | LOONGSON_INT_ROUTER_INTENCLR = 1 << 10; | ||
58 | LOONGSON_INT_ROUTER_LPC = 0x10 + (1<<cpu); | ||
59 | } | ||
60 | } | ||
61 | |||
62 | static inline void unmask_loongson_irq(struct irq_data *d) | ||
63 | { | ||
64 | /* Workaround: UART IRQ may deliver to any core */ | ||
65 | if (d->irq == LOONGSON_UART_IRQ) { | ||
66 | int cpu = smp_processor_id(); | ||
67 | |||
68 | LOONGSON_INT_ROUTER_INTENSET = 1 << 10; | ||
69 | LOONGSON_INT_ROUTER_LPC = 0x10 + (1<<cpu); | ||
70 | } | ||
71 | |||
72 | set_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE)); | ||
73 | irq_enable_hazard(); | ||
74 | } | ||
75 | |||
76 | /* For MIPS IRQs which shared by all cores */ | ||
77 | static struct irq_chip loongson_irq_chip = { | ||
78 | .name = "Loongson", | ||
79 | .irq_ack = mask_loongson_irq, | ||
80 | .irq_mask = mask_loongson_irq, | ||
81 | .irq_mask_ack = mask_loongson_irq, | ||
82 | .irq_unmask = unmask_loongson_irq, | ||
83 | .irq_eoi = unmask_loongson_irq, | ||
84 | }; | ||
85 | |||
86 | void irq_router_init(void) | ||
87 | { | ||
88 | int i; | ||
89 | |||
90 | /* route LPC int to cpu core0 int 0 */ | ||
91 | LOONGSON_INT_ROUTER_LPC = LOONGSON_INT_CORE0_INT0; | ||
92 | /* route HT1 int0 ~ int7 to cpu core0 INT1*/ | ||
93 | for (i = 0; i < 8; i++) | ||
94 | LOONGSON_INT_ROUTER_HT1(i) = LOONGSON_INT_CORE0_INT1; | ||
95 | /* enable HT1 interrupt */ | ||
96 | LOONGSON_HT1_INTN_EN(0) = 0xffffffff; | ||
97 | /* enable router interrupt intenset */ | ||
98 | LOONGSON_INT_ROUTER_INTENSET = | ||
99 | LOONGSON_INT_ROUTER_INTEN | (0xffff << 16) | 0x1 << 10; | ||
100 | } | ||
101 | |||
102 | void __init mach_init_irq(void) | ||
103 | { | ||
104 | clear_c0_status(ST0_IM | ST0_BEV); | ||
105 | |||
106 | irq_router_init(); | ||
107 | mips_cpu_irq_init(); | ||
108 | init_i8259_irqs(); | ||
109 | irq_set_chip_and_handler(LOONGSON_UART_IRQ, | ||
110 | &loongson_irq_chip, handle_level_irq); | ||
111 | |||
112 | /* setup HT1 irq */ | ||
113 | setup_irq(LOONGSON_HT1_IRQ, &cascade_irqaction); | ||
114 | |||
115 | set_c0_status(STATUSF_IP2 | STATUSF_IP6); | ||
116 | } | ||
117 | |||
118 | #ifdef CONFIG_HOTPLUG_CPU | ||
119 | |||
120 | void fixup_irqs(void) | ||
121 | { | ||
122 | irq_cpu_offline(); | ||
123 | clear_c0_status(ST0_IM); | ||
124 | } | ||
125 | |||
126 | #endif | ||
diff --git a/arch/mips/loongson/loongson-3/smp.c b/arch/mips/loongson/loongson-3/smp.c new file mode 100644 index 000000000000..c665fe16d4c9 --- /dev/null +++ b/arch/mips/loongson/loongson-3/smp.c | |||
@@ -0,0 +1,443 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010, 2011, 2012, Lemote, Inc. | ||
3 | * Author: Chen Huacai, chenhc@lemote.com | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License | ||
7 | * as published by the Free Software Foundation; either version 2 | ||
8 | * of the License, or (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/init.h> | ||
18 | #include <linux/cpu.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/smp.h> | ||
21 | #include <linux/cpufreq.h> | ||
22 | #include <asm/processor.h> | ||
23 | #include <asm/time.h> | ||
24 | #include <asm/clock.h> | ||
25 | #include <asm/tlbflush.h> | ||
26 | #include <asm/cacheflush.h> | ||
27 | #include <loongson.h> | ||
28 | |||
29 | #include "smp.h" | ||
30 | |||
31 | DEFINE_PER_CPU(int, cpu_state); | ||
32 | DEFINE_PER_CPU(uint32_t, core0_c0count); | ||
33 | |||
34 | /* read a 32bit value from ipi register */ | ||
35 | #define loongson3_ipi_read32(addr) readl(addr) | ||
36 | /* read a 64bit value from ipi register */ | ||
37 | #define loongson3_ipi_read64(addr) readq(addr) | ||
38 | /* write a 32bit value to ipi register */ | ||
39 | #define loongson3_ipi_write32(action, addr) \ | ||
40 | do { \ | ||
41 | writel(action, addr); \ | ||
42 | __wbflush(); \ | ||
43 | } while (0) | ||
44 | /* write a 64bit value to ipi register */ | ||
45 | #define loongson3_ipi_write64(action, addr) \ | ||
46 | do { \ | ||
47 | writeq(action, addr); \ | ||
48 | __wbflush(); \ | ||
49 | } while (0) | ||
50 | |||
51 | static void *ipi_set0_regs[] = { | ||
52 | (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + SET0), | ||
53 | (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + SET0), | ||
54 | (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + SET0), | ||
55 | (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + SET0), | ||
56 | (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + SET0), | ||
57 | (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + SET0), | ||
58 | (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + SET0), | ||
59 | (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + SET0), | ||
60 | (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + SET0), | ||
61 | (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + SET0), | ||
62 | (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + SET0), | ||
63 | (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + SET0), | ||
64 | (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + SET0), | ||
65 | (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + SET0), | ||
66 | (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + SET0), | ||
67 | (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + SET0), | ||
68 | }; | ||
69 | |||
70 | static void *ipi_clear0_regs[] = { | ||
71 | (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + CLEAR0), | ||
72 | (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + CLEAR0), | ||
73 | (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + CLEAR0), | ||
74 | (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + CLEAR0), | ||
75 | (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + CLEAR0), | ||
76 | (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + CLEAR0), | ||
77 | (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + CLEAR0), | ||
78 | (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + CLEAR0), | ||
79 | (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + CLEAR0), | ||
80 | (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + CLEAR0), | ||
81 | (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + CLEAR0), | ||
82 | (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + CLEAR0), | ||
83 | (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + CLEAR0), | ||
84 | (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + CLEAR0), | ||
85 | (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + CLEAR0), | ||
86 | (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + CLEAR0), | ||
87 | }; | ||
88 | |||
89 | static void *ipi_status0_regs[] = { | ||
90 | (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + STATUS0), | ||
91 | (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + STATUS0), | ||
92 | (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + STATUS0), | ||
93 | (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + STATUS0), | ||
94 | (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + STATUS0), | ||
95 | (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + STATUS0), | ||
96 | (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + STATUS0), | ||
97 | (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + STATUS0), | ||
98 | (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + STATUS0), | ||
99 | (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + STATUS0), | ||
100 | (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + STATUS0), | ||
101 | (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + STATUS0), | ||
102 | (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + STATUS0), | ||
103 | (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + STATUS0), | ||
104 | (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + STATUS0), | ||
105 | (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + STATUS0), | ||
106 | }; | ||
107 | |||
108 | static void *ipi_en0_regs[] = { | ||
109 | (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + EN0), | ||
110 | (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + EN0), | ||
111 | (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + EN0), | ||
112 | (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + EN0), | ||
113 | (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + EN0), | ||
114 | (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + EN0), | ||
115 | (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + EN0), | ||
116 | (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + EN0), | ||
117 | (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + EN0), | ||
118 | (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + EN0), | ||
119 | (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + EN0), | ||
120 | (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + EN0), | ||
121 | (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + EN0), | ||
122 | (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + EN0), | ||
123 | (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + EN0), | ||
124 | (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + EN0), | ||
125 | }; | ||
126 | |||
127 | static void *ipi_mailbox_buf[] = { | ||
128 | (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE0_OFFSET + BUF), | ||
129 | (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE1_OFFSET + BUF), | ||
130 | (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE2_OFFSET + BUF), | ||
131 | (void *)(SMP_CORE_GROUP0_BASE + SMP_CORE3_OFFSET + BUF), | ||
132 | (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE0_OFFSET + BUF), | ||
133 | (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE1_OFFSET + BUF), | ||
134 | (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE2_OFFSET + BUF), | ||
135 | (void *)(SMP_CORE_GROUP1_BASE + SMP_CORE3_OFFSET + BUF), | ||
136 | (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE0_OFFSET + BUF), | ||
137 | (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE1_OFFSET + BUF), | ||
138 | (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE2_OFFSET + BUF), | ||
139 | (void *)(SMP_CORE_GROUP2_BASE + SMP_CORE3_OFFSET + BUF), | ||
140 | (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE0_OFFSET + BUF), | ||
141 | (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE1_OFFSET + BUF), | ||
142 | (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE2_OFFSET + BUF), | ||
143 | (void *)(SMP_CORE_GROUP3_BASE + SMP_CORE3_OFFSET + BUF), | ||
144 | }; | ||
145 | |||
146 | /* | ||
147 | * Simple enough, just poke the appropriate ipi register | ||
148 | */ | ||
149 | static void loongson3_send_ipi_single(int cpu, unsigned int action) | ||
150 | { | ||
151 | loongson3_ipi_write32((u32)action, ipi_set0_regs[cpu]); | ||
152 | } | ||
153 | |||
154 | static void | ||
155 | loongson3_send_ipi_mask(const struct cpumask *mask, unsigned int action) | ||
156 | { | ||
157 | unsigned int i; | ||
158 | |||
159 | for_each_cpu(i, mask) | ||
160 | loongson3_ipi_write32((u32)action, ipi_set0_regs[i]); | ||
161 | } | ||
162 | |||
163 | void loongson3_ipi_interrupt(struct pt_regs *regs) | ||
164 | { | ||
165 | int i, cpu = smp_processor_id(); | ||
166 | unsigned int action, c0count; | ||
167 | |||
168 | /* Load the ipi register to figure out what we're supposed to do */ | ||
169 | action = loongson3_ipi_read32(ipi_status0_regs[cpu]); | ||
170 | |||
171 | /* Clear the ipi register to clear the interrupt */ | ||
172 | loongson3_ipi_write32((u32)action, ipi_clear0_regs[cpu]); | ||
173 | |||
174 | if (action & SMP_RESCHEDULE_YOURSELF) | ||
175 | scheduler_ipi(); | ||
176 | |||
177 | if (action & SMP_CALL_FUNCTION) | ||
178 | smp_call_function_interrupt(); | ||
179 | |||
180 | if (action & SMP_ASK_C0COUNT) { | ||
181 | BUG_ON(cpu != 0); | ||
182 | c0count = read_c0_count(); | ||
183 | for (i = 1; i < loongson_sysconf.nr_cpus; i++) | ||
184 | per_cpu(core0_c0count, i) = c0count; | ||
185 | } | ||
186 | } | ||
187 | |||
188 | #define MAX_LOOPS 1111 | ||
189 | /* | ||
190 | * SMP init and finish on secondary CPUs | ||
191 | */ | ||
192 | static void loongson3_init_secondary(void) | ||
193 | { | ||
194 | int i; | ||
195 | uint32_t initcount; | ||
196 | unsigned int cpu = smp_processor_id(); | ||
197 | unsigned int imask = STATUSF_IP7 | STATUSF_IP6 | | ||
198 | STATUSF_IP3 | STATUSF_IP2; | ||
199 | |||
200 | /* Set interrupt mask, but don't enable */ | ||
201 | change_c0_status(ST0_IM, imask); | ||
202 | |||
203 | for (i = 0; i < loongson_sysconf.nr_cpus; i++) | ||
204 | loongson3_ipi_write32(0xffffffff, ipi_en0_regs[i]); | ||
205 | |||
206 | per_cpu(cpu_state, cpu) = CPU_ONLINE; | ||
207 | |||
208 | i = 0; | ||
209 | __get_cpu_var(core0_c0count) = 0; | ||
210 | loongson3_send_ipi_single(0, SMP_ASK_C0COUNT); | ||
211 | while (!__get_cpu_var(core0_c0count)) { | ||
212 | i++; | ||
213 | cpu_relax(); | ||
214 | } | ||
215 | |||
216 | if (i > MAX_LOOPS) | ||
217 | i = MAX_LOOPS; | ||
218 | initcount = __get_cpu_var(core0_c0count) + i; | ||
219 | write_c0_count(initcount); | ||
220 | } | ||
221 | |||
222 | static void loongson3_smp_finish(void) | ||
223 | { | ||
224 | write_c0_compare(read_c0_count() + mips_hpt_frequency/HZ); | ||
225 | local_irq_enable(); | ||
226 | loongson3_ipi_write64(0, | ||
227 | (void *)(ipi_mailbox_buf[smp_processor_id()]+0x0)); | ||
228 | pr_info("CPU#%d finished, CP0_ST=%x\n", | ||
229 | smp_processor_id(), read_c0_status()); | ||
230 | } | ||
231 | |||
232 | static void __init loongson3_smp_setup(void) | ||
233 | { | ||
234 | int i, num; | ||
235 | |||
236 | init_cpu_possible(cpu_none_mask); | ||
237 | set_cpu_possible(0, true); | ||
238 | |||
239 | __cpu_number_map[0] = 0; | ||
240 | __cpu_logical_map[0] = 0; | ||
241 | |||
242 | /* For unified kernel, NR_CPUS is the maximum possible value, | ||
243 | * loongson_sysconf.nr_cpus is the really present value */ | ||
244 | for (i = 1, num = 0; i < loongson_sysconf.nr_cpus; i++) { | ||
245 | set_cpu_possible(i, true); | ||
246 | __cpu_number_map[i] = ++num; | ||
247 | __cpu_logical_map[num] = i; | ||
248 | } | ||
249 | pr_info("Detected %i available secondary CPU(s)\n", num); | ||
250 | } | ||
251 | |||
252 | static void __init loongson3_prepare_cpus(unsigned int max_cpus) | ||
253 | { | ||
254 | init_cpu_present(cpu_possible_mask); | ||
255 | per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE; | ||
256 | } | ||
257 | |||
258 | /* | ||
259 | * Setup the PC, SP, and GP of a secondary processor and start it runing! | ||
260 | */ | ||
261 | static void loongson3_boot_secondary(int cpu, struct task_struct *idle) | ||
262 | { | ||
263 | unsigned long startargs[4]; | ||
264 | |||
265 | pr_info("Booting CPU#%d...\n", cpu); | ||
266 | |||
267 | /* startargs[] are initial PC, SP and GP for secondary CPU */ | ||
268 | startargs[0] = (unsigned long)&smp_bootstrap; | ||
269 | startargs[1] = (unsigned long)__KSTK_TOS(idle); | ||
270 | startargs[2] = (unsigned long)task_thread_info(idle); | ||
271 | startargs[3] = 0; | ||
272 | |||
273 | pr_debug("CPU#%d, func_pc=%lx, sp=%lx, gp=%lx\n", | ||
274 | cpu, startargs[0], startargs[1], startargs[2]); | ||
275 | |||
276 | loongson3_ipi_write64(startargs[3], (void *)(ipi_mailbox_buf[cpu]+0x18)); | ||
277 | loongson3_ipi_write64(startargs[2], (void *)(ipi_mailbox_buf[cpu]+0x10)); | ||
278 | loongson3_ipi_write64(startargs[1], (void *)(ipi_mailbox_buf[cpu]+0x8)); | ||
279 | loongson3_ipi_write64(startargs[0], (void *)(ipi_mailbox_buf[cpu]+0x0)); | ||
280 | } | ||
281 | |||
282 | /* | ||
283 | * Final cleanup after all secondaries booted | ||
284 | */ | ||
285 | static void __init loongson3_cpus_done(void) | ||
286 | { | ||
287 | } | ||
288 | |||
289 | #ifdef CONFIG_HOTPLUG_CPU | ||
290 | |||
291 | static int loongson3_cpu_disable(void) | ||
292 | { | ||
293 | unsigned long flags; | ||
294 | unsigned int cpu = smp_processor_id(); | ||
295 | |||
296 | if (cpu == 0) | ||
297 | return -EBUSY; | ||
298 | |||
299 | set_cpu_online(cpu, false); | ||
300 | cpu_clear(cpu, cpu_callin_map); | ||
301 | local_irq_save(flags); | ||
302 | fixup_irqs(); | ||
303 | local_irq_restore(flags); | ||
304 | flush_cache_all(); | ||
305 | local_flush_tlb_all(); | ||
306 | |||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | |||
311 | static void loongson3_cpu_die(unsigned int cpu) | ||
312 | { | ||
313 | while (per_cpu(cpu_state, cpu) != CPU_DEAD) | ||
314 | cpu_relax(); | ||
315 | |||
316 | mb(); | ||
317 | } | ||
318 | |||
319 | /* To shutdown a core in Loongson 3, the target core should go to CKSEG1 and | ||
320 | * flush all L1 entries at first. Then, another core (usually Core 0) can | ||
321 | * safely disable the clock of the target core. loongson3_play_dead() is | ||
322 | * called via CKSEG1 (uncached and unmmaped) */ | ||
323 | static void loongson3_play_dead(int *state_addr) | ||
324 | { | ||
325 | register int val; | ||
326 | register long cpuid, core, node, count; | ||
327 | register void *addr, *base, *initfunc; | ||
328 | |||
329 | __asm__ __volatile__( | ||
330 | " .set push \n" | ||
331 | " .set noreorder \n" | ||
332 | " li %[addr], 0x80000000 \n" /* KSEG0 */ | ||
333 | "1: cache 0, 0(%[addr]) \n" /* flush L1 ICache */ | ||
334 | " cache 0, 1(%[addr]) \n" | ||
335 | " cache 0, 2(%[addr]) \n" | ||
336 | " cache 0, 3(%[addr]) \n" | ||
337 | " cache 1, 0(%[addr]) \n" /* flush L1 DCache */ | ||
338 | " cache 1, 1(%[addr]) \n" | ||
339 | " cache 1, 2(%[addr]) \n" | ||
340 | " cache 1, 3(%[addr]) \n" | ||
341 | " addiu %[sets], %[sets], -1 \n" | ||
342 | " bnez %[sets], 1b \n" | ||
343 | " addiu %[addr], %[addr], 0x20 \n" | ||
344 | " li %[val], 0x7 \n" /* *state_addr = CPU_DEAD; */ | ||
345 | " sw %[val], (%[state_addr]) \n" | ||
346 | " sync \n" | ||
347 | " cache 21, (%[state_addr]) \n" /* flush entry of *state_addr */ | ||
348 | " .set pop \n" | ||
349 | : [addr] "=&r" (addr), [val] "=&r" (val) | ||
350 | : [state_addr] "r" (state_addr), | ||
351 | [sets] "r" (cpu_data[smp_processor_id()].dcache.sets)); | ||
352 | |||
353 | __asm__ __volatile__( | ||
354 | " .set push \n" | ||
355 | " .set noreorder \n" | ||
356 | " .set mips64 \n" | ||
357 | " mfc0 %[cpuid], $15, 1 \n" | ||
358 | " andi %[cpuid], 0x3ff \n" | ||
359 | " dli %[base], 0x900000003ff01000 \n" | ||
360 | " andi %[core], %[cpuid], 0x3 \n" | ||
361 | " sll %[core], 8 \n" /* get core id */ | ||
362 | " or %[base], %[base], %[core] \n" | ||
363 | " andi %[node], %[cpuid], 0xc \n" | ||
364 | " dsll %[node], 42 \n" /* get node id */ | ||
365 | " or %[base], %[base], %[node] \n" | ||
366 | "1: li %[count], 0x100 \n" /* wait for init loop */ | ||
367 | "2: bnez %[count], 2b \n" /* limit mailbox access */ | ||
368 | " addiu %[count], -1 \n" | ||
369 | " ld %[initfunc], 0x20(%[base]) \n" /* get PC via mailbox */ | ||
370 | " beqz %[initfunc], 1b \n" | ||
371 | " nop \n" | ||
372 | " ld $sp, 0x28(%[base]) \n" /* get SP via mailbox */ | ||
373 | " ld $gp, 0x30(%[base]) \n" /* get GP via mailbox */ | ||
374 | " ld $a1, 0x38(%[base]) \n" | ||
375 | " jr %[initfunc] \n" /* jump to initial PC */ | ||
376 | " nop \n" | ||
377 | " .set pop \n" | ||
378 | : [core] "=&r" (core), [node] "=&r" (node), | ||
379 | [base] "=&r" (base), [cpuid] "=&r" (cpuid), | ||
380 | [count] "=&r" (count), [initfunc] "=&r" (initfunc) | ||
381 | : /* No Input */ | ||
382 | : "a1"); | ||
383 | } | ||
384 | |||
385 | void play_dead(void) | ||
386 | { | ||
387 | int *state_addr; | ||
388 | unsigned int cpu = smp_processor_id(); | ||
389 | void (*play_dead_at_ckseg1)(int *); | ||
390 | |||
391 | idle_task_exit(); | ||
392 | play_dead_at_ckseg1 = | ||
393 | (void *)CKSEG1ADDR((unsigned long)loongson3_play_dead); | ||
394 | state_addr = &per_cpu(cpu_state, cpu); | ||
395 | mb(); | ||
396 | play_dead_at_ckseg1(state_addr); | ||
397 | } | ||
398 | |||
399 | #define CPU_POST_DEAD_FROZEN (CPU_POST_DEAD | CPU_TASKS_FROZEN) | ||
400 | static int loongson3_cpu_callback(struct notifier_block *nfb, | ||
401 | unsigned long action, void *hcpu) | ||
402 | { | ||
403 | unsigned int cpu = (unsigned long)hcpu; | ||
404 | |||
405 | switch (action) { | ||
406 | case CPU_POST_DEAD: | ||
407 | case CPU_POST_DEAD_FROZEN: | ||
408 | pr_info("Disable clock for CPU#%d\n", cpu); | ||
409 | LOONGSON_CHIPCFG0 &= ~(1 << (12 + cpu)); | ||
410 | break; | ||
411 | case CPU_UP_PREPARE: | ||
412 | case CPU_UP_PREPARE_FROZEN: | ||
413 | pr_info("Enable clock for CPU#%d\n", cpu); | ||
414 | LOONGSON_CHIPCFG0 |= 1 << (12 + cpu); | ||
415 | break; | ||
416 | } | ||
417 | |||
418 | return NOTIFY_OK; | ||
419 | } | ||
420 | |||
421 | static int register_loongson3_notifier(void) | ||
422 | { | ||
423 | hotcpu_notifier(loongson3_cpu_callback, 0); | ||
424 | return 0; | ||
425 | } | ||
426 | early_initcall(register_loongson3_notifier); | ||
427 | |||
428 | #endif | ||
429 | |||
430 | struct plat_smp_ops loongson3_smp_ops = { | ||
431 | .send_ipi_single = loongson3_send_ipi_single, | ||
432 | .send_ipi_mask = loongson3_send_ipi_mask, | ||
433 | .init_secondary = loongson3_init_secondary, | ||
434 | .smp_finish = loongson3_smp_finish, | ||
435 | .cpus_done = loongson3_cpus_done, | ||
436 | .boot_secondary = loongson3_boot_secondary, | ||
437 | .smp_setup = loongson3_smp_setup, | ||
438 | .prepare_cpus = loongson3_prepare_cpus, | ||
439 | #ifdef CONFIG_HOTPLUG_CPU | ||
440 | .cpu_disable = loongson3_cpu_disable, | ||
441 | .cpu_die = loongson3_cpu_die, | ||
442 | #endif | ||
443 | }; | ||
diff --git a/arch/mips/loongson/loongson-3/smp.h b/arch/mips/loongson/loongson-3/smp.h new file mode 100644 index 000000000000..3453e8c4f2f0 --- /dev/null +++ b/arch/mips/loongson/loongson-3/smp.h | |||
@@ -0,0 +1,29 @@ | |||
1 | #ifndef __LOONGSON_SMP_H_ | ||
2 | #define __LOONGSON_SMP_H_ | ||
3 | |||
4 | /* for Loongson-3A smp support */ | ||
5 | |||
6 | /* 4 groups(nodes) in maximum in numa case */ | ||
7 | #define SMP_CORE_GROUP0_BASE 0x900000003ff01000 | ||
8 | #define SMP_CORE_GROUP1_BASE 0x900010003ff01000 | ||
9 | #define SMP_CORE_GROUP2_BASE 0x900020003ff01000 | ||
10 | #define SMP_CORE_GROUP3_BASE 0x900030003ff01000 | ||
11 | |||
12 | /* 4 cores in each group(node) */ | ||
13 | #define SMP_CORE0_OFFSET 0x000 | ||
14 | #define SMP_CORE1_OFFSET 0x100 | ||
15 | #define SMP_CORE2_OFFSET 0x200 | ||
16 | #define SMP_CORE3_OFFSET 0x300 | ||
17 | |||
18 | /* ipi registers offsets */ | ||
19 | #define STATUS0 0x00 | ||
20 | #define EN0 0x04 | ||
21 | #define SET0 0x08 | ||
22 | #define CLEAR0 0x0c | ||
23 | #define STATUS1 0x10 | ||
24 | #define MASK1 0x14 | ||
25 | #define SET1 0x18 | ||
26 | #define CLEAR1 0x1c | ||
27 | #define BUF 0x20 | ||
28 | |||
29 | #endif | ||