提交 ee1262db 编写于 作者: L Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next-2.6:
  sparc: Set UTS_MACHINE correctly.
  sparc,leon: init_leon srmmu cleanup
  sparc32: Remove early interrupt enable.
  sparc, leon: Added Aeroflex Gaisler entry in manufacturer_info structure
  sparc64: Faster early-boot framebuffer console.
  Revert "sparc: Make atomic locks raw"
  sparc: remove unused nfsd #includes
  sparc: Fixup last users of irq_chip->typename
  Added sparc_leon3_snooping_enabled() and converted extern inline to static inline
  No auxio on LEON
  apbuart: Use of_find_node_by_path to find root node.
  sparc: Replace old style lock initializer
  sparc: Make atomic locks raw
  apbuart: Fix build and missing driver unregister.
  apbuart: Kill dependency on deprecated Sparc-only PROM interfaces.
  apbuart: Fix build warning.
  sparc: Support for GRLIB APBUART serial port
  watchdog: Remove BKL from rio watchdog driver
  sparc: Remove BKL from apc
  sparc,leon: Sparc-Leon SMP support
...@@ -221,6 +221,13 @@ config SPARC64_SMP ...@@ -221,6 +221,13 @@ config SPARC64_SMP
default y default y
depends on SPARC64 && SMP depends on SPARC64 && SMP
config EARLYFB
bool "Support for early boot text console"
default y
depends on SPARC64
help
Say Y here to enable a faster early framebuffer boot console.
choice choice
prompt "Kernel page size" if SPARC64 prompt "Kernel page size" if SPARC64
default SPARC64_PAGE_SIZE_8KB default SPARC64_PAGE_SIZE_8KB
......
...@@ -27,6 +27,7 @@ AS := $(AS) -32 ...@@ -27,6 +27,7 @@ AS := $(AS) -32
LDFLAGS := -m elf32_sparc LDFLAGS := -m elf32_sparc
CHECKFLAGS += -D__sparc__ CHECKFLAGS += -D__sparc__
export BITS := 32 export BITS := 32
UTS_MACHINE := sparc
#KBUILD_CFLAGS += -g -pipe -fcall-used-g5 -fcall-used-g7 #KBUILD_CFLAGS += -g -pipe -fcall-used-g5 -fcall-used-g7
KBUILD_CFLAGS += -m32 -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7 KBUILD_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,6 +47,7 @@ CHECKFLAGS += -D__sparc__ -D__sparc_v9__ -D__arch64__ -m64
LDFLAGS := -m elf64_sparc LDFLAGS := -m elf64_sparc
export BITS := 64 export BITS := 64
UTS_MACHINE := sparc64
KBUILD_CFLAGS += -m64 -pipe -mno-fpu -mcpu=ultrasparc -mcmodel=medlow \ KBUILD_CFLAGS += -m64 -pipe -mno-fpu -mcpu=ultrasparc -mcmodel=medlow \
-ffixed-g4 -ffixed-g5 -fcall-used-g7 -Wno-sign-compare \ -ffixed-g4 -ffixed-g5 -fcall-used-g7 -Wno-sign-compare \
......
#ifndef _SPARC_BTEXT_H
#define _SPARC_BTEXT_H
extern int btext_find_display(void);
#endif /* _SPARC_BTEXT_H */
...@@ -148,7 +148,7 @@ static inline unsigned long leon_load_reg(unsigned long paddr) ...@@ -148,7 +148,7 @@ static inline unsigned long leon_load_reg(unsigned long paddr)
return retval; return retval;
} }
extern inline void leon_srmmu_disabletlb(void) static inline void leon_srmmu_disabletlb(void)
{ {
unsigned int retval; unsigned int retval;
__asm__ __volatile__("lda [%%g0] %2, %0\n\t" : "=r"(retval) : "r"(0), __asm__ __volatile__("lda [%%g0] %2, %0\n\t" : "=r"(retval) : "r"(0),
...@@ -158,7 +158,7 @@ extern inline void leon_srmmu_disabletlb(void) ...@@ -158,7 +158,7 @@ extern inline void leon_srmmu_disabletlb(void)
"i"(ASI_LEON_MMUREGS) : "memory"); "i"(ASI_LEON_MMUREGS) : "memory");
} }
extern inline void leon_srmmu_enabletlb(void) static inline void leon_srmmu_enabletlb(void)
{ {
unsigned int retval; unsigned int retval;
__asm__ __volatile__("lda [%%g0] %2, %0\n\t" : "=r"(retval) : "r"(0), __asm__ __volatile__("lda [%%g0] %2, %0\n\t" : "=r"(retval) : "r"(0),
...@@ -190,7 +190,7 @@ extern void leon_init_IRQ(void); ...@@ -190,7 +190,7 @@ extern void leon_init_IRQ(void);
extern unsigned long last_valid_pfn; extern unsigned long last_valid_pfn;
extern inline unsigned long sparc_leon3_get_dcachecfg(void) static inline unsigned long sparc_leon3_get_dcachecfg(void)
{ {
unsigned int retval; unsigned int retval;
__asm__ __volatile__("lda [%1] %2, %0\n\t" : __asm__ __volatile__("lda [%1] %2, %0\n\t" :
...@@ -201,7 +201,7 @@ extern inline unsigned long sparc_leon3_get_dcachecfg(void) ...@@ -201,7 +201,7 @@ extern inline unsigned long sparc_leon3_get_dcachecfg(void)
} }
/* enable snooping */ /* enable snooping */
extern inline void sparc_leon3_enable_snooping(void) static inline void sparc_leon3_enable_snooping(void)
{ {
__asm__ __volatile__ ("lda [%%g0] 2, %%l1\n\t" __asm__ __volatile__ ("lda [%%g0] 2, %%l1\n\t"
"set 0x800000, %%l2\n\t" "set 0x800000, %%l2\n\t"
...@@ -209,7 +209,14 @@ extern inline void sparc_leon3_enable_snooping(void) ...@@ -209,7 +209,14 @@ extern inline void sparc_leon3_enable_snooping(void)
"sta %%l2, [%%g0] 2\n\t" : : : "l1", "l2"); "sta %%l2, [%%g0] 2\n\t" : : : "l1", "l2");
}; };
extern inline void sparc_leon3_disable_cache(void) static inline int sparc_leon3_snooping_enabled(void)
{
u32 cctrl;
__asm__ __volatile__("lda [%%g0] 2, %0\n\t" : "=r"(cctrl));
return (cctrl >> 23) & 1;
};
static inline void sparc_leon3_disable_cache(void)
{ {
__asm__ __volatile__ ("lda [%%g0] 2, %%l1\n\t" __asm__ __volatile__ ("lda [%%g0] 2, %%l1\n\t"
"set 0x00000f, %%l2\n\t" "set 0x00000f, %%l2\n\t"
...@@ -340,6 +347,30 @@ extern int leon_flush_needed(void); ...@@ -340,6 +347,30 @@ extern int leon_flush_needed(void);
extern void leon_switch_mm(void); extern void leon_switch_mm(void);
extern int srmmu_swprobe_trace; extern int srmmu_swprobe_trace;
#ifdef CONFIG_SMP
extern int leon_smp_nrcpus(void);
extern void leon_clear_profile_irq(int cpu);
extern void leon_smp_done(void);
extern void leon_boot_cpus(void);
extern int leon_boot_one_cpu(int i);
void leon_init_smp(void);
extern void cpu_probe(void);
extern void cpu_idle(void);
extern void init_IRQ(void);
extern void cpu_panic(void);
extern int __leon_processor_id(void);
void leon_enable_irq_cpu(unsigned int irq_nr, unsigned int cpu);
extern unsigned int real_irq_entry[], smpleon_ticker[];
extern unsigned int patchme_maybe_smp_msg[];
extern unsigned long trapbase_cpu1[];
extern unsigned long trapbase_cpu2[];
extern unsigned long trapbase_cpu3[];
extern unsigned int t_nmi[], linux_trap_ipi15_leon[];
extern unsigned int linux_trap_ipi15_sun4m[];
#endif /* CONFIG_SMP */
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */
...@@ -356,6 +387,10 @@ extern int srmmu_swprobe_trace; ...@@ -356,6 +387,10 @@ extern int srmmu_swprobe_trace;
#define leon_switch_mm() do {} while (0) #define leon_switch_mm() do {} while (0)
#define leon_init_IRQ() do {} while (0) #define leon_init_IRQ() do {} while (0)
#define init_leon() do {} while (0) #define init_leon() do {} while (0)
#define leon_smp_done() do {} while (0)
#define leon_boot_cpus() do {} while (0)
#define leon_boot_one_cpu(i) 1
#define leon_init_smp() do {} while (0)
#endif /* !defined(CONFIG_SPARC_LEON) */ #endif /* !defined(CONFIG_SPARC_LEON) */
......
...@@ -35,8 +35,8 @@ struct rw_semaphore { ...@@ -35,8 +35,8 @@ struct rw_semaphore {
#endif #endif
#define __RWSEM_INITIALIZER(name) \ #define __RWSEM_INITIALIZER(name) \
{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) \ { RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED((name).wait_lock), \
__RWSEM_DEP_MAP_INIT(name) } LIST_HEAD_INIT((name).wait_list) __RWSEM_DEP_MAP_INIT(name) }
#define DECLARE_RWSEM(name) \ #define DECLARE_RWSEM(name) \
struct rw_semaphore name = __RWSEM_INITIALIZER(name) struct rw_semaphore name = __RWSEM_INITIALIZER(name)
......
...@@ -106,6 +106,15 @@ static inline int hard_smp4d_processor_id(void) ...@@ -106,6 +106,15 @@ static inline int hard_smp4d_processor_id(void)
return cpuid; return cpuid;
} }
extern inline int hard_smpleon_processor_id(void)
{
int cpuid;
__asm__ __volatile__("rd %%asr17,%0\n\t"
"srl %0,28,%0" :
"=&r" (cpuid) : );
return cpuid;
}
#ifndef MODULE #ifndef MODULE
static inline int hard_smp_processor_id(void) static inline int hard_smp_processor_id(void)
{ {
......
...@@ -72,7 +72,7 @@ obj-y += dma.o ...@@ -72,7 +72,7 @@ obj-y += dma.o
obj-$(CONFIG_SPARC32_PCI) += pcic.o obj-$(CONFIG_SPARC32_PCI) += pcic.o
obj-$(CONFIG_SMP) += trampoline_$(BITS).o smp_$(BITS).o obj-$(CONFIG_SMP) += trampoline_$(BITS).o smp_$(BITS).o
obj-$(CONFIG_SPARC32_SMP) += sun4m_smp.o sun4d_smp.o obj-$(CONFIG_SPARC32_SMP) += sun4m_smp.o sun4d_smp.o leon_smp.o
obj-$(CONFIG_SPARC64_SMP) += hvtramp.o obj-$(CONFIG_SPARC64_SMP) += hvtramp.o
obj-y += auxio_$(BITS).o obj-y += auxio_$(BITS).o
...@@ -87,6 +87,7 @@ obj-$(CONFIG_KGDB) += kgdb_$(BITS).o ...@@ -87,6 +87,7 @@ obj-$(CONFIG_KGDB) += kgdb_$(BITS).o
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
CFLAGS_REMOVE_ftrace.o := -pg CFLAGS_REMOVE_ftrace.o := -pg
obj-$(CONFIG_EARLYFB) += btext.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_STACKTRACE) += stacktrace.o
# sparc64 PCI # sparc64 PCI
obj-$(CONFIG_SPARC64_PCI) += pci.o pci_common.o psycho_common.o obj-$(CONFIG_SPARC64_PCI) += pci.o pci_common.o psycho_common.o
......
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/smp_lock.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
...@@ -76,7 +75,6 @@ static inline void apc_free(struct of_device *op) ...@@ -76,7 +75,6 @@ static inline void apc_free(struct of_device *op)
static int apc_open(struct inode *inode, struct file *f) static int apc_open(struct inode *inode, struct file *f)
{ {
cycle_kernel_lock();
return 0; return 0;
} }
...@@ -87,61 +85,46 @@ static int apc_release(struct inode *inode, struct file *f) ...@@ -87,61 +85,46 @@ static int apc_release(struct inode *inode, struct file *f)
static long apc_ioctl(struct file *f, unsigned int cmd, unsigned long __arg) static long apc_ioctl(struct file *f, unsigned int cmd, unsigned long __arg)
{ {
__u8 inarg, __user *arg; __u8 inarg, __user *arg = (__u8 __user *) __arg;
arg = (__u8 __user *) __arg;
lock_kernel();
switch (cmd) { switch (cmd) {
case APCIOCGFANCTL: case APCIOCGFANCTL:
if (put_user(apc_readb(APC_FANCTL_REG) & APC_REGMASK, arg)) { if (put_user(apc_readb(APC_FANCTL_REG) & APC_REGMASK, arg))
unlock_kernel();
return -EFAULT; return -EFAULT;
}
break; break;
case APCIOCGCPWR: case APCIOCGCPWR:
if (put_user(apc_readb(APC_CPOWER_REG) & APC_REGMASK, arg)) { if (put_user(apc_readb(APC_CPOWER_REG) & APC_REGMASK, arg))
unlock_kernel();
return -EFAULT; return -EFAULT;
}
break; break;
case APCIOCGBPORT: case APCIOCGBPORT:
if (put_user(apc_readb(APC_BPORT_REG) & APC_BPMASK, arg)) { if (put_user(apc_readb(APC_BPORT_REG) & APC_BPMASK, arg))
unlock_kernel();
return -EFAULT; return -EFAULT;
}
break; break;
case APCIOCSFANCTL: case APCIOCSFANCTL:
if (get_user(inarg, arg)) { if (get_user(inarg, arg))
unlock_kernel();
return -EFAULT; return -EFAULT;
}
apc_writeb(inarg & APC_REGMASK, APC_FANCTL_REG); apc_writeb(inarg & APC_REGMASK, APC_FANCTL_REG);
break; break;
case APCIOCSCPWR: case APCIOCSCPWR:
if (get_user(inarg, arg)) { if (get_user(inarg, arg))
unlock_kernel();
return -EFAULT; return -EFAULT;
}
apc_writeb(inarg & APC_REGMASK, APC_CPOWER_REG); apc_writeb(inarg & APC_REGMASK, APC_CPOWER_REG);
break; break;
case APCIOCSBPORT: case APCIOCSBPORT:
if (get_user(inarg, arg)) { if (get_user(inarg, arg))
unlock_kernel();
return -EFAULT; return -EFAULT;
}
apc_writeb(inarg & APC_BPMASK, APC_BPORT_REG); apc_writeb(inarg & APC_BPMASK, APC_BPORT_REG);
break; break;
default: default:
unlock_kernel();
return -EINVAL; return -EINVAL;
}; };
unlock_kernel();
return 0; return 0;
} }
......
...@@ -28,6 +28,7 @@ void __init auxio_probe(void) ...@@ -28,6 +28,7 @@ void __init auxio_probe(void)
struct resource r; struct resource r;
switch (sparc_cpu_model) { switch (sparc_cpu_model) {
case sparc_leon:
case sun4d: case sun4d:
case sun4: case sun4:
return; return;
......
此差异已折叠。
...@@ -184,6 +184,17 @@ static const struct manufacturer_info __initconst manufacturer_info[] = { ...@@ -184,6 +184,17 @@ static const struct manufacturer_info __initconst manufacturer_info[] = {
FPU(3, "Fujitsu or Weitek on-chip FPU"), FPU(3, "Fujitsu or Weitek on-chip FPU"),
FPU(-1, NULL) FPU(-1, NULL)
} }
},{
0xF, /* Aeroflex Gaisler */
.cpu_info = {
CPU(3, "LEON"),
CPU(-1, NULL)
},
.fpu_info = {
FPU(2, "GRFPU"),
FPU(3, "GRFPU-Lite"),
FPU(-1, NULL)
}
},{ },{
0x17, 0x17,
.cpu_info = { .cpu_info = {
......
...@@ -400,6 +400,39 @@ linux_trap_ipi15_sun4d: ...@@ -400,6 +400,39 @@ linux_trap_ipi15_sun4d:
/* FIXME */ /* FIXME */
1: b,a 1b 1: b,a 1b
#ifdef CONFIG_SPARC_LEON
.globl smpleon_ticker
/* SMP per-cpu ticker interrupts are handled specially. */
smpleon_ticker:
SAVE_ALL
or %l0, PSR_PIL, %g2
wr %g2, 0x0, %psr
WRITE_PAUSE
wr %g2, PSR_ET, %psr
WRITE_PAUSE
call leon_percpu_timer_interrupt
add %sp, STACKFRAME_SZ, %o0
wr %l0, PSR_ET, %psr
WRITE_PAUSE
RESTORE_ALL
.align 4
.globl linux_trap_ipi15_leon
linux_trap_ipi15_leon:
SAVE_ALL
or %l0, PSR_PIL, %l4
wr %l4, 0x0, %psr
WRITE_PAUSE
wr %l4, PSR_ET, %psr
WRITE_PAUSE
call leon_cross_call_irq
nop
b ret_trap_lockless_ipi
clr %l6
#endif /* CONFIG_SPARC_LEON */
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
/* This routine handles illegal instructions and privileged /* This routine handles illegal instructions and privileged
......
...@@ -811,8 +811,30 @@ found_version: ...@@ -811,8 +811,30 @@ found_version:
got_prop: got_prop:
#ifdef CONFIG_SPARC_LEON #ifdef CONFIG_SPARC_LEON
/* no cpu-type check is needed, it is a SPARC-LEON */ /* no cpu-type check is needed, it is a SPARC-LEON */
#ifdef CONFIG_SMP
ba leon_smp_init
nop
.global leon_smp_init
leon_smp_init:
sethi %hi(boot_cpu_id), %g1 ! master always 0
stb %g0, [%g1 + %lo(boot_cpu_id)]
sethi %hi(boot_cpu_id4), %g1 ! master always 0
stb %g0, [%g1 + %lo(boot_cpu_id4)]
rd %asr17,%g1
srl %g1,28,%g1
cmp %g0,%g1
beq sun4c_continue_boot !continue with master
nop
ba leon_smp_cpu_startup
nop
#else
ba sun4c_continue_boot ba sun4c_continue_boot
nop nop
#endif
#endif #endif
set cputypval, %o2 set cputypval, %o2
ldub [%o2 + 0x4], %l1 ldub [%o2 + 0x4], %l1
......
...@@ -48,8 +48,13 @@ ...@@ -48,8 +48,13 @@
#include <asm/dma.h> #include <asm/dma.h>
#include <asm/iommu.h> #include <asm/iommu.h>
#include <asm/io-unit.h> #include <asm/io-unit.h>
#include <asm/leon.h>
#ifdef CONFIG_SPARC_LEON
#define mmu_inval_dma_area(p, l) leon_flush_dcache_all()
#else
#define mmu_inval_dma_area(p, l) /* Anton pulled it out for 2.4.0-xx */ #define mmu_inval_dma_area(p, l) /* Anton pulled it out for 2.4.0-xx */
#endif
static struct resource *_sparc_find_resource(struct resource *r, static struct resource *_sparc_find_resource(struct resource *r,
unsigned long); unsigned long);
......
...@@ -187,7 +187,7 @@ int show_interrupts(struct seq_file *p, void *v) ...@@ -187,7 +187,7 @@ int show_interrupts(struct seq_file *p, void *v)
for_each_online_cpu(j) for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_irqs_cpu(i, j)); seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
#endif #endif
seq_printf(p, " %9s", irq_desc[i].chip->typename); seq_printf(p, " %9s", irq_desc[i].chip->name);
seq_printf(p, " %s", action->name); seq_printf(p, " %s", action->name);
for (action=action->next; action; action = action->next) for (action=action->next; action; action = action->next)
...@@ -484,7 +484,7 @@ static void sun4v_virq_eoi(unsigned int virt_irq) ...@@ -484,7 +484,7 @@ static void sun4v_virq_eoi(unsigned int virt_irq)
} }
static struct irq_chip sun4u_irq = { static struct irq_chip sun4u_irq = {
.typename = "sun4u", .name = "sun4u",
.enable = sun4u_irq_enable, .enable = sun4u_irq_enable,
.disable = sun4u_irq_disable, .disable = sun4u_irq_disable,
.eoi = sun4u_irq_eoi, .eoi = sun4u_irq_eoi,
...@@ -492,7 +492,7 @@ static struct irq_chip sun4u_irq = { ...@@ -492,7 +492,7 @@ static struct irq_chip sun4u_irq = {
}; };
static struct irq_chip sun4v_irq = { static struct irq_chip sun4v_irq = {
.typename = "sun4v", .name = "sun4v",
.enable = sun4v_irq_enable, .enable = sun4v_irq_enable,
.disable = sun4v_irq_disable, .disable = sun4v_irq_disable,
.eoi = sun4v_irq_eoi, .eoi = sun4v_irq_eoi,
...@@ -500,7 +500,7 @@ static struct irq_chip sun4v_irq = { ...@@ -500,7 +500,7 @@ static struct irq_chip sun4v_irq = {
}; };
static struct irq_chip sun4v_virq = { static struct irq_chip sun4v_virq = {
.typename = "vsun4v", .name = "vsun4v",
.enable = sun4v_virq_enable, .enable = sun4v_virq_enable,
.disable = sun4v_virq_disable, .disable = sun4v_virq_disable,
.eoi = sun4v_virq_eoi, .eoi = sun4v_virq_eoi,
......
...@@ -12,11 +12,14 @@ ...@@ -12,11 +12,14 @@
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <asm/oplib.h> #include <asm/oplib.h>
#include <asm/timer.h> #include <asm/timer.h>
#include <asm/prom.h> #include <asm/prom.h>
#include <asm/leon.h> #include <asm/leon.h>
#include <asm/leon_amba.h> #include <asm/leon_amba.h>
#include <asm/traps.h>
#include <asm/cacheflush.h>
#include "prom.h" #include "prom.h"
#include "irq.h" #include "irq.h"
...@@ -115,6 +118,21 @@ void __init leon_init_timers(irq_handler_t counter_fn) ...@@ -115,6 +118,21 @@ void __init leon_init_timers(irq_handler_t counter_fn)
(((1000000 / 100) - 1))); (((1000000 / 100) - 1)));
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].ctrl, 0); LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].ctrl, 0);
#ifdef CONFIG_SMP
leon_percpu_timer_dev[0].start = (int)leon3_gptimer_regs;
leon_percpu_timer_dev[0].irq = leon3_gptimer_irq+1;
if (!(LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->config) &
(1<<LEON3_GPTIMER_SEPIRQ))) {
prom_printf("irq timer not configured with seperate irqs \n");
BUG();
}
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].val, 0);
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].rld, (((1000000/100) - 1)));
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].ctrl, 0);
# endif
} else { } else {
printk(KERN_ERR "No Timer/irqctrl found\n"); printk(KERN_ERR "No Timer/irqctrl found\n");
BUG(); BUG();
...@@ -130,11 +148,41 @@ void __init leon_init_timers(irq_handler_t counter_fn) ...@@ -130,11 +148,41 @@ void __init leon_init_timers(irq_handler_t counter_fn)
prom_halt(); prom_halt();
} }
# ifdef CONFIG_SMP
{
unsigned long flags;
struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (leon_percpu_timer_dev[0].irq - 1)];
/* For SMP we use the level 14 ticker, however the bootup code
* has copied the firmwares level 14 vector into boot cpu's
* trap table, we must fix this now or we get squashed.
*/
local_irq_save(flags);
patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
/* Adjust so that we jump directly to smpleon_ticker */
trap_table->inst_three += smpleon_ticker - real_irq_entry;
local_flush_cache_all();
local_irq_restore(flags);
}
# endif
if (leon3_gptimer_regs) { if (leon3_gptimer_regs) {
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].ctrl, LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].ctrl,
LEON3_GPTIMER_EN | LEON3_GPTIMER_EN |
LEON3_GPTIMER_RL | LEON3_GPTIMER_RL |
LEON3_GPTIMER_LD | LEON3_GPTIMER_IRQEN); LEON3_GPTIMER_LD | LEON3_GPTIMER_IRQEN);
#ifdef CONFIG_SMP
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].ctrl,
LEON3_GPTIMER_EN |
LEON3_GPTIMER_RL |
LEON3_GPTIMER_LD |
LEON3_GPTIMER_IRQEN);
#endif
} }
} }
...@@ -175,6 +223,42 @@ void __init leon_node_init(struct device_node *dp, struct device_node ***nextp) ...@@ -175,6 +223,42 @@ void __init leon_node_init(struct device_node *dp, struct device_node ***nextp)
} }
} }
#ifdef CONFIG_SMP
void leon_set_cpu_int(int cpu, int level)
{
unsigned long mask;
mask = get_irqmask(level);
LEON3_BYPASS_STORE_PA(&leon3_irqctrl_regs->force[cpu], mask);
}
static void leon_clear_ipi(int cpu, int level)
{
unsigned long mask;
mask = get_irqmask(level);
LEON3_BYPASS_STORE_PA(&leon3_irqctrl_regs->force[cpu], mask<<16);
}
static void leon_set_udt(int cpu)
{
}
void leon_clear_profile_irq(int cpu)
{
}
void leon_enable_irq_cpu(unsigned int irq_nr, unsigned int cpu)
{
unsigned long mask, flags, *addr;
mask = get_irqmask(irq_nr);
local_irq_save(flags);
addr = (unsigned long *)&(leon3_irqctrl_regs->mask[cpu]);
LEON3_BYPASS_STORE_PA(addr, (LEON3_BYPASS_LOAD_PA(addr) | (mask)));
local_irq_restore(flags);
}
#endif
void __init leon_init_IRQ(void) void __init leon_init_IRQ(void)
{ {
sparc_init_timers = leon_init_timers; sparc_init_timers = leon_init_timers;
......
/* leon_smp.c: Sparc-Leon SMP support.
*
* based on sun4m_smp.c
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 2009 Daniel Hellstrom (daniel@gaisler.com) Aeroflex Gaisler AB
* Copyright (C) 2009 Konrad Eisele (konrad@gaisler.com) Aeroflex Gaisler AB
*/
#include <asm/head.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/threads.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/profile.h>
#include <linux/pm.h>
#include <linux/delay.h>
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
#include <asm/ptrace.h>
#include <asm/atomic.h>
#include <asm/irq_regs.h>
#include <asm/delay.h>
#include <asm/irq.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/oplib.h>
#include <asm/cpudata.h>
#include <asm/asi.h>
#include <asm/leon.h>
#include <asm/leon_amba.h>
#ifdef CONFIG_SPARC_LEON
#include "irq.h"
extern ctxd_t *srmmu_ctx_table_phys;
static int smp_processors_ready;
extern volatile unsigned long cpu_callin_map[NR_CPUS];
extern unsigned char boot_cpu_id;
extern cpumask_t smp_commenced_mask;
void __init leon_configure_cache_smp(void);
static inline unsigned long do_swap(volatile unsigned long *ptr,
unsigned long val)
{
__asm__ __volatile__("swapa [%1] %2, %0\n\t" : "=&r"(val)
: "r"(ptr), "i"(ASI_LEON_DCACHE_MISS)
: "memory");
return val;
}
static void smp_setup_percpu_timer(void);
void __cpuinit leon_callin(void)
{
int cpuid = hard_smpleon_processor_id();
local_flush_cache_all();
local_flush_tlb_all();
leon_configure_cache_smp();
/* Get our local ticker going. */
smp_setup_percpu_timer();
calibrate_delay();
smp_store_cpu_info(cpuid);
local_flush_cache_all();
local_flush_tlb_all();
/*
* Unblock the master CPU _only_ when the scheduler state
* of all secondary CPUs will be up-to-date, so after
* the SMP initialization the master will be just allowed
* to call the scheduler code.
* Allow master to continue.
*/
do_swap(&cpu_callin_map[cpuid], 1);
local_flush_cache_all();
local_flush_tlb_all();
cpu_probe();
/* Fix idle thread fields. */
__asm__ __volatile__("ld [%0], %%g6\n\t" : : "r"(&current_set[cpuid])
: "memory" /* paranoid */);
/* Attach to the address space of init_task. */
atomic_inc(&init_mm.mm_count);
current->active_mm = &init_mm;
while (!cpu_isset(cpuid, smp_commenced_mask))
mb();
local_irq_enable();
cpu_set(cpuid, cpu_online_map);
}
/*
* Cycle through the processors asking the PROM to start each one.
*/
extern struct linux_prom_registers smp_penguin_ctable;
void __init leon_configure_cache_smp(void)
{
unsigned long cfg = sparc_leon3_get_dcachecfg();
int me = smp_processor_id();
if (ASI_LEON3_SYSCTRL_CFG_SSIZE(cfg) > 4) {
printk(KERN_INFO "Note: SMP with snooping only works on 4k cache, found %dk(0x%x) on cpu %d, disabling caches\n",
(unsigned int)ASI_LEON3_SYSCTRL_CFG_SSIZE(cfg),
(unsigned int)cfg, (unsigned int)me);
sparc_leon3_disable_cache();
} else {
if (cfg & ASI_LEON3_SYSCTRL_CFG_SNOOPING) {
sparc_leon3_enable_snooping();
} else {
printk(KERN_INFO "Note: You have to enable snooping in the vhdl model cpu %d, disabling caches\n",
me);
sparc_leon3_disable_cache();
}
}
local_flush_cache_all();
local_flush_tlb_all();
}
void leon_smp_setbroadcast(unsigned int mask)
{
int broadcast =
((LEON3_BYPASS_LOAD_PA(&(leon3_irqctrl_regs->mpstatus)) >>
LEON3_IRQMPSTATUS_BROADCAST) & 1);
if (!broadcast) {
prom_printf("######## !!!! The irqmp-ctrl must have broadcast enabled, smp wont work !!!!! ####### nr cpus: %d\n",
leon_smp_nrcpus());
if (leon_smp_nrcpus() > 1) {
BUG();
} else {
prom_printf("continue anyway\n");
return;
}
}
LEON_BYPASS_STORE_PA(&(leon3_irqctrl_regs->mpbroadcast), mask);
}
unsigned int leon_smp_getbroadcast(void)
{
unsigned int mask;
mask = LEON_BYPASS_LOAD_PA(&(leon3_irqctrl_regs->mpbroadcast));
return mask;
}
int leon_smp_nrcpus(void)
{
int nrcpu =
((LEON3_BYPASS_LOAD_PA(&(leon3_irqctrl_regs->mpstatus)) >>
LEON3_IRQMPSTATUS_CPUNR) & 0xf) + 1;
return nrcpu;
}
void __init leon_boot_cpus(void)
{
int nrcpu = leon_smp_nrcpus();
int me = smp_processor_id();
printk(KERN_INFO "%d:(%d:%d) cpus mpirq at 0x%x \n", (unsigned int)me,
(unsigned int)nrcpu, (unsigned int)NR_CPUS,
(unsigned int)&(leon3_irqctrl_regs->mpstatus));
leon_enable_irq_cpu(LEON3_IRQ_CROSS_CALL, me);
leon_enable_irq_cpu(LEON3_IRQ_TICKER, me);
leon_enable_irq_cpu(LEON3_IRQ_RESCHEDULE, me);
leon_smp_setbroadcast(1 << LEON3_IRQ_TICKER);
leon_configure_cache_smp();
smp_setup_percpu_timer();
local_flush_cache_all();
}
int __cpuinit leon_boot_one_cpu(int i)
{
struct task_struct *p;
int timeout;
/* Cook up an idler for this guy. */
p = fork_idle(i);
current_set[i] = task_thread_info(p);
/* See trampoline.S:leon_smp_cpu_startup for details...
* Initialize the contexts table
* Since the call to prom_startcpu() trashes the structure,
* we need to re-initialize it for each cpu
*/
smp_penguin_ctable.which_io = 0;
smp_penguin_ctable.phys_addr = (unsigned int)srmmu_ctx_table_phys;
smp_penguin_ctable.reg_size = 0;
/* whirrr, whirrr, whirrrrrrrrr... */
printk(KERN_INFO "Starting CPU %d : (irqmp: 0x%x)\n", (unsigned int)i,
(unsigned int)&leon3_irqctrl_regs->mpstatus);
local_flush_cache_all();
LEON_BYPASS_STORE_PA(&(leon3_irqctrl_regs->mpstatus), 1 << i);
/* wheee... it's going... */
for (timeout = 0; timeout < 10000; timeout++) {
if (cpu_callin_map[i])
break;
udelay(200);
}
printk(KERN_INFO "Started CPU %d \n", (unsigned int)i);
if (!(cpu_callin_map[i])) {
printk(KERN_ERR "Processor %d is stuck.\n", i);
return -ENODEV;
} else {
leon_enable_irq_cpu(LEON3_IRQ_CROSS_CALL, i);
leon_enable_irq_cpu(LEON3_IRQ_TICKER, i);
leon_enable_irq_cpu(LEON3_IRQ_RESCHEDULE, i);
}
local_flush_cache_all();
return 0;
}
void __init leon_smp_done(void)
{
int i, first;
int *prev;
/* setup cpu list for irq rotation */
first = 0;
prev = &first;
for (i = 0; i < NR_CPUS; i++) {
if (cpu_online(i)) {
*prev = i;
prev = &cpu_data(i).next;
}
}
*prev = first;
local_flush_cache_all();
/* Free unneeded trap tables */
if (!cpu_isset(1, cpu_present_map)) {
ClearPageReserved(virt_to_page(trapbase_cpu1));
init_page_count(virt_to_page(trapbase_cpu1));
free_page((unsigned long)trapbase_cpu1);
totalram_pages++;
num_physpages++;
}
if (!cpu_isset(2, cpu_present_map)) {
ClearPageReserved(virt_to_page(trapbase_cpu2));
init_page_count(virt_to_page(trapbase_cpu2));
free_page((unsigned long)trapbase_cpu2);
totalram_pages++;
num_physpages++;
}
if (!cpu_isset(3, cpu_present_map)) {
ClearPageReserved(virt_to_page(trapbase_cpu3));
init_page_count(virt_to_page(trapbase_cpu3));
free_page((unsigned long)trapbase_cpu3);
totalram_pages++;
num_physpages++;
}
/* Ok, they are spinning and ready to go. */
smp_processors_ready = 1;
}
void leon_irq_rotate(int cpu)
{
}
static struct smp_funcall {
smpfunc_t func;
unsigned long arg1;
unsigned long arg2;
unsigned long arg3;
unsigned long arg4;
unsigned long arg5;
unsigned long processors_in[NR_CPUS]; /* Set when ipi entered. */
unsigned long processors_out[NR_CPUS]; /* Set when ipi exited. */
} ccall_info;
static DEFINE_SPINLOCK(cross_call_lock);
/* Cross calls must be serialized, at least currently. */
static void leon_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1,
unsigned long arg2, unsigned long arg3,
unsigned long arg4)
{
if (smp_processors_ready) {
register int high = NR_CPUS - 1;
unsigned long flags;
spin_lock_irqsave(&cross_call_lock, flags);
{
/* If you make changes here, make sure gcc generates proper code... */
register smpfunc_t f asm("i0") = func;
register unsigned long a1 asm("i1") = arg1;
register unsigned long a2 asm("i2") = arg2;
register unsigned long a3 asm("i3") = arg3;
register unsigned long a4 asm("i4") = arg4;
register unsigned long a5 asm("i5") = 0;
__asm__ __volatile__("std %0, [%6]\n\t"
"std %2, [%6 + 8]\n\t"
"std %4, [%6 + 16]\n\t" : :
"r"(f), "r"(a1), "r"(a2), "r"(a3),
"r"(a4), "r"(a5),
"r"(&ccall_info.func));
}
/* Init receive/complete mapping, plus fire the IPI's off. */
{
register int i;
cpu_clear(smp_processor_id(), mask);
cpus_and(mask, cpu_online_map, mask);
for (i = 0; i <= high; i++) {
if (cpu_isset(i, mask)) {
ccall_info.processors_in[i] = 0;
ccall_info.processors_out[i] = 0;
set_cpu_int(i, LEON3_IRQ_CROSS_CALL);
}
}
}
{
register int i;
i = 0;
do {
if (!cpu_isset(i, mask))
continue;
while (!ccall_info.processors_in[i])
barrier();
} while (++i <= high);
i = 0;
do {
if (!cpu_isset(i, mask))
continue;
while (!ccall_info.processors_out[i])
barrier();
} while (++i <= high);
}
spin_unlock_irqrestore(&cross_call_lock, flags);
}
}
/* Running cross calls. */
void leon_cross_call_irq(void)
{
int i = smp_processor_id();
ccall_info.processors_in[i] = 1;
ccall_info.func(ccall_info.arg1, ccall_info.arg2, ccall_info.arg3,
ccall_info.arg4, ccall_info.arg5);
ccall_info.processors_out[i] = 1;
}
void leon_percpu_timer_interrupt(struct pt_regs *regs)
{
struct pt_regs *old_regs;
int cpu = smp_processor_id();
old_regs = set_irq_regs(regs);
leon_clear_profile_irq(cpu);
profile_tick(CPU_PROFILING);
if (!--prof_counter(cpu)) {
int user = user_mode(regs);
irq_enter();
update_process_times(user);
irq_exit();
prof_counter(cpu) = prof_multiplier(cpu);
}
set_irq_regs(old_regs);
}
static void __init smp_setup_percpu_timer(void)
{
int cpu = smp_processor_id();
prof_counter(cpu) = prof_multiplier(cpu) = 1;
}
void __init leon_blackbox_id(unsigned *addr)
{
int rd = *addr & 0x3e000000;
int rs1 = rd >> 11;
/* patch places where ___b_hard_smp_processor_id appears */
addr[0] = 0x81444000 | rd; /* rd %asr17, reg */
addr[1] = 0x8130201c | rd | rs1; /* srl reg, 0x1c, reg */
addr[2] = 0x01000000; /* nop */
}
void __init leon_blackbox_current(unsigned *addr)
{
int rd = *addr & 0x3e000000;
int rs1 = rd >> 11;
/* patch LOAD_CURRENT macro where ___b_load_current appears */
addr[0] = 0x81444000 | rd; /* rd %asr17, reg */
addr[2] = 0x8130201c | rd | rs1; /* srl reg, 0x1c, reg */
addr[4] = 0x81282002 | rd | rs1; /* sll reg, 0x2, reg */
}
/*
* CPU idle callback function
* See .../arch/sparc/kernel/process.c
*/
void pmc_leon_idle(void)
{
__asm__ volatile ("mov %g0, %asr19");
}
void __init leon_init_smp(void)
{
/* Patch ipi15 trap table */
t_nmi[1] = t_nmi[1] + (linux_trap_ipi15_leon - linux_trap_ipi15_sun4m);
BTFIXUPSET_BLACKBOX(hard_smp_processor_id, leon_blackbox_id);
BTFIXUPSET_BLACKBOX(load_current, leon_blackbox_current);
BTFIXUPSET_CALL(smp_cross_call, leon_cross_call, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(__hard_smp_processor_id, __leon_processor_id,
BTFIXUPCALL_NORM);
#ifndef PMC_NO_IDLE
/* Assign power management IDLE handler */
pm_idle = pmc_leon_idle;
printk(KERN_INFO "leon: power management initialized\n");
#endif
}
#endif /* CONFIG_SPARC_LEON */
...@@ -112,7 +112,7 @@ static void free_msi(struct pci_pbm_info *pbm, int msi_num) ...@@ -112,7 +112,7 @@ static void free_msi(struct pci_pbm_info *pbm, int msi_num)
} }
static struct irq_chip msi_irq = { static struct irq_chip msi_irq = {
.typename = "PCI-MSI", .name = "PCI-MSI",
.mask = mask_msi_irq, .mask = mask_msi_irq,
.unmask = unmask_msi_irq, .unmask = unmask_msi_irq,
.enable = unmask_msi_irq, .enable = unmask_msi_irq,
......
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#include <asm/setup.h> #include <asm/setup.h>
#include <asm/mmu.h> #include <asm/mmu.h>
#include <asm/ns87303.h> #include <asm/ns87303.h>
#include <asm/btext.h>
#ifdef CONFIG_IP_PNP #ifdef CONFIG_IP_PNP
#include <net/ipconfig.h> #include <net/ipconfig.h>
...@@ -286,7 +287,10 @@ void __init setup_arch(char **cmdline_p) ...@@ -286,7 +287,10 @@ void __init setup_arch(char **cmdline_p)
parse_early_param(); parse_early_param();
boot_flags_init(*cmdline_p); boot_flags_init(*cmdline_p);
register_console(&prom_early_console); #ifdef CONFIG_EARLYFB
if (btext_find_display())
#endif
register_console(&prom_early_console);
if (tlb_type == hypervisor) if (tlb_type == hypervisor)
printk("ARCH: SUN4V\n"); printk("ARCH: SUN4V\n");
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#include <asm/cpudata.h> #include <asm/cpudata.h>
#include <asm/leon.h>
#include "irq.h" #include "irq.h"
...@@ -96,6 +97,9 @@ void __init smp_cpus_done(unsigned int max_cpus) ...@@ -96,6 +97,9 @@ void __init smp_cpus_done(unsigned int max_cpus)
case sun4d: case sun4d:
smp4d_smp_done(); smp4d_smp_done();
break; break;
case sparc_leon:
leon_smp_done();
break;
case sun4e: case sun4e:
printk("SUN4E\n"); printk("SUN4E\n");
BUG(); BUG();
...@@ -306,6 +310,9 @@ void __init smp_prepare_cpus(unsigned int max_cpus) ...@@ -306,6 +310,9 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
case sun4d: case sun4d:
smp4d_boot_cpus(); smp4d_boot_cpus();
break; break;
case sparc_leon:
leon_boot_cpus();
break;
case sun4e: case sun4e:
printk("SUN4E\n"); printk("SUN4E\n");
BUG(); BUG();
...@@ -376,6 +383,9 @@ int __cpuinit __cpu_up(unsigned int cpu) ...@@ -376,6 +383,9 @@ int __cpuinit __cpu_up(unsigned int cpu)
case sun4d: case sun4d:
ret = smp4d_boot_one_cpu(cpu); ret = smp4d_boot_one_cpu(cpu);
break; break;
case sparc_leon:
ret = leon_boot_one_cpu(cpu);
break;
case sun4e: case sun4e:
printk("SUN4E\n"); printk("SUN4E\n");
BUG(); BUG();
......
...@@ -26,11 +26,6 @@ ...@@ -26,11 +26,6 @@
#include <linux/nfs_fs.h> #include <linux/nfs_fs.h>
#include <linux/quota.h> #include <linux/quota.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/sunrpc/svc.h>
#include <linux/nfsd/nfsd.h>
#include <linux/nfsd/cache.h>
#include <linux/nfsd/xdr.h>
#include <linux/nfsd/syscall.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/personality.h> #include <linux/personality.h>
#include <linux/stat.h> #include <linux/stat.h>
......
...@@ -210,9 +210,6 @@ static void __init sbus_time_init(void) ...@@ -210,9 +210,6 @@ static void __init sbus_time_init(void)
btfixup(); btfixup();
sparc_init_timers(timer_interrupt); sparc_init_timers(timer_interrupt);
/* Now that OBP ticker has been silenced, it is safe to enable IRQ. */
local_irq_enable();
} }
void __init time_init(void) void __init time_init(void)
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#include <asm/contregs.h> #include <asm/contregs.h>
#include <asm/thread_info.h> #include <asm/thread_info.h>
.globl sun4m_cpu_startup, __smp4m_processor_id .globl sun4m_cpu_startup, __smp4m_processor_id, __leon_processor_id
.globl sun4d_cpu_startup, __smp4d_processor_id .globl sun4d_cpu_startup, __smp4d_processor_id
__CPUINIT __CPUINIT
...@@ -106,6 +106,12 @@ __smp4d_processor_id: ...@@ -106,6 +106,12 @@ __smp4d_processor_id:
retl retl
mov %g1, %o7 mov %g1, %o7
__leon_processor_id:
rd %asr17,%g2
srl %g2,28,%g2
retl
mov %g1, %o7
/* CPUID in bootbus can be found at PA 0xff0140000 */ /* CPUID in bootbus can be found at PA 0xff0140000 */
#define SUN4D_BOOTBUS_CPUID 0xf0140000 #define SUN4D_BOOTBUS_CPUID 0xf0140000
...@@ -160,3 +166,64 @@ sun4d_cpu_startup: ...@@ -160,3 +166,64 @@ sun4d_cpu_startup:
nop nop
b,a smp_do_cpu_idle b,a smp_do_cpu_idle
#ifdef CONFIG_SPARC_LEON
__CPUINIT
.align 4
.global leon_smp_cpu_startup, smp_penguin_ctable
leon_smp_cpu_startup:
set smp_penguin_ctable,%g1
ld [%g1+4],%g1
srl %g1,4,%g1
set 0x00000100,%g5 /* SRMMU_CTXTBL_PTR */
sta %g1, [%g5] ASI_M_MMUREGS
/* Set up a sane %psr -- PIL<0xf> S<0x1> PS<0x1> CWP<0x0> */
set (PSR_PIL | PSR_S | PSR_PS), %g1
wr %g1, 0x0, %psr ! traps off though
WRITE_PAUSE
/* Our %wim is one behind CWP */
mov 2, %g1
wr %g1, 0x0, %wim
WRITE_PAUSE
/* Set tbr - we use just one trap table. */
set trapbase, %g1
wr %g1, 0x0, %tbr
WRITE_PAUSE
/* Get our CPU id */
rd %asr17,%g3
/* Give ourselves a stack and curptr. */
set current_set, %g5
srl %g3, 28, %g4
sll %g4, 2, %g4
ld [%g5 + %g4], %g6
sethi %hi(THREAD_SIZE - STACKFRAME_SZ), %sp
or %sp, %lo(THREAD_SIZE - STACKFRAME_SZ), %sp
add %g6, %sp, %sp
/* Turn on traps (PSR_ET). */
rd %psr, %g1
wr %g1, PSR_ET, %psr ! traps on
WRITE_PAUSE
/* Init our caches, etc. */
set poke_srmmu, %g5
ld [%g5], %g5
call %g5
nop
/* Start this processor. */
call leon_callin
nop
b,a smp_do_cpu_idle
#endif
...@@ -1990,7 +1990,7 @@ void __init poke_leonsparc(void) ...@@ -1990,7 +1990,7 @@ void __init poke_leonsparc(void)
void __init init_leon(void) void __init init_leon(void)
{ {
srmmu_name = "Leon"; srmmu_name = "LEON";
BTFIXUPSET_CALL(flush_cache_all, leon_flush_cache_all, BTFIXUPSET_CALL(flush_cache_all, leon_flush_cache_all,
BTFIXUPCALL_NORM); BTFIXUPCALL_NORM);
...@@ -2037,8 +2037,6 @@ static void __init get_srmmu_type(void) ...@@ -2037,8 +2037,6 @@ static void __init get_srmmu_type(void)
/* First, check for sparc-leon. */ /* First, check for sparc-leon. */
if (sparc_cpu_model == sparc_leon) { if (sparc_cpu_model == sparc_leon) {
psr_typ = 0xf; /* hardcoded ids for older models/simulators */
psr_vers = 2;
init_leon(); init_leon();
return; return;
} }
...@@ -2301,7 +2299,8 @@ void __init ld_mmu_srmmu(void) ...@@ -2301,7 +2299,8 @@ void __init ld_mmu_srmmu(void)
BTFIXUPSET_CALL(flush_cache_mm, smp_flush_cache_mm, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_cache_mm, smp_flush_cache_mm, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(flush_cache_range, smp_flush_cache_range, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_cache_range, smp_flush_cache_range, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(flush_cache_page, smp_flush_cache_page, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_cache_page, smp_flush_cache_page, BTFIXUPCALL_NORM);
if (sparc_cpu_model != sun4d) { if (sparc_cpu_model != sun4d &&
sparc_cpu_model != sparc_leon) {
BTFIXUPSET_CALL(flush_tlb_all, smp_flush_tlb_all, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_tlb_all, smp_flush_tlb_all, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(flush_tlb_mm, smp_flush_tlb_mm, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_tlb_mm, smp_flush_tlb_mm, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(flush_tlb_range, smp_flush_tlb_range, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_tlb_range, smp_flush_tlb_range, BTFIXUPCALL_NORM);
...@@ -2330,6 +2329,8 @@ void __init ld_mmu_srmmu(void) ...@@ -2330,6 +2329,8 @@ void __init ld_mmu_srmmu(void)
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
if (sparc_cpu_model == sun4d) if (sparc_cpu_model == sun4d)
sun4d_init_smp(); sun4d_init_smp();
else if (sparc_cpu_model == sparc_leon)
leon_init_smp();
else else
sun4m_init_smp(); sun4m_init_smp();
#endif #endif
......
...@@ -1477,4 +1477,17 @@ config SERIAL_BCM63XX_CONSOLE ...@@ -1477,4 +1477,17 @@ config SERIAL_BCM63XX_CONSOLE
If you have enabled the serial port on the bcm63xx CPU If you have enabled the serial port on the bcm63xx CPU
you can make it the console by answering Y to this option. you can make it the console by answering Y to this option.
config SERIAL_GRLIB_GAISLER_APBUART
tristate "GRLIB APBUART serial support"
depends on OF
---help---
Add support for the GRLIB APBUART serial port.
config SERIAL_GRLIB_GAISLER_APBUART_CONSOLE
bool "Console on GRLIB APBUART serial port"
depends on SERIAL_GRLIB_GAISLER_APBUART=y
select SERIAL_CORE_CONSOLE
help
Support for running a console on the GRLIB APBUART
endmenu endmenu
...@@ -81,3 +81,4 @@ obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o ...@@ -81,3 +81,4 @@ obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
obj-$(CONFIG_SERIAL_QE) += ucc_uart.o obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o
obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
/*
* Driver for GRLIB serial ports (APBUART)
*
* Based on linux/drivers/serial/amba.c
*
* Copyright (C) 2000 Deep Blue Solutions Ltd.
* Copyright (C) 2003 Konrad Eisele <eiselekd@web.de>
* Copyright (C) 2006 Daniel Hellstrom <daniel@gaisler.com>, Aeroflex Gaisler AB
* Copyright (C) 2008 Gilead Kutnick <kutnickg@zin-tech.com>
* Copyright (C) 2009 Kristoffer Glembo <kristoffer@gaisler.com>, Aeroflex Gaisler AB
*/
#if defined(CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/serial.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/kthread.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/serial_core.h>
#include <asm/irq.h>
#include "apbuart.h"
#define SERIAL_APBUART_MAJOR TTY_MAJOR
#define SERIAL_APBUART_MINOR 64
#define UART_DUMMY_RSR_RX 0x8000 /* for ignore all read */
static void apbuart_tx_chars(struct uart_port *port);
static void apbuart_stop_tx(struct uart_port *port)
{
unsigned int cr;
cr = UART_GET_CTRL(port);
cr &= ~UART_CTRL_TI;
UART_PUT_CTRL(port, cr);
}
static void apbuart_start_tx(struct uart_port *port)
{
unsigned int cr;
cr = UART_GET_CTRL(port);
cr |= UART_CTRL_TI;
UART_PUT_CTRL(port, cr);
if (UART_GET_STATUS(port) & UART_STATUS_THE)
apbuart_tx_chars(port);
}
static void apbuart_stop_rx(struct uart_port *port)
{
unsigned int cr;
cr = UART_GET_CTRL(port);
cr &= ~(UART_CTRL_RI);
UART_PUT_CTRL(port, cr);
}
static void apbuart_enable_ms(struct uart_port *port)
{
/* No modem status change interrupts for APBUART */
}
static void apbuart_rx_chars(struct uart_port *port)
{
struct tty_struct *tty = port->state->port.tty;
unsigned int status, ch, rsr, flag;
unsigned int max_chars = port->fifosize;
status = UART_GET_STATUS(port);
while (UART_RX_DATA(status) && (max_chars--)) {
ch = UART_GET_CHAR(port);
flag = TTY_NORMAL;
port->icount.rx++;
rsr = UART_GET_STATUS(port) | UART_DUMMY_RSR_RX;
UART_PUT_STATUS(port, 0);
if (rsr & UART_STATUS_ERR) {
if (rsr & UART_STATUS_BR) {
rsr &= ~(UART_STATUS_FE | UART_STATUS_PE);
port->icount.brk++;
if (uart_handle_break(port))
goto ignore_char;
} else if (rsr & UART_STATUS_PE) {
port->icount.parity++;
} else if (rsr & UART_STATUS_FE) {
port->icount.frame++;
}
if (rsr & UART_STATUS_OE)
port->icount.overrun++;
rsr &= port->read_status_mask;
if (rsr & UART_STATUS_PE)
flag = TTY_PARITY;
else if (rsr & UART_STATUS_FE)
flag = TTY_FRAME;
}
if (uart_handle_sysrq_char(port, ch))
goto ignore_char;
uart_insert_char(port, rsr, UART_STATUS_OE, ch, flag);
ignore_char:
status = UART_GET_STATUS(port);
}
tty_flip_buffer_push(tty);
}
static void apbuart_tx_chars(struct uart_port *port)
{
struct circ_buf *xmit = &port->state->xmit;
int count;
if (port->x_char) {
UART_PUT_CHAR(port, port->x_char);
port->icount.tx++;
port->x_char = 0;
return;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
apbuart_stop_tx(port);
return;
}
/* amba: fill FIFO */
count = port->fifosize >> 1;
do {
UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
if (uart_circ_empty(xmit))
break;
} while (--count > 0);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (uart_circ_empty(xmit))
apbuart_stop_tx(port);
}
static irqreturn_t apbuart_int(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
unsigned int status;
spin_lock(&port->lock);
status = UART_GET_STATUS(port);
if (status & UART_STATUS_DR)
apbuart_rx_chars(port);
if (status & UART_STATUS_THE)
apbuart_tx_chars(port);
spin_unlock(&port->lock);
return IRQ_HANDLED;
}
static unsigned int apbuart_tx_empty(struct uart_port *port)
{
unsigned int status = UART_GET_STATUS(port);
return status & UART_STATUS_THE ? TIOCSER_TEMT : 0;
}
static unsigned int apbuart_get_mctrl(struct uart_port *port)
{
/* The GRLIB APBUART handles flow control in hardware */
return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
}
static void apbuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
/* The GRLIB APBUART handles flow control in hardware */
}
static void apbuart_break_ctl(struct uart_port *port, int break_state)
{
/* We don't support sending break */
}
static int apbuart_startup(struct uart_port *port)
{
int retval;
unsigned int cr;
/* Allocate the IRQ */
retval = request_irq(port->irq, apbuart_int, 0, "apbuart", port);
if (retval)
return retval;
/* Finally, enable interrupts */
cr = UART_GET_CTRL(port);
UART_PUT_CTRL(port,
cr | UART_CTRL_RE | UART_CTRL_TE |
UART_CTRL_RI | UART_CTRL_TI);
return 0;
}
static void apbuart_shutdown(struct uart_port *port)
{
unsigned int cr;
/* disable all interrupts, disable the port */
cr = UART_GET_CTRL(port);
UART_PUT_CTRL(port,
cr & ~(UART_CTRL_RE | UART_CTRL_TE |
UART_CTRL_RI | UART_CTRL_TI));
/* Free the interrupt */
free_irq(port->irq, port);
}
static void apbuart_set_termios(struct uart_port *port,
struct ktermios *termios, struct ktermios *old)
{
unsigned int cr;
unsigned long flags;
unsigned int baud, quot;
/* Ask the core to calculate the divisor for us. */
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
if (baud == 0)
panic("invalid baudrate %i\n", port->uartclk / 16);
/* uart_get_divisor calc a *16 uart freq, apbuart is *8 */
quot = (uart_get_divisor(port, baud)) * 2;
cr = UART_GET_CTRL(port);
cr &= ~(UART_CTRL_PE | UART_CTRL_PS);
if (termios->c_cflag & PARENB) {
cr |= UART_CTRL_PE;
if ((termios->c_cflag & PARODD))
cr |= UART_CTRL_PS;
}
/* Enable flow control. */
if (termios->c_cflag & CRTSCTS)
cr |= UART_CTRL_FL;
spin_lock_irqsave(&port->lock, flags);
/* Update the per-port timeout. */
uart_update_timeout(port, termios->c_cflag, baud);
port->read_status_mask = UART_STATUS_OE;
if (termios->c_iflag & INPCK)
port->read_status_mask |= UART_STATUS_FE | UART_STATUS_PE;
/* Characters to ignore */
port->ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= UART_STATUS_FE | UART_STATUS_PE;
/* Ignore all characters if CREAD is not set. */
if ((termios->c_cflag & CREAD) == 0)
port->ignore_status_mask |= UART_DUMMY_RSR_RX;
/* Set baud rate */
quot -= 1;
UART_PUT_SCAL(port, quot);
UART_PUT_CTRL(port, cr);
spin_unlock_irqrestore(&port->lock, flags);
}
static const char *apbuart_type(struct uart_port *port)
{
return port->type == PORT_APBUART ? "GRLIB/APBUART" : NULL;
}
static void apbuart_release_port(struct uart_port *port)
{
release_mem_region(port->mapbase, 0x100);
}
static int apbuart_request_port(struct uart_port *port)
{
return request_mem_region(port->mapbase, 0x100, "grlib-apbuart")
!= NULL ? 0 : -EBUSY;
return 0;
}
/* Configure/autoconfigure the port */
static void apbuart_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE) {
port->type = PORT_APBUART;
apbuart_request_port(port);
}
}
/* Verify the new serial_struct (for TIOCSSERIAL) */
static int apbuart_verify_port(struct uart_port *port,
struct serial_struct *ser)
{
int ret = 0;
if (ser->type != PORT_UNKNOWN && ser->type != PORT_APBUART)
ret = -EINVAL;
if (ser->irq < 0 || ser->irq >= NR_IRQS)
ret = -EINVAL;
if (ser->baud_base < 9600)
ret = -EINVAL;
return ret;
}
static struct uart_ops grlib_apbuart_ops = {
.tx_empty = apbuart_tx_empty,
.set_mctrl = apbuart_set_mctrl,
.get_mctrl = apbuart_get_mctrl,
.stop_tx = apbuart_stop_tx,
.start_tx = apbuart_start_tx,
.stop_rx = apbuart_stop_rx,
.enable_ms = apbuart_enable_ms,
.break_ctl = apbuart_break_ctl,
.startup = apbuart_startup,
.shutdown = apbuart_shutdown,
.set_termios = apbuart_set_termios,
.type = apbuart_type,
.release_port = apbuart_release_port,
.request_port = apbuart_request_port,
.config_port = apbuart_config_port,
.verify_port = apbuart_verify_port,
};
static struct uart_port grlib_apbuart_ports[UART_NR];
static struct device_node *grlib_apbuart_nodes[UART_NR];
static int apbuart_scan_fifo_size(struct uart_port *port, int portnumber)
{
int ctrl, loop = 0;
int status;
int fifosize;
unsigned long flags;
ctrl = UART_GET_CTRL(port);
/*
* Enable the transceiver and wait for it to be ready to send data.
* Clear interrupts so that this process will not be externally
* interrupted in the middle (which can cause the transceiver to
* drain prematurely).
*/
local_irq_save(flags);
UART_PUT_CTRL(port, ctrl | UART_CTRL_TE);
while (!UART_TX_READY(UART_GET_STATUS(port)))
loop++;
/*
* Disable the transceiver so data isn't actually sent during the
* actual test.
*/
UART_PUT_CTRL(port, ctrl & ~(UART_CTRL_TE));
fifosize = 1;
UART_PUT_CHAR(port, 0);
/*
* So long as transmitting a character increments the tranceivier FIFO
* length the FIFO must be at least that big. These bytes will
* automatically drain off of the FIFO.
*/
status = UART_GET_STATUS(port);
while (((status >> 20) & 0x3F) == fifosize) {
fifosize++;
UART_PUT_CHAR(port, 0);
status = UART_GET_STATUS(port);
}
fifosize--;
UART_PUT_CTRL(port, ctrl);
local_irq_restore(flags);
if (fifosize == 0)
fifosize = 1;
return fifosize;
}
static void apbuart_flush_fifo(struct uart_port *port)
{
int i;
for (i = 0; i < port->fifosize; i++)
UART_GET_CHAR(port);
}
/* ======================================================================== */
/* Console driver, if enabled */
/* ======================================================================== */
#ifdef CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE
static void apbuart_console_putchar(struct uart_port *port, int ch)
{
unsigned int status;
do {
status = UART_GET_STATUS(port);
} while (!UART_TX_READY(status));
UART_PUT_CHAR(port, ch);
}
static void
apbuart_console_write(struct console *co, const char *s, unsigned int count)
{
struct uart_port *port = &grlib_apbuart_ports[co->index];
unsigned int status, old_cr, new_cr;
/* First save the CR then disable the interrupts */
old_cr = UART_GET_CTRL(port);
new_cr = old_cr & ~(UART_CTRL_RI | UART_CTRL_TI);
UART_PUT_CTRL(port, new_cr);
uart_console_write(port, s, count, apbuart_console_putchar);
/*
* Finally, wait for transmitter to become empty
* and restore the TCR
*/
do {
status = UART_GET_STATUS(port);
} while (!UART_TX_READY(status));
UART_PUT_CTRL(port, old_cr);
}
static void __init
apbuart_console_get_options(struct uart_port *port, int *baud,
int *parity, int *bits)
{
if (UART_GET_CTRL(port) & (UART_CTRL_RE | UART_CTRL_TE)) {
unsigned int quot, status;
status = UART_GET_STATUS(port);
*parity = 'n';
if (status & UART_CTRL_PE) {
if ((status & UART_CTRL_PS) == 0)
*parity = 'e';
else
*parity = 'o';
}
*bits = 8;
quot = UART_GET_SCAL(port) / 8;
*baud = port->uartclk / (16 * (quot + 1));
}
}
static int __init apbuart_console_setup(struct console *co, char *options)
{
struct uart_port *port;
int baud = 38400;
int bits = 8;
int parity = 'n';
int flow = 'n';
pr_debug("apbuart_console_setup co=%p, co->index=%i, options=%s\n",
co, co->index, options);
/*
* Check whether an invalid uart number has been specified, and
* if so, search for the first available port that does have
* console support.
*/
if (co->index >= grlib_apbuart_port_nr)
co->index = 0;
port = &grlib_apbuart_ports[co->index];
spin_lock_init(&port->lock);
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
apbuart_console_get_options(port, &baud, &parity, &bits);
return uart_set_options(port, co, baud, parity, bits, flow);
}
static struct uart_driver grlib_apbuart_driver;
static struct console grlib_apbuart_console = {
.name = "ttyS",
.write = apbuart_console_write,
.device = uart_console_device,
.setup = apbuart_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &grlib_apbuart_driver,
};
static void grlib_apbuart_configure(void);
static int __init apbuart_console_init(void)
{
grlib_apbuart_configure();
register_console(&grlib_apbuart_console);
return 0;
}
console_initcall(apbuart_console_init);
#define APBUART_CONSOLE (&grlib_apbuart_console)
#else
#define APBUART_CONSOLE NULL
#endif
static struct uart_driver grlib_apbuart_driver = {
.owner = THIS_MODULE,
.driver_name = "serial",
.dev_name = "ttyS",
.major = SERIAL_APBUART_MAJOR,
.minor = SERIAL_APBUART_MINOR,
.nr = UART_NR,
.cons = APBUART_CONSOLE,
};
/* ======================================================================== */
/* OF Platform Driver */
/* ======================================================================== */
static int __devinit apbuart_probe(struct of_device *op,
const struct of_device_id *match)
{
int i = -1;
struct uart_port *port = NULL;
i = 0;
for (i = 0; i < grlib_apbuart_port_nr; i++) {
if (op->node == grlib_apbuart_nodes[i])
break;
}
port = &grlib_apbuart_ports[i];
port->dev = &op->dev;
uart_add_one_port(&grlib_apbuart_driver, (struct uart_port *) port);
apbuart_flush_fifo((struct uart_port *) port);
printk(KERN_INFO "grlib-apbuart at 0x%llx, irq %d\n",
(unsigned long long) port->mapbase, port->irq);
return 0;
}
static struct of_device_id __initdata apbuart_match[] = {
{
.name = "GAISLER_APBUART",
},
{},
};
static struct of_platform_driver grlib_apbuart_of_driver = {
.match_table = apbuart_match,
.probe = apbuart_probe,
.driver = {
.owner = THIS_MODULE,
.name = "grlib-apbuart",
},
};
static void grlib_apbuart_configure(void)
{
static int enum_done;
struct device_node *np, *rp;
struct uart_port *port = NULL;
const u32 *prop;
int freq_khz;
int v = 0, d = 0;
unsigned int addr;
int irq, line;
struct amba_prom_registers *regs;
if (enum_done)
return;
/* Get bus frequency */
rp = of_find_node_by_path("/");
rp = of_get_next_child(rp, NULL);
prop = of_get_property(rp, "clock-frequency", NULL);
freq_khz = *prop;
line = 0;
for_each_matching_node(np, apbuart_match) {
int *vendor = (int *) of_get_property(np, "vendor", NULL);
int *device = (int *) of_get_property(np, "device", NULL);
int *irqs = (int *) of_get_property(np, "interrupts", NULL);
regs = (struct amba_prom_registers *)
of_get_property(np, "reg", NULL);
if (vendor)
v = *vendor;
if (device)
d = *device;
if (!irqs || !regs)
return;
grlib_apbuart_nodes[line] = np;
addr = regs->phys_addr;
irq = *irqs;
port = &grlib_apbuart_ports[line];
port->mapbase = addr;
port->membase = ioremap(addr, sizeof(struct grlib_apbuart_regs_map));
port->irq = irq;
port->iotype = UPIO_MEM;
port->ops = &grlib_apbuart_ops;
port->flags = UPF_BOOT_AUTOCONF;
port->line = line;
port->uartclk = freq_khz * 1000;
port->fifosize = apbuart_scan_fifo_size((struct uart_port *) port, line);
line++;
/* We support maximum UART_NR uarts ... */
if (line == UART_NR)
break;
}
enum_done = 1;
grlib_apbuart_driver.nr = grlib_apbuart_port_nr = line;
}
static int __init grlib_apbuart_init(void)
{
int ret;
/* Find all APBUARTS in device the tree and initialize their ports */
grlib_apbuart_configure();
printk(KERN_INFO "Serial: GRLIB APBUART driver\n");
ret = uart_register_driver(&grlib_apbuart_driver);
if (ret) {
printk(KERN_ERR "%s: uart_register_driver failed (%i)\n",
__FILE__, ret);
return ret;
}
ret = of_register_platform_driver(&grlib_apbuart_of_driver);
if (ret) {
printk(KERN_ERR
"%s: of_register_platform_driver failed (%i)\n",
__FILE__, ret);
uart_unregister_driver(&grlib_apbuart_driver);
return ret;
}
return ret;
}
static void __exit grlib_apbuart_exit(void)
{
int i;
for (i = 0; i < grlib_apbuart_port_nr; i++)
uart_remove_one_port(&grlib_apbuart_driver,
&grlib_apbuart_ports[i]);
uart_unregister_driver(&grlib_apbuart_driver);
of_unregister_platform_driver(&grlib_apbuart_of_driver);
}
module_init(grlib_apbuart_init);
module_exit(grlib_apbuart_exit);
MODULE_AUTHOR("Aeroflex Gaisler AB");
MODULE_DESCRIPTION("GRLIB APBUART serial driver");
MODULE_VERSION("2.1");
MODULE_LICENSE("GPL");
#ifndef __GRLIB_APBUART_H__
#define __GRLIB_APBUART_H__
#include <asm/io.h>
#define UART_NR 8
static int grlib_apbuart_port_nr;
struct grlib_apbuart_regs_map {
u32 data;
u32 status;
u32 ctrl;
u32 scaler;
};
struct amba_prom_registers {
unsigned int phys_addr;
unsigned int reg_size;
};
/*
* The following defines the bits in the APBUART Status Registers.
*/
#define UART_STATUS_DR 0x00000001 /* Data Ready */
#define UART_STATUS_TSE 0x00000002 /* TX Send Register Empty */
#define UART_STATUS_THE 0x00000004 /* TX Hold Register Empty */
#define UART_STATUS_BR 0x00000008 /* Break Error */
#define UART_STATUS_OE 0x00000010 /* RX Overrun Error */
#define UART_STATUS_PE 0x00000020 /* RX Parity Error */
#define UART_STATUS_FE 0x00000040 /* RX Framing Error */
#define UART_STATUS_ERR 0x00000078 /* Error Mask */
/*
* The following defines the bits in the APBUART Ctrl Registers.
*/
#define UART_CTRL_RE 0x00000001 /* Receiver enable */
#define UART_CTRL_TE 0x00000002 /* Transmitter enable */
#define UART_CTRL_RI 0x00000004 /* Receiver interrupt enable */
#define UART_CTRL_TI 0x00000008 /* Transmitter irq */
#define UART_CTRL_PS 0x00000010 /* Parity select */
#define UART_CTRL_PE 0x00000020 /* Parity enable */
#define UART_CTRL_FL 0x00000040 /* Flow control enable */
#define UART_CTRL_LB 0x00000080 /* Loopback enable */
#define APBBASE(port) ((struct grlib_apbuart_regs_map *)((port)->membase))
#define APBBASE_DATA_P(port) (&(APBBASE(port)->data))
#define APBBASE_STATUS_P(port) (&(APBBASE(port)->status))
#define APBBASE_CTRL_P(port) (&(APBBASE(port)->ctrl))
#define APBBASE_SCALAR_P(port) (&(APBBASE(port)->scaler))
#define UART_GET_CHAR(port) (__raw_readl(APBBASE_DATA_P(port)))
#define UART_PUT_CHAR(port, v) (__raw_writel(v, APBBASE_DATA_P(port)))
#define UART_GET_STATUS(port) (__raw_readl(APBBASE_STATUS_P(port)))
#define UART_PUT_STATUS(port, v)(__raw_writel(v, APBBASE_STATUS_P(port)))
#define UART_GET_CTRL(port) (__raw_readl(APBBASE_CTRL_P(port)))
#define UART_PUT_CTRL(port, v) (__raw_writel(v, APBBASE_CTRL_P(port)))
#define UART_GET_SCAL(port) (__raw_readl(APBBASE_SCALAR_P(port)))
#define UART_PUT_SCAL(port, v) (__raw_writel(v, APBBASE_SCALAR_P(port)))
#define UART_RX_DATA(s) (((s) & UART_STATUS_DR) != 0)
#define UART_TX_READY(s) (((s) & UART_STATUS_THE) != 0)
#endif /* __GRLIB_APBUART_H__ */
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/smp_lock.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
...@@ -75,7 +74,6 @@ static void riowd_writereg(struct riowd *p, u8 val, int index) ...@@ -75,7 +74,6 @@ static void riowd_writereg(struct riowd *p, u8 val, int index)
static int riowd_open(struct inode *inode, struct file *filp) static int riowd_open(struct inode *inode, struct file *filp)
{ {
cycle_kernel_lock();
nonseekable_open(inode, filp); nonseekable_open(inode, filp);
return 0; return 0;
} }
...@@ -194,6 +192,8 @@ static int __devinit riowd_probe(struct of_device *op, ...@@ -194,6 +192,8 @@ static int __devinit riowd_probe(struct of_device *op,
printk(KERN_ERR PFX "Cannot map registers.\n"); printk(KERN_ERR PFX "Cannot map registers.\n");
goto out_free; goto out_free;
} }
/* Make miscdev useable right away */
riowd_device = p;
err = misc_register(&riowd_miscdev); err = misc_register(&riowd_miscdev);
if (err) { if (err) {
...@@ -205,10 +205,10 @@ static int __devinit riowd_probe(struct of_device *op, ...@@ -205,10 +205,10 @@ static int __devinit riowd_probe(struct of_device *op,
"regs at %p\n", riowd_timeout, p->regs); "regs at %p\n", riowd_timeout, p->regs);
dev_set_drvdata(&op->dev, p); dev_set_drvdata(&op->dev, p);
riowd_device = p;
return 0; return 0;
out_iounmap: out_iounmap:
riowd_device = NULL;
of_iounmap(&op->resource[0], p->regs, 2); of_iounmap(&op->resource[0], p->regs, 2);
out_free: out_free:
......
...@@ -179,6 +179,9 @@ ...@@ -179,6 +179,9 @@
/* BCM63xx family SoCs */ /* BCM63xx family SoCs */
#define PORT_BCM63XX 89 #define PORT_BCM63XX 89
/* Aeroflex Gaisler GRLIB APBUART */
#define PORT_APBUART 90
#ifdef __KERNEL__ #ifdef __KERNEL__
#include <linux/compiler.h> #include <linux/compiler.h>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册