aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/sparc/Kconfig7
-rw-r--r--arch/sparc/Makefile2
-rw-r--r--arch/sparc/include/asm/btext.h6
-rw-r--r--arch/sparc/include/asm/leon.h45
-rw-r--r--arch/sparc/include/asm/rwsem.h4
-rw-r--r--arch/sparc/include/asm/smp_32.h9
-rw-r--r--arch/sparc/kernel/Makefile3
-rw-r--r--arch/sparc/kernel/apc.c37
-rw-r--r--arch/sparc/kernel/auxio_32.c1
-rw-r--r--arch/sparc/kernel/btext.c673
-rw-r--r--arch/sparc/kernel/cpu.c11
-rw-r--r--arch/sparc/kernel/entry.S33
-rw-r--r--arch/sparc/kernel/head_32.S22
-rw-r--r--arch/sparc/kernel/ioport.c5
-rw-r--r--arch/sparc/kernel/irq_64.c8
-rw-r--r--arch/sparc/kernel/leon_kernel.c84
-rw-r--r--arch/sparc/kernel/leon_smp.c468
-rw-r--r--arch/sparc/kernel/pci_msi.c2
-rw-r--r--arch/sparc/kernel/setup_64.c6
-rw-r--r--arch/sparc/kernel/smp_32.c10
-rw-r--r--arch/sparc/kernel/sys_sparc32.c5
-rw-r--r--arch/sparc/kernel/time_32.c3
-rw-r--r--arch/sparc/kernel/trampoline_32.S69
-rw-r--r--arch/sparc/mm/srmmu.c9
-rw-r--r--drivers/serial/Kconfig13
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/apbuart.c710
-rw-r--r--drivers/serial/apbuart.h64
-rw-r--r--drivers/watchdog/riowd.c6
-rw-r--r--include/linux/serial_core.h3
30 files changed, 2262 insertions, 57 deletions
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 05ef5380a687..33ac1a9ac881 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -221,6 +221,13 @@ config SPARC64_SMP
221 default y 221 default y
222 depends on SPARC64 && SMP 222 depends on SPARC64 && SMP
223 223
224config EARLYFB
225 bool "Support for early boot text console"
226 default y
227 depends on SPARC64
228 help
229 Say Y here to enable a faster early framebuffer boot console.
230
224choice 231choice
225 prompt "Kernel page size" if SPARC64 232 prompt "Kernel page size" if SPARC64
226 default SPARC64_PAGE_SIZE_8KB 233 default SPARC64_PAGE_SIZE_8KB
diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile
index dfe272d14465..113225b241e0 100644
--- a/arch/sparc/Makefile
+++ b/arch/sparc/Makefile
@@ -27,6 +27,7 @@ AS := $(AS) -32
27LDFLAGS := -m elf32_sparc 27LDFLAGS := -m elf32_sparc
28CHECKFLAGS += -D__sparc__ 28CHECKFLAGS += -D__sparc__
29export BITS := 32 29export BITS := 32
30UTS_MACHINE := sparc
30 31
31#KBUILD_CFLAGS += -g -pipe -fcall-used-g5 -fcall-used-g7 32#KBUILD_CFLAGS += -g -pipe -fcall-used-g5 -fcall-used-g7
32KBUILD_CFLAGS += -m32 -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7 33KBUILD_CFLAGS += -m32 -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7
@@ -46,6 +47,7 @@ CHECKFLAGS += -D__sparc__ -D__sparc_v9__ -D__arch64__ -m64
46 47
47LDFLAGS := -m elf64_sparc 48LDFLAGS := -m elf64_sparc
48export BITS := 64 49export BITS := 64
50UTS_MACHINE := sparc64
49 51
50KBUILD_CFLAGS += -m64 -pipe -mno-fpu -mcpu=ultrasparc -mcmodel=medlow \ 52KBUILD_CFLAGS += -m64 -pipe -mno-fpu -mcpu=ultrasparc -mcmodel=medlow \
51 -ffixed-g4 -ffixed-g5 -fcall-used-g7 -Wno-sign-compare \ 53 -ffixed-g4 -ffixed-g5 -fcall-used-g7 -Wno-sign-compare \
diff --git a/arch/sparc/include/asm/btext.h b/arch/sparc/include/asm/btext.h
new file mode 100644
index 000000000000..9b2bc6b6ed0a
--- /dev/null
+++ b/arch/sparc/include/asm/btext.h
@@ -0,0 +1,6 @@
1#ifndef _SPARC_BTEXT_H
2#define _SPARC_BTEXT_H
3
4extern int btext_find_display(void);
5
6#endif /* _SPARC_BTEXT_H */
diff --git a/arch/sparc/include/asm/leon.h b/arch/sparc/include/asm/leon.h
index 28a42b73f64f..3ea5964c43b4 100644
--- a/arch/sparc/include/asm/leon.h
+++ b/arch/sparc/include/asm/leon.h
@@ -148,7 +148,7 @@ static inline unsigned long leon_load_reg(unsigned long paddr)
148 return retval; 148 return retval;
149} 149}
150 150
151extern inline void leon_srmmu_disabletlb(void) 151static inline void leon_srmmu_disabletlb(void)
152{ 152{
153 unsigned int retval; 153 unsigned int retval;
154 __asm__ __volatile__("lda [%%g0] %2, %0\n\t" : "=r"(retval) : "r"(0), 154 __asm__ __volatile__("lda [%%g0] %2, %0\n\t" : "=r"(retval) : "r"(0),
@@ -158,7 +158,7 @@ extern inline void leon_srmmu_disabletlb(void)
158 "i"(ASI_LEON_MMUREGS) : "memory"); 158 "i"(ASI_LEON_MMUREGS) : "memory");
159} 159}
160 160
161extern inline void leon_srmmu_enabletlb(void) 161static inline void leon_srmmu_enabletlb(void)
162{ 162{
163 unsigned int retval; 163 unsigned int retval;
164 __asm__ __volatile__("lda [%%g0] %2, %0\n\t" : "=r"(retval) : "r"(0), 164 __asm__ __volatile__("lda [%%g0] %2, %0\n\t" : "=r"(retval) : "r"(0),
@@ -190,7 +190,7 @@ extern void leon_init_IRQ(void);
190 190
191extern unsigned long last_valid_pfn; 191extern unsigned long last_valid_pfn;
192 192
193extern inline unsigned long sparc_leon3_get_dcachecfg(void) 193static inline unsigned long sparc_leon3_get_dcachecfg(void)
194{ 194{
195 unsigned int retval; 195 unsigned int retval;
196 __asm__ __volatile__("lda [%1] %2, %0\n\t" : 196 __asm__ __volatile__("lda [%1] %2, %0\n\t" :
@@ -201,7 +201,7 @@ extern inline unsigned long sparc_leon3_get_dcachecfg(void)
201} 201}
202 202
203/* enable snooping */ 203/* enable snooping */
204extern inline void sparc_leon3_enable_snooping(void) 204static inline void sparc_leon3_enable_snooping(void)
205{ 205{
206 __asm__ __volatile__ ("lda [%%g0] 2, %%l1\n\t" 206 __asm__ __volatile__ ("lda [%%g0] 2, %%l1\n\t"
207 "set 0x800000, %%l2\n\t" 207 "set 0x800000, %%l2\n\t"
@@ -209,7 +209,14 @@ extern inline void sparc_leon3_enable_snooping(void)
209 "sta %%l2, [%%g0] 2\n\t" : : : "l1", "l2"); 209 "sta %%l2, [%%g0] 2\n\t" : : : "l1", "l2");
210}; 210};
211 211
212extern inline void sparc_leon3_disable_cache(void) 212static inline int sparc_leon3_snooping_enabled(void)
213{
214 u32 cctrl;
215 __asm__ __volatile__("lda [%%g0] 2, %0\n\t" : "=r"(cctrl));
216 return (cctrl >> 23) & 1;
217};
218
219static inline void sparc_leon3_disable_cache(void)
213{ 220{
214 __asm__ __volatile__ ("lda [%%g0] 2, %%l1\n\t" 221 __asm__ __volatile__ ("lda [%%g0] 2, %%l1\n\t"
215 "set 0x00000f, %%l2\n\t" 222 "set 0x00000f, %%l2\n\t"
@@ -340,6 +347,30 @@ extern int leon_flush_needed(void);
340extern void leon_switch_mm(void); 347extern void leon_switch_mm(void);
341extern int srmmu_swprobe_trace; 348extern int srmmu_swprobe_trace;
342 349
350#ifdef CONFIG_SMP
351extern int leon_smp_nrcpus(void);
352extern void leon_clear_profile_irq(int cpu);
353extern void leon_smp_done(void);
354extern void leon_boot_cpus(void);
355extern int leon_boot_one_cpu(int i);
356void leon_init_smp(void);
357extern void cpu_probe(void);
358extern void cpu_idle(void);
359extern void init_IRQ(void);
360extern void cpu_panic(void);
361extern int __leon_processor_id(void);
362void leon_enable_irq_cpu(unsigned int irq_nr, unsigned int cpu);
363
364extern unsigned int real_irq_entry[], smpleon_ticker[];
365extern unsigned int patchme_maybe_smp_msg[];
366extern unsigned long trapbase_cpu1[];
367extern unsigned long trapbase_cpu2[];
368extern unsigned long trapbase_cpu3[];
369extern unsigned int t_nmi[], linux_trap_ipi15_leon[];
370extern unsigned int linux_trap_ipi15_sun4m[];
371
372#endif /* CONFIG_SMP */
373
343#endif /* __KERNEL__ */ 374#endif /* __KERNEL__ */
344 375
345#endif /* __ASSEMBLY__ */ 376#endif /* __ASSEMBLY__ */
@@ -356,6 +387,10 @@ extern int srmmu_swprobe_trace;
356#define leon_switch_mm() do {} while (0) 387#define leon_switch_mm() do {} while (0)
357#define leon_init_IRQ() do {} while (0) 388#define leon_init_IRQ() do {} while (0)
358#define init_leon() do {} while (0) 389#define init_leon() do {} while (0)
390#define leon_smp_done() do {} while (0)
391#define leon_boot_cpus() do {} while (0)
392#define leon_boot_one_cpu(i) 1
393#define leon_init_smp() do {} while (0)
359 394
360#endif /* !defined(CONFIG_SPARC_LEON) */ 395#endif /* !defined(CONFIG_SPARC_LEON) */
361 396
diff --git a/arch/sparc/include/asm/rwsem.h b/arch/sparc/include/asm/rwsem.h
index 1dc129ac2feb..6e5621006f85 100644
--- a/arch/sparc/include/asm/rwsem.h
+++ b/arch/sparc/include/asm/rwsem.h
@@ -35,8 +35,8 @@ struct rw_semaphore {
35#endif 35#endif
36 36
37#define __RWSEM_INITIALIZER(name) \ 37#define __RWSEM_INITIALIZER(name) \
38{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) \ 38{ RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED((name).wait_lock), \
39 __RWSEM_DEP_MAP_INIT(name) } 39 LIST_HEAD_INIT((name).wait_list) __RWSEM_DEP_MAP_INIT(name) }
40 40
41#define DECLARE_RWSEM(name) \ 41#define DECLARE_RWSEM(name) \
42 struct rw_semaphore name = __RWSEM_INITIALIZER(name) 42 struct rw_semaphore name = __RWSEM_INITIALIZER(name)
diff --git a/arch/sparc/include/asm/smp_32.h b/arch/sparc/include/asm/smp_32.h
index 58101dc70493..841905c10215 100644
--- a/arch/sparc/include/asm/smp_32.h
+++ b/arch/sparc/include/asm/smp_32.h
@@ -106,6 +106,15 @@ static inline int hard_smp4d_processor_id(void)
106 return cpuid; 106 return cpuid;
107} 107}
108 108
109extern inline int hard_smpleon_processor_id(void)
110{
111 int cpuid;
112 __asm__ __volatile__("rd %%asr17,%0\n\t"
113 "srl %0,28,%0" :
114 "=&r" (cpuid) : );
115 return cpuid;
116}
117
109#ifndef MODULE 118#ifndef MODULE
110static inline int hard_smp_processor_id(void) 119static inline int hard_smp_processor_id(void)
111{ 120{
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index 5b47fab9966e..c6316142db4e 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -72,7 +72,7 @@ obj-y += dma.o
72obj-$(CONFIG_SPARC32_PCI) += pcic.o 72obj-$(CONFIG_SPARC32_PCI) += pcic.o
73 73
74obj-$(CONFIG_SMP) += trampoline_$(BITS).o smp_$(BITS).o 74obj-$(CONFIG_SMP) += trampoline_$(BITS).o smp_$(BITS).o
75obj-$(CONFIG_SPARC32_SMP) += sun4m_smp.o sun4d_smp.o 75obj-$(CONFIG_SPARC32_SMP) += sun4m_smp.o sun4d_smp.o leon_smp.o
76obj-$(CONFIG_SPARC64_SMP) += hvtramp.o 76obj-$(CONFIG_SPARC64_SMP) += hvtramp.o
77 77
78obj-y += auxio_$(BITS).o 78obj-y += auxio_$(BITS).o
@@ -87,6 +87,7 @@ obj-$(CONFIG_KGDB) += kgdb_$(BITS).o
87obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o 87obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
88CFLAGS_REMOVE_ftrace.o := -pg 88CFLAGS_REMOVE_ftrace.o := -pg
89 89
90obj-$(CONFIG_EARLYFB) += btext.o
90obj-$(CONFIG_STACKTRACE) += stacktrace.o 91obj-$(CONFIG_STACKTRACE) += stacktrace.o
91# sparc64 PCI 92# sparc64 PCI
92obj-$(CONFIG_SPARC64_PCI) += pci.o pci_common.o psycho_common.o 93obj-$(CONFIG_SPARC64_PCI) += pci.o pci_common.o psycho_common.o
diff --git a/arch/sparc/kernel/apc.c b/arch/sparc/kernel/apc.c
index 9c115823c4b5..71ec90b9e316 100644
--- a/arch/sparc/kernel/apc.c
+++ b/arch/sparc/kernel/apc.c
@@ -10,7 +10,6 @@
10#include <linux/errno.h> 10#include <linux/errno.h>
11#include <linux/init.h> 11#include <linux/init.h>
12#include <linux/miscdevice.h> 12#include <linux/miscdevice.h>
13#include <linux/smp_lock.h>
14#include <linux/pm.h> 13#include <linux/pm.h>
15#include <linux/of.h> 14#include <linux/of.h>
16#include <linux/of_device.h> 15#include <linux/of_device.h>
@@ -76,7 +75,6 @@ static inline void apc_free(struct of_device *op)
76 75
77static int apc_open(struct inode *inode, struct file *f) 76static int apc_open(struct inode *inode, struct file *f)
78{ 77{
79 cycle_kernel_lock();
80 return 0; 78 return 0;
81} 79}
82 80
@@ -87,61 +85,46 @@ static int apc_release(struct inode *inode, struct file *f)
87 85
88static long apc_ioctl(struct file *f, unsigned int cmd, unsigned long __arg) 86static long apc_ioctl(struct file *f, unsigned int cmd, unsigned long __arg)
89{ 87{
90 __u8 inarg, __user *arg; 88 __u8 inarg, __user *arg = (__u8 __user *) __arg;
91
92 arg = (__u8 __user *) __arg;
93
94 lock_kernel();
95 89
96 switch (cmd) { 90 switch (cmd) {
97 case APCIOCGFANCTL: 91 case APCIOCGFANCTL:
98 if (put_user(apc_readb(APC_FANCTL_REG) & APC_REGMASK, arg)) { 92 if (put_user(apc_readb(APC_FANCTL_REG) & APC_REGMASK, arg))
99 unlock_kernel();
100 return -EFAULT; 93 return -EFAULT;
101 }
102 break; 94 break;
103 95
104 case APCIOCGCPWR: 96 case APCIOCGCPWR:
105 if (put_user(apc_readb(APC_CPOWER_REG) & APC_REGMASK, arg)) { 97 if (put_user(apc_readb(APC_CPOWER_REG) & APC_REGMASK, arg))
106 unlock_kernel();
107 return -EFAULT; 98 return -EFAULT;
108 }
109 break; 99 break;
110 100
111 case APCIOCGBPORT: 101 case APCIOCGBPORT:
112 if (put_user(apc_readb(APC_BPORT_REG) & APC_BPMASK, arg)) { 102 if (put_user(apc_readb(APC_BPORT_REG) & APC_BPMASK, arg))
113 unlock_kernel();
114 return -EFAULT; 103 return -EFAULT;
115 }
116 break; 104 break;
117 105
118 case APCIOCSFANCTL: 106 case APCIOCSFANCTL:
119 if (get_user(inarg, arg)) { 107 if (get_user(inarg, arg))
120 unlock_kernel();
121 return -EFAULT; 108 return -EFAULT;
122 }
123 apc_writeb(inarg & APC_REGMASK, APC_FANCTL_REG); 109 apc_writeb(inarg & APC_REGMASK, APC_FANCTL_REG);
124 break; 110 break;
111
125 case APCIOCSCPWR: 112 case APCIOCSCPWR:
126 if (get_user(inarg, arg)) { 113 if (get_user(inarg, arg))
127 unlock_kernel();
128 return -EFAULT; 114 return -EFAULT;
129 }
130 apc_writeb(inarg & APC_REGMASK, APC_CPOWER_REG); 115 apc_writeb(inarg & APC_REGMASK, APC_CPOWER_REG);
131 break; 116 break;
117
132 case APCIOCSBPORT: 118 case APCIOCSBPORT:
133 if (get_user(inarg, arg)) { 119 if (get_user(inarg, arg))
134 unlock_kernel();
135 return -EFAULT; 120 return -EFAULT;
136 }
137 apc_writeb(inarg & APC_BPMASK, APC_BPORT_REG); 121 apc_writeb(inarg & APC_BPMASK, APC_BPORT_REG);
138 break; 122 break;
123
139 default: 124 default:
140 unlock_kernel();
141 return -EINVAL; 125 return -EINVAL;
142 }; 126 };
143 127
144 unlock_kernel();
145 return 0; 128 return 0;
146} 129}
147 130
diff --git a/arch/sparc/kernel/auxio_32.c b/arch/sparc/kernel/auxio_32.c
index 45c41232fc4c..ee8d214cae1e 100644
--- a/arch/sparc/kernel/auxio_32.c
+++ b/arch/sparc/kernel/auxio_32.c
@@ -28,6 +28,7 @@ void __init auxio_probe(void)
28 struct resource r; 28 struct resource r;
29 29
30 switch (sparc_cpu_model) { 30 switch (sparc_cpu_model) {
31 case sparc_leon:
31 case sun4d: 32 case sun4d:
32 case sun4: 33 case sun4:
33 return; 34 return;
diff --git a/arch/sparc/kernel/btext.c b/arch/sparc/kernel/btext.c
new file mode 100644
index 000000000000..8cc2d56ffe9a
--- /dev/null
+++ b/arch/sparc/kernel/btext.c
@@ -0,0 +1,673 @@
1/*
2 * Procedures for drawing on the screen early on in the boot process.
3 *
4 * Benjamin Herrenschmidt <benh@kernel.crashing.org>
5 */
6#include <linux/kernel.h>
7#include <linux/string.h>
8#include <linux/init.h>
9#include <linux/module.h>
10#include <linux/console.h>
11
12#include <asm/btext.h>
13#include <asm/oplib.h>
14#include <asm/io.h>
15
16#define NO_SCROLL
17
18#ifndef NO_SCROLL
19static void scrollscreen(void);
20#endif
21
22static void draw_byte(unsigned char c, long locX, long locY);
23static void draw_byte_32(unsigned char *bits, unsigned int *base, int rb);
24static void draw_byte_16(unsigned char *bits, unsigned int *base, int rb);
25static void draw_byte_8(unsigned char *bits, unsigned int *base, int rb);
26
27#define __force_data __attribute__((__section__(".data")))
28
29static int g_loc_X __force_data;
30static int g_loc_Y __force_data;
31static int g_max_loc_X __force_data;
32static int g_max_loc_Y __force_data;
33
34static int dispDeviceRowBytes __force_data;
35static int dispDeviceDepth __force_data;
36static int dispDeviceRect[4] __force_data;
37static unsigned char *dispDeviceBase __force_data;
38
39#define cmapsz (16*256)
40
41static unsigned char vga_font[cmapsz];
42
43static int __init btext_initialize(unsigned int node)
44{
45 unsigned int width, height, depth, pitch;
46 unsigned long address = 0;
47 u32 prop;
48
49 if (prom_getproperty(node, "width", (char *)&width, 4) < 0)
50 return -EINVAL;
51 if (prom_getproperty(node, "height", (char *)&height, 4) < 0)
52 return -EINVAL;
53 if (prom_getproperty(node, "depth", (char *)&depth, 4) < 0)
54 return -EINVAL;
55 pitch = width * ((depth + 7) / 8);
56
57 if (prom_getproperty(node, "linebytes", (char *)&prop, 4) >= 0 &&
58 prop != 0xffffffffu)
59 pitch = prop;
60
61 if (pitch == 1)
62 pitch = 0x1000;
63
64 if (prom_getproperty(node, "address", (char *)&prop, 4) >= 0)
65 address = prop;
66
67 /* FIXME: Add support for PCI reg properties. Right now, only
68 * reliable on macs
69 */
70 if (address == 0)
71 return -EINVAL;
72
73 g_loc_X = 0;
74 g_loc_Y = 0;
75 g_max_loc_X = width / 8;
76 g_max_loc_Y = height / 16;
77 dispDeviceBase = (unsigned char *)address;
78 dispDeviceRowBytes = pitch;
79 dispDeviceDepth = depth == 15 ? 16 : depth;
80 dispDeviceRect[0] = dispDeviceRect[1] = 0;
81 dispDeviceRect[2] = width;
82 dispDeviceRect[3] = height;
83
84 return 0;
85}
86
87/* Calc the base address of a given point (x,y) */
88static unsigned char * calc_base(int x, int y)
89{
90 unsigned char *base = dispDeviceBase;
91
92 base += (x + dispDeviceRect[0]) * (dispDeviceDepth >> 3);
93 base += (y + dispDeviceRect[1]) * dispDeviceRowBytes;
94 return base;
95}
96
97static void btext_clearscreen(void)
98{
99 unsigned int *base = (unsigned int *)calc_base(0, 0);
100 unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) *
101 (dispDeviceDepth >> 3)) >> 2;
102 int i,j;
103
104 for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1]); i++)
105 {
106 unsigned int *ptr = base;
107 for(j=width; j; --j)
108 *(ptr++) = 0;
109 base += (dispDeviceRowBytes >> 2);
110 }
111}
112
113#ifndef NO_SCROLL
114static void scrollscreen(void)
115{
116 unsigned int *src = (unsigned int *)calc_base(0,16);
117 unsigned int *dst = (unsigned int *)calc_base(0,0);
118 unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) *
119 (dispDeviceDepth >> 3)) >> 2;
120 int i,j;
121
122 for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1] - 16); i++)
123 {
124 unsigned int *src_ptr = src;
125 unsigned int *dst_ptr = dst;
126 for(j=width; j; --j)
127 *(dst_ptr++) = *(src_ptr++);
128 src += (dispDeviceRowBytes >> 2);
129 dst += (dispDeviceRowBytes >> 2);
130 }
131 for (i=0; i<16; i++)
132 {
133 unsigned int *dst_ptr = dst;
134 for(j=width; j; --j)
135 *(dst_ptr++) = 0;
136 dst += (dispDeviceRowBytes >> 2);
137 }
138}
139#endif /* ndef NO_SCROLL */
140
141void btext_drawchar(char c)
142{
143 int cline = 0;
144#ifdef NO_SCROLL
145 int x;
146#endif
147 switch (c) {
148 case '\b':
149 if (g_loc_X > 0)
150 --g_loc_X;
151 break;
152 case '\t':
153 g_loc_X = (g_loc_X & -8) + 8;
154 break;
155 case '\r':
156 g_loc_X = 0;
157 break;
158 case '\n':
159 g_loc_X = 0;
160 g_loc_Y++;
161 cline = 1;
162 break;
163 default:
164 draw_byte(c, g_loc_X++, g_loc_Y);
165 }
166 if (g_loc_X >= g_max_loc_X) {
167 g_loc_X = 0;
168 g_loc_Y++;
169 cline = 1;
170 }
171#ifndef NO_SCROLL
172 while (g_loc_Y >= g_max_loc_Y) {
173 scrollscreen();
174 g_loc_Y--;
175 }
176#else
177 /* wrap around from bottom to top of screen so we don't
178 waste time scrolling each line. -- paulus. */
179 if (g_loc_Y >= g_max_loc_Y)
180 g_loc_Y = 0;
181 if (cline) {
182 for (x = 0; x < g_max_loc_X; ++x)
183 draw_byte(' ', x, g_loc_Y);
184 }
185#endif
186}
187
188static void btext_drawtext(const char *c, unsigned int len)
189{
190 while (len--)
191 btext_drawchar(*c++);
192}
193
194static void draw_byte(unsigned char c, long locX, long locY)
195{
196 unsigned char *base = calc_base(locX << 3, locY << 4);
197 unsigned char *font = &vga_font[((unsigned int)c) * 16];
198 int rb = dispDeviceRowBytes;
199
200 switch(dispDeviceDepth) {
201 case 24:
202 case 32:
203 draw_byte_32(font, (unsigned int *)base, rb);
204 break;
205 case 15:
206 case 16:
207 draw_byte_16(font, (unsigned int *)base, rb);
208 break;
209 case 8:
210 draw_byte_8(font, (unsigned int *)base, rb);
211 break;
212 }
213}
214
215static unsigned int expand_bits_8[16] = {
216 0x00000000,
217 0x000000ff,
218 0x0000ff00,
219 0x0000ffff,
220 0x00ff0000,
221 0x00ff00ff,
222 0x00ffff00,
223 0x00ffffff,
224 0xff000000,
225 0xff0000ff,
226 0xff00ff00,
227 0xff00ffff,
228 0xffff0000,
229 0xffff00ff,
230 0xffffff00,
231 0xffffffff
232};
233
234static unsigned int expand_bits_16[4] = {
235 0x00000000,
236 0x0000ffff,
237 0xffff0000,
238 0xffffffff
239};
240
241
242static void draw_byte_32(unsigned char *font, unsigned int *base, int rb)
243{
244 int l, bits;
245 int fg = 0xFFFFFFFFUL;
246 int bg = 0x00000000UL;
247
248 for (l = 0; l < 16; ++l)
249 {
250 bits = *font++;
251 base[0] = (-(bits >> 7) & fg) ^ bg;
252 base[1] = (-((bits >> 6) & 1) & fg) ^ bg;
253 base[2] = (-((bits >> 5) & 1) & fg) ^ bg;
254 base[3] = (-((bits >> 4) & 1) & fg) ^ bg;
255 base[4] = (-((bits >> 3) & 1) & fg) ^ bg;
256 base[5] = (-((bits >> 2) & 1) & fg) ^ bg;
257 base[6] = (-((bits >> 1) & 1) & fg) ^ bg;
258 base[7] = (-(bits & 1) & fg) ^ bg;
259 base = (unsigned int *) ((char *)base + rb);
260 }
261}
262
263static void draw_byte_16(unsigned char *font, unsigned int *base, int rb)
264{
265 int l, bits;
266 int fg = 0xFFFFFFFFUL;
267 int bg = 0x00000000UL;
268 unsigned int *eb = (int *)expand_bits_16;
269
270 for (l = 0; l < 16; ++l)
271 {
272 bits = *font++;
273 base[0] = (eb[bits >> 6] & fg) ^ bg;
274 base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg;
275 base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg;
276 base[3] = (eb[bits & 3] & fg) ^ bg;
277 base = (unsigned int *) ((char *)base + rb);
278 }
279}
280
281static void draw_byte_8(unsigned char *font, unsigned int *base, int rb)
282{
283 int l, bits;
284 int fg = 0x0F0F0F0FUL;
285 int bg = 0x00000000UL;
286 unsigned int *eb = (int *)expand_bits_8;
287
288 for (l = 0; l < 16; ++l)
289 {
290 bits = *font++;
291 base[0] = (eb[bits >> 4] & fg) ^ bg;
292 base[1] = (eb[bits & 0xf] & fg) ^ bg;
293 base = (unsigned int *) ((char *)base + rb);
294 }
295}
296
297static void btext_console_write(struct console *con, const char *s,
298 unsigned int n)
299{
300 btext_drawtext(s, n);
301}
302
303static struct console btext_console = {
304 .name = "btext",
305 .write = btext_console_write,
306 .flags = CON_PRINTBUFFER | CON_ENABLED | CON_BOOT | CON_ANYTIME,
307 .index = 0,
308};
309
310int __init btext_find_display(void)
311{
312 unsigned int node;
313 char type[32];
314 int ret;
315
316 node = prom_inst2pkg(prom_stdout);
317 if (prom_getproperty(node, "device_type", type, 32) < 0)
318 return -ENODEV;
319 if (strcmp(type, "display"))
320 return -ENODEV;
321
322 ret = btext_initialize(node);
323 if (!ret) {
324 btext_clearscreen();
325 register_console(&btext_console);
326 }
327 return ret;
328}
329
330static unsigned char vga_font[cmapsz] = {
3310x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3320x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd,
3330x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff,
3340xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00,
3350x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10,
3360x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe,
3370x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
3380x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
3390x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c,
3400x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c,
3410x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
3420xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
3430x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
3440x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd,
3450xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e,
3460x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
3470x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18,
3480x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30,
3490x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63,
3500x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00,
3510x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18,
3520x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8,
3530xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e,
3540x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
3550x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
3560x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
3570x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb,
3580xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00,
3590x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6,
3600x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3610xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c,
3620x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
3630x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
3640x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
3650x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3660x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3670x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
3680x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0,
3690xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3700x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3710x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00,
3720x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c,
3730x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3740x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3750x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,
3760x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00,
3770x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c,
3780x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
3790x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c,
3800x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18,
3810x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
3820x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
3830x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3840x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30,
3850x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18,
3860x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
3870x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
3880x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e,
3890x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3900x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
3910x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
3920x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3930x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3940x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
3950x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c,
3960x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18,
3970x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
3980x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
3990x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c,
4000x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe,
4010x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0,
4020xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
4030x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
4040x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18,
4050x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
4060xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
4070x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78,
4080x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
4090x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4100x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
4110x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06,
4120x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
4130x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
4140x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
4150x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,
4160x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde,
4170xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38,
4180x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
4190x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc,
4200x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0,
4210xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c,
4220x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00,
4230x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe,
4240x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68,
4250x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66,
4260xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00,
4270x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
4280x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18,
4290x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c,
4300x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
4310x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6,
4320x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60,
4330x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7,
4340xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
4350x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6,
4360x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
4370xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66,
4380x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
4390x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c,
4400x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c,
4410x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
4420xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
4430x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
4440x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
4450xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3,
4460xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
4470x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66,
4480x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18,
4490x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3,
4500xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
4510x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff,
4520x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30,
4530x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
4540xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
4550x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c,
4560x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
4570x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4580x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
4590x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4600x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c,
4610xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60,
4620x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00,
4630x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c,
4640x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc,
4650xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4660x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
4670x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0,
4680x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc,
4690xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60,
4700x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
4710x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
4720x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06,
4730x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60,
4740x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
4750x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
4760x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb,
4770xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4780x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
4790x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
4800x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66,
4810x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
4820x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
4830x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0,
4840x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60,
4850x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30,
4860x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,
4870x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76,
4880x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3,
4890xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4900x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00,
4910x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3,
4920x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6,
4930xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00,
4940x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
4950x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e,
4960x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18,
4970x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18,
4980x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
4990x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5000x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6,
5010xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66,
5020xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00,
5030x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76,
5040x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe,
5050xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c,
5060x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
5070x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76,
5080x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c,
5090xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38,
5100x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
5110x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06,
5120x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe,
5130xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00,
5140x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
5150x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c,
5160x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18,
5170x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66,
5180x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
5190x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
5200x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6,
5210xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00,
5220x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
5230x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe,
5240x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b,
5250x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c,
5260xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00,
5270x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
5280x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6,
5290xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18,
5300x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
5310x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76,
5320x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc,
5330xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00,
5340x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
5350x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
5360x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
5370xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e,
5380xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
5390x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc,
5400x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18,
5410xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66,
5420x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00,
5430x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18,
5440xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c,
5450xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30,
5460x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
5470x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
5480x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc,
5490xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc,
5500x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
5510x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6,
5520x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00,
5530x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c,
5540x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5550x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c,
5560x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0,
5570xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5580x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
5590x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06,
5600x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30,
5610x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18,
5620x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
5630x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00,
5640x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36,
5650x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44,
5660x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
5670x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
5680x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
5690xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18,
5700x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
5710x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18,
5720x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8,
5730x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
5740x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
5750x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36,
5760x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8,
5770x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
5780x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
5790x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
5800x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6,
5810x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
5820x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5830x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00,
5840x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8,
5850x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5860x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
5870x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00,
5880x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff,
5890x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5900x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
5910x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
5920x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
5930x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
5940x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
5950x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
5960x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37,
5970x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
5980x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5990x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
6000x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff,
6010x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6020x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
6030x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
6040x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
6050x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36,
6060x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
6070x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
6080x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff,
6090x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6100x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
6110x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36,
6120x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f,
6130x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
6140x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6150x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
6160x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
6170x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
6180x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
6190x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18,
6200x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8,
6210x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6220x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
6230xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
6240xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
6250xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0,
6260xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
6270x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
6280x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
6290x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6300x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00,
6310x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc,
6320x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0,
6330xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6340xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
6350x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe,
6360x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8,
6370xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6380x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00,
6390x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
6400x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66,
6410x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38,
6420x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
6430x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee,
6440x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66,
6450x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6460x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6470x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0,
6480x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60,
6490x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
6500xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
6510x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00,
6520x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18,
6530x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
6540x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
6550x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e,
6560x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18,
6570x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
6580x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
6590x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00,
6600x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00,
6610x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c,
6620x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6630x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
6640x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6650x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c,
6660x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00,
6670x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
6680x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00,
6690x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6700x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
6710x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6720x00, 0x00, 0x00, 0x00,
673};
diff --git a/arch/sparc/kernel/cpu.c b/arch/sparc/kernel/cpu.c
index 1446df90ef85..e447938d39cf 100644
--- a/arch/sparc/kernel/cpu.c
+++ b/arch/sparc/kernel/cpu.c
@@ -185,6 +185,17 @@ static const struct manufacturer_info __initconst manufacturer_info[] = {
185 FPU(-1, NULL) 185 FPU(-1, NULL)
186 } 186 }
187},{ 187},{
188 0xF, /* Aeroflex Gaisler */
189 .cpu_info = {
190 CPU(3, "LEON"),
191 CPU(-1, NULL)
192 },
193 .fpu_info = {
194 FPU(2, "GRFPU"),
195 FPU(3, "GRFPU-Lite"),
196 FPU(-1, NULL)
197 }
198},{
188 0x17, 199 0x17,
189 .cpu_info = { 200 .cpu_info = {
190 CPU_PMU(0x10, "TI UltraSparc I (SpitFire)", "ultra12"), 201 CPU_PMU(0x10, "TI UltraSparc I (SpitFire)", "ultra12"),
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
index f41ecc5ac0b4..ec9c7bc67d21 100644
--- a/arch/sparc/kernel/entry.S
+++ b/arch/sparc/kernel/entry.S
@@ -400,6 +400,39 @@ linux_trap_ipi15_sun4d:
400 /* FIXME */ 400 /* FIXME */
4011: b,a 1b 4011: b,a 1b
402 402
403#ifdef CONFIG_SPARC_LEON
404
405 .globl smpleon_ticker
406 /* SMP per-cpu ticker interrupts are handled specially. */
407smpleon_ticker:
408 SAVE_ALL
409 or %l0, PSR_PIL, %g2
410 wr %g2, 0x0, %psr
411 WRITE_PAUSE
412 wr %g2, PSR_ET, %psr
413 WRITE_PAUSE
414 call leon_percpu_timer_interrupt
415 add %sp, STACKFRAME_SZ, %o0
416 wr %l0, PSR_ET, %psr
417 WRITE_PAUSE
418 RESTORE_ALL
419
420 .align 4
421 .globl linux_trap_ipi15_leon
422linux_trap_ipi15_leon:
423 SAVE_ALL
424 or %l0, PSR_PIL, %l4
425 wr %l4, 0x0, %psr
426 WRITE_PAUSE
427 wr %l4, PSR_ET, %psr
428 WRITE_PAUSE
429 call leon_cross_call_irq
430 nop
431 b ret_trap_lockless_ipi
432 clr %l6
433
434#endif /* CONFIG_SPARC_LEON */
435
403#endif /* CONFIG_SMP */ 436#endif /* CONFIG_SMP */
404 437
405 /* This routine handles illegal instructions and privileged 438 /* This routine handles illegal instructions and privileged
diff --git a/arch/sparc/kernel/head_32.S b/arch/sparc/kernel/head_32.S
index 439d82a95ac9..21bb2590d4ae 100644
--- a/arch/sparc/kernel/head_32.S
+++ b/arch/sparc/kernel/head_32.S
@@ -811,9 +811,31 @@ found_version:
811got_prop: 811got_prop:
812#ifdef CONFIG_SPARC_LEON 812#ifdef CONFIG_SPARC_LEON
813 /* no cpu-type check is needed, it is a SPARC-LEON */ 813 /* no cpu-type check is needed, it is a SPARC-LEON */
814#ifdef CONFIG_SMP
815 ba leon_smp_init
816 nop
817
818 .global leon_smp_init
819leon_smp_init:
820 sethi %hi(boot_cpu_id), %g1 ! master always 0
821 stb %g0, [%g1 + %lo(boot_cpu_id)]
822 sethi %hi(boot_cpu_id4), %g1 ! master always 0
823 stb %g0, [%g1 + %lo(boot_cpu_id4)]
824
825 rd %asr17,%g1
826 srl %g1,28,%g1
827
828 cmp %g0,%g1
829 beq sun4c_continue_boot !continue with master
830 nop
831
832 ba leon_smp_cpu_startup
833 nop
834#else
814 ba sun4c_continue_boot 835 ba sun4c_continue_boot
815 nop 836 nop
816#endif 837#endif
838#endif
817 set cputypval, %o2 839 set cputypval, %o2
818 ldub [%o2 + 0x4], %l1 840 ldub [%o2 + 0x4], %l1
819 841
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
index 9f61fd8cbb7b..3c8c44f6a41c 100644
--- a/arch/sparc/kernel/ioport.c
+++ b/arch/sparc/kernel/ioport.c
@@ -48,8 +48,13 @@
48#include <asm/dma.h> 48#include <asm/dma.h>
49#include <asm/iommu.h> 49#include <asm/iommu.h>
50#include <asm/io-unit.h> 50#include <asm/io-unit.h>
51#include <asm/leon.h>
51 52
53#ifdef CONFIG_SPARC_LEON
54#define mmu_inval_dma_area(p, l) leon_flush_dcache_all()
55#else
52#define mmu_inval_dma_area(p, l) /* Anton pulled it out for 2.4.0-xx */ 56#define mmu_inval_dma_area(p, l) /* Anton pulled it out for 2.4.0-xx */
57#endif
53 58
54static struct resource *_sparc_find_resource(struct resource *r, 59static struct resource *_sparc_find_resource(struct resource *r,
55 unsigned long); 60 unsigned long);
diff --git a/arch/sparc/kernel/irq_64.c b/arch/sparc/kernel/irq_64.c
index 8ab1d4728a4b..ce996f97855f 100644
--- a/arch/sparc/kernel/irq_64.c
+++ b/arch/sparc/kernel/irq_64.c
@@ -187,7 +187,7 @@ int show_interrupts(struct seq_file *p, void *v)
187 for_each_online_cpu(j) 187 for_each_online_cpu(j)
188 seq_printf(p, "%10u ", kstat_irqs_cpu(i, j)); 188 seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
189#endif 189#endif
190 seq_printf(p, " %9s", irq_desc[i].chip->typename); 190 seq_printf(p, " %9s", irq_desc[i].chip->name);
191 seq_printf(p, " %s", action->name); 191 seq_printf(p, " %s", action->name);
192 192
193 for (action=action->next; action; action = action->next) 193 for (action=action->next; action; action = action->next)
@@ -484,7 +484,7 @@ static void sun4v_virq_eoi(unsigned int virt_irq)
484} 484}
485 485
486static struct irq_chip sun4u_irq = { 486static struct irq_chip sun4u_irq = {
487 .typename = "sun4u", 487 .name = "sun4u",
488 .enable = sun4u_irq_enable, 488 .enable = sun4u_irq_enable,
489 .disable = sun4u_irq_disable, 489 .disable = sun4u_irq_disable,
490 .eoi = sun4u_irq_eoi, 490 .eoi = sun4u_irq_eoi,
@@ -492,7 +492,7 @@ static struct irq_chip sun4u_irq = {
492}; 492};
493 493
494static struct irq_chip sun4v_irq = { 494static struct irq_chip sun4v_irq = {
495 .typename = "sun4v", 495 .name = "sun4v",
496 .enable = sun4v_irq_enable, 496 .enable = sun4v_irq_enable,
497 .disable = sun4v_irq_disable, 497 .disable = sun4v_irq_disable,
498 .eoi = sun4v_irq_eoi, 498 .eoi = sun4v_irq_eoi,
@@ -500,7 +500,7 @@ static struct irq_chip sun4v_irq = {
500}; 500};
501 501
502static struct irq_chip sun4v_virq = { 502static struct irq_chip sun4v_virq = {
503 .typename = "vsun4v", 503 .name = "vsun4v",
504 .enable = sun4v_virq_enable, 504 .enable = sun4v_virq_enable,
505 .disable = sun4v_virq_disable, 505 .disable = sun4v_virq_disable,
506 .eoi = sun4v_virq_eoi, 506 .eoi = sun4v_virq_eoi,
diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c
index 54d8a5bd4824..87f1760c0aa2 100644
--- a/arch/sparc/kernel/leon_kernel.c
+++ b/arch/sparc/kernel/leon_kernel.c
@@ -12,11 +12,14 @@
12#include <linux/of_platform.h> 12#include <linux/of_platform.h>
13#include <linux/interrupt.h> 13#include <linux/interrupt.h>
14#include <linux/of_device.h> 14#include <linux/of_device.h>
15
15#include <asm/oplib.h> 16#include <asm/oplib.h>
16#include <asm/timer.h> 17#include <asm/timer.h>
17#include <asm/prom.h> 18#include <asm/prom.h>
18#include <asm/leon.h> 19#include <asm/leon.h>
19#include <asm/leon_amba.h> 20#include <asm/leon_amba.h>
21#include <asm/traps.h>
22#include <asm/cacheflush.h>
20 23
21#include "prom.h" 24#include "prom.h"
22#include "irq.h" 25#include "irq.h"
@@ -115,6 +118,21 @@ void __init leon_init_timers(irq_handler_t counter_fn)
115 (((1000000 / 100) - 1))); 118 (((1000000 / 100) - 1)));
116 LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].ctrl, 0); 119 LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].ctrl, 0);
117 120
121#ifdef CONFIG_SMP
122 leon_percpu_timer_dev[0].start = (int)leon3_gptimer_regs;
123 leon_percpu_timer_dev[0].irq = leon3_gptimer_irq+1;
124
125 if (!(LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->config) &
126 (1<<LEON3_GPTIMER_SEPIRQ))) {
127 prom_printf("irq timer not configured with seperate irqs \n");
128 BUG();
129 }
130
131 LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].val, 0);
132 LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].rld, (((1000000/100) - 1)));
133 LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].ctrl, 0);
134# endif
135
118 } else { 136 } else {
119 printk(KERN_ERR "No Timer/irqctrl found\n"); 137 printk(KERN_ERR "No Timer/irqctrl found\n");
120 BUG(); 138 BUG();
@@ -130,11 +148,41 @@ void __init leon_init_timers(irq_handler_t counter_fn)
130 prom_halt(); 148 prom_halt();
131 } 149 }
132 150
151# ifdef CONFIG_SMP
152 {
153 unsigned long flags;
154 struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (leon_percpu_timer_dev[0].irq - 1)];
155
156 /* For SMP we use the level 14 ticker, however the bootup code
157 * has copied the firmwares level 14 vector into boot cpu's
158 * trap table, we must fix this now or we get squashed.
159 */
160 local_irq_save(flags);
161
162 patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
163
164 /* Adjust so that we jump directly to smpleon_ticker */
165 trap_table->inst_three += smpleon_ticker - real_irq_entry;
166
167 local_flush_cache_all();
168 local_irq_restore(flags);
169 }
170# endif
171
133 if (leon3_gptimer_regs) { 172 if (leon3_gptimer_regs) {
134 LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].ctrl, 173 LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].ctrl,
135 LEON3_GPTIMER_EN | 174 LEON3_GPTIMER_EN |
136 LEON3_GPTIMER_RL | 175 LEON3_GPTIMER_RL |
137 LEON3_GPTIMER_LD | LEON3_GPTIMER_IRQEN); 176 LEON3_GPTIMER_LD | LEON3_GPTIMER_IRQEN);
177
178#ifdef CONFIG_SMP
179 LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].ctrl,
180 LEON3_GPTIMER_EN |
181 LEON3_GPTIMER_RL |
182 LEON3_GPTIMER_LD |
183 LEON3_GPTIMER_IRQEN);
184#endif
185
138 } 186 }
139} 187}
140 188
@@ -175,6 +223,42 @@ void __init leon_node_init(struct device_node *dp, struct device_node ***nextp)
175 } 223 }
176} 224}
177 225
226#ifdef CONFIG_SMP
227
228void leon_set_cpu_int(int cpu, int level)
229{
230 unsigned long mask;
231 mask = get_irqmask(level);
232 LEON3_BYPASS_STORE_PA(&leon3_irqctrl_regs->force[cpu], mask);
233}
234
235static void leon_clear_ipi(int cpu, int level)
236{
237 unsigned long mask;
238 mask = get_irqmask(level);
239 LEON3_BYPASS_STORE_PA(&leon3_irqctrl_regs->force[cpu], mask<<16);
240}
241
242static void leon_set_udt(int cpu)
243{
244}
245
246void leon_clear_profile_irq(int cpu)
247{
248}
249
250void leon_enable_irq_cpu(unsigned int irq_nr, unsigned int cpu)
251{
252 unsigned long mask, flags, *addr;
253 mask = get_irqmask(irq_nr);
254 local_irq_save(flags);
255 addr = (unsigned long *)&(leon3_irqctrl_regs->mask[cpu]);
256 LEON3_BYPASS_STORE_PA(addr, (LEON3_BYPASS_LOAD_PA(addr) | (mask)));
257 local_irq_restore(flags);
258}
259
260#endif
261
178void __init leon_init_IRQ(void) 262void __init leon_init_IRQ(void)
179{ 263{
180 sparc_init_timers = leon_init_timers; 264 sparc_init_timers = leon_init_timers;
diff --git a/arch/sparc/kernel/leon_smp.c b/arch/sparc/kernel/leon_smp.c
new file mode 100644
index 000000000000..05c0dadd6371
--- /dev/null
+++ b/arch/sparc/kernel/leon_smp.c
@@ -0,0 +1,468 @@
1/* leon_smp.c: Sparc-Leon SMP support.
2 *
3 * based on sun4m_smp.c
4 * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
5 * Copyright (C) 2009 Daniel Hellstrom (daniel@gaisler.com) Aeroflex Gaisler AB
6 * Copyright (C) 2009 Konrad Eisele (konrad@gaisler.com) Aeroflex Gaisler AB
7 */
8
9#include <asm/head.h>
10
11#include <linux/kernel.h>
12#include <linux/sched.h>
13#include <linux/threads.h>
14#include <linux/smp.h>
15#include <linux/smp_lock.h>
16#include <linux/interrupt.h>
17#include <linux/kernel_stat.h>
18#include <linux/init.h>
19#include <linux/spinlock.h>
20#include <linux/mm.h>
21#include <linux/swap.h>
22#include <linux/profile.h>
23#include <linux/pm.h>
24#include <linux/delay.h>
25
26#include <asm/cacheflush.h>
27#include <asm/tlbflush.h>
28
29#include <asm/ptrace.h>
30#include <asm/atomic.h>
31#include <asm/irq_regs.h>
32
33#include <asm/delay.h>
34#include <asm/irq.h>
35#include <asm/page.h>
36#include <asm/pgalloc.h>
37#include <asm/pgtable.h>
38#include <asm/oplib.h>
39#include <asm/cpudata.h>
40#include <asm/asi.h>
41#include <asm/leon.h>
42#include <asm/leon_amba.h>
43
44#ifdef CONFIG_SPARC_LEON
45
46#include "irq.h"
47
48extern ctxd_t *srmmu_ctx_table_phys;
49static int smp_processors_ready;
50extern volatile unsigned long cpu_callin_map[NR_CPUS];
51extern unsigned char boot_cpu_id;
52extern cpumask_t smp_commenced_mask;
53void __init leon_configure_cache_smp(void);
54
55static inline unsigned long do_swap(volatile unsigned long *ptr,
56 unsigned long val)
57{
58 __asm__ __volatile__("swapa [%1] %2, %0\n\t" : "=&r"(val)
59 : "r"(ptr), "i"(ASI_LEON_DCACHE_MISS)
60 : "memory");
61 return val;
62}
63
64static void smp_setup_percpu_timer(void);
65
66void __cpuinit leon_callin(void)
67{
68 int cpuid = hard_smpleon_processor_id();
69
70 local_flush_cache_all();
71 local_flush_tlb_all();
72 leon_configure_cache_smp();
73
74 /* Get our local ticker going. */
75 smp_setup_percpu_timer();
76
77 calibrate_delay();
78 smp_store_cpu_info(cpuid);
79
80 local_flush_cache_all();
81 local_flush_tlb_all();
82
83 /*
84 * Unblock the master CPU _only_ when the scheduler state
85 * of all secondary CPUs will be up-to-date, so after
86 * the SMP initialization the master will be just allowed
87 * to call the scheduler code.
88 * Allow master to continue.
89 */
90 do_swap(&cpu_callin_map[cpuid], 1);
91
92 local_flush_cache_all();
93 local_flush_tlb_all();
94
95 cpu_probe();
96
97 /* Fix idle thread fields. */
98 __asm__ __volatile__("ld [%0], %%g6\n\t" : : "r"(&current_set[cpuid])
99 : "memory" /* paranoid */);
100
101 /* Attach to the address space of init_task. */
102 atomic_inc(&init_mm.mm_count);
103 current->active_mm = &init_mm;
104
105 while (!cpu_isset(cpuid, smp_commenced_mask))
106 mb();
107
108 local_irq_enable();
109 cpu_set(cpuid, cpu_online_map);
110}
111
112/*
113 * Cycle through the processors asking the PROM to start each one.
114 */
115
116extern struct linux_prom_registers smp_penguin_ctable;
117
118void __init leon_configure_cache_smp(void)
119{
120 unsigned long cfg = sparc_leon3_get_dcachecfg();
121 int me = smp_processor_id();
122
123 if (ASI_LEON3_SYSCTRL_CFG_SSIZE(cfg) > 4) {
124 printk(KERN_INFO "Note: SMP with snooping only works on 4k cache, found %dk(0x%x) on cpu %d, disabling caches\n",
125 (unsigned int)ASI_LEON3_SYSCTRL_CFG_SSIZE(cfg),
126 (unsigned int)cfg, (unsigned int)me);
127 sparc_leon3_disable_cache();
128 } else {
129 if (cfg & ASI_LEON3_SYSCTRL_CFG_SNOOPING) {
130 sparc_leon3_enable_snooping();
131 } else {
132 printk(KERN_INFO "Note: You have to enable snooping in the vhdl model cpu %d, disabling caches\n",
133 me);
134 sparc_leon3_disable_cache();
135 }
136 }
137
138 local_flush_cache_all();
139 local_flush_tlb_all();
140}
141
142void leon_smp_setbroadcast(unsigned int mask)
143{
144 int broadcast =
145 ((LEON3_BYPASS_LOAD_PA(&(leon3_irqctrl_regs->mpstatus)) >>
146 LEON3_IRQMPSTATUS_BROADCAST) & 1);
147 if (!broadcast) {
148 prom_printf("######## !!!! The irqmp-ctrl must have broadcast enabled, smp wont work !!!!! ####### nr cpus: %d\n",
149 leon_smp_nrcpus());
150 if (leon_smp_nrcpus() > 1) {
151 BUG();
152 } else {
153 prom_printf("continue anyway\n");
154 return;
155 }
156 }
157 LEON_BYPASS_STORE_PA(&(leon3_irqctrl_regs->mpbroadcast), mask);
158}
159
160unsigned int leon_smp_getbroadcast(void)
161{
162 unsigned int mask;
163 mask = LEON_BYPASS_LOAD_PA(&(leon3_irqctrl_regs->mpbroadcast));
164 return mask;
165}
166
167int leon_smp_nrcpus(void)
168{
169 int nrcpu =
170 ((LEON3_BYPASS_LOAD_PA(&(leon3_irqctrl_regs->mpstatus)) >>
171 LEON3_IRQMPSTATUS_CPUNR) & 0xf) + 1;
172 return nrcpu;
173}
174
175void __init leon_boot_cpus(void)
176{
177 int nrcpu = leon_smp_nrcpus();
178 int me = smp_processor_id();
179
180 printk(KERN_INFO "%d:(%d:%d) cpus mpirq at 0x%x \n", (unsigned int)me,
181 (unsigned int)nrcpu, (unsigned int)NR_CPUS,
182 (unsigned int)&(leon3_irqctrl_regs->mpstatus));
183
184 leon_enable_irq_cpu(LEON3_IRQ_CROSS_CALL, me);
185 leon_enable_irq_cpu(LEON3_IRQ_TICKER, me);
186 leon_enable_irq_cpu(LEON3_IRQ_RESCHEDULE, me);
187
188 leon_smp_setbroadcast(1 << LEON3_IRQ_TICKER);
189
190 leon_configure_cache_smp();
191 smp_setup_percpu_timer();
192 local_flush_cache_all();
193
194}
195
196int __cpuinit leon_boot_one_cpu(int i)
197{
198
199 struct task_struct *p;
200 int timeout;
201
202 /* Cook up an idler for this guy. */
203 p = fork_idle(i);
204
205 current_set[i] = task_thread_info(p);
206
207 /* See trampoline.S:leon_smp_cpu_startup for details...
208 * Initialize the contexts table
209 * Since the call to prom_startcpu() trashes the structure,
210 * we need to re-initialize it for each cpu
211 */
212 smp_penguin_ctable.which_io = 0;
213 smp_penguin_ctable.phys_addr = (unsigned int)srmmu_ctx_table_phys;
214 smp_penguin_ctable.reg_size = 0;
215
216 /* whirrr, whirrr, whirrrrrrrrr... */
217 printk(KERN_INFO "Starting CPU %d : (irqmp: 0x%x)\n", (unsigned int)i,
218 (unsigned int)&leon3_irqctrl_regs->mpstatus);
219 local_flush_cache_all();
220
221 LEON_BYPASS_STORE_PA(&(leon3_irqctrl_regs->mpstatus), 1 << i);
222
223 /* wheee... it's going... */
224 for (timeout = 0; timeout < 10000; timeout++) {
225 if (cpu_callin_map[i])
226 break;
227 udelay(200);
228 }
229 printk(KERN_INFO "Started CPU %d \n", (unsigned int)i);
230
231 if (!(cpu_callin_map[i])) {
232 printk(KERN_ERR "Processor %d is stuck.\n", i);
233 return -ENODEV;
234 } else {
235 leon_enable_irq_cpu(LEON3_IRQ_CROSS_CALL, i);
236 leon_enable_irq_cpu(LEON3_IRQ_TICKER, i);
237 leon_enable_irq_cpu(LEON3_IRQ_RESCHEDULE, i);
238 }
239
240 local_flush_cache_all();
241 return 0;
242}
243
244void __init leon_smp_done(void)
245{
246
247 int i, first;
248 int *prev;
249
250 /* setup cpu list for irq rotation */
251 first = 0;
252 prev = &first;
253 for (i = 0; i < NR_CPUS; i++) {
254 if (cpu_online(i)) {
255 *prev = i;
256 prev = &cpu_data(i).next;
257 }
258 }
259 *prev = first;
260 local_flush_cache_all();
261
262 /* Free unneeded trap tables */
263 if (!cpu_isset(1, cpu_present_map)) {
264 ClearPageReserved(virt_to_page(trapbase_cpu1));
265 init_page_count(virt_to_page(trapbase_cpu1));
266 free_page((unsigned long)trapbase_cpu1);
267 totalram_pages++;
268 num_physpages++;
269 }
270 if (!cpu_isset(2, cpu_present_map)) {
271 ClearPageReserved(virt_to_page(trapbase_cpu2));
272 init_page_count(virt_to_page(trapbase_cpu2));
273 free_page((unsigned long)trapbase_cpu2);
274 totalram_pages++;
275 num_physpages++;
276 }
277 if (!cpu_isset(3, cpu_present_map)) {
278 ClearPageReserved(virt_to_page(trapbase_cpu3));
279 init_page_count(virt_to_page(trapbase_cpu3));
280 free_page((unsigned long)trapbase_cpu3);
281 totalram_pages++;
282 num_physpages++;
283 }
284 /* Ok, they are spinning and ready to go. */
285 smp_processors_ready = 1;
286
287}
288
289void leon_irq_rotate(int cpu)
290{
291}
292
293static struct smp_funcall {
294 smpfunc_t func;
295 unsigned long arg1;
296 unsigned long arg2;
297 unsigned long arg3;
298 unsigned long arg4;
299 unsigned long arg5;
300 unsigned long processors_in[NR_CPUS]; /* Set when ipi entered. */
301 unsigned long processors_out[NR_CPUS]; /* Set when ipi exited. */
302} ccall_info;
303
304static DEFINE_SPINLOCK(cross_call_lock);
305
306/* Cross calls must be serialized, at least currently. */
307static void leon_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1,
308 unsigned long arg2, unsigned long arg3,
309 unsigned long arg4)
310{
311 if (smp_processors_ready) {
312 register int high = NR_CPUS - 1;
313 unsigned long flags;
314
315 spin_lock_irqsave(&cross_call_lock, flags);
316
317 {
318 /* If you make changes here, make sure gcc generates proper code... */
319 register smpfunc_t f asm("i0") = func;
320 register unsigned long a1 asm("i1") = arg1;
321 register unsigned long a2 asm("i2") = arg2;
322 register unsigned long a3 asm("i3") = arg3;
323 register unsigned long a4 asm("i4") = arg4;
324 register unsigned long a5 asm("i5") = 0;
325
326 __asm__ __volatile__("std %0, [%6]\n\t"
327 "std %2, [%6 + 8]\n\t"
328 "std %4, [%6 + 16]\n\t" : :
329 "r"(f), "r"(a1), "r"(a2), "r"(a3),
330 "r"(a4), "r"(a5),
331 "r"(&ccall_info.func));
332 }
333
334 /* Init receive/complete mapping, plus fire the IPI's off. */
335 {
336 register int i;
337
338 cpu_clear(smp_processor_id(), mask);
339 cpus_and(mask, cpu_online_map, mask);
340 for (i = 0; i <= high; i++) {
341 if (cpu_isset(i, mask)) {
342 ccall_info.processors_in[i] = 0;
343 ccall_info.processors_out[i] = 0;
344 set_cpu_int(i, LEON3_IRQ_CROSS_CALL);
345
346 }
347 }
348 }
349
350 {
351 register int i;
352
353 i = 0;
354 do {
355 if (!cpu_isset(i, mask))
356 continue;
357
358 while (!ccall_info.processors_in[i])
359 barrier();
360 } while (++i <= high);
361
362 i = 0;
363 do {
364 if (!cpu_isset(i, mask))
365 continue;
366
367 while (!ccall_info.processors_out[i])
368 barrier();
369 } while (++i <= high);
370 }
371
372 spin_unlock_irqrestore(&cross_call_lock, flags);
373 }
374}
375
376/* Running cross calls. */
377void leon_cross_call_irq(void)
378{
379 int i = smp_processor_id();
380
381 ccall_info.processors_in[i] = 1;
382 ccall_info.func(ccall_info.arg1, ccall_info.arg2, ccall_info.arg3,
383 ccall_info.arg4, ccall_info.arg5);
384 ccall_info.processors_out[i] = 1;
385}
386
387void leon_percpu_timer_interrupt(struct pt_regs *regs)
388{
389 struct pt_regs *old_regs;
390 int cpu = smp_processor_id();
391
392 old_regs = set_irq_regs(regs);
393
394 leon_clear_profile_irq(cpu);
395
396 profile_tick(CPU_PROFILING);
397
398 if (!--prof_counter(cpu)) {
399 int user = user_mode(regs);
400
401 irq_enter();
402 update_process_times(user);
403 irq_exit();
404
405 prof_counter(cpu) = prof_multiplier(cpu);
406 }
407 set_irq_regs(old_regs);
408}
409
410static void __init smp_setup_percpu_timer(void)
411{
412 int cpu = smp_processor_id();
413
414 prof_counter(cpu) = prof_multiplier(cpu) = 1;
415}
416
417void __init leon_blackbox_id(unsigned *addr)
418{
419 int rd = *addr & 0x3e000000;
420 int rs1 = rd >> 11;
421
422 /* patch places where ___b_hard_smp_processor_id appears */
423 addr[0] = 0x81444000 | rd; /* rd %asr17, reg */
424 addr[1] = 0x8130201c | rd | rs1; /* srl reg, 0x1c, reg */
425 addr[2] = 0x01000000; /* nop */
426}
427
428void __init leon_blackbox_current(unsigned *addr)
429{
430 int rd = *addr & 0x3e000000;
431 int rs1 = rd >> 11;
432
433 /* patch LOAD_CURRENT macro where ___b_load_current appears */
434 addr[0] = 0x81444000 | rd; /* rd %asr17, reg */
435 addr[2] = 0x8130201c | rd | rs1; /* srl reg, 0x1c, reg */
436 addr[4] = 0x81282002 | rd | rs1; /* sll reg, 0x2, reg */
437
438}
439
440/*
441 * CPU idle callback function
442 * See .../arch/sparc/kernel/process.c
443 */
444void pmc_leon_idle(void)
445{
446 __asm__ volatile ("mov %g0, %asr19");
447}
448
449void __init leon_init_smp(void)
450{
451 /* Patch ipi15 trap table */
452 t_nmi[1] = t_nmi[1] + (linux_trap_ipi15_leon - linux_trap_ipi15_sun4m);
453
454 BTFIXUPSET_BLACKBOX(hard_smp_processor_id, leon_blackbox_id);
455 BTFIXUPSET_BLACKBOX(load_current, leon_blackbox_current);
456 BTFIXUPSET_CALL(smp_cross_call, leon_cross_call, BTFIXUPCALL_NORM);
457 BTFIXUPSET_CALL(__hard_smp_processor_id, __leon_processor_id,
458 BTFIXUPCALL_NORM);
459
460#ifndef PMC_NO_IDLE
461 /* Assign power management IDLE handler */
462 pm_idle = pmc_leon_idle;
463 printk(KERN_INFO "leon: power management initialized\n");
464#endif
465
466}
467
468#endif /* CONFIG_SPARC_LEON */
diff --git a/arch/sparc/kernel/pci_msi.c b/arch/sparc/kernel/pci_msi.c
index f1be37a7b123..e1b0541feb19 100644
--- a/arch/sparc/kernel/pci_msi.c
+++ b/arch/sparc/kernel/pci_msi.c
@@ -112,7 +112,7 @@ static void free_msi(struct pci_pbm_info *pbm, int msi_num)
112} 112}
113 113
114static struct irq_chip msi_irq = { 114static struct irq_chip msi_irq = {
115 .typename = "PCI-MSI", 115 .name = "PCI-MSI",
116 .mask = mask_msi_irq, 116 .mask = mask_msi_irq,
117 .unmask = unmask_msi_irq, 117 .unmask = unmask_msi_irq,
118 .enable = unmask_msi_irq, 118 .enable = unmask_msi_irq,
diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c
index 21180339cb09..a2a79e76344f 100644
--- a/arch/sparc/kernel/setup_64.c
+++ b/arch/sparc/kernel/setup_64.c
@@ -46,6 +46,7 @@
46#include <asm/setup.h> 46#include <asm/setup.h>
47#include <asm/mmu.h> 47#include <asm/mmu.h>
48#include <asm/ns87303.h> 48#include <asm/ns87303.h>
49#include <asm/btext.h>
49 50
50#ifdef CONFIG_IP_PNP 51#ifdef CONFIG_IP_PNP
51#include <net/ipconfig.h> 52#include <net/ipconfig.h>
@@ -286,7 +287,10 @@ void __init setup_arch(char **cmdline_p)
286 parse_early_param(); 287 parse_early_param();
287 288
288 boot_flags_init(*cmdline_p); 289 boot_flags_init(*cmdline_p);
289 register_console(&prom_early_console); 290#ifdef CONFIG_EARLYFB
291 if (btext_find_display())
292#endif
293 register_console(&prom_early_console);
290 294
291 if (tlb_type == hypervisor) 295 if (tlb_type == hypervisor)
292 printk("ARCH: SUN4V\n"); 296 printk("ARCH: SUN4V\n");
diff --git a/arch/sparc/kernel/smp_32.c b/arch/sparc/kernel/smp_32.c
index 132d81fb2616..91c10fb70858 100644
--- a/arch/sparc/kernel/smp_32.c
+++ b/arch/sparc/kernel/smp_32.c
@@ -32,6 +32,7 @@
32#include <asm/cacheflush.h> 32#include <asm/cacheflush.h>
33#include <asm/tlbflush.h> 33#include <asm/tlbflush.h>
34#include <asm/cpudata.h> 34#include <asm/cpudata.h>
35#include <asm/leon.h>
35 36
36#include "irq.h" 37#include "irq.h"
37 38
@@ -96,6 +97,9 @@ void __init smp_cpus_done(unsigned int max_cpus)
96 case sun4d: 97 case sun4d:
97 smp4d_smp_done(); 98 smp4d_smp_done();
98 break; 99 break;
100 case sparc_leon:
101 leon_smp_done();
102 break;
99 case sun4e: 103 case sun4e:
100 printk("SUN4E\n"); 104 printk("SUN4E\n");
101 BUG(); 105 BUG();
@@ -306,6 +310,9 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
306 case sun4d: 310 case sun4d:
307 smp4d_boot_cpus(); 311 smp4d_boot_cpus();
308 break; 312 break;
313 case sparc_leon:
314 leon_boot_cpus();
315 break;
309 case sun4e: 316 case sun4e:
310 printk("SUN4E\n"); 317 printk("SUN4E\n");
311 BUG(); 318 BUG();
@@ -376,6 +383,9 @@ int __cpuinit __cpu_up(unsigned int cpu)
376 case sun4d: 383 case sun4d:
377 ret = smp4d_boot_one_cpu(cpu); 384 ret = smp4d_boot_one_cpu(cpu);
378 break; 385 break;
386 case sparc_leon:
387 ret = leon_boot_one_cpu(cpu);
388 break;
379 case sun4e: 389 case sun4e:
380 printk("SUN4E\n"); 390 printk("SUN4E\n");
381 BUG(); 391 BUG();
diff --git a/arch/sparc/kernel/sys_sparc32.c b/arch/sparc/kernel/sys_sparc32.c
index f862372074bc..00abe87e5b51 100644
--- a/arch/sparc/kernel/sys_sparc32.c
+++ b/arch/sparc/kernel/sys_sparc32.c
@@ -26,11 +26,6 @@
26#include <linux/nfs_fs.h> 26#include <linux/nfs_fs.h>
27#include <linux/quota.h> 27#include <linux/quota.h>
28#include <linux/module.h> 28#include <linux/module.h>
29#include <linux/sunrpc/svc.h>
30#include <linux/nfsd/nfsd.h>
31#include <linux/nfsd/cache.h>
32#include <linux/nfsd/xdr.h>
33#include <linux/nfsd/syscall.h>
34#include <linux/poll.h> 29#include <linux/poll.h>
35#include <linux/personality.h> 30#include <linux/personality.h>
36#include <linux/stat.h> 31#include <linux/stat.h>
diff --git a/arch/sparc/kernel/time_32.c b/arch/sparc/kernel/time_32.c
index 614ac7b4a9dd..5b2f595fe65b 100644
--- a/arch/sparc/kernel/time_32.c
+++ b/arch/sparc/kernel/time_32.c
@@ -210,9 +210,6 @@ static void __init sbus_time_init(void)
210 btfixup(); 210 btfixup();
211 211
212 sparc_init_timers(timer_interrupt); 212 sparc_init_timers(timer_interrupt);
213
214 /* Now that OBP ticker has been silenced, it is safe to enable IRQ. */
215 local_irq_enable();
216} 213}
217 214
218void __init time_init(void) 215void __init time_init(void)
diff --git a/arch/sparc/kernel/trampoline_32.S b/arch/sparc/kernel/trampoline_32.S
index 5e235c52d667..691f484e03b3 100644
--- a/arch/sparc/kernel/trampoline_32.S
+++ b/arch/sparc/kernel/trampoline_32.S
@@ -15,7 +15,7 @@
15#include <asm/contregs.h> 15#include <asm/contregs.h>
16#include <asm/thread_info.h> 16#include <asm/thread_info.h>
17 17
18 .globl sun4m_cpu_startup, __smp4m_processor_id 18 .globl sun4m_cpu_startup, __smp4m_processor_id, __leon_processor_id
19 .globl sun4d_cpu_startup, __smp4d_processor_id 19 .globl sun4d_cpu_startup, __smp4d_processor_id
20 20
21 __CPUINIT 21 __CPUINIT
@@ -106,6 +106,12 @@ __smp4d_processor_id:
106 retl 106 retl
107 mov %g1, %o7 107 mov %g1, %o7
108 108
109__leon_processor_id:
110 rd %asr17,%g2
111 srl %g2,28,%g2
112 retl
113 mov %g1, %o7
114
109/* CPUID in bootbus can be found at PA 0xff0140000 */ 115/* CPUID in bootbus can be found at PA 0xff0140000 */
110#define SUN4D_BOOTBUS_CPUID 0xf0140000 116#define SUN4D_BOOTBUS_CPUID 0xf0140000
111 117
@@ -160,3 +166,64 @@ sun4d_cpu_startup:
160 nop 166 nop
161 167
162 b,a smp_do_cpu_idle 168 b,a smp_do_cpu_idle
169
170#ifdef CONFIG_SPARC_LEON
171
172 __CPUINIT
173 .align 4
174 .global leon_smp_cpu_startup, smp_penguin_ctable
175
176leon_smp_cpu_startup:
177
178 set smp_penguin_ctable,%g1
179 ld [%g1+4],%g1
180 srl %g1,4,%g1
181 set 0x00000100,%g5 /* SRMMU_CTXTBL_PTR */
182 sta %g1, [%g5] ASI_M_MMUREGS
183
184 /* Set up a sane %psr -- PIL<0xf> S<0x1> PS<0x1> CWP<0x0> */
185 set (PSR_PIL | PSR_S | PSR_PS), %g1
186 wr %g1, 0x0, %psr ! traps off though
187 WRITE_PAUSE
188
189 /* Our %wim is one behind CWP */
190 mov 2, %g1
191 wr %g1, 0x0, %wim
192 WRITE_PAUSE
193
194 /* Set tbr - we use just one trap table. */
195 set trapbase, %g1
196 wr %g1, 0x0, %tbr
197 WRITE_PAUSE
198
199 /* Get our CPU id */
200 rd %asr17,%g3
201
202 /* Give ourselves a stack and curptr. */
203 set current_set, %g5
204 srl %g3, 28, %g4
205 sll %g4, 2, %g4
206 ld [%g5 + %g4], %g6
207
208 sethi %hi(THREAD_SIZE - STACKFRAME_SZ), %sp
209 or %sp, %lo(THREAD_SIZE - STACKFRAME_SZ), %sp
210 add %g6, %sp, %sp
211
212 /* Turn on traps (PSR_ET). */
213 rd %psr, %g1
214 wr %g1, PSR_ET, %psr ! traps on
215 WRITE_PAUSE
216
217 /* Init our caches, etc. */
218 set poke_srmmu, %g5
219 ld [%g5], %g5
220 call %g5
221 nop
222
223 /* Start this processor. */
224 call leon_callin
225 nop
226
227 b,a smp_do_cpu_idle
228
229#endif
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index 509b1ffeba66..367321a030dd 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -1990,7 +1990,7 @@ void __init poke_leonsparc(void)
1990void __init init_leon(void) 1990void __init init_leon(void)
1991{ 1991{
1992 1992
1993 srmmu_name = "Leon"; 1993 srmmu_name = "LEON";
1994 1994
1995 BTFIXUPSET_CALL(flush_cache_all, leon_flush_cache_all, 1995 BTFIXUPSET_CALL(flush_cache_all, leon_flush_cache_all,
1996 BTFIXUPCALL_NORM); 1996 BTFIXUPCALL_NORM);
@@ -2037,8 +2037,6 @@ static void __init get_srmmu_type(void)
2037 2037
2038 /* First, check for sparc-leon. */ 2038 /* First, check for sparc-leon. */
2039 if (sparc_cpu_model == sparc_leon) { 2039 if (sparc_cpu_model == sparc_leon) {
2040 psr_typ = 0xf; /* hardcoded ids for older models/simulators */
2041 psr_vers = 2;
2042 init_leon(); 2040 init_leon();
2043 return; 2041 return;
2044 } 2042 }
@@ -2301,7 +2299,8 @@ void __init ld_mmu_srmmu(void)
2301 BTFIXUPSET_CALL(flush_cache_mm, smp_flush_cache_mm, BTFIXUPCALL_NORM); 2299 BTFIXUPSET_CALL(flush_cache_mm, smp_flush_cache_mm, BTFIXUPCALL_NORM);
2302 BTFIXUPSET_CALL(flush_cache_range, smp_flush_cache_range, BTFIXUPCALL_NORM); 2300 BTFIXUPSET_CALL(flush_cache_range, smp_flush_cache_range, BTFIXUPCALL_NORM);
2303 BTFIXUPSET_CALL(flush_cache_page, smp_flush_cache_page, BTFIXUPCALL_NORM); 2301 BTFIXUPSET_CALL(flush_cache_page, smp_flush_cache_page, BTFIXUPCALL_NORM);
2304 if (sparc_cpu_model != sun4d) { 2302 if (sparc_cpu_model != sun4d &&
2303 sparc_cpu_model != sparc_leon) {
2305 BTFIXUPSET_CALL(flush_tlb_all, smp_flush_tlb_all, BTFIXUPCALL_NORM); 2304 BTFIXUPSET_CALL(flush_tlb_all, smp_flush_tlb_all, BTFIXUPCALL_NORM);
2306 BTFIXUPSET_CALL(flush_tlb_mm, smp_flush_tlb_mm, BTFIXUPCALL_NORM); 2305 BTFIXUPSET_CALL(flush_tlb_mm, smp_flush_tlb_mm, BTFIXUPCALL_NORM);
2307 BTFIXUPSET_CALL(flush_tlb_range, smp_flush_tlb_range, BTFIXUPCALL_NORM); 2306 BTFIXUPSET_CALL(flush_tlb_range, smp_flush_tlb_range, BTFIXUPCALL_NORM);
@@ -2330,6 +2329,8 @@ void __init ld_mmu_srmmu(void)
2330#ifdef CONFIG_SMP 2329#ifdef CONFIG_SMP
2331 if (sparc_cpu_model == sun4d) 2330 if (sparc_cpu_model == sun4d)
2332 sun4d_init_smp(); 2331 sun4d_init_smp();
2332 else if (sparc_cpu_model == sparc_leon)
2333 leon_init_smp();
2333 else 2334 else
2334 sun4m_init_smp(); 2335 sun4m_init_smp();
2335#endif 2336#endif
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index e52257257279..50943ff78f4b 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1477,4 +1477,17 @@ config SERIAL_BCM63XX_CONSOLE
1477 If you have enabled the serial port on the bcm63xx CPU 1477 If you have enabled the serial port on the bcm63xx CPU
1478 you can make it the console by answering Y to this option. 1478 you can make it the console by answering Y to this option.
1479 1479
1480config SERIAL_GRLIB_GAISLER_APBUART
1481 tristate "GRLIB APBUART serial support"
1482 depends on OF
1483 ---help---
1484 Add support for the GRLIB APBUART serial port.
1485
1486config SERIAL_GRLIB_GAISLER_APBUART_CONSOLE
1487 bool "Console on GRLIB APBUART serial port"
1488 depends on SERIAL_GRLIB_GAISLER_APBUART=y
1489 select SERIAL_CORE_CONSOLE
1490 help
1491 Support for running a console on the GRLIB APBUART
1492
1480endmenu 1493endmenu
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index d21d5dd5d048..5548fe7df61d 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -81,3 +81,4 @@ obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
81obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o 81obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
82obj-$(CONFIG_SERIAL_QE) += ucc_uart.o 82obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
83obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o 83obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o
84obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
diff --git a/drivers/serial/apbuart.c b/drivers/serial/apbuart.c
new file mode 100644
index 000000000000..fe91319b5f65
--- /dev/null
+++ b/drivers/serial/apbuart.c
@@ -0,0 +1,710 @@
1/*
2 * Driver for GRLIB serial ports (APBUART)
3 *
4 * Based on linux/drivers/serial/amba.c
5 *
6 * Copyright (C) 2000 Deep Blue Solutions Ltd.
7 * Copyright (C) 2003 Konrad Eisele <eiselekd@web.de>
8 * Copyright (C) 2006 Daniel Hellstrom <daniel@gaisler.com>, Aeroflex Gaisler AB
9 * Copyright (C) 2008 Gilead Kutnick <kutnickg@zin-tech.com>
10 * Copyright (C) 2009 Kristoffer Glembo <kristoffer@gaisler.com>, Aeroflex Gaisler AB
11 */
12
13#if defined(CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
14#define SUPPORT_SYSRQ
15#endif
16
17#include <linux/module.h>
18#include <linux/tty.h>
19#include <linux/ioport.h>
20#include <linux/init.h>
21#include <linux/serial.h>
22#include <linux/console.h>
23#include <linux/sysrq.h>
24#include <linux/kthread.h>
25#include <linux/device.h>
26#include <linux/of.h>
27#include <linux/of_device.h>
28#include <linux/of_platform.h>
29#include <linux/platform_device.h>
30#include <linux/io.h>
31#include <linux/serial_core.h>
32#include <asm/irq.h>
33
34#include "apbuart.h"
35
36#define SERIAL_APBUART_MAJOR TTY_MAJOR
37#define SERIAL_APBUART_MINOR 64
38#define UART_DUMMY_RSR_RX 0x8000 /* for ignore all read */
39
40static void apbuart_tx_chars(struct uart_port *port);
41
42static void apbuart_stop_tx(struct uart_port *port)
43{
44 unsigned int cr;
45
46 cr = UART_GET_CTRL(port);
47 cr &= ~UART_CTRL_TI;
48 UART_PUT_CTRL(port, cr);
49}
50
51static void apbuart_start_tx(struct uart_port *port)
52{
53 unsigned int cr;
54
55 cr = UART_GET_CTRL(port);
56 cr |= UART_CTRL_TI;
57 UART_PUT_CTRL(port, cr);
58
59 if (UART_GET_STATUS(port) & UART_STATUS_THE)
60 apbuart_tx_chars(port);
61}
62
63static void apbuart_stop_rx(struct uart_port *port)
64{
65 unsigned int cr;
66
67 cr = UART_GET_CTRL(port);
68 cr &= ~(UART_CTRL_RI);
69 UART_PUT_CTRL(port, cr);
70}
71
72static void apbuart_enable_ms(struct uart_port *port)
73{
74 /* No modem status change interrupts for APBUART */
75}
76
77static void apbuart_rx_chars(struct uart_port *port)
78{
79 struct tty_struct *tty = port->state->port.tty;
80 unsigned int status, ch, rsr, flag;
81 unsigned int max_chars = port->fifosize;
82
83 status = UART_GET_STATUS(port);
84
85 while (UART_RX_DATA(status) && (max_chars--)) {
86
87 ch = UART_GET_CHAR(port);
88 flag = TTY_NORMAL;
89
90 port->icount.rx++;
91
92 rsr = UART_GET_STATUS(port) | UART_DUMMY_RSR_RX;
93 UART_PUT_STATUS(port, 0);
94 if (rsr & UART_STATUS_ERR) {
95
96 if (rsr & UART_STATUS_BR) {
97 rsr &= ~(UART_STATUS_FE | UART_STATUS_PE);
98 port->icount.brk++;
99 if (uart_handle_break(port))
100 goto ignore_char;
101 } else if (rsr & UART_STATUS_PE) {
102 port->icount.parity++;
103 } else if (rsr & UART_STATUS_FE) {
104 port->icount.frame++;
105 }
106 if (rsr & UART_STATUS_OE)
107 port->icount.overrun++;
108
109 rsr &= port->read_status_mask;
110
111 if (rsr & UART_STATUS_PE)
112 flag = TTY_PARITY;
113 else if (rsr & UART_STATUS_FE)
114 flag = TTY_FRAME;
115 }
116
117 if (uart_handle_sysrq_char(port, ch))
118 goto ignore_char;
119
120 uart_insert_char(port, rsr, UART_STATUS_OE, ch, flag);
121
122
123 ignore_char:
124 status = UART_GET_STATUS(port);
125 }
126
127 tty_flip_buffer_push(tty);
128}
129
130static void apbuart_tx_chars(struct uart_port *port)
131{
132 struct circ_buf *xmit = &port->state->xmit;
133 int count;
134
135 if (port->x_char) {
136 UART_PUT_CHAR(port, port->x_char);
137 port->icount.tx++;
138 port->x_char = 0;
139 return;
140 }
141
142 if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
143 apbuart_stop_tx(port);
144 return;
145 }
146
147 /* amba: fill FIFO */
148 count = port->fifosize >> 1;
149 do {
150 UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
151 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
152 port->icount.tx++;
153 if (uart_circ_empty(xmit))
154 break;
155 } while (--count > 0);
156
157 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
158 uart_write_wakeup(port);
159
160 if (uart_circ_empty(xmit))
161 apbuart_stop_tx(port);
162}
163
164static irqreturn_t apbuart_int(int irq, void *dev_id)
165{
166 struct uart_port *port = dev_id;
167 unsigned int status;
168
169 spin_lock(&port->lock);
170
171 status = UART_GET_STATUS(port);
172 if (status & UART_STATUS_DR)
173 apbuart_rx_chars(port);
174 if (status & UART_STATUS_THE)
175 apbuart_tx_chars(port);
176
177 spin_unlock(&port->lock);
178
179 return IRQ_HANDLED;
180}
181
182static unsigned int apbuart_tx_empty(struct uart_port *port)
183{
184 unsigned int status = UART_GET_STATUS(port);
185 return status & UART_STATUS_THE ? TIOCSER_TEMT : 0;
186}
187
188static unsigned int apbuart_get_mctrl(struct uart_port *port)
189{
190 /* The GRLIB APBUART handles flow control in hardware */
191 return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
192}
193
194static void apbuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
195{
196 /* The GRLIB APBUART handles flow control in hardware */
197}
198
199static void apbuart_break_ctl(struct uart_port *port, int break_state)
200{
201 /* We don't support sending break */
202}
203
204static int apbuart_startup(struct uart_port *port)
205{
206 int retval;
207 unsigned int cr;
208
209 /* Allocate the IRQ */
210 retval = request_irq(port->irq, apbuart_int, 0, "apbuart", port);
211 if (retval)
212 return retval;
213
214 /* Finally, enable interrupts */
215 cr = UART_GET_CTRL(port);
216 UART_PUT_CTRL(port,
217 cr | UART_CTRL_RE | UART_CTRL_TE |
218 UART_CTRL_RI | UART_CTRL_TI);
219
220 return 0;
221}
222
223static void apbuart_shutdown(struct uart_port *port)
224{
225 unsigned int cr;
226
227 /* disable all interrupts, disable the port */
228 cr = UART_GET_CTRL(port);
229 UART_PUT_CTRL(port,
230 cr & ~(UART_CTRL_RE | UART_CTRL_TE |
231 UART_CTRL_RI | UART_CTRL_TI));
232
233 /* Free the interrupt */
234 free_irq(port->irq, port);
235}
236
237static void apbuart_set_termios(struct uart_port *port,
238 struct ktermios *termios, struct ktermios *old)
239{
240 unsigned int cr;
241 unsigned long flags;
242 unsigned int baud, quot;
243
244 /* Ask the core to calculate the divisor for us. */
245 baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
246 if (baud == 0)
247 panic("invalid baudrate %i\n", port->uartclk / 16);
248
249 /* uart_get_divisor calc a *16 uart freq, apbuart is *8 */
250 quot = (uart_get_divisor(port, baud)) * 2;
251 cr = UART_GET_CTRL(port);
252 cr &= ~(UART_CTRL_PE | UART_CTRL_PS);
253
254 if (termios->c_cflag & PARENB) {
255 cr |= UART_CTRL_PE;
256 if ((termios->c_cflag & PARODD))
257 cr |= UART_CTRL_PS;
258 }
259
260 /* Enable flow control. */
261 if (termios->c_cflag & CRTSCTS)
262 cr |= UART_CTRL_FL;
263
264 spin_lock_irqsave(&port->lock, flags);
265
266 /* Update the per-port timeout. */
267 uart_update_timeout(port, termios->c_cflag, baud);
268
269 port->read_status_mask = UART_STATUS_OE;
270 if (termios->c_iflag & INPCK)
271 port->read_status_mask |= UART_STATUS_FE | UART_STATUS_PE;
272
273 /* Characters to ignore */
274 port->ignore_status_mask = 0;
275 if (termios->c_iflag & IGNPAR)
276 port->ignore_status_mask |= UART_STATUS_FE | UART_STATUS_PE;
277
278 /* Ignore all characters if CREAD is not set. */
279 if ((termios->c_cflag & CREAD) == 0)
280 port->ignore_status_mask |= UART_DUMMY_RSR_RX;
281
282 /* Set baud rate */
283 quot -= 1;
284 UART_PUT_SCAL(port, quot);
285 UART_PUT_CTRL(port, cr);
286
287 spin_unlock_irqrestore(&port->lock, flags);
288}
289
290static const char *apbuart_type(struct uart_port *port)
291{
292 return port->type == PORT_APBUART ? "GRLIB/APBUART" : NULL;
293}
294
295static void apbuart_release_port(struct uart_port *port)
296{
297 release_mem_region(port->mapbase, 0x100);
298}
299
300static int apbuart_request_port(struct uart_port *port)
301{
302 return request_mem_region(port->mapbase, 0x100, "grlib-apbuart")
303 != NULL ? 0 : -EBUSY;
304 return 0;
305}
306
307/* Configure/autoconfigure the port */
308static void apbuart_config_port(struct uart_port *port, int flags)
309{
310 if (flags & UART_CONFIG_TYPE) {
311 port->type = PORT_APBUART;
312 apbuart_request_port(port);
313 }
314}
315
316/* Verify the new serial_struct (for TIOCSSERIAL) */
317static int apbuart_verify_port(struct uart_port *port,
318 struct serial_struct *ser)
319{
320 int ret = 0;
321 if (ser->type != PORT_UNKNOWN && ser->type != PORT_APBUART)
322 ret = -EINVAL;
323 if (ser->irq < 0 || ser->irq >= NR_IRQS)
324 ret = -EINVAL;
325 if (ser->baud_base < 9600)
326 ret = -EINVAL;
327 return ret;
328}
329
330static struct uart_ops grlib_apbuart_ops = {
331 .tx_empty = apbuart_tx_empty,
332 .set_mctrl = apbuart_set_mctrl,
333 .get_mctrl = apbuart_get_mctrl,
334 .stop_tx = apbuart_stop_tx,
335 .start_tx = apbuart_start_tx,
336 .stop_rx = apbuart_stop_rx,
337 .enable_ms = apbuart_enable_ms,
338 .break_ctl = apbuart_break_ctl,
339 .startup = apbuart_startup,
340 .shutdown = apbuart_shutdown,
341 .set_termios = apbuart_set_termios,
342 .type = apbuart_type,
343 .release_port = apbuart_release_port,
344 .request_port = apbuart_request_port,
345 .config_port = apbuart_config_port,
346 .verify_port = apbuart_verify_port,
347};
348
349static struct uart_port grlib_apbuart_ports[UART_NR];
350static struct device_node *grlib_apbuart_nodes[UART_NR];
351
352static int apbuart_scan_fifo_size(struct uart_port *port, int portnumber)
353{
354 int ctrl, loop = 0;
355 int status;
356 int fifosize;
357 unsigned long flags;
358
359 ctrl = UART_GET_CTRL(port);
360
361 /*
362 * Enable the transceiver and wait for it to be ready to send data.
363 * Clear interrupts so that this process will not be externally
364 * interrupted in the middle (which can cause the transceiver to
365 * drain prematurely).
366 */
367
368 local_irq_save(flags);
369
370 UART_PUT_CTRL(port, ctrl | UART_CTRL_TE);
371
372 while (!UART_TX_READY(UART_GET_STATUS(port)))
373 loop++;
374
375 /*
376 * Disable the transceiver so data isn't actually sent during the
377 * actual test.
378 */
379
380 UART_PUT_CTRL(port, ctrl & ~(UART_CTRL_TE));
381
382 fifosize = 1;
383 UART_PUT_CHAR(port, 0);
384
385 /*
386 * So long as transmitting a character increments the tranceivier FIFO
387 * length the FIFO must be at least that big. These bytes will
388 * automatically drain off of the FIFO.
389 */
390
391 status = UART_GET_STATUS(port);
392 while (((status >> 20) & 0x3F) == fifosize) {
393 fifosize++;
394 UART_PUT_CHAR(port, 0);
395 status = UART_GET_STATUS(port);
396 }
397
398 fifosize--;
399
400 UART_PUT_CTRL(port, ctrl);
401 local_irq_restore(flags);
402
403 if (fifosize == 0)
404 fifosize = 1;
405
406 return fifosize;
407}
408
409static void apbuart_flush_fifo(struct uart_port *port)
410{
411 int i;
412
413 for (i = 0; i < port->fifosize; i++)
414 UART_GET_CHAR(port);
415}
416
417
418/* ======================================================================== */
419/* Console driver, if enabled */
420/* ======================================================================== */
421
422#ifdef CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE
423
424static void apbuart_console_putchar(struct uart_port *port, int ch)
425{
426 unsigned int status;
427 do {
428 status = UART_GET_STATUS(port);
429 } while (!UART_TX_READY(status));
430 UART_PUT_CHAR(port, ch);
431}
432
433static void
434apbuart_console_write(struct console *co, const char *s, unsigned int count)
435{
436 struct uart_port *port = &grlib_apbuart_ports[co->index];
437 unsigned int status, old_cr, new_cr;
438
439 /* First save the CR then disable the interrupts */
440 old_cr = UART_GET_CTRL(port);
441 new_cr = old_cr & ~(UART_CTRL_RI | UART_CTRL_TI);
442 UART_PUT_CTRL(port, new_cr);
443
444 uart_console_write(port, s, count, apbuart_console_putchar);
445
446 /*
447 * Finally, wait for transmitter to become empty
448 * and restore the TCR
449 */
450 do {
451 status = UART_GET_STATUS(port);
452 } while (!UART_TX_READY(status));
453 UART_PUT_CTRL(port, old_cr);
454}
455
456static void __init
457apbuart_console_get_options(struct uart_port *port, int *baud,
458 int *parity, int *bits)
459{
460 if (UART_GET_CTRL(port) & (UART_CTRL_RE | UART_CTRL_TE)) {
461
462 unsigned int quot, status;
463 status = UART_GET_STATUS(port);
464
465 *parity = 'n';
466 if (status & UART_CTRL_PE) {
467 if ((status & UART_CTRL_PS) == 0)
468 *parity = 'e';
469 else
470 *parity = 'o';
471 }
472
473 *bits = 8;
474 quot = UART_GET_SCAL(port) / 8;
475 *baud = port->uartclk / (16 * (quot + 1));
476 }
477}
478
479static int __init apbuart_console_setup(struct console *co, char *options)
480{
481 struct uart_port *port;
482 int baud = 38400;
483 int bits = 8;
484 int parity = 'n';
485 int flow = 'n';
486
487 pr_debug("apbuart_console_setup co=%p, co->index=%i, options=%s\n",
488 co, co->index, options);
489
490 /*
491 * Check whether an invalid uart number has been specified, and
492 * if so, search for the first available port that does have
493 * console support.
494 */
495 if (co->index >= grlib_apbuart_port_nr)
496 co->index = 0;
497
498 port = &grlib_apbuart_ports[co->index];
499
500 spin_lock_init(&port->lock);
501
502 if (options)
503 uart_parse_options(options, &baud, &parity, &bits, &flow);
504 else
505 apbuart_console_get_options(port, &baud, &parity, &bits);
506
507 return uart_set_options(port, co, baud, parity, bits, flow);
508}
509
510static struct uart_driver grlib_apbuart_driver;
511
512static struct console grlib_apbuart_console = {
513 .name = "ttyS",
514 .write = apbuart_console_write,
515 .device = uart_console_device,
516 .setup = apbuart_console_setup,
517 .flags = CON_PRINTBUFFER,
518 .index = -1,
519 .data = &grlib_apbuart_driver,
520};
521
522
523static void grlib_apbuart_configure(void);
524
525static int __init apbuart_console_init(void)
526{
527 grlib_apbuart_configure();
528 register_console(&grlib_apbuart_console);
529 return 0;
530}
531
532console_initcall(apbuart_console_init);
533
534#define APBUART_CONSOLE (&grlib_apbuart_console)
535#else
536#define APBUART_CONSOLE NULL
537#endif
538
539static struct uart_driver grlib_apbuart_driver = {
540 .owner = THIS_MODULE,
541 .driver_name = "serial",
542 .dev_name = "ttyS",
543 .major = SERIAL_APBUART_MAJOR,
544 .minor = SERIAL_APBUART_MINOR,
545 .nr = UART_NR,
546 .cons = APBUART_CONSOLE,
547};
548
549
550/* ======================================================================== */
551/* OF Platform Driver */
552/* ======================================================================== */
553
554static int __devinit apbuart_probe(struct of_device *op,
555 const struct of_device_id *match)
556{
557 int i = -1;
558 struct uart_port *port = NULL;
559
560 i = 0;
561 for (i = 0; i < grlib_apbuart_port_nr; i++) {
562 if (op->node == grlib_apbuart_nodes[i])
563 break;
564 }
565
566 port = &grlib_apbuart_ports[i];
567 port->dev = &op->dev;
568
569 uart_add_one_port(&grlib_apbuart_driver, (struct uart_port *) port);
570
571 apbuart_flush_fifo((struct uart_port *) port);
572
573 printk(KERN_INFO "grlib-apbuart at 0x%llx, irq %d\n",
574 (unsigned long long) port->mapbase, port->irq);
575 return 0;
576
577}
578
579static struct of_device_id __initdata apbuart_match[] = {
580 {
581 .name = "GAISLER_APBUART",
582 },
583 {},
584};
585
586static struct of_platform_driver grlib_apbuart_of_driver = {
587 .match_table = apbuart_match,
588 .probe = apbuart_probe,
589 .driver = {
590 .owner = THIS_MODULE,
591 .name = "grlib-apbuart",
592 },
593};
594
595
596static void grlib_apbuart_configure(void)
597{
598 static int enum_done;
599 struct device_node *np, *rp;
600 struct uart_port *port = NULL;
601 const u32 *prop;
602 int freq_khz;
603 int v = 0, d = 0;
604 unsigned int addr;
605 int irq, line;
606 struct amba_prom_registers *regs;
607
608 if (enum_done)
609 return;
610
611 /* Get bus frequency */
612 rp = of_find_node_by_path("/");
613 rp = of_get_next_child(rp, NULL);
614 prop = of_get_property(rp, "clock-frequency", NULL);
615 freq_khz = *prop;
616
617 line = 0;
618 for_each_matching_node(np, apbuart_match) {
619
620 int *vendor = (int *) of_get_property(np, "vendor", NULL);
621 int *device = (int *) of_get_property(np, "device", NULL);
622 int *irqs = (int *) of_get_property(np, "interrupts", NULL);
623 regs = (struct amba_prom_registers *)
624 of_get_property(np, "reg", NULL);
625
626 if (vendor)
627 v = *vendor;
628 if (device)
629 d = *device;
630
631 if (!irqs || !regs)
632 return;
633
634 grlib_apbuart_nodes[line] = np;
635
636 addr = regs->phys_addr;
637 irq = *irqs;
638
639 port = &grlib_apbuart_ports[line];
640
641 port->mapbase = addr;
642 port->membase = ioremap(addr, sizeof(struct grlib_apbuart_regs_map));
643 port->irq = irq;
644 port->iotype = UPIO_MEM;
645 port->ops = &grlib_apbuart_ops;
646 port->flags = UPF_BOOT_AUTOCONF;
647 port->line = line;
648 port->uartclk = freq_khz * 1000;
649 port->fifosize = apbuart_scan_fifo_size((struct uart_port *) port, line);
650 line++;
651
652 /* We support maximum UART_NR uarts ... */
653 if (line == UART_NR)
654 break;
655
656 }
657
658 enum_done = 1;
659
660 grlib_apbuart_driver.nr = grlib_apbuart_port_nr = line;
661}
662
663static int __init grlib_apbuart_init(void)
664{
665 int ret;
666
667 /* Find all APBUARTS in device the tree and initialize their ports */
668 grlib_apbuart_configure();
669
670 printk(KERN_INFO "Serial: GRLIB APBUART driver\n");
671
672 ret = uart_register_driver(&grlib_apbuart_driver);
673
674 if (ret) {
675 printk(KERN_ERR "%s: uart_register_driver failed (%i)\n",
676 __FILE__, ret);
677 return ret;
678 }
679
680 ret = of_register_platform_driver(&grlib_apbuart_of_driver);
681 if (ret) {
682 printk(KERN_ERR
683 "%s: of_register_platform_driver failed (%i)\n",
684 __FILE__, ret);
685 uart_unregister_driver(&grlib_apbuart_driver);
686 return ret;
687 }
688
689 return ret;
690}
691
692static void __exit grlib_apbuart_exit(void)
693{
694 int i;
695
696 for (i = 0; i < grlib_apbuart_port_nr; i++)
697 uart_remove_one_port(&grlib_apbuart_driver,
698 &grlib_apbuart_ports[i]);
699
700 uart_unregister_driver(&grlib_apbuart_driver);
701 of_unregister_platform_driver(&grlib_apbuart_of_driver);
702}
703
704module_init(grlib_apbuart_init);
705module_exit(grlib_apbuart_exit);
706
707MODULE_AUTHOR("Aeroflex Gaisler AB");
708MODULE_DESCRIPTION("GRLIB APBUART serial driver");
709MODULE_VERSION("2.1");
710MODULE_LICENSE("GPL");
diff --git a/drivers/serial/apbuart.h b/drivers/serial/apbuart.h
new file mode 100644
index 000000000000..5faf87c8d2bc
--- /dev/null
+++ b/drivers/serial/apbuart.h
@@ -0,0 +1,64 @@
1#ifndef __GRLIB_APBUART_H__
2#define __GRLIB_APBUART_H__
3
4#include <asm/io.h>
5
6#define UART_NR 8
7static int grlib_apbuart_port_nr;
8
9struct grlib_apbuart_regs_map {
10 u32 data;
11 u32 status;
12 u32 ctrl;
13 u32 scaler;
14};
15
16struct amba_prom_registers {
17 unsigned int phys_addr;
18 unsigned int reg_size;
19};
20
21/*
22 * The following defines the bits in the APBUART Status Registers.
23 */
24#define UART_STATUS_DR 0x00000001 /* Data Ready */
25#define UART_STATUS_TSE 0x00000002 /* TX Send Register Empty */
26#define UART_STATUS_THE 0x00000004 /* TX Hold Register Empty */
27#define UART_STATUS_BR 0x00000008 /* Break Error */
28#define UART_STATUS_OE 0x00000010 /* RX Overrun Error */
29#define UART_STATUS_PE 0x00000020 /* RX Parity Error */
30#define UART_STATUS_FE 0x00000040 /* RX Framing Error */
31#define UART_STATUS_ERR 0x00000078 /* Error Mask */
32
33/*
34 * The following defines the bits in the APBUART Ctrl Registers.
35 */
36#define UART_CTRL_RE 0x00000001 /* Receiver enable */
37#define UART_CTRL_TE 0x00000002 /* Transmitter enable */
38#define UART_CTRL_RI 0x00000004 /* Receiver interrupt enable */
39#define UART_CTRL_TI 0x00000008 /* Transmitter irq */
40#define UART_CTRL_PS 0x00000010 /* Parity select */
41#define UART_CTRL_PE 0x00000020 /* Parity enable */
42#define UART_CTRL_FL 0x00000040 /* Flow control enable */
43#define UART_CTRL_LB 0x00000080 /* Loopback enable */
44
45#define APBBASE(port) ((struct grlib_apbuart_regs_map *)((port)->membase))
46
47#define APBBASE_DATA_P(port) (&(APBBASE(port)->data))
48#define APBBASE_STATUS_P(port) (&(APBBASE(port)->status))
49#define APBBASE_CTRL_P(port) (&(APBBASE(port)->ctrl))
50#define APBBASE_SCALAR_P(port) (&(APBBASE(port)->scaler))
51
52#define UART_GET_CHAR(port) (__raw_readl(APBBASE_DATA_P(port)))
53#define UART_PUT_CHAR(port, v) (__raw_writel(v, APBBASE_DATA_P(port)))
54#define UART_GET_STATUS(port) (__raw_readl(APBBASE_STATUS_P(port)))
55#define UART_PUT_STATUS(port, v)(__raw_writel(v, APBBASE_STATUS_P(port)))
56#define UART_GET_CTRL(port) (__raw_readl(APBBASE_CTRL_P(port)))
57#define UART_PUT_CTRL(port, v) (__raw_writel(v, APBBASE_CTRL_P(port)))
58#define UART_GET_SCAL(port) (__raw_readl(APBBASE_SCALAR_P(port)))
59#define UART_PUT_SCAL(port, v) (__raw_writel(v, APBBASE_SCALAR_P(port)))
60
61#define UART_RX_DATA(s) (((s) & UART_STATUS_DR) != 0)
62#define UART_TX_READY(s) (((s) & UART_STATUS_THE) != 0)
63
64#endif /* __GRLIB_APBUART_H__ */
diff --git a/drivers/watchdog/riowd.c b/drivers/watchdog/riowd.c
index d3c824dc2358..c14ae8676903 100644
--- a/drivers/watchdog/riowd.c
+++ b/drivers/watchdog/riowd.c
@@ -10,7 +10,6 @@
10#include <linux/errno.h> 10#include <linux/errno.h>
11#include <linux/init.h> 11#include <linux/init.h>
12#include <linux/miscdevice.h> 12#include <linux/miscdevice.h>
13#include <linux/smp_lock.h>
14#include <linux/watchdog.h> 13#include <linux/watchdog.h>
15#include <linux/of.h> 14#include <linux/of.h>
16#include <linux/of_device.h> 15#include <linux/of_device.h>
@@ -75,7 +74,6 @@ static void riowd_writereg(struct riowd *p, u8 val, int index)
75 74
76static int riowd_open(struct inode *inode, struct file *filp) 75static int riowd_open(struct inode *inode, struct file *filp)
77{ 76{
78 cycle_kernel_lock();
79 nonseekable_open(inode, filp); 77 nonseekable_open(inode, filp);
80 return 0; 78 return 0;
81} 79}
@@ -194,6 +192,8 @@ static int __devinit riowd_probe(struct of_device *op,
194 printk(KERN_ERR PFX "Cannot map registers.\n"); 192 printk(KERN_ERR PFX "Cannot map registers.\n");
195 goto out_free; 193 goto out_free;
196 } 194 }
195 /* Make miscdev useable right away */
196 riowd_device = p;
197 197
198 err = misc_register(&riowd_miscdev); 198 err = misc_register(&riowd_miscdev);
199 if (err) { 199 if (err) {
@@ -205,10 +205,10 @@ static int __devinit riowd_probe(struct of_device *op,
205 "regs at %p\n", riowd_timeout, p->regs); 205 "regs at %p\n", riowd_timeout, p->regs);
206 206
207 dev_set_drvdata(&op->dev, p); 207 dev_set_drvdata(&op->dev, p);
208 riowd_device = p;
209 return 0; 208 return 0;
210 209
211out_iounmap: 210out_iounmap:
211 riowd_device = NULL;
212 of_iounmap(&op->resource[0], p->regs, 2); 212 of_iounmap(&op->resource[0], p->regs, 2);
213 213
214out_free: 214out_free:
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index db532ce288be..8c3dd36fe91a 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -179,6 +179,9 @@
179/* BCM63xx family SoCs */ 179/* BCM63xx family SoCs */
180#define PORT_BCM63XX 89 180#define PORT_BCM63XX 89
181 181
182/* Aeroflex Gaisler GRLIB APBUART */
183#define PORT_APBUART 90
184
182#ifdef __KERNEL__ 185#ifdef __KERNEL__
183 186
184#include <linux/compiler.h> 187#include <linux/compiler.h>