From ce7a3fdc5c55fd01d8e2deda0daef84473644f8b Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 15 Jun 2006 18:00:34 +0100 Subject: [ARM] Remove rt_sigframe puc and pinfo pointers These two members appear to be surplus to requirements. Discussing this issue with glibc folk: | > Additionally, do you see any need for these weird "puc" and "pinfo" | > pointers in the kernels rt_sigframe structure? Can we kill them? | | We can kill them. I checked with Phil B. about them last week, and he | didn't remember any reason they still needed to be there. And nothing | should know where they are on the stack. Unfortunately, doing this | will upset GDB, which knows that the saved registers are 0x88 bytes | above the stack pointer on entrance to an rt signal trampoline; but, | since puc and pinfo are quite recognizable, I can adapt GDB to support | the new layout if you want to remove them. So remove them. Signed-off-by: Russell King --- arch/arm/kernel/signal.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'arch') diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index a0cd0a90a10..0ddbf2795c5 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -200,8 +200,6 @@ struct sigframe { }; struct rt_sigframe { - struct siginfo __user *pinfo; - void __user *puc; struct siginfo info; struct ucontext uc; unsigned long retcode[2]; @@ -511,8 +509,6 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, if (!frame) return 1; - __put_user_error(&frame->info, &frame->pinfo, err); - __put_user_error(&frame->uc, &frame->puc, err); err |= copy_siginfo_to_user(&frame->info, info); __put_user_error(0, &frame->uc.uc_flags, err); -- cgit v1.2.3-70-g09d2 From cc1a852137d6c12d50c372d61a1c5f763998536b Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 15 Jun 2006 18:02:25 +0100 Subject: [ARM] Replace extramask with a full copy of the sigmask There's not much point in splitting the sigmask between two different locations, so copy it entirely into a proper sigset_t. This will eventually allow rt_sigframe and sigframe to share more code. Signed-off-by: Russell King --- arch/arm/kernel/signal.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) (limited to 'arch') diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 0ddbf2795c5..7a4213ef0f4 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -194,7 +194,7 @@ struct aux_sigframe { */ struct sigframe { struct sigcontext sc; - unsigned long extramask[_NSIG_WORDS-1]; + sigset_t sigmask; unsigned long retcode[2]; struct aux_sigframe aux __attribute__((aligned(8))); }; @@ -264,10 +264,7 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs) if (!access_ok(VERIFY_READ, frame, sizeof (*frame))) goto badframe; - if (__get_user(set.sig[0], &frame->sc.oldmask) - || (_NSIG_WORDS > 1 - && __copy_from_user(&set.sig[1], &frame->extramask, - sizeof(frame->extramask)))) + if (__copy_from_user(&set, &frame->sigmask, sizeof(set))) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); @@ -486,11 +483,7 @@ setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *reg return 1; err |= setup_sigcontext(&frame->sc, &frame->aux, regs, set->sig[0]); - - if (_NSIG_WORDS > 1) { - err |= __copy_to_user(frame->extramask, &set->sig[1], - sizeof(frame->extramask)); - } + err |= __copy_to_user(&frame->sigmask, set, sizeof(*set)); if (err == 0) err = setup_return(regs, ka, frame->retcode, frame, usig); -- cgit v1.2.3-70-g09d2 From 7d4fdc19fc134f69f3711c14e63caef56aee0f2a Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 15 Jun 2006 20:13:25 +0100 Subject: [ARM] Merge sigcontext and sigmask members of sigframe ucontext contains both the sigcontext and sigmask structures, and is also used for rt signal contexts. Re-use this structure for non-rt signals. Signed-off-by: Russell King --- arch/arm/kernel/signal.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'arch') diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 7a4213ef0f4..9f1e1768e4a 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -193,8 +193,7 @@ struct aux_sigframe { * Do a signal return; undo the signal stack. These are aligned to 64-bit. */ struct sigframe { - struct sigcontext sc; - sigset_t sigmask; + struct ucontext uc; unsigned long retcode[2]; struct aux_sigframe aux __attribute__((aligned(8))); }; @@ -264,7 +263,7 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs) if (!access_ok(VERIFY_READ, frame, sizeof (*frame))) goto badframe; - if (__copy_from_user(&set, &frame->sigmask, sizeof(set))) + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); @@ -273,7 +272,7 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs) recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - if (restore_sigcontext(regs, &frame->sc, &frame->aux)) + if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &frame->aux)) goto badframe; /* Send SIGTRAP if we're single-stepping */ @@ -482,8 +481,8 @@ setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *reg if (!frame) return 1; - err |= setup_sigcontext(&frame->sc, &frame->aux, regs, set->sig[0]); - err |= __copy_to_user(&frame->sigmask, set, sizeof(*set)); + err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->aux, regs, set->sig[0]); + err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); if (err == 0) err = setup_return(regs, ka, frame->retcode, frame, usig); -- cgit v1.2.3-70-g09d2 From cb3504e8fa84870aabcf51c67e29675817e30836 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 15 Jun 2006 20:18:25 +0100 Subject: [ARM] Re-use sigframe within rt_sigframe sigframe is now a contained subset of rt_sigframe, so we can start to re-use code which accesses sigframe data for both rt and non-rt signals. Signed-off-by: Russell King --- arch/arm/kernel/signal.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) (limited to 'arch') diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 9f1e1768e4a..652bb1a33c0 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -200,9 +200,7 @@ struct sigframe { struct rt_sigframe { struct siginfo info; - struct ucontext uc; - unsigned long retcode[2]; - struct aux_sigframe aux __attribute__((aligned(8))); + struct sigframe sig; }; static int @@ -308,7 +306,7 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) if (!access_ok(VERIFY_READ, frame, sizeof (*frame))) goto badframe; - if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) + if (__copy_from_user(&set, &frame->sig.uc.uc_sigmask, sizeof(set))) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); @@ -317,10 +315,10 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &frame->aux)) + if (restore_sigcontext(regs, &frame->sig.uc.uc_mcontext, &frame->sig.aux)) goto badframe; - if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT) + if (do_sigaltstack(&frame->sig.uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT) goto badframe; /* Send SIGTRAP if we're single-stepping */ @@ -503,21 +501,21 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, err |= copy_siginfo_to_user(&frame->info, info); - __put_user_error(0, &frame->uc.uc_flags, err); - __put_user_error(NULL, &frame->uc.uc_link, err); + __put_user_error(0, &frame->sig.uc.uc_flags, err); + __put_user_error(NULL, &frame->sig.uc.uc_link, err); memset(&stack, 0, sizeof(stack)); stack.ss_sp = (void __user *)current->sas_ss_sp; stack.ss_flags = sas_ss_flags(regs->ARM_sp); stack.ss_size = current->sas_ss_size; - err |= __copy_to_user(&frame->uc.uc_stack, &stack, sizeof(stack)); + err |= __copy_to_user(&frame->sig.uc.uc_stack, &stack, sizeof(stack)); - err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->aux, + err |= setup_sigcontext(&frame->sig.uc.uc_mcontext, &frame->sig.aux, regs, set->sig[0]); - err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + err |= __copy_to_user(&frame->sig.uc.uc_sigmask, set, sizeof(*set)); if (err == 0) - err = setup_return(regs, ka, frame->retcode, frame, usig); + err = setup_return(regs, ka, frame->sig.retcode, frame, usig); if (err == 0) { /* @@ -526,7 +524,7 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, * -- Peter Maydell 2000-12-06 */ regs->ARM_r1 = (unsigned long)&frame->info; - regs->ARM_r2 = (unsigned long)&frame->uc; + regs->ARM_r2 = (unsigned long)&frame->sig.uc; } return err; -- cgit v1.2.3-70-g09d2 From 680714844fd1dcc6f03b22353103985be9d58db6 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 15 Jun 2006 20:23:02 +0100 Subject: [ARM] Gather common sigframe restoration code into restore_sigframe() Gather the sigmask restoration code inside restore_sigcontext(), and rename the function restore_sigframe(). Pass it a sigframe structure. Signed-off-by: Russell King --- arch/arm/kernel/signal.c | 76 +++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 43 deletions(-) (limited to 'arch') diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 652bb1a33c0..1e2b54d3217 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -203,39 +203,47 @@ struct rt_sigframe { struct sigframe sig; }; -static int -restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, - struct aux_sigframe __user *aux) +static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf) { - int err = 0; + sigset_t set; + int err; - __get_user_error(regs->ARM_r0, &sc->arm_r0, err); - __get_user_error(regs->ARM_r1, &sc->arm_r1, err); - __get_user_error(regs->ARM_r2, &sc->arm_r2, err); - __get_user_error(regs->ARM_r3, &sc->arm_r3, err); - __get_user_error(regs->ARM_r4, &sc->arm_r4, err); - __get_user_error(regs->ARM_r5, &sc->arm_r5, err); - __get_user_error(regs->ARM_r6, &sc->arm_r6, err); - __get_user_error(regs->ARM_r7, &sc->arm_r7, err); - __get_user_error(regs->ARM_r8, &sc->arm_r8, err); - __get_user_error(regs->ARM_r9, &sc->arm_r9, err); - __get_user_error(regs->ARM_r10, &sc->arm_r10, err); - __get_user_error(regs->ARM_fp, &sc->arm_fp, err); - __get_user_error(regs->ARM_ip, &sc->arm_ip, err); - __get_user_error(regs->ARM_sp, &sc->arm_sp, err); - __get_user_error(regs->ARM_lr, &sc->arm_lr, err); - __get_user_error(regs->ARM_pc, &sc->arm_pc, err); - __get_user_error(regs->ARM_cpsr, &sc->arm_cpsr, err); + err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set)); + if (err == 0) { + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + } + + __get_user_error(regs->ARM_r0, &sf->uc.uc_mcontext.arm_r0, err); + __get_user_error(regs->ARM_r1, &sf->uc.uc_mcontext.arm_r1, err); + __get_user_error(regs->ARM_r2, &sf->uc.uc_mcontext.arm_r2, err); + __get_user_error(regs->ARM_r3, &sf->uc.uc_mcontext.arm_r3, err); + __get_user_error(regs->ARM_r4, &sf->uc.uc_mcontext.arm_r4, err); + __get_user_error(regs->ARM_r5, &sf->uc.uc_mcontext.arm_r5, err); + __get_user_error(regs->ARM_r6, &sf->uc.uc_mcontext.arm_r6, err); + __get_user_error(regs->ARM_r7, &sf->uc.uc_mcontext.arm_r7, err); + __get_user_error(regs->ARM_r8, &sf->uc.uc_mcontext.arm_r8, err); + __get_user_error(regs->ARM_r9, &sf->uc.uc_mcontext.arm_r9, err); + __get_user_error(regs->ARM_r10, &sf->uc.uc_mcontext.arm_r10, err); + __get_user_error(regs->ARM_fp, &sf->uc.uc_mcontext.arm_fp, err); + __get_user_error(regs->ARM_ip, &sf->uc.uc_mcontext.arm_ip, err); + __get_user_error(regs->ARM_sp, &sf->uc.uc_mcontext.arm_sp, err); + __get_user_error(regs->ARM_lr, &sf->uc.uc_mcontext.arm_lr, err); + __get_user_error(regs->ARM_pc, &sf->uc.uc_mcontext.arm_pc, err); + __get_user_error(regs->ARM_cpsr, &sf->uc.uc_mcontext.arm_cpsr, err); err |= !valid_user_regs(regs); #ifdef CONFIG_IWMMXT if (err == 0 && test_thread_flag(TIF_USING_IWMMXT)) - err |= restore_iwmmxt_context(&aux->iwmmxt); + err |= restore_iwmmxt_context(&sf->aux.iwmmxt); #endif #ifdef CONFIG_VFP // if (err == 0) -// err |= vfp_restore_state(&aux->vfp); +// err |= vfp_restore_state(&sf->aux.vfp); #endif return err; @@ -244,7 +252,6 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, asmlinkage int sys_sigreturn(struct pt_regs *regs) { struct sigframe __user *frame; - sigset_t set; /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; @@ -261,16 +268,8 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs) if (!access_ok(VERIFY_READ, frame, sizeof (*frame))) goto badframe; - if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) - goto badframe; - - sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &frame->aux)) + if (restore_sigframe(regs, frame)) goto badframe; /* Send SIGTRAP if we're single-stepping */ @@ -289,7 +288,6 @@ badframe: asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) { struct rt_sigframe __user *frame; - sigset_t set; /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; @@ -306,16 +304,8 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) if (!access_ok(VERIFY_READ, frame, sizeof (*frame))) goto badframe; - if (__copy_from_user(&set, &frame->sig.uc.uc_sigmask, sizeof(set))) - goto badframe; - - sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - if (restore_sigcontext(regs, &frame->sig.uc.uc_mcontext, &frame->sig.aux)) + if (restore_sigframe(regs, &frame->sig)) goto badframe; if (do_sigaltstack(&frame->sig.uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT) -- cgit v1.2.3-70-g09d2 From aca6ca10974aa78adfb47291722ce851160213e4 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 15 Jun 2006 20:28:03 +0100 Subject: [ARM] Gather common sigframe saving code into setup_sigframe() Gather the common sigmask savbing code inside setup_sigcontext(), and rename the function setup_sigframe(). Pass it a sigframe structure. Signed-off-by: Russell King --- arch/arm/kernel/signal.c | 62 ++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 33 deletions(-) (limited to 'arch') diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 1e2b54d3217..96285114409 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -325,41 +325,42 @@ badframe: } static int -setup_sigcontext(struct sigcontext __user *sc, struct aux_sigframe __user *aux, - struct pt_regs *regs, unsigned long mask) +setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set) { int err = 0; - __put_user_error(regs->ARM_r0, &sc->arm_r0, err); - __put_user_error(regs->ARM_r1, &sc->arm_r1, err); - __put_user_error(regs->ARM_r2, &sc->arm_r2, err); - __put_user_error(regs->ARM_r3, &sc->arm_r3, err); - __put_user_error(regs->ARM_r4, &sc->arm_r4, err); - __put_user_error(regs->ARM_r5, &sc->arm_r5, err); - __put_user_error(regs->ARM_r6, &sc->arm_r6, err); - __put_user_error(regs->ARM_r7, &sc->arm_r7, err); - __put_user_error(regs->ARM_r8, &sc->arm_r8, err); - __put_user_error(regs->ARM_r9, &sc->arm_r9, err); - __put_user_error(regs->ARM_r10, &sc->arm_r10, err); - __put_user_error(regs->ARM_fp, &sc->arm_fp, err); - __put_user_error(regs->ARM_ip, &sc->arm_ip, err); - __put_user_error(regs->ARM_sp, &sc->arm_sp, err); - __put_user_error(regs->ARM_lr, &sc->arm_lr, err); - __put_user_error(regs->ARM_pc, &sc->arm_pc, err); - __put_user_error(regs->ARM_cpsr, &sc->arm_cpsr, err); - - __put_user_error(current->thread.trap_no, &sc->trap_no, err); - __put_user_error(current->thread.error_code, &sc->error_code, err); - __put_user_error(current->thread.address, &sc->fault_address, err); - __put_user_error(mask, &sc->oldmask, err); + __put_user_error(regs->ARM_r0, &sf->uc.uc_mcontext.arm_r0, err); + __put_user_error(regs->ARM_r1, &sf->uc.uc_mcontext.arm_r1, err); + __put_user_error(regs->ARM_r2, &sf->uc.uc_mcontext.arm_r2, err); + __put_user_error(regs->ARM_r3, &sf->uc.uc_mcontext.arm_r3, err); + __put_user_error(regs->ARM_r4, &sf->uc.uc_mcontext.arm_r4, err); + __put_user_error(regs->ARM_r5, &sf->uc.uc_mcontext.arm_r5, err); + __put_user_error(regs->ARM_r6, &sf->uc.uc_mcontext.arm_r6, err); + __put_user_error(regs->ARM_r7, &sf->uc.uc_mcontext.arm_r7, err); + __put_user_error(regs->ARM_r8, &sf->uc.uc_mcontext.arm_r8, err); + __put_user_error(regs->ARM_r9, &sf->uc.uc_mcontext.arm_r9, err); + __put_user_error(regs->ARM_r10, &sf->uc.uc_mcontext.arm_r10, err); + __put_user_error(regs->ARM_fp, &sf->uc.uc_mcontext.arm_fp, err); + __put_user_error(regs->ARM_ip, &sf->uc.uc_mcontext.arm_ip, err); + __put_user_error(regs->ARM_sp, &sf->uc.uc_mcontext.arm_sp, err); + __put_user_error(regs->ARM_lr, &sf->uc.uc_mcontext.arm_lr, err); + __put_user_error(regs->ARM_pc, &sf->uc.uc_mcontext.arm_pc, err); + __put_user_error(regs->ARM_cpsr, &sf->uc.uc_mcontext.arm_cpsr, err); + + __put_user_error(current->thread.trap_no, &sf->uc.uc_mcontext.trap_no, err); + __put_user_error(current->thread.error_code, &sf->uc.uc_mcontext.error_code, err); + __put_user_error(current->thread.address, &sf->uc.uc_mcontext.fault_address, err); + __put_user_error(set->sig[0], &sf->uc.uc_mcontext.oldmask, err); + + err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set)); #ifdef CONFIG_IWMMXT if (err == 0 && test_thread_flag(TIF_USING_IWMMXT)) - err |= preserve_iwmmxt_context(&aux->iwmmxt); + err |= preserve_iwmmxt_context(&sf->aux.iwmmxt); #endif #ifdef CONFIG_VFP // if (err == 0) -// err |= vfp_save_state(&aux->vfp); +// err |= vfp_save_state(&sf->aux.vfp); #endif return err; @@ -469,9 +470,7 @@ setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *reg if (!frame) return 1; - err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->aux, regs, set->sig[0]); - err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); - + err |= setup_sigframe(frame, regs, set); if (err == 0) err = setup_return(regs, ka, frame->retcode, frame, usig); @@ -500,10 +499,7 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, stack.ss_size = current->sas_ss_size; err |= __copy_to_user(&frame->sig.uc.uc_stack, &stack, sizeof(stack)); - err |= setup_sigcontext(&frame->sig.uc.uc_mcontext, &frame->sig.aux, - regs, set->sig[0]); - err |= __copy_to_user(&frame->sig.uc.uc_sigmask, set, sizeof(*set)); - + err |= setup_sigframe(&frame->sig, regs, set); if (err == 0) err = setup_return(regs, ka, frame->sig.retcode, frame, usig); -- cgit v1.2.3-70-g09d2 From 3da4bd2bfc672a484d2a5df9f89b79f5e1e634dc Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Sat, 24 Jun 2006 09:57:13 +0100 Subject: [ARM] 3632/1: iwmmxt: fix up argument comment for iwmmxt_task_restore() Patch from Lennert Buytenhek Commit d6551e884cf66de072b81f8b6d23259462c40baf forgot to update the description of what goes into r2 when calling iwmmxt_task_restore(). Signed-off-by: Lennert Buytenhek Signed-off-by: Russell King --- arch/arm/kernel/iwmmxt.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/kernel/iwmmxt.S b/arch/arm/kernel/iwmmxt.S index af9e0ae952d..a3bae95e536 100644 --- a/arch/arm/kernel/iwmmxt.S +++ b/arch/arm/kernel/iwmmxt.S @@ -273,7 +273,7 @@ ENTRY(iwmmxt_task_restore) * * r0 = previous task_struct pointer (must be preserved) * r1 = previous thread_info pointer - * r2 = next thread_info.cpu_domain pointer (must be preserved) + * r2 = next thread_info pointer (must be preserved) * * Called only from __switch_to with task preemption disabled. * No need to care about preserving r4 and above. -- cgit v1.2.3-70-g09d2 From 1d81eedb8f6c13c262a70b8167530ec24b09c0ff Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Sat, 24 Jun 2006 10:33:02 +0100 Subject: [ARM] 3634/1: ep93xx: initial implementation of the clk_* API Patch from Lennert Buytenhek Add an initial implementation of the clk_* API for the cirrus ep93xx to the tree. The initial implementation is somewhat minimal, with the intention of extending it as we go along. Signed-off-by: Lennert Buytenhek Signed-off-by: Russell King --- arch/arm/mach-ep93xx/Makefile | 2 +- arch/arm/mach-ep93xx/clock.c | 156 ++++++++++++++++++++++++++++++ arch/arm/mach-ep93xx/core.c | 2 + include/asm-arm/arch-ep93xx/ep93xx-regs.h | 2 + include/asm-arm/arch-ep93xx/platform.h | 1 + 5 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-ep93xx/clock.c (limited to 'arch') diff --git a/arch/arm/mach-ep93xx/Makefile b/arch/arm/mach-ep93xx/Makefile index 5393af989e9..05a48a21038 100644 --- a/arch/arm/mach-ep93xx/Makefile +++ b/arch/arm/mach-ep93xx/Makefile @@ -1,7 +1,7 @@ # # Makefile for the linux kernel. # -obj-y := core.o +obj-y := core.o clock.o obj-m := obj-n := obj- := diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c new file mode 100644 index 00000000000..08ad782c164 --- /dev/null +++ b/arch/arm/mach-ep93xx/clock.c @@ -0,0 +1,156 @@ +/* + * arch/arm/mach-ep93xx/clock.c + * Clock control for Cirrus EP93xx chips. + * + * Copyright (C) 2006 Lennert Buytenhek + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +struct clk { + char *name; + unsigned long rate; + int users; + u32 enable_reg; + u32 enable_mask; +}; + +static struct clk clk_pll1 = { + .name = "pll1", +}; +static struct clk clk_f = { + .name = "fclk", +}; +static struct clk clk_h = { + .name = "hclk", +}; +static struct clk clk_p = { + .name = "pclk", +}; +static struct clk clk_pll2 = { + .name = "pll2", +}; +static struct clk clk_usb_host = { + .name = "usb_host", + .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, + .enable_mask = EP93XX_SYSCON_CLOCK_USH_EN, +}; + + +static struct clk *clocks[] = { + &clk_pll1, + &clk_f, + &clk_h, + &clk_p, + &clk_pll2, + &clk_usb_host, +}; + +struct clk *clk_get(struct device *dev, const char *id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(clocks); i++) { + if (!strcmp(clocks[i]->name, id)) + return clocks[i]; + } + + return ERR_PTR(-ENOENT); +} + +int clk_enable(struct clk *clk) +{ + if (!clk->users++ && clk->enable_reg) { + u32 value; + + value = __raw_readl(clk->enable_reg); + __raw_writel(value | clk->enable_mask, clk->enable_reg); + } + + return 0; +} + +void clk_disable(struct clk *clk) +{ + if (!--clk->users && clk->enable_reg) { + u32 value; + + value = __raw_readl(clk->enable_reg); + __raw_writel(value & ~clk->enable_mask, clk->enable_reg); + } +} + +unsigned long clk_get_rate(struct clk *clk) +{ + return clk->rate; +} + +void clk_put(struct clk *clk) +{ +} + + + +static char fclk_divisors[] = { 1, 2, 4, 8, 16, 1, 1, 1 }; +static char hclk_divisors[] = { 1, 2, 4, 5, 6, 8, 16, 32 }; +static char pclk_divisors[] = { 1, 2, 4, 8 }; + +/* + * PLL rate = 14.7456 MHz * (X1FBD + 1) * (X2FBD + 1) / (X2IPD + 1) / 2^PS + */ +static unsigned long calc_pll_rate(u32 config_word) +{ + unsigned long long rate; + int i; + + rate = 14745600; + rate *= ((config_word >> 11) & 0x1f) + 1; /* X1FBD */ + rate *= ((config_word >> 5) & 0x3f) + 1; /* X2FBD */ + do_div(rate, (config_word & 0x1f) + 1); /* X2IPD */ + for (i = 0; i < ((config_word >> 16) & 3); i++) /* PS */ + rate >>= 1; + + return (unsigned long)rate; +} + +void ep93xx_clock_init(void) +{ + u32 value; + + value = __raw_readl(EP93XX_SYSCON_CLOCK_SET1); + if (!(value & 0x00800000)) { /* PLL1 bypassed? */ + clk_pll1.rate = 14745600; + } else { + clk_pll1.rate = calc_pll_rate(value); + } + clk_f.rate = clk_pll1.rate / fclk_divisors[(value >> 25) & 0x7]; + clk_h.rate = clk_pll1.rate / hclk_divisors[(value >> 20) & 0x7]; + clk_p.rate = clk_h.rate / pclk_divisors[(value >> 18) & 0x3]; + + value = __raw_readl(EP93XX_SYSCON_CLOCK_SET2); + if (!(value & 0x00080000)) { /* PLL2 bypassed? */ + clk_pll2.rate = 14745600; + } else if (value & 0x00040000) { /* PLL2 enabled? */ + clk_pll2.rate = calc_pll_rate(value); + } else { + clk_pll2.rate = 0; + } + clk_usb_host.rate = clk_pll2.rate / (((value >> 28) & 0xf) + 1); + + printk(KERN_INFO "ep93xx: PLL1 running at %ld MHz, PLL2 at %ld MHz\n", + clk_pll1.rate / 1000000, clk_pll2.rate / 1000000); + printk(KERN_INFO "ep93xx: FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n", + clk_f.rate / 1000000, clk_h.rate / 1000000, + clk_p.rate / 1000000); +} diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c index bf6bd71bdd0..6fd6aa74a1f 100644 --- a/arch/arm/mach-ep93xx/core.c +++ b/arch/arm/mach-ep93xx/core.c @@ -437,6 +437,8 @@ void __init ep93xx_init_devices(void) { unsigned int v; + ep93xx_clock_init(); + /* * Disallow access to MaverickCrunch initially. */ diff --git a/include/asm-arm/arch-ep93xx/ep93xx-regs.h b/include/asm-arm/arch-ep93xx/ep93xx-regs.h index 71cea0b5841..8c322975f96 100644 --- a/include/asm-arm/arch-ep93xx/ep93xx-regs.h +++ b/include/asm-arm/arch-ep93xx/ep93xx-regs.h @@ -115,6 +115,8 @@ #define EP93XX_SYSCON_CLOCK_USH_EN 0x10000000 #define EP93XX_SYSCON_HALT EP93XX_SYSCON_REG(0x08) #define EP93XX_SYSCON_STANDBY EP93XX_SYSCON_REG(0x0c) +#define EP93XX_SYSCON_CLOCK_SET1 EP93XX_SYSCON_REG(0x20) +#define EP93XX_SYSCON_CLOCK_SET2 EP93XX_SYSCON_REG(0x24) #define EP93XX_SYSCON_DEVICE_CONFIG EP93XX_SYSCON_REG(0x80) #define EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE 0x00800000 #define EP93XX_SYSCON_SWLOCK EP93XX_SYSCON_REG(0xc0) diff --git a/include/asm-arm/arch-ep93xx/platform.h b/include/asm-arm/arch-ep93xx/platform.h index df9cbb6ef66..d7a34ce2029 100644 --- a/include/asm-arm/arch-ep93xx/platform.h +++ b/include/asm-arm/arch-ep93xx/platform.h @@ -8,6 +8,7 @@ void ep93xx_map_io(void); void ep93xx_init_irq(void); void ep93xx_init_time(unsigned long); void ep93xx_init_devices(void); +void ep93xx_clock_init(void); extern struct sys_timer ep93xx_timer; -- cgit v1.2.3-70-g09d2 From 1f64eb379cfc95d5f627b779685f7ac6721df322 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Sat, 24 Jun 2006 10:33:03 +0100 Subject: [ARM] 3646/1: ep93xx: instantiate ep93xx-ohci platform device Patch from Lennert Buytenhek The ep93xx ohci bits have been merged into the gregkh-2.6 tree, which means that they will probably go upstream soon, so make the core ep93xx code instantiate an appropriate ep93xx-ohci platform device. Signed-off-by: Lennert Buytenhek Signed-off-by: Russell King --- arch/arm/mach-ep93xx/core.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c index 6fd6aa74a1f..1fe73c0a9d0 100644 --- a/arch/arm/mach-ep93xx/core.c +++ b/arch/arm/mach-ep93xx/core.c @@ -433,6 +433,31 @@ static struct platform_device ep93xx_rtc_device = { }; +static struct resource ep93xx_ohci_resources[] = { + [0] = { + .start = EP93XX_USB_PHYS_BASE, + .end = EP93XX_USB_PHYS_BASE + 0x0fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_EP93XX_USB, + .end = IRQ_EP93XX_USB, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device ep93xx_ohci_device = { + .name = "ep93xx-ohci", + .id = -1, + .dev = { + .dma_mask = (void *)0xffffffff, + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = ARRAY_SIZE(ep93xx_ohci_resources), + .resource = ep93xx_ohci_resources, +}; + + void __init ep93xx_init_devices(void) { unsigned int v; @@ -452,4 +477,5 @@ void __init ep93xx_init_devices(void) amba_device_register(&uart3_device, &iomem_resource); platform_device_register(&ep93xx_rtc_device); + platform_device_register(&ep93xx_ohci_device); } -- cgit v1.2.3-70-g09d2 From fc8ea7a1eae3034505f70f02981d33bbc1284a86 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Sat, 24 Jun 2006 09:57:14 +0100 Subject: [ARM] 3644/1: ixp2000: export gpio_line_config() Patch from Lennert Buytenhek Signed-off-by: Lennert Buytenhek Signed-off-by: Russell King --- arch/arm/mach-ixp2000/core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'arch') diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c index 186f632035b..ebe4391dd7f 100644 --- a/arch/arm/mach-ixp2000/core.c +++ b/arch/arm/mach-ixp2000/core.c @@ -302,6 +302,7 @@ void gpio_line_config(int line, int direction) } local_irq_restore(flags); } +EXPORT_SYMBOL(gpio_line_config); /************************************************************************* -- cgit v1.2.3-70-g09d2 From a3ff55026e59687040f00fc35680fc0e774859f4 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sat, 24 Jun 2006 21:21:26 +0100 Subject: [ARM] 3633/1: S3C24XX: s3c2410 gpio bugfix - wrong pin nos Patch from Ben Dooks The s3c2410 gpio functions have a pair of bugs where the code is using the pin function definitions instead of the pin gpio numbers. Also remove the changelog Signed-off-by: Ben Dooks Signed-off-by: Russell King --- arch/arm/mach-s3c2410/s3c2410-gpio.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-s3c2410/s3c2410-gpio.c b/arch/arm/mach-s3c2410/s3c2410-gpio.c index d5e1caea1d2..17519b3281b 100644 --- a/arch/arm/mach-s3c2410/s3c2410-gpio.c +++ b/arch/arm/mach-s3c2410/s3c2410-gpio.c @@ -18,9 +18,6 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Changelog - * 15-Jan-2006 LCVR Splitted from gpio.c */ #include @@ -47,7 +44,7 @@ int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on, config &= 0xff; - pin -= S3C2410_GPG8_EINT16; + pin -= S3C2410_GPG8; reg += pin & ~3; local_irq_save(flags); @@ -75,7 +72,7 @@ EXPORT_SYMBOL(s3c2410_gpio_irqfilter); int s3c2410_gpio_getirq(unsigned int pin) { - if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15_EINT23) + if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15) return -1; /* not valid interrupts */ if (pin < S3C2410_GPG0 && pin > S3C2410_GPF7) -- cgit v1.2.3-70-g09d2 From 68d9ab394f06f95fd4ca612c08edf13e410fd8d0 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sat, 24 Jun 2006 21:21:27 +0100 Subject: [ARM] 3635/1: S3C24XX: Add S3C2412 core cpu support Patch from Ben Dooks Add support for the Samsung S3C2412 and S3C2413 range of SoCs. This patch contains the core identification, debug macros, and basic register updates to get these to build. Signed-off-by: Ben Dooks Signed-off-by: Russell King --- arch/arm/mach-s3c2410/Kconfig | 14 +++ arch/arm/mach-s3c2410/Makefile | 4 + arch/arm/mach-s3c2410/cpu.c | 37 +++++- arch/arm/mach-s3c2410/cpu.h | 1 + arch/arm/mach-s3c2410/s3c2412.c | 195 +++++++++++++++++++++++++++++ arch/arm/mach-s3c2410/s3c2412.h | 29 +++++ include/asm-arm/arch-s3c2410/debug-macro.S | 10 +- include/asm-arm/arch-s3c2410/map.h | 16 +++ include/asm-arm/arch-s3c2410/regs-dsc.h | 3 + include/asm-arm/arch-s3c2410/regs-gpio.h | 63 +++++++++- include/asm-arm/arch-s3c2410/regs-gpioj.h | 5 + 11 files changed, 369 insertions(+), 8 deletions(-) create mode 100644 arch/arm/mach-s3c2410/s3c2412.c create mode 100644 arch/arm/mach-s3c2410/s3c2412.h (limited to 'arch') diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig index 7b786d72563..b61af3a6a41 100644 --- a/arch/arm/mach-s3c2410/Kconfig +++ b/arch/arm/mach-s3c2410/Kconfig @@ -127,6 +127,20 @@ config CPU_S3C2410 Support for S3C2410 and S3C2410A family from the S3C24XX line of Samsung Mobile CPUs. +# internal node to signify if we are only dealing with an S3C2412 + +config CPU_S3C2412_ONLY + bool + depends on ARCH_S3C2410 && !CPU_S3C2400 && !CPU_S3C2410 && \ + !CPU_S3C2440 && !CPU_S3C2442 && CPU_S3C2412 + default y if CPU_S3C2412 + +config CPU_S3C2412 + bool + depends on ARCH_S3C2410 + help + Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line + config CPU_S3C244X bool depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442) diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile index 372dbcea143..86219c6df32 100644 --- a/arch/arm/mach-s3c2410/Makefile +++ b/arch/arm/mach-s3c2410/Makefile @@ -24,6 +24,10 @@ obj-$(CONFIG_S3C2410_DMA) += dma.o obj-$(CONFIG_PM) += pm.o sleep.o obj-$(CONFIG_PM_SIMTEC) += pm-simtec.o +# S3C2412 support +obj-$(CONFIG_CPU_S3C2412) += s3c2412.o + +# # S3C244X support obj-$(CONFIG_CPU_S3C244X) += s3c244x.o diff --git a/arch/arm/mach-s3c2410/cpu.c b/arch/arm/mach-s3c2410/cpu.c index 52842e6e86e..1c3c6adae6c 100644 --- a/arch/arm/mach-s3c2410/cpu.c +++ b/arch/arm/mach-s3c2410/cpu.c @@ -44,6 +44,7 @@ #include "clock.h" #include "s3c2400.h" #include "s3c2410.h" +#include "s3c2412.h" #include "s3c244x.h" #include "s3c2440.h" #include "s3c2442.h" @@ -62,6 +63,7 @@ struct cpu_table { static const char name_s3c2400[] = "S3C2400"; static const char name_s3c2410[] = "S3C2410"; +static const char name_s3c2412[] = "S3C2412"; static const char name_s3c2440[] = "S3C2440"; static const char name_s3c2442[] = "S3C2442"; static const char name_s3c2410a[] = "S3C2410A"; @@ -113,6 +115,15 @@ static struct cpu_table cpu_ids[] __initdata = { .init = s3c2442_init, .name = name_s3c2442 }, + { + .idcode = 0x32412001, + .idmask = 0xffffffff, + .map_io = s3c2412_map_io, + .init_clocks = s3c2412_init_clocks, + .init_uarts = s3c2412_init_uarts, + .init = s3c2412_init, + .name = name_s3c2412, + }, { .idcode = 0x0, /* S3C2400 doesn't have an idcode */ .idmask = 0xffffffff, @@ -171,6 +182,24 @@ void s3c24xx_set_board(struct s3c24xx_board *b) static struct cpu_table *cpu; +static unsigned long s3c24xx_read_idcode_v5(void) +{ +#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) + return __raw_readl(S3C2412_GSTATUS1); +#else + return 1UL; /* don't look like an 2400 */ +#endif +} + +static unsigned long s3c24xx_read_idcode_v4(void) +{ +#ifndef CONFIG_CPU_S3C2400 + return __raw_readl(S3C2410_GSTATUS1); +#else + return 0UL; +#endif +} + void __init s3c24xx_init_io(struct map_desc *mach_desc, int size) { unsigned long idcode = 0x0; @@ -178,9 +207,11 @@ void __init s3c24xx_init_io(struct map_desc *mach_desc, int size) /* initialise the io descriptors we need for initialisation */ iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc)); -#ifndef CONFIG_CPU_S3C2400 - idcode = __raw_readl(S3C2410_GSTATUS1); -#endif + if (cpu_architecture() >= CPU_ARCH_ARMv5) { + idcode = s3c24xx_read_idcode_v5(); + } else { + idcode = s3c24xx_read_idcode_v4(); + } cpu = s3c_lookup_cpu(idcode); diff --git a/arch/arm/mach-s3c2410/cpu.h b/arch/arm/mach-s3c2410/cpu.h index 21c62dc29bb..b0ed9d2d141 100644 --- a/arch/arm/mach-s3c2410/cpu.h +++ b/arch/arm/mach-s3c2410/cpu.h @@ -74,5 +74,6 @@ extern struct sys_timer s3c24xx_timer; /* system device classes */ extern struct sysdev_class s3c2410_sysclass; +extern struct sysdev_class s3c2412_sysclass; extern struct sysdev_class s3c2440_sysclass; extern struct sysdev_class s3c2442_sysclass; diff --git a/arch/arm/mach-s3c2410/s3c2412.c b/arch/arm/mach-s3c2410/s3c2412.c new file mode 100644 index 00000000000..e24ffd5e478 --- /dev/null +++ b/arch/arm/mach-s3c2410/s3c2412.c @@ -0,0 +1,195 @@ +/* linux/arch/arm/mach-s3c2410/s3c2412.c + * + * Copyright (c) 2006 Simtec Electronics + * Ben Dooks + * + * http://armlinux.simtec.co.uk/. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Modifications: + * 16-May-2003 BJD Created initial version + * 16-Aug-2003 BJD Fixed header files and copyright, added URL + * 05-Sep-2003 BJD Moved to kernel v2.6 + * 18-Jan-2004 BJD Added serial port configuration + * 21-Aug-2004 BJD Added new struct s3c2410_board handler + * 28-Sep-2004 BJD Updates for new serial port bits + * 04-Nov-2004 BJD Updated UART configuration process + * 10-Jan-2005 BJD Removed s3c2410_clock_tick_rate + * 13-Aug-2005 DA Removed UART from initial I/O mappings +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "s3c2412.h" +#include "cpu.h" +#include "devs.h" +#include "clock.h" +#include "pm.h" + +#ifndef CONFIG_CPU_S3C2412_ONLY +void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO; +#endif + +/* Initial IO mappings */ + +static struct map_desc s3c2412_iodesc[] __initdata = { + IODESC_ENT(CLKPWR), + IODESC_ENT(LCD), + IODESC_ENT(TIMER), + IODESC_ENT(ADC), + IODESC_ENT(WATCHDOG), +}; + +/* uart registration process */ + +void __init s3c2412_init_uarts(struct s3c2410_uartcfg *cfg, int no) +{ + s3c24xx_init_uartdevs("s3c2412-uart", s3c2410_uart_resources, cfg, no); + + /* rename devices that are s3c2412/s3c2413 specific */ + s3c_device_sdi.name = "s3c2412-sdi"; + s3c_device_nand.name = "s3c2412-nand"; +} + +/* s3c2412_map_io + * + * register the standard cpu IO areas, and any passed in from the + * machine specific initialisation. +*/ + +void __init s3c2412_map_io(struct map_desc *mach_desc, int mach_size) +{ + /* move base of IO */ + + s3c24xx_va_gpio2 = S3C24XX_VA_GPIO + 0x10; + + /* register our io-tables */ + + iotable_init(s3c2412_iodesc, ARRAY_SIZE(s3c2412_iodesc)); + iotable_init(mach_desc, mach_size); +} + +void __init s3c2412_init_clocks(int xtal) +{ + unsigned long tmp; + unsigned long fclk; + unsigned long hclk; + unsigned long pclk; + + /* now we've got our machine bits initialised, work out what + * clocks we've got */ + + fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal*2); + + tmp = __raw_readl(S3C2410_CLKDIVN); + + /* work out clock scalings */ + + hclk = fclk / ((tmp & S3C2412_CLKDIVN_HDIVN_MASK) + 1); + hclk /= ((tmp & S3C2421_CLKDIVN_ARMDIVN) ? 2 : 1); + pclk = hclk / ((tmp & S3C2412_CLKDIVN_PDIVN) ? 2 : 1); + + /* print brieft summary of clocks, etc */ + + printk("S3C2412: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n", + print_mhz(fclk), print_mhz(hclk), print_mhz(pclk)); + + /* initialise the clocks here, to allow other things like the + * console to use them + */ + + s3c24xx_setup_clocks(xtal, fclk, hclk, pclk); + s3c2412_baseclk_add(); +} + +/* need to register class before we actually register the device, and + * we also need to ensure that it has been initialised before any of the + * drivers even try to use it (even if not on an s3c2412 based system) + * as a driver which may support both 2410 and 2440 may try and use it. +*/ + +#ifdef CONFIG_PM +static struct sleep_save s3c2412_sleep[] = { + SAVE_ITEM(S3C2412_DSC0), + SAVE_ITEM(S3C2412_DSC1), + SAVE_ITEM(S3C2413_GPJDAT), + SAVE_ITEM(S3C2413_GPJCON), + SAVE_ITEM(S3C2413_GPJUP), + + /* save the sleep configuration anyway, just in case these + * get damaged during wakeup */ + + SAVE_ITEM(S3C2412_GPBSLPCON), + SAVE_ITEM(S3C2412_GPCSLPCON), + SAVE_ITEM(S3C2412_GPDSLPCON), + SAVE_ITEM(S3C2412_GPESLPCON), + SAVE_ITEM(S3C2412_GPFSLPCON), + SAVE_ITEM(S3C2412_GPGSLPCON), + SAVE_ITEM(S3C2412_GPHSLPCON), + SAVE_ITEM(S3C2413_GPJSLPCON), +}; + +static int s3c2412_suspend(struct sys_device *dev, pm_message_t state) +{ + s3c2410_pm_do_save(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep)); + return 0; +} + +static int s3c2412_resume(struct sys_device *dev) +{ + s3c2410_pm_do_restore(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep)); + return 0; +} + +#else +#define s3c2412_suspend NULL +#define s3c2412_resume NULL +#endif + +struct sysdev_class s3c2412_sysclass = { + set_kset_name("s3c2412-core"), + .suspend = s3c2412_suspend, + .resume = s3c2412_resume +}; + +static int __init s3c2412_core_init(void) +{ + return sysdev_class_register(&s3c2412_sysclass); +} + +core_initcall(s3c2412_core_init); + +static struct sys_device s3c2412_sysdev = { + .cls = &s3c2412_sysclass, +}; + +int __init s3c2412_init(void) +{ + printk("S3C2412: Initialising architecture\n"); + + return sysdev_register(&s3c2412_sysdev); +} diff --git a/arch/arm/mach-s3c2410/s3c2412.h b/arch/arm/mach-s3c2410/s3c2412.h new file mode 100644 index 00000000000..c6e56032a6e --- /dev/null +++ b/arch/arm/mach-s3c2410/s3c2412.h @@ -0,0 +1,29 @@ +/* arch/arm/mach-s3c2410/s3c2412.h + * + * Copyright (c) 2006 Simtec Electronics + * Ben Dooks + * + * Header file for s3c2412 cpu support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#ifdef CONFIG_CPU_S3C2412 + +extern int s3c2412_init(void); + +extern void s3c2412_map_io(struct map_desc *mach_desc, int size); + +extern void s3c2412_init_uarts(struct s3c2410_uartcfg *cfg, int no); + +extern void s3c2412_init_clocks(int xtal); + +extern int s3c2412_baseclk_add(void); +#else +#define s3c2412_init_clocks NULL +#define s3c2412_init_uarts NULL +#define s3c2412_map_io NULL +#define s3c2412_init NULL +#endif diff --git a/include/asm-arm/arch-s3c2410/debug-macro.S b/include/asm-arm/arch-s3c2410/debug-macro.S index 5f8223e700d..b7d15d12545 100644 --- a/include/asm-arm/arch-s3c2410/debug-macro.S +++ b/include/asm-arm/arch-s3c2410/debug-macro.S @@ -33,7 +33,7 @@ .endm .macro senduart,rd,rx - str \rd, [\rx, # S3C2410_UTXH ] + strb \rd, [\rx, # S3C2410_UTXH ] .endm .macro busyuart, rd, rx @@ -42,6 +42,12 @@ beq 1001f @ @ FIFO enabled... 1003: + @ check for arm920 vs arm926. currently assume all arm926 + @ devices have an 64 byte FIFO identical to the s3c2440 + mrc p15, 0, \rd, c0, c0 + and \rd, \rd, #0xff0 + teq \rd, #0x260 + beq 1004f mrc p15, 0, \rd, c1, c0 tst \rd, #1 addeq \rd, \rx, #(S3C24XX_PA_GPIO - S3C24XX_PA_UART) @@ -50,7 +56,7 @@ ldr \rd, [ \rd, # S3C2410_GSTATUS1 - S3C2410_GPIOREG(0) ] and \rd, \rd, #0x00ff0000 teq \rd, #0x00440000 @ is it 2440? - +1004: ldr \rd, [ \rx, # S3C2410_UFSTAT ] moveq \rd, \rd, lsr #SHIFT_2440TXF tst \rd, #S3C2410_UFSTAT_TXFULL diff --git a/include/asm-arm/arch-s3c2410/map.h b/include/asm-arm/arch-s3c2410/map.h index 5e4c8c37bc6..fae2766ff32 100644 --- a/include/asm-arm/arch-s3c2410/map.h +++ b/include/asm-arm/arch-s3c2410/map.h @@ -236,4 +236,20 @@ #define S3C24XX_PA_SPI S3C2410_PA_SPI #endif +/* deal with the registers that move under the 2412/2413 */ + +#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) +#ifndef __ASSEMBLY__ +extern void __iomem *s3c24xx_va_gpio2; +#endif +#ifdef CONFIG_CPU_S3C2412_ONLY +#define S3C24XX_VA_GPIO2 (S3C24XX_VA_GPIO + 0x10) +#else +#define S3C24XX_VA_GPIO2 s3c24xx_va_gpio2 +#endif +#else +#define s3c24xx_va_gpio2 S3C24XX_VA_GPIO +#define S3C24XX_VA_GPIO2 S3C24XX_VA_GPIO +#endif + #endif /* __ASM_ARCH_MAP_H */ diff --git a/include/asm-arm/arch-s3c2410/regs-dsc.h b/include/asm-arm/arch-s3c2410/regs-dsc.h index ba13a2c9e54..84aca61cbaa 100644 --- a/include/asm-arm/arch-s3c2410/regs-dsc.h +++ b/include/asm-arm/arch-s3c2410/regs-dsc.h @@ -23,6 +23,9 @@ #define S3C2440_DSC0 S3C2410_GPIOREG(0xc4) #define S3C2440_DSC1 S3C2410_GPIOREG(0xc8) +#define S3C2412_DSC0 S3C2410_GPIOREG(0xdc) +#define S3C2412_DSC1 S3C2410_GPIOREG(0xe0) + #define S3C2440_SELECT_DSC0 (0) #define S3C2440_SELECT_DSC1 (1<<31) diff --git a/include/asm-arm/arch-s3c2410/regs-gpio.h b/include/asm-arm/arch-s3c2410/regs-gpio.h index 5f10334f06b..6dd17f0f84e 100644 --- a/include/asm-arm/arch-s3c2410/regs-gpio.h +++ b/include/asm-arm/arch-s3c2410/regs-gpio.h @@ -45,7 +45,7 @@ #define S3C24XX_MISCCR S3C2400_MISCCR #else #define S3C24XX_GPIO_BASE(x) S3C2410_GPIO_BASE(x) -#define S3C24XX_MISCCR S3C2410_MISCCR +#define S3C24XX_MISCCR S3C24XX_GPIOREG2(0x80) #endif /* CONFIG_CPU_S3C2400 */ @@ -73,9 +73,15 @@ #define S3C2410_GPIO_SFN2 (0xFFFFFFF2) /* not available on A */ #define S3C2410_GPIO_SFN3 (0xFFFFFFF3) /* not available on A */ -/* configure GPIO ports A..G */ +/* register address for the GPIO registers. + * S3C24XX_GPIOREG2 is for the second set of registers in the + * GPIO which move between s3c2410 and s3c2412 type systems */ #define S3C2410_GPIOREG(x) ((x) + S3C24XX_VA_GPIO) +#define S3C24XX_GPIOREG2(x) ((x) + S3C24XX_VA_GPIO2) + + +/* configure GPIO ports A..G */ /* port A - S3C2410: 22bits, zero in bit X makes pin X output * S3C2400: 18bits, zero in bit X makes pin X output @@ -953,11 +959,18 @@ #define S3C2410_GPH10_OUTP (0x01 << 20) #define S3C2410_GPH10_CLKOUT1 (0x02 << 20) +/* The S3C2412 and S3C2413 move the GPJ register set to after + * GPH, which means all registers after 0x80 are now offset by 0x10 + * for the 2412/2413 from the 2410/2440/2442 +*/ + /* miscellaneous control */ #define S3C2400_MISCCR S3C2410_GPIOREG(0x54) #define S3C2410_MISCCR S3C2410_GPIOREG(0x80) #define S3C2410_DCLKCON S3C2410_GPIOREG(0x84) +#define S3C24XX_DCLKCON S3C24XX_GPIOREG2(0x84) + /* see clock.h for dclk definitions */ /* pullup control on databus */ @@ -985,6 +998,8 @@ #define S3C2410_MISCCR_CLK0_DCLK0 (5<<4) #define S3C2410_MISCCR_CLK0_MASK (7<<4) +#define S3C2412_MISCCR_CLK0_RTC (2<<4) + #define S3C2410_MISCCR_CLK1_MPLL (0<<8) #define S3C2410_MISCCR_CLK1_UPLL (1<<8) #define S3C2410_MISCCR_CLK1_FCLK (2<<8) @@ -993,6 +1008,8 @@ #define S3C2410_MISCCR_CLK1_DCLK1 (5<<8) #define S3C2410_MISCCR_CLK1_MASK (7<<8) +#define S3C2412_MISCCR_CLK1_CLKsrc (0<<8) + #define S3C2410_MISCCR_USBSUSPND0 (1<<12) #define S3C2410_MISCCR_USBSUSPND1 (1<<13) @@ -1000,7 +1017,7 @@ #define S3C2410_MISCCR_nEN_SCLK0 (1<<17) #define S3C2410_MISCCR_nEN_SCLK1 (1<<18) -#define S3C2410_MISCCR_nEN_SCLKE (1<<19) +#define S3C2410_MISCCR_nEN_SCLKE (1<<19) /* not 2412 */ #define S3C2410_MISCCR_SDSLEEP (7<<17) /* external interrupt control... */ @@ -1017,6 +1034,10 @@ #define S3C2410_EXTINT1 S3C2410_GPIOREG(0x8C) #define S3C2410_EXTINT2 S3C2410_GPIOREG(0x90) +#define S3C24XX_EXTINT0 S3C24XX_GPIOREG2(0x88) +#define S3C24XX_EXTINT1 S3C24XX_GPIOREG2(0x8C) +#define S3C24XX_EXTINT2 S3C24XX_GPIOREG2(0x90) + /* values for S3C2410_EXTINT0/1/2 */ #define S3C2410_EXTINT_LOWLEV (0x00) #define S3C2410_EXTINT_HILEV (0x01) @@ -1030,6 +1051,11 @@ #define S3C2410_EINFLT2 S3C2410_GPIOREG(0x9C) #define S3C2410_EINFLT3 S3C2410_GPIOREG(0xA0) +#define S3C24XX_EINFLT0 S3C24XX_GPIOREG2(0x94) +#define S3C24XX_EINFLT1 S3C24XX_GPIOREG2(0x98) +#define S3C24XX_EINFLT2 S3C24XX_GPIOREG2(0x9C) +#define S3C24XX_EINFLT3 S3C24XX_GPIOREG2(0xA0) + /* values for interrupt filtering */ #define S3C2410_EINTFLT_PCLK (0x00) #define S3C2410_EINTFLT_EXTCLK (1<<7) @@ -1039,6 +1065,7 @@ /* GSTATUS have miscellaneous information in them * + * These move between s3c2410 and s3c2412 style systems. */ #define S3C2410_GSTATUS0 S3C2410_GPIOREG(0x0AC) @@ -1047,6 +1074,18 @@ #define S3C2410_GSTATUS3 S3C2410_GPIOREG(0x0B8) #define S3C2410_GSTATUS4 S3C2410_GPIOREG(0x0BC) +#define S3C2412_GSTATUS0 S3C2410_GPIOREG(0x0BC) +#define S3C2412_GSTATUS1 S3C2410_GPIOREG(0x0C0) +#define S3C2412_GSTATUS2 S3C2410_GPIOREG(0x0C4) +#define S3C2412_GSTATUS3 S3C2410_GPIOREG(0x0C8) +#define S3C2412_GSTATUS4 S3C2410_GPIOREG(0x0CC) + +#define S3C24XX_GSTATUS0 S3C24XX_GPIOREG2(0x0AC) +#define S3C24XX_GSTATUS1 S3C24XX_GPIOREG2(0x0B0) +#define S3C24XX_GSTATUS2 S3C24XX_GPIOREG2(0x0B4) +#define S3C24XX_GSTATUS3 S3C24XX_GPIOREG2(0x0B8) +#define S3C24XX_GSTATUS4 S3C24XX_GPIOREG2(0x0BC) + #define S3C2410_GSTATUS0_nWAIT (1<<3) #define S3C2410_GSTATUS0_NCON (1<<2) #define S3C2410_GSTATUS0_RnB (1<<1) @@ -1054,6 +1093,7 @@ #define S3C2410_GSTATUS1_IDMASK (0xffff0000) #define S3C2410_GSTATUS1_2410 (0x32410000) +#define S3C2410_GSTATUS1_2412 (0x32412001) #define S3C2410_GSTATUS1_2440 (0x32440000) #define S3C2410_GSTATUS1_2442 (0x32440aaa) @@ -1077,5 +1117,22 @@ #define S3C2400_OPENCR_OPC_MOSIDIS (0<<5) #define S3C2400_OPENCR_OPC_MOSIEN (1<<5) +/* 2412/2413 sleep configuration registers */ + +#define S3C2412_GPBSLPCON S3C2410_GPIOREG(0x1C) +#define S3C2412_GPCSLPCON S3C2410_GPIOREG(0x2C) +#define S3C2412_GPDSLPCON S3C2410_GPIOREG(0x3C) +#define S3C2412_GPESLPCON S3C2410_GPIOREG(0x4C) +#define S3C2412_GPFSLPCON S3C2410_GPIOREG(0x5C) +#define S3C2412_GPGSLPCON S3C2410_GPIOREG(0x6C) +#define S3C2412_GPHSLPCON S3C2410_GPIOREG(0x7C) + +/* definitions for each pin bit */ +#define S3C2412_SLPCON_LOW(x) ( 0x00 << ((x) * 2)) +#define S3C2412_SLPCON_HI(x) ( 0x01 << ((x) * 2)) +#define S3C2412_SLPCON_IN(x) ( 0x02 << ((x) * 2)) +#define S3C2412_SLPCON_PDWN(x) ( 0x03 << ((x) * 2)) +#define S3C2412_SLPCON_MASK(x) ( 0x03 << ((x) * 2)) + #endif /* __ASM_ARCH_REGS_GPIO_H */ diff --git a/include/asm-arm/arch-s3c2410/regs-gpioj.h b/include/asm-arm/arch-s3c2410/regs-gpioj.h index 3ad2324acc3..18edae50d0b 100644 --- a/include/asm-arm/arch-s3c2410/regs-gpioj.h +++ b/include/asm-arm/arch-s3c2410/regs-gpioj.h @@ -32,6 +32,11 @@ #define S3C2440_GPJDAT S3C2410_GPIOREG(0xd4) #define S3C2440_GPJUP S3C2410_GPIOREG(0xd8) +#define S3C2413_GPJCON S3C2410_GPIOREG(0x80) +#define S3C2413_GPJDAT S3C2410_GPIOREG(0x84) +#define S3C2413_GPJUP S3C2410_GPIOREG(0x88) +#define S3C2413_GPJSLPCON S3C2410_GPIOREG(0x8C) + #define S3C2440_GPJ0 S3C2410_GPIONO(S3C2440_GPIO_BANKJ, 0) #define S3C2440_GPJ0_INP (0x00 << 0) #define S3C2440_GPJ0_OUTP (0x01 << 0) -- cgit v1.2.3-70-g09d2 From 3434d9d9fc0fec0b96ab128ee0d743b6a0d90160 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sat, 24 Jun 2006 21:21:28 +0100 Subject: [ARM] 3636/1: S3C2412: Add selection of CPU_ARM926 Patch from Ben Dooks Select CONFIG_CPU_ARM926 when CONFIG_CPU_S3C2412 is selected. Signed-off-by: Ben Dooks Signed-off-by: Russell King --- arch/arm/mm/Kconfig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'arch') diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 4221d054a1e..ecf5e232a6f 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -61,9 +61,9 @@ config CPU_ARM720T # ARM920T config CPU_ARM920T - bool "Support ARM920T processor" if !ARCH_S3C2410 - depends on ARCH_EP93XX || ARCH_INTEGRATOR || ARCH_S3C2410 || ARCH_IMX || ARCH_AAEC2000 || ARCH_AT91RM9200 - default y if ARCH_S3C2410 || ARCH_AT91RM9200 + bool "Support ARM920T processor" + depends on ARCH_EP93XX || ARCH_INTEGRATOR || CPU_S3C2410 || CPU_S3C2440 || CPU_S3C2442 || ARCH_IMX || ARCH_AAEC2000 || ARCH_AT91RM9200 + default y if CPU_S3C2410 || CPU_S3C2440 || CPU_S3C2442 || ARCH_AT91RM9200 select CPU_32v4 select CPU_ABRT_EV4T select CPU_CACHE_V4WT @@ -121,8 +121,8 @@ config CPU_ARM925T # ARM926T config CPU_ARM926T bool "Support ARM926T processor" - depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB || ARCH_PNX4008 || ARCH_NETX - default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || ARCH_PNX4008 || ARCH_NETX + depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 + default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 select CPU_32v5 select CPU_ABRT_EV5TJ select CPU_CACHE_VIVT -- cgit v1.2.3-70-g09d2 From 513846f82829efd5bab5359bdc33509e6386fd49 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sat, 24 Jun 2006 21:21:29 +0100 Subject: [ARM] 3637/1: S3C24XX: Add mpll clock, and set as fclk parent Patch from Ben Dooks Update the clocks with the MPLL clock, and use it as the parent. Also export these to the rest of arch/arm/mach-s3c2410 Signed-off-by: Ben Dooks Signed-off-by: Russell King --- arch/arm/mach-s3c2410/clock.c | 13 +++++++++++-- arch/arm/mach-s3c2410/clock.h | 2 ++ 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c index c5c93c333ac..90a0610b514 100644 --- a/arch/arm/mach-s3c2410/clock.c +++ b/arch/arm/mach-s3c2410/clock.c @@ -213,7 +213,7 @@ EXPORT_SYMBOL(clk_set_parent); /* base clocks */ -static struct clk clk_xtal = { +struct clk clk_xtal = { .name = "xtal", .id = -1, .rate = 0, @@ -221,6 +221,11 @@ static struct clk clk_xtal = { .ctrlbit = 0, }; +struct clk clk_mpll = { + .name = "mpll", + .id = -1, +}; + struct clk clk_upll = { .name = "upll", .id = -1, @@ -232,7 +237,7 @@ struct clk clk_f = { .name = "fclk", .id = -1, .rate = 0, - .parent = NULL, + .parent = &clk_mpll, .ctrlbit = 0, }; @@ -413,6 +418,7 @@ int __init s3c24xx_setup_clocks(unsigned long xtal, clk_xtal.rate = xtal; clk_upll.rate = s3c2410_get_pll(__raw_readl(S3C2410_UPLLCON), xtal); + clk_mpll.rate = fclk; clk_h.rate = hclk; clk_p.rate = pclk; clk_f.rate = fclk; @@ -424,6 +430,9 @@ int __init s3c24xx_setup_clocks(unsigned long xtal, if (s3c24xx_register_clock(&clk_xtal) < 0) printk(KERN_ERR "failed to register master xtal\n"); + if (s3c24xx_register_clock(&clk_mpll) < 0) + printk(KERN_ERR "failed to register mpll clock\n"); + if (s3c24xx_register_clock(&clk_upll) < 0) printk(KERN_ERR "failed to register upll clock\n"); diff --git a/arch/arm/mach-s3c2410/clock.h b/arch/arm/mach-s3c2410/clock.h index 9456c81eb5d..7f0ea03e1d4 100644 --- a/arch/arm/mach-s3c2410/clock.h +++ b/arch/arm/mach-s3c2410/clock.h @@ -42,7 +42,9 @@ extern struct clk clk_usb_bus; extern struct clk clk_f; extern struct clk clk_h; extern struct clk clk_p; +extern struct clk clk_mpll; extern struct clk clk_upll; +extern struct clk clk_xtal; /* exports for arch/arm/mach-s3c2410 * -- cgit v1.2.3-70-g09d2 From 736855f0c748dacb624070b8d6ffffe4532cf4dc Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sat, 24 Jun 2006 21:21:31 +0100 Subject: [ARM] 3638/1: S3C2412: core clocks Patch from Ben Dooks Clock support for the clocks on the Samsung S3C2412 and S3C2413 SoCs. This provides clock enables and parent selection for all the standard clocks. Signed-off-by: Ben Dooks Signed-off-by: Russell King --- arch/arm/mach-s3c2410/Makefile | 1 + arch/arm/mach-s3c2410/s3c2412-clock.c | 711 ++++++++++++++++++++++++++++++ include/asm-arm/arch-s3c2410/regs-clock.h | 63 ++- 3 files changed, 774 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-s3c2410/s3c2412-clock.c (limited to 'arch') diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile index 86219c6df32..d934a89179a 100644 --- a/arch/arm/mach-s3c2410/Makefile +++ b/arch/arm/mach-s3c2410/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_PM_SIMTEC) += pm-simtec.o # S3C2412 support obj-$(CONFIG_CPU_S3C2412) += s3c2412.o +obj-$(CONFIG_CPU_S3C2412) += s3c2412-clock.o # # S3C244X support diff --git a/arch/arm/mach-s3c2410/s3c2412-clock.c b/arch/arm/mach-s3c2410/s3c2412-clock.c new file mode 100644 index 00000000000..c95ed3e1858 --- /dev/null +++ b/arch/arm/mach-s3c2410/s3c2412-clock.c @@ -0,0 +1,711 @@ +/* linux/arch/arm/mach-s3c2410/s3c2412-clock.c + * + * Copyright (c) 2006 Simtec Electronics + * Ben Dooks + * + * S3C2412,S3C2413 Clock control support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "clock.h" +#include "cpu.h" + +/* We currently have to assume that the system is running + * from the XTPll input, and that all ***REFCLKs are being + * fed from it, as we cannot read the state of OM[4] from + * software. + * + * It would be possible for each board initialisation to + * set the correct muxing at initialisation +*/ + +int s3c2412_clkcon_enable(struct clk *clk, int enable) +{ + unsigned int clocks = clk->ctrlbit; + unsigned long clkcon; + + clkcon = __raw_readl(S3C2410_CLKCON); + + if (enable) + clkcon |= clocks; + else + clkcon &= ~clocks; + + __raw_writel(clkcon, S3C2410_CLKCON); + + return 0; +} + +static int s3c2412_upll_enable(struct clk *clk, int enable) +{ + unsigned long upllcon = __raw_readl(S3C2410_UPLLCON); + unsigned long orig = upllcon; + + if (!enable) + upllcon |= S3C2412_PLLCON_OFF; + else + upllcon &= ~S3C2412_PLLCON_OFF; + + __raw_writel(upllcon, S3C2410_UPLLCON); + + /* allow ~150uS for the PLL to settle and lock */ + + if (enable && (orig & S3C2412_PLLCON_OFF)) + udelay(150); + + return 0; +} + +/* clock selections */ + +/* CPU EXTCLK input */ +static struct clk clk_ext = { + .name = "extclk", + .id = -1, +}; + +static struct clk clk_erefclk = { + .name = "erefclk", + .id = -1, +}; + +static struct clk clk_urefclk = { + .name = "urefclk", + .id = -1, +}; + +static int s3c2412_setparent_usysclk(struct clk *clk, struct clk *parent) +{ + unsigned long clksrc = __raw_readl(S3C2412_CLKSRC); + + if (parent == &clk_urefclk) + clksrc &= ~S3C2412_CLKSRC_USYSCLK_UPLL; + else if (parent == &clk_upll) + clksrc |= S3C2412_CLKSRC_USYSCLK_UPLL; + else + return -EINVAL; + + clk->parent = parent; + + __raw_writel(clksrc, S3C2412_CLKSRC); + return 0; +} + +static struct clk clk_usysclk = { + .name = "usysclk", + .id = -1, + .parent = &clk_xtal, + .set_parent = s3c2412_setparent_usysclk, +}; + +static struct clk clk_mrefclk = { + .name = "mrefclk", + .parent = &clk_xtal, + .id = -1, +}; + +static struct clk clk_mdivclk = { + .name = "mdivclk", + .parent = &clk_xtal, + .id = -1, +}; + +static int s3c2412_setparent_usbsrc(struct clk *clk, struct clk *parent) +{ + unsigned long clksrc = __raw_readl(S3C2412_CLKSRC); + + if (parent == &clk_usysclk) + clksrc &= ~S3C2412_CLKSRC_USBCLK_HCLK; + else if (parent == &clk_h) + clksrc |= S3C2412_CLKSRC_USBCLK_HCLK; + else + return -EINVAL; + + clk->parent = parent; + + __raw_writel(clksrc, S3C2412_CLKSRC); + return 0; +} + +static unsigned long s3c2412_roundrate_usbsrc(struct clk *clk, + unsigned long rate) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + int div; + + if (rate > parent_rate) + return parent_rate; + + div = parent_rate / rate; + if (div > 2) + div = 2; + + return parent_rate / div; +} + +static unsigned long s3c2412_getrate_usbsrc(struct clk *clk) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long div = __raw_readl(S3C2410_CLKDIVN); + + return parent_rate / ((div & S3C2412_CLKDIVN_USB48DIV) ? 2 : 1); +} + +static int s3c2412_setrate_usbsrc(struct clk *clk, unsigned long rate) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN); + + rate = s3c2412_roundrate_usbsrc(clk, rate); + + if ((parent_rate / rate) == 2) + clkdivn |= S3C2412_CLKDIVN_USB48DIV; + else + clkdivn &= ~S3C2412_CLKDIVN_USB48DIV; + + __raw_writel(clkdivn, S3C2410_CLKDIVN); + return 0; +} + +static struct clk clk_usbsrc = { + .name = "usbsrc", + .id = -1, + .get_rate = s3c2412_getrate_usbsrc, + .set_rate = s3c2412_setrate_usbsrc, + .round_rate = s3c2412_roundrate_usbsrc, + .set_parent = s3c2412_setparent_usbsrc, +}; + +static int s3c2412_setparent_msysclk(struct clk *clk, struct clk *parent) +{ + unsigned long clksrc = __raw_readl(S3C2412_CLKSRC); + + if (parent == &clk_mdivclk) + clksrc &= ~S3C2412_CLKSRC_MSYSCLK_MPLL; + else if (parent == &clk_upll) + clksrc |= S3C2412_CLKSRC_MSYSCLK_MPLL; + else + return -EINVAL; + + clk->parent = parent; + + __raw_writel(clksrc, S3C2412_CLKSRC); + return 0; +} + +static struct clk clk_msysclk = { + .name = "msysclk", + .id = -1, + .set_parent = s3c2412_setparent_msysclk, +}; + +/* these next clocks have an divider immediately after them, + * so we can register them with their divider and leave out the + * intermediate clock stage +*/ +static unsigned long s3c2412_roundrate_clksrc(struct clk *clk, + unsigned long rate) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + int div; + + if (rate > parent_rate) + return parent_rate; + + /* note, we remove the +/- 1 calculations as they cancel out */ + + div = (rate / parent_rate); + + if (div < 1) + div = 1; + else if (div > 16) + div = 16; + + return parent_rate / div; +} + +static int s3c2412_setparent_uart(struct clk *clk, struct clk *parent) +{ + unsigned long clksrc = __raw_readl(S3C2412_CLKSRC); + + if (parent == &clk_erefclk) + clksrc &= ~S3C2412_CLKSRC_UARTCLK_MPLL; + else if (parent == &clk_mpll) + clksrc |= S3C2412_CLKSRC_UARTCLK_MPLL; + else + return -EINVAL; + + clk->parent = parent; + + __raw_writel(clksrc, S3C2412_CLKSRC); + return 0; +} + +static unsigned long s3c2412_getrate_uart(struct clk *clk) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long div = __raw_readl(S3C2410_CLKDIVN); + + div &= S3C2412_CLKDIVN_UARTDIV_MASK; + div >>= S3C2412_CLKDIVN_UARTDIV_SHIFT; + + return parent_rate / (div + 1); +} + +static int s3c2412_setrate_uart(struct clk *clk, unsigned long rate) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN); + + rate = s3c2412_roundrate_clksrc(clk, rate); + + clkdivn &= ~S3C2412_CLKDIVN_UARTDIV_MASK; + clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_UARTDIV_SHIFT; + + __raw_writel(clkdivn, S3C2410_CLKDIVN); + return 0; +} + +static struct clk clk_uart = { + .name = "uartclk", + .id = -1, + .get_rate = s3c2412_getrate_uart, + .set_rate = s3c2412_setrate_uart, + .set_parent = s3c2412_setparent_uart, + .round_rate = s3c2412_roundrate_clksrc, +}; + +static int s3c2412_setparent_i2s(struct clk *clk, struct clk *parent) +{ + unsigned long clksrc = __raw_readl(S3C2412_CLKSRC); + + if (parent == &clk_erefclk) + clksrc &= ~S3C2412_CLKSRC_I2SCLK_MPLL; + else if (parent == &clk_mpll) + clksrc |= S3C2412_CLKSRC_I2SCLK_MPLL; + else + return -EINVAL; + + clk->parent = parent; + + __raw_writel(clksrc, S3C2412_CLKSRC); + return 0; +} + +static unsigned long s3c2412_getrate_i2s(struct clk *clk) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long div = __raw_readl(S3C2410_CLKDIVN); + + div &= S3C2412_CLKDIVN_I2SDIV_MASK; + div >>= S3C2412_CLKDIVN_I2SDIV_SHIFT; + + return parent_rate / (div + 1); +} + +static int s3c2412_setrate_i2s(struct clk *clk, unsigned long rate) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN); + + rate = s3c2412_roundrate_clksrc(clk, rate); + + clkdivn &= ~S3C2412_CLKDIVN_I2SDIV_MASK; + clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_I2SDIV_SHIFT; + + __raw_writel(clkdivn, S3C2410_CLKDIVN); + return 0; +} + +static struct clk clk_i2s = { + .name = "i2sclk", + .id = -1, + .get_rate = s3c2412_getrate_i2s, + .set_rate = s3c2412_setrate_i2s, + .set_parent = s3c2412_setparent_i2s, + .round_rate = s3c2412_roundrate_clksrc, +}; + +static int s3c2412_setparent_cam(struct clk *clk, struct clk *parent) +{ + unsigned long clksrc = __raw_readl(S3C2412_CLKSRC); + + if (parent == &clk_usysclk) + clksrc &= ~S3C2412_CLKSRC_CAMCLK_HCLK; + else if (parent == &clk_h) + clksrc |= S3C2412_CLKSRC_CAMCLK_HCLK; + else + return -EINVAL; + + clk->parent = parent; + + __raw_writel(clksrc, S3C2412_CLKSRC); + return 0; +} +static unsigned long s3c2412_getrate_cam(struct clk *clk) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long div = __raw_readl(S3C2410_CLKDIVN); + + div &= S3C2412_CLKDIVN_CAMDIV_MASK; + div >>= S3C2412_CLKDIVN_CAMDIV_SHIFT; + + return parent_rate / (div + 1); +} + +static int s3c2412_setrate_cam(struct clk *clk, unsigned long rate) +{ + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN); + + rate = s3c2412_roundrate_clksrc(clk, rate); + + clkdivn &= ~S3C2412_CLKDIVN_CAMDIV_MASK; + clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_CAMDIV_SHIFT; + + __raw_writel(clkdivn, S3C2410_CLKDIVN); + return 0; +} + +static struct clk clk_cam = { + .name = "camif-upll", /* same as 2440 name */ + .id = -1, + .get_rate = s3c2412_getrate_cam, + .set_rate = s3c2412_setrate_cam, + .set_parent = s3c2412_setparent_cam, + .round_rate = s3c2412_roundrate_clksrc, +}; + +/* standard clock definitions */ + +static struct clk init_clocks_disable[] = { + { + .name = "nand", + .id = -1, + .parent = &clk_h, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_NAND, + }, { + .name = "sdi", + .id = -1, + .parent = &clk_p, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_SDI, + }, { + .name = "adc", + .id = -1, + .parent = &clk_p, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_ADC, + }, { + .name = "i2c", + .id = -1, + .parent = &clk_p, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_IIC, + }, { + .name = "iis", + .id = -1, + .parent = &clk_p, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_IIS, + }, { + .name = "spi", + .id = -1, + .parent = &clk_p, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_SPI, + } +}; + +static struct clk init_clocks[] = { + { + .name = "dma", + .id = 0, + .parent = &clk_h, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_DMA0, + }, { + .name = "dma", + .id = 1, + .parent = &clk_h, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_DMA1, + }, { + .name = "dma", + .id = 2, + .parent = &clk_h, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_DMA2, + }, { + .name = "dma", + .id = 3, + .parent = &clk_h, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_DMA3, + }, { + .name = "lcd", + .id = -1, + .parent = &clk_h, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_LCDC, + }, { + .name = "gpio", + .id = -1, + .parent = &clk_p, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_GPIO, + }, { + .name = "usb-host", + .id = -1, + .parent = &clk_h, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_USBH, + }, { + .name = "usb-device", + .id = -1, + .parent = &clk_h, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_USBD, + }, { + .name = "timers", + .id = -1, + .parent = &clk_p, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_PWMT, + }, { + .name = "uart", + .id = 0, + .parent = &clk_p, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_UART0, + }, { + .name = "uart", + .id = 1, + .parent = &clk_p, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_UART1, + }, { + .name = "uart", + .id = 2, + .parent = &clk_p, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_UART2, + }, { + .name = "rtc", + .id = -1, + .parent = &clk_p, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_RTC, + }, { + .name = "watchdog", + .id = -1, + .parent = &clk_p, + .ctrlbit = 0, + }, { + .name = "usb-bus-gadget", + .id = -1, + .parent = &clk_usb_bus, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_USB_DEV48, + }, { + .name = "usb-bus-host", + .id = -1, + .parent = &clk_usb_bus, + .enable = s3c2412_clkcon_enable, + .ctrlbit = S3C2412_CLKCON_USB_HOST48, + } +}; + +/* clocks to add where we need to check their parentage */ + +struct clk_init { + struct clk *clk; + unsigned int bit; + struct clk *src_0; + struct clk *src_1; +}; + +struct clk_init clks_src[] __initdata = { + { + .clk = &clk_usysclk, + .bit = S3C2412_CLKSRC_USBCLK_HCLK, + .src_0 = &clk_urefclk, + .src_1 = &clk_upll, + }, { + .clk = &clk_i2s, + .bit = S3C2412_CLKSRC_I2SCLK_MPLL, + .src_0 = &clk_erefclk, + .src_1 = &clk_mpll, + }, { + .clk = &clk_cam, + .bit = S3C2412_CLKSRC_CAMCLK_HCLK, + .src_0 = &clk_usysclk, + .src_1 = &clk_h, + }, { + .clk = &clk_msysclk, + .bit = S3C2412_CLKSRC_MSYSCLK_MPLL, + .src_0 = &clk_mdivclk, + .src_1 = &clk_mpll, + }, { + .clk = &clk_uart, + .bit = S3C2412_CLKSRC_UARTCLK_MPLL, + .src_0 = &clk_erefclk, + .src_1 = &clk_mpll, + }, { + .clk = &clk_usbsrc, + .bit = S3C2412_CLKSRC_USBCLK_HCLK, + .src_0 = &clk_usysclk, + .src_1 = &clk_h, + }, +}; + +/* s3c2412_clk_initparents + * + * Initialise the parents for the clocks that we get at start-time +*/ + +static void __init s3c2412_clk_initparents(void) +{ + unsigned long clksrc = __raw_readl(S3C2412_CLKSRC); + struct clk_init *cip = clks_src; + struct clk *src; + int ptr; + int ret; + + for (ptr = 0; ptr < ARRAY_SIZE(clks_src); ptr++, cip++) { + ret = s3c24xx_register_clock(cip->clk); + if (ret < 0) { + printk(KERN_ERR "Failed to register clock %s (%d)\n", + cip->clk->name, ret); + } + + src = (clksrc & cip->bit) ? cip->src_1 : cip->src_0; + + printk(KERN_INFO "%s: parent %s\n", cip->clk->name, src->name); + clk_set_parent(cip->clk, src); + } +} + +/* clocks to add straight away */ + +struct clk *clks[] __initdata = { + &clk_ext, + &clk_usb_bus, + &clk_erefclk, + &clk_urefclk, + &clk_mrefclk, +}; + +int __init s3c2412_baseclk_add(void) +{ + unsigned long clkcon = __raw_readl(S3C2410_CLKCON); + struct clk *clkp; + int ret; + int ptr; + + clk_upll.enable = s3c2412_upll_enable; + clk_usb_bus.parent = &clk_usbsrc; + clk_usb_bus.rate = 0x0; + + s3c2412_clk_initparents(); + + for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) { + clkp = clks[ptr]; + + ret = s3c24xx_register_clock(clkp); + if (ret < 0) { + printk(KERN_ERR "Failed to register clock %s (%d)\n", + clkp->name, ret); + } + } + + /* ensure usb bus clock is within correct rate of 48MHz */ + + if (clk_get_rate(&clk_usb_bus) != (48 * 1000 * 1000)) { + printk(KERN_INFO "Warning: USB bus clock not at 48MHz\n"); + + /* for the moment, let's use the UPLL, and see if we can + * get 48MHz */ + + clk_set_parent(&clk_usysclk, &clk_upll); + clk_set_parent(&clk_usbsrc, &clk_usysclk); + clk_set_rate(&clk_usbsrc, 48*1000*1000); + } + + printk("S3C2412: upll %s, %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n", + (__raw_readl(S3C2410_UPLLCON) & S3C2412_PLLCON_OFF) ? "off":"on", + print_mhz(clk_get_rate(&clk_upll)), + print_mhz(clk_get_rate(&clk_usb_bus))); + + /* register clocks from clock array */ + + clkp = init_clocks; + for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) { + /* ensure that we note the clock state */ + + clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0; + + ret = s3c24xx_register_clock(clkp); + if (ret < 0) { + printk(KERN_ERR "Failed to register clock %s (%d)\n", + clkp->name, ret); + } + } + + /* We must be careful disabling the clocks we are not intending to + * be using at boot time, as subsytems such as the LCD which do + * their own DMA requests to the bus can cause the system to lockup + * if they where in the middle of requesting bus access. + * + * Disabling the LCD clock if the LCD is active is very dangerous, + * and therefore the bootloader should be careful to not enable + * the LCD clock if it is not needed. + */ + + /* install (and disable) the clocks we do not need immediately */ + + clkp = init_clocks_disable; + for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) { + + ret = s3c24xx_register_clock(clkp); + if (ret < 0) { + printk(KERN_ERR "Failed to register clock %s (%d)\n", + clkp->name, ret); + } + + s3c2412_clkcon_enable(clkp, 0); + } + + return 0; +} diff --git a/include/asm-arm/arch-s3c2410/regs-clock.h b/include/asm-arm/arch-s3c2410/regs-clock.h index 6c92faffe98..a7c61feb843 100644 --- a/include/asm-arm/arch-s3c2410/regs-clock.h +++ b/include/asm-arm/arch-s3c2410/regs-clock.h @@ -1,6 +1,6 @@ /* linux/include/asm/arch-s3c2410/regs-clock.h * - * Copyright (c) 2003,2004,2005 Simtec Electronics + * Copyright (c) 2003,2004,2005,2006 Simtec Electronics * http://armlinux.simtec.co.uk/ * * This program is free software; you can redistribute it and/or modify @@ -140,5 +140,66 @@ s3c2410_get_pll(unsigned int pllval, unsigned int baseclk) #endif /* CONFIG_CPU_S3C2440 or CONFIG_CPU_S3C2442 */ +#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) + +#define S3C2412_OSCSET S3C2410_CLKREG(0x18) +#define S3C2412_CLKSRC S3C2410_CLKREG(0x1C) + +#define S3C2412_PLLCON_OFF (1<<20) + +#define S3C2412_CLKDIVN_PDIVN (1<<2) +#define S3C2412_CLKDIVN_HDIVN_MASK (3<<0) +#define S3C2421_CLKDIVN_ARMDIVN (1<<3) +#define S3C2412_CLKDIVN_USB48DIV (1<<6) +#define S3C2412_CLKDIVN_UARTDIV_MASK (15<<8) +#define S3C2412_CLKDIVN_UARTDIV_SHIFT (8) +#define S3C2412_CLKDIVN_I2SDIV_MASK (15<<12) +#define S3C2412_CLKDIVN_I2SDIV_SHIFT (12) +#define S3C2412_CLKDIVN_CAMDIV_MASK (15<<16) +#define S3C2412_CLKDIVN_CAMDIV_SHIFT (16) + +#define S3C2412_CLKCON_WDT (1<<28) +#define S3C2412_CLKCON_SPI (1<<27) +#define S3C2412_CLKCON_IIS (1<<26) +#define S3C2412_CLKCON_IIC (1<<25) +#define S3C2412_CLKCON_ADC (1<<24) +#define S3C2412_CLKCON_RTC (1<<23) +#define S3C2412_CLKCON_GPIO (1<<22) +#define S3C2412_CLKCON_UART2 (1<<21) +#define S3C2412_CLKCON_UART1 (1<<20) +#define S3C2412_CLKCON_UART0 (1<<19) +#define S3C2412_CLKCON_SDI (1<<18) +#define S3C2412_CLKCON_PWMT (1<<17) +#define S3C2412_CLKCON_USBD (1<<16) +#define S3C2412_CLKCON_CAMCLK (1<<15) +#define S3C2412_CLKCON_UARTCLK (1<<14) +/* missing 13 */ +#define S3C2412_CLKCON_USB_HOST48 (1<<12) +#define S3C2412_CLKCON_USB_DEV48 (1<<11) +#define S3C2412_CLKCON_HCLKdiv2 (1<<10) +#define S3C2412_CLKCON_HCLKx2 (1<<9) +#define S3C2412_CLKCON_SDRAM (1<<8) +/* missing 7 */ +#define S3C2412_CLKCON_USBH S3C2410_CLKCON_USBH +#define S3C2412_CLKCON_LCDC S3C2410_CLKCON_LCDC +#define S3C2412_CLKCON_NAND S3C2410_CLKCON_NAND +#define S3C2412_CLKCON_DMA3 (1<<3) +#define S3C2412_CLKCON_DMA2 (1<<2) +#define S3C2412_CLKCON_DMA1 (1<<1) +#define S3C2412_CLKCON_DMA0 (1<<0) + +/* clock sourec controls */ + +#define S3C2412_CLKSRC_EXTCLKDIV_MASK (7 << 0) +#define S3C2412_CLKSRC_EXTCLKDIV_SHIFT (0) +#define S3C2412_CLKSRC_MDIVCLK_EXTCLKDIV (1<<3) +#define S3C2412_CLKSRC_MSYSCLK_MPLL (1<<4) +#define S3C2412_CLKSRC_USYSCLK_UPLL (1<<5) +#define S3C2412_CLKSRC_UARTCLK_MPLL (1<<8) +#define S3C2412_CLKSRC_I2SCLK_MPLL (1<<9) +#define S3C2412_CLKSRC_USBCLK_HCLK (1<<10) +#define S3C2412_CLKSRC_CAMCLK_HCLK (1<<11) + +#endif /* CONFIG_CPU_S3C2412 | CONFIG_CPU_S3C2413 */ #endif /* __ASM_ARM_REGS_CLOCK */ -- cgit v1.2.3-70-g09d2 From 46491c94d39a519178ba8c6b5b5d6a839210124d Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sat, 24 Jun 2006 21:21:32 +0100 Subject: [ARM] 3640/1: S3C2412: Use S3C24XX_DCLKCON instead of S3C2410_DCLKCON Patch from Ben Dooks The current S3C2412 support has moved to using S3C24XX_DCLKCON unless the specific DCLKCON is required (S3C2412_DCLKCON or S3C2410_DKCLKCON) Move the few places using S3C2410_DCLKCON to S3C24XX_DCLKCON Depends on Patch #3635/1 Signed-off-by: Ben Dooks Signed-off-by: Russell King --- arch/arm/mach-s3c2410/clock.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c index 90a0610b514..e13fb677889 100644 --- a/arch/arm/mach-s3c2410/clock.c +++ b/arch/arm/mach-s3c2410/clock.c @@ -268,14 +268,14 @@ struct clk clk_usb_bus = { static int s3c24xx_dclk_enable(struct clk *clk, int enable) { - unsigned long dclkcon = __raw_readl(S3C2410_DCLKCON); + unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON); if (enable) dclkcon |= clk->ctrlbit; else dclkcon &= ~clk->ctrlbit; - __raw_writel(dclkcon, S3C2410_DCLKCON); + __raw_writel(dclkcon, S3C24XX_DCLKCON); return 0; } @@ -294,7 +294,7 @@ static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent) clk->parent = parent; - dclkcon = __raw_readl(S3C2410_DCLKCON); + dclkcon = __raw_readl(S3C24XX_DCLKCON); if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) { if (uclk) @@ -308,7 +308,7 @@ static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent) dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK; } - __raw_writel(dclkcon, S3C2410_DCLKCON); + __raw_writel(dclkcon, S3C24XX_DCLKCON); return 0; } -- cgit v1.2.3-70-g09d2 From 44cc7c9c15124c4506da96304e5f9eb88200fc35 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sat, 24 Jun 2006 21:21:33 +0100 Subject: [ARM] 3641/1: S3C2412: Fixup gpio register naming Patch from Ben Dooks The current S3C2412 has used to moving S3C24XX_ for the generic form of an register has been moved from the S3C2410. Fixup S3C2410_EXTINTx and S3C2410_EINFLTx to S3C24XX_EXTINTx and S3C24XX_EXTINTx Depends on Patch #3635/1, Patch #3640/1 Signed-off-by: Ben Dooks Signed-off-by: Russell King --- arch/arm/mach-s3c2410/irq.c | 8 ++++---- arch/arm/mach-s3c2410/s3c2410-gpio.c | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-s3c2410/irq.c b/arch/arm/mach-s3c2410/irq.c index 66d8c068e94..46465742ed7 100644 --- a/arch/arm/mach-s3c2410/irq.c +++ b/arch/arm/mach-s3c2410/irq.c @@ -275,28 +275,28 @@ s3c_irqext_type(unsigned int irq, unsigned int type) if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3)) { gpcon_reg = S3C2410_GPFCON; - extint_reg = S3C2410_EXTINT0; + extint_reg = S3C24XX_EXTINT0; gpcon_offset = (irq - IRQ_EINT0) * 2; extint_offset = (irq - IRQ_EINT0) * 4; } else if ((irq >= IRQ_EINT4) && (irq <= IRQ_EINT7)) { gpcon_reg = S3C2410_GPFCON; - extint_reg = S3C2410_EXTINT0; + extint_reg = S3C24XX_EXTINT0; gpcon_offset = (irq - (EXTINT_OFF)) * 2; extint_offset = (irq - (EXTINT_OFF)) * 4; } else if ((irq >= IRQ_EINT8) && (irq <= IRQ_EINT15)) { gpcon_reg = S3C2410_GPGCON; - extint_reg = S3C2410_EXTINT1; + extint_reg = S3C24XX_EXTINT1; gpcon_offset = (irq - IRQ_EINT8) * 2; extint_offset = (irq - IRQ_EINT8) * 4; } else if ((irq >= IRQ_EINT16) && (irq <= IRQ_EINT23)) { gpcon_reg = S3C2410_GPGCON; - extint_reg = S3C2410_EXTINT2; + extint_reg = S3C24XX_EXTINT2; gpcon_offset = (irq - IRQ_EINT8) * 2; extint_offset = (irq - IRQ_EINT16) * 4; } else diff --git a/arch/arm/mach-s3c2410/s3c2410-gpio.c b/arch/arm/mach-s3c2410/s3c2410-gpio.c index 17519b3281b..471a7149001 100644 --- a/arch/arm/mach-s3c2410/s3c2410-gpio.c +++ b/arch/arm/mach-s3c2410/s3c2410-gpio.c @@ -35,7 +35,7 @@ int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on, unsigned int config) { - void __iomem *reg = S3C2410_EINFLT0; + void __iomem *reg = S3C24XX_EINFLT0; unsigned long flags; unsigned long val; @@ -58,10 +58,10 @@ int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on, /* update filter enable */ - val = __raw_readl(S3C2410_EXTINT2); + val = __raw_readl(S3C24XX_EXTINT2); val &= ~(1 << ((pin * 4) + 3)); val |= on << ((pin * 4) + 3); - __raw_writel(val, S3C2410_EXTINT2); + __raw_writel(val, S3C24XX_EXTINT2); local_irq_restore(flags); -- cgit v1.2.3-70-g09d2 From 66c594098db1ee885f486a684b66937e28e792b1 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sat, 24 Jun 2006 21:21:35 +0100 Subject: [ARM] 3642/1: S3C24XX: Add machine SMDK2413 Patch from Ben Dooks Add basic support for the Samsung/Aiji SMDK2413 Signed-off-by: Ben Dooks Signed-off-by: Russell King --- arch/arm/mach-s3c2410/Kconfig | 6 ++ arch/arm/mach-s3c2410/Makefile | 1 + arch/arm/mach-s3c2410/mach-smdk2413.c | 126 ++++++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+) create mode 100644 arch/arm/mach-s3c2410/mach-smdk2413.c (limited to 'arch') diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig index b61af3a6a41..f5d9cd498a5 100644 --- a/arch/arm/mach-s3c2410/Kconfig +++ b/arch/arm/mach-s3c2410/Kconfig @@ -81,6 +81,12 @@ config SMDK2440_CPU2442 depends on ARCH_S3C2440 select CPU_S3C2442 +config MACH_SMDK2413 + bool "SMDK2413" + select CPU_S3C2412 + select MACH_SMDK + help + Say Y here if you are using an SMDK2413 config MACH_VR1000 bool "Thorcom VR1000" diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile index d934a89179a..0c7938645df 100644 --- a/arch/arm/mach-s3c2410/Makefile +++ b/arch/arm/mach-s3c2410/Makefile @@ -62,6 +62,7 @@ obj-$(CONFIG_ARCH_BAST) += mach-bast.o usb-simtec.o obj-$(CONFIG_ARCH_H1940) += mach-h1940.o obj-$(CONFIG_MACH_N30) += mach-n30.o obj-$(CONFIG_ARCH_SMDK2410) += mach-smdk2410.o +obj-$(CONFIG_MACH_SMDK2413) += mach-smdk2413.o obj-$(CONFIG_ARCH_S3C2440) += mach-smdk2440.o obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o usb-simtec.o obj-$(CONFIG_MACH_RX3715) += mach-rx3715.o diff --git a/arch/arm/mach-s3c2410/mach-smdk2413.c b/arch/arm/mach-s3c2410/mach-smdk2413.c new file mode 100644 index 00000000000..b7ef7d3c54a --- /dev/null +++ b/arch/arm/mach-s3c2410/mach-smdk2413.c @@ -0,0 +1,126 @@ +/* linux/arch/arm/mach-s3c2410/mach-smdk2413.c + * + * Copyright (c) 2006 Simtec Electronics + * Ben Dooks + * + * Thanks to Dimity Andric (TomTom) and Steven Ryu (Samsung) for the + * loans of SMDK2413 to work with. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +//#include +#include +#include +#include + +#include +#include + +#include "s3c2410.h" +#include "s3c2412.h" +#include "clock.h" +#include "devs.h" +#include "cpu.h" + +#include "common-smdk.h" + +static struct map_desc smdk2413_iodesc[] __initdata = { +}; + +static struct s3c2410_uartcfg smdk2413_uartcfgs[] __initdata = { + [0] = { + .hwport = 0, + .flags = 0, + .ucon = 0x3c5, + .ulcon = 0x03, + .ufcon = 0x51, + }, + [1] = { + .hwport = 1, + .flags = 0, + .ucon = 0x3c5, + .ulcon = 0x03, + .ufcon = 0x51, + }, + /* IR port */ + [2] = { + .hwport = 2, + .flags = 0, + .ucon = 0x3c5, + .ulcon = 0x43, + .ufcon = 0x51, + } +}; + +static struct platform_device *smdk2413_devices[] __initdata = { + &s3c_device_usb, + //&s3c_device_lcd, + &s3c_device_wdt, + &s3c_device_i2c, + &s3c_device_iis, +}; + +static struct s3c24xx_board smdk2413_board __initdata = { + .devices = smdk2413_devices, + .devices_count = ARRAY_SIZE(smdk2413_devices) +}; + +static void __init smdk2413_fixup(struct machine_desc *desc, + struct tag *tags, char **cmdline, + struct meminfo *mi) +{ + if (tags != phys_to_virt(S3C2410_SDRAM_PA + 0x100)) { + mi->nr_banks=1; + mi->bank[0].start = 0x30000000; + mi->bank[0].size = SZ_64M; + mi->bank[0].node = 0; + } +} + +static void __init smdk2413_map_io(void) +{ + s3c24xx_init_io(smdk2413_iodesc, ARRAY_SIZE(smdk2413_iodesc)); + s3c24xx_init_clocks(12000000); + s3c24xx_init_uarts(smdk2413_uartcfgs, ARRAY_SIZE(smdk2413_uartcfgs)); + s3c24xx_set_board(&smdk2413_board); +} + +static void __init smdk2413_machine_init(void) +{ + smdk_machine_init(); +} + +MACHINE_START(S3C2413, "SMDK2413") + /* Maintainer: Ben Dooks */ + .phys_io = S3C2410_PA_UART, + .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc, + .boot_params = S3C2410_SDRAM_PA + 0x100, + + .fixup = smdk2413_fixup, + .init_irq = s3c24xx_init_irq, + .map_io = smdk2413_map_io, + .init_machine = smdk2413_machine_init, + .timer = &s3c24xx_timer, +MACHINE_END -- cgit v1.2.3-70-g09d2 From 22346aea8d39372d6fd207468701e90bf546b882 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sat, 24 Jun 2006 21:21:36 +0100 Subject: [ARM] 3643/1: S3C2410: Add new usb clocks Patch from Ben Dooks Make the S3C2410 use the same usb clock naming as the S3C2412 Signed-off-by: Ben Dooks Signed-off-by: Russell King --- arch/arm/mach-s3c2410/s3c2410-clock.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-s3c2410/s3c2410-clock.c b/arch/arm/mach-s3c2410/s3c2410-clock.c index fd17c60e113..99718663318 100644 --- a/arch/arm/mach-s3c2410/s3c2410-clock.c +++ b/arch/arm/mach-s3c2410/s3c2410-clock.c @@ -182,7 +182,15 @@ static struct clk init_clocks[] = { .id = -1, .parent = &clk_p, .ctrlbit = 0, - } + }, { + .name = "usb-bus-host", + .id = -1, + .parent = &clk_usb_bus, + }, { + .name = "usb-bus-gadget", + .id = -1, + .parent = &clk_usb_bus, + }, }; /* s3c2410_baseclk_add() -- cgit v1.2.3-70-g09d2 From a019f4a9a7b4ec4986918e9aefa06815cf77b714 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sat, 24 Jun 2006 21:21:37 +0100 Subject: [ARM] 3645/1: S3C2412: irq support for external interrupts Patch from Ben Dooks Move the decoding of the IRQ_EXT4 and above out of the entry macro, and into an chained irq handler as the EXTINT registers move depending on the CPU being used. Signed-off-by: Ben Dooks Signed-off-by: Russell King --- arch/arm/mach-s3c2410/irq.c | 49 ++++++++++++++++++++---------- include/asm-arm/arch-s3c2410/entry-macro.S | 30 +++++------------- include/asm-arm/arch-s3c2410/regs-irq.h | 6 ++++ 3 files changed, 46 insertions(+), 39 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-s3c2410/irq.c b/arch/arm/mach-s3c2410/irq.c index 46465742ed7..6822dc7f779 100644 --- a/arch/arm/mach-s3c2410/irq.c +++ b/arch/arm/mach-s3c2410/irq.c @@ -191,13 +191,9 @@ static struct irqchip s3c_irq_chip = { .ack = s3c_irq_ack, .mask = s3c_irq_mask, .unmask = s3c_irq_unmask, - .set_wake = s3c_irq_wake + .set_wake = s3c_irq_wake }; -/* S3C2410_EINTMASK - * S3C2410_EINTPEND - */ - static void s3c_irqext_mask(unsigned int irqno) { @@ -205,9 +201,9 @@ s3c_irqext_mask(unsigned int irqno) irqno -= EXTINT_OFF; - mask = __raw_readl(S3C2410_EINTMASK); + mask = __raw_readl(S3C24XX_EINTMASK); mask |= ( 1UL << irqno); - __raw_writel(mask, S3C2410_EINTMASK); + __raw_writel(mask, S3C24XX_EINTMASK); if (irqno <= (IRQ_EINT7 - EXTINT_OFF)) { /* check to see if all need masking */ @@ -232,11 +228,11 @@ s3c_irqext_ack(unsigned int irqno) bit = 1UL << (irqno - EXTINT_OFF); - mask = __raw_readl(S3C2410_EINTMASK); + mask = __raw_readl(S3C24XX_EINTMASK); - __raw_writel(bit, S3C2410_EINTPEND); + __raw_writel(bit, S3C24XX_EINTPEND); - req = __raw_readl(S3C2410_EINTPEND); + req = __raw_readl(S3C24XX_EINTPEND); req &= ~mask; /* not sure if we should be acking the parent irq... */ @@ -257,9 +253,9 @@ s3c_irqext_unmask(unsigned int irqno) irqno -= EXTINT_OFF; - mask = __raw_readl(S3C2410_EINTMASK); + mask = __raw_readl(S3C24XX_EINTMASK); mask &= ~( 1UL << irqno); - __raw_writel(mask, S3C2410_EINTMASK); + __raw_writel(mask, S3C24XX_EINTMASK); s3c_irq_unmask((irqno <= (IRQ_EINT7 - EXTINT_OFF)) ? IRQ_EINT4t7 : IRQ_EINT8t23); } @@ -572,6 +568,23 @@ s3c_irq_demux_uart2(unsigned int irq, s3c_irq_demux_uart(IRQ_S3CUART_RX2, regs); } +static void +s3c_irq_demux_extint(unsigned int irq, + struct irqdesc *desc, + struct pt_regs *regs) +{ + unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND); + unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK); + + eintpnd &= ~eintmsk; + + if (eintpnd) { + irq = fls(eintpnd); + irq += (IRQ_EINT4 - (4 + 1)); + + desc_handle_irq(irq, irq_desc + irq, regs); + } +} /* s3c24xx_init_irq * @@ -591,12 +604,12 @@ void __init s3c24xx_init_irq(void) last = 0; for (i = 0; i < 4; i++) { - pend = __raw_readl(S3C2410_EINTPEND); + pend = __raw_readl(S3C24XX_EINTPEND); if (pend == 0 || pend == last) break; - __raw_writel(pend, S3C2410_EINTPEND); + __raw_writel(pend, S3C24XX_EINTPEND); printk("irq: clearing pending ext status %08x\n", (int)pend); last = pend; } @@ -630,12 +643,14 @@ void __init s3c24xx_init_irq(void) irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n"); - for (irqno = IRQ_BATT_FLT; irqno <= IRQ_ADCPARENT; irqno++) { + for (irqno = IRQ_EINT4t7; irqno <= IRQ_ADCPARENT; irqno++) { /* set all the s3c2410 internal irqs */ switch (irqno) { /* deal with the special IRQs (cascaded) */ + case IRQ_EINT4t7: + case IRQ_EINT8t23: case IRQ_UART0: case IRQ_UART1: case IRQ_UART2: @@ -659,12 +674,14 @@ void __init s3c24xx_init_irq(void) /* setup the cascade irq handlers */ + set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint); + set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint); + set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0); set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1); set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2); set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc); - /* external interrupts */ for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) { diff --git a/include/asm-arm/arch-s3c2410/entry-macro.S b/include/asm-arm/arch-s3c2410/entry-macro.S index 894c35cf3b1..e09a6b8ec15 100644 --- a/include/asm-arm/arch-s3c2410/entry-macro.S +++ b/include/asm-arm/arch-s3c2410/entry-macro.S @@ -18,8 +18,6 @@ #define INTPND (0x10) #define INTOFFSET (0x14) -#define EXTINTPEND (0xa8) -#define EXTINTMASK (0xa4) #include #include @@ -28,37 +26,23 @@ mov \base, #S3C24XX_VA_IRQ - ldr \irqstat, [ \base, #INTPND] - bics \irqnr, \irqstat, #3<<4 @@ only an GPIO IRQ - beq 2000f - @@ try the interrupt offset register, since it is there + ldr \irqstat, [ \base, #INTPND ] + teq \irqstat, #0 + beq 1002f ldr \irqnr, [ \base, #INTOFFSET ] mov \tmp, #1 tst \irqstat, \tmp, lsl \irqnr - addne \irqnr, \irqnr, #IRQ_EINT0 bne 1001f @@ the number specified is not a valid irq, so try @@ and work it out for ourselves - mov \irqnr, #IRQ_EINT0 @@ start here - b 3000f - -2000: - @@ load the GPIO interrupt register, and check it - - add \tmp, \base, #S3C24XX_VA_GPIO - S3C24XX_VA_IRQ - ldr \irqstat, [ \tmp, # EXTINTPEND ] - ldr \irqnr, [ \tmp, # EXTINTMASK ] - bics \irqstat, \irqstat, \irqnr - beq 1001f - - mov \irqnr, #(IRQ_EINT4 - 4) + mov \irqnr, #0 @@ start here @@ work out which irq (if any) we got -3000: + movs \tmp, \irqstat, lsl#16 addeq \irqnr, \irqnr, #16 moveq \irqstat, \irqstat, lsr#16 @@ -75,9 +59,9 @@ addeq \irqnr, \irqnr, #1 @@ we have the value - movs \irqnr, \irqnr - 1001: + adds \irqnr, \irqnr, #IRQ_EINT0 +1002: @@ exit here, Z flag unset if IRQ .endm diff --git a/include/asm-arm/arch-s3c2410/regs-irq.h b/include/asm-arm/arch-s3c2410/regs-irq.h index 24b7292df79..572fca5d9ac 100644 --- a/include/asm-arm/arch-s3c2410/regs-irq.h +++ b/include/asm-arm/arch-s3c2410/regs-irq.h @@ -23,6 +23,7 @@ #define S3C2410_IRQREG(x) ((x) + S3C24XX_VA_IRQ) #define S3C2410_EINTREG(x) ((x) + S3C24XX_VA_GPIO) +#define S3C24XX_EINTREG(x) ((x) + S3C24XX_VA_GPIO2) #define S3C2410_SRCPND S3C2410_IRQREG(0x000) #define S3C2410_INTMOD S3C2410_IRQREG(0x004) @@ -40,5 +41,10 @@ #define S3C2410_EINTMASK S3C2410_EINTREG(0x0A4) #define S3C2410_EINTPEND S3C2410_EINTREG(0X0A8) +#define S3C2412_EINTMASK S3C2410_EINTREG(0x0B4) +#define S3C2412_EINTPEND S3C2410_EINTREG(0X0B8) + +#define S3C24XX_EINTMASK S3C24XX_EINTREG(0x0A4) +#define S3C24XX_EINTPEND S3C24XX_EINTREG(0X0A8) #endif /* ___ASM_ARCH_REGS_IRQ_H */ -- cgit v1.2.3-70-g09d2 From c9b949a734adef5d05cbaa0b0546b924ca517155 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sat, 24 Jun 2006 21:22:35 +0100 Subject: [ARM] 3647/1: S3C24XX: add Osiris to the list of simtec pm machines Patch from Ben Dooks Enable power management for Simtec Osiris Signed-off-by: Ben Dooks Signed-off-by: Russell King --- arch/arm/mach-s3c2410/pm-simtec.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-s3c2410/pm-simtec.c b/arch/arm/mach-s3c2410/pm-simtec.c index 4c7ccef6c20..7b244566a43 100644 --- a/arch/arm/mach-s3c2410/pm-simtec.c +++ b/arch/arm/mach-s3c2410/pm-simtec.c @@ -48,7 +48,8 @@ static __init int pm_simtec_init(void) /* check which machine we are running on */ - if (!machine_is_bast() && !machine_is_vr1000() && !machine_is_anubis()) + if (!machine_is_bast() && !machine_is_vr1000() && + !machine_is_anubis() && !machine_is_osiris()) return 0; printk(KERN_INFO "Simtec Board Power Manangement" COPYRIGHT "\n"); -- cgit v1.2.3-70-g09d2 From ca195cfec9fff622a61b1b72534e73360747f735 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 24 Jun 2006 22:41:09 +0100 Subject: [ARM] Add identifying number for non-rt sigframe GDB couldn't reliably tell the difference between the old and new non-rt sigframes, so provide it with a number at the beginning which will never appear in the old sigframe, and hence provide gdb with a reliable way to tell the two apart. Signed-off-by: Russell King --- arch/arm/kernel/signal.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'arch') diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 96285114409..c0ba8afee42 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -470,6 +470,11 @@ setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *reg if (!frame) return 1; + /* + * Set uc.uc_flags to a value which sc.trap_no would never have. + */ + __put_user_error(0x5ac3c35a, &frame->uc.uc_flags, err); + err |= setup_sigframe(frame, regs, set); if (err == 0) err = setup_return(regs, ka, frame->retcode, frame, usig); -- cgit v1.2.3-70-g09d2 From 85fe068123aa11d3477ce88c7d365e233b1f2e10 Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Sat, 24 Jun 2006 23:46:21 +0100 Subject: [ARM] 3648/1: Update struct ucontext layout for coprocessor registers Patch from Daniel Jacobowitz In order for userspace to find saved coprocessor registers, move them from struct rt_sigframe into struct ucontext. Also allow space for glibc's sigset_t, so that userspace and kernelspace can use the same ucontext layout. Define the magic numbers for iWMMXt in the header file for easier reference. Include the size of the coprocessor data in the magic numbers. Also define magic numbers and layout for VFP, not yet saved. Signed-off-by: Daniel Jacobowitz Signed-off-by: Russell King --- arch/arm/kernel/signal.c | 42 +++++++----------------- include/asm-arm/ucontext.h | 79 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 89 insertions(+), 32 deletions(-) (limited to 'arch') diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index c0ba8afee42..e5802bfda31 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -134,17 +134,6 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, #ifdef CONFIG_IWMMXT -/* iwmmxt_area is 0x98 bytes long, preceeded by 8 bytes of signature */ -#define IWMMXT_STORAGE_SIZE (0x98 + 8) -#define IWMMXT_MAGIC0 0x12ef842a -#define IWMMXT_MAGIC1 0x1c07ca71 - -struct iwmmxt_sigframe { - unsigned long magic0; - unsigned long magic1; - unsigned long storage[0x98/4]; -}; - static int preserve_iwmmxt_context(struct iwmmxt_sigframe *frame) { char kbuf[sizeof(*frame) + 8]; @@ -152,8 +141,8 @@ static int preserve_iwmmxt_context(struct iwmmxt_sigframe *frame) /* the iWMMXt context must be 64 bit aligned */ kframe = (struct iwmmxt_sigframe *)((unsigned long)(kbuf + 8) & ~7); - kframe->magic0 = IWMMXT_MAGIC0; - kframe->magic1 = IWMMXT_MAGIC1; + kframe->magic = IWMMXT_MAGIC; + kframe->size = IWMMXT_STORAGE_SIZE; iwmmxt_task_copy(current_thread_info(), &kframe->storage); return __copy_to_user(frame, kframe, sizeof(*frame)); } @@ -167,8 +156,8 @@ static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame) kframe = (struct iwmmxt_sigframe *)((unsigned long)(kbuf + 8) & ~7); if (__copy_from_user(kframe, frame, sizeof(*frame))) return -1; - if (kframe->magic0 != IWMMXT_MAGIC0 || - kframe->magic1 != IWMMXT_MAGIC1) + if (kframe->magic != IWMMXT_MAGIC || + kframe->size != IWMMXT_STORAGE_SIZE) return -1; iwmmxt_task_restore(current_thread_info(), &kframe->storage); return 0; @@ -176,26 +165,12 @@ static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame) #endif -/* - * Auxiliary signal frame. This saves stuff like FP state. - * The layout of this structure is not part of the user ABI. - */ -struct aux_sigframe { -#ifdef CONFIG_IWMMXT - struct iwmmxt_sigframe iwmmxt; -#endif -#ifdef CONFIG_VFP - union vfp_state vfp; -#endif -}; - /* * Do a signal return; undo the signal stack. These are aligned to 64-bit. */ struct sigframe { struct ucontext uc; unsigned long retcode[2]; - struct aux_sigframe aux __attribute__((aligned(8))); }; struct rt_sigframe { @@ -205,6 +180,7 @@ struct rt_sigframe { static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf) { + struct aux_sigframe __user *aux; sigset_t set; int err; @@ -237,9 +213,10 @@ static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf) err |= !valid_user_regs(regs); + aux = (struct aux_sigframe __user *) sf->uc.uc_regspace; #ifdef CONFIG_IWMMXT if (err == 0 && test_thread_flag(TIF_USING_IWMMXT)) - err |= restore_iwmmxt_context(&sf->aux.iwmmxt); + err |= restore_iwmmxt_context(&aux->iwmmxt); #endif #ifdef CONFIG_VFP // if (err == 0) @@ -327,6 +304,7 @@ badframe: static int setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set) { + struct aux_sigframe __user *aux; int err = 0; __put_user_error(regs->ARM_r0, &sf->uc.uc_mcontext.arm_r0, err); @@ -354,14 +332,16 @@ setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set) err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set)); + aux = (struct aux_sigframe __user *) sf->uc.uc_regspace; #ifdef CONFIG_IWMMXT if (err == 0 && test_thread_flag(TIF_USING_IWMMXT)) - err |= preserve_iwmmxt_context(&sf->aux.iwmmxt); + err |= preserve_iwmmxt_context(&aux->iwmmxt); #endif #ifdef CONFIG_VFP // if (err == 0) // err |= vfp_save_state(&sf->aux.vfp); #endif + __put_user_error(0, &aux->end_magic, err); return err; } diff --git a/include/asm-arm/ucontext.h b/include/asm-arm/ucontext.h index f853130137c..9e6f7ca9f5a 100644 --- a/include/asm-arm/ucontext.h +++ b/include/asm-arm/ucontext.h @@ -1,12 +1,89 @@ #ifndef _ASMARM_UCONTEXT_H #define _ASMARM_UCONTEXT_H +#include + +/* + * struct sigcontext only has room for the basic registers, but struct + * ucontext now has room for all registers which need to be saved and + * restored. Coprocessor registers are stored in uc_regspace. Each + * coprocessor's saved state should start with a documented 32-bit magic + * number, followed by a 32-bit word giving the coproccesor's saved size. + * uc_regspace may be expanded if necessary, although this takes some + * coordination with glibc. + */ + struct ucontext { unsigned long uc_flags; struct ucontext *uc_link; stack_t uc_stack; struct sigcontext uc_mcontext; - sigset_t uc_sigmask; /* mask last for extensibility */ + sigset_t uc_sigmask; + /* Allow for uc_sigmask growth. Glibc uses a 1024-bit sigset_t. */ + int __unused[32 - (sizeof (sigset_t) / sizeof (int))]; + /* Last for extensibility. Eight byte aligned because some + coprocessors require eight byte alignment. */ + unsigned long uc_regspace[128] __attribute__((__aligned__(8))); }; +#ifdef __KERNEL__ + +/* + * Coprocessor save state. The magic values and specific + * coprocessor's layouts are part of the userspace ABI. Each one of + * these should be a multiple of eight bytes and aligned to eight + * bytes, to prevent unpredictable padding in the signal frame. + */ + +#ifdef CONFIG_IWMMXT +/* iwmmxt_area is 0x98 bytes long, preceeded by 8 bytes of signature */ +#define IWMMXT_MAGIC 0x12ef842a +#define IWMMXT_STORAGE_SIZE (IWMMXT_SIZE + 8) + +struct iwmmxt_sigframe { + unsigned long magic; + unsigned long size; + struct iwmmxt_struct storage; +} __attribute__((__aligned__(8))); +#endif /* CONFIG_IWMMXT */ + +#ifdef CONFIG_VFP +#if __LINUX_ARM_ARCH__ < 6 +/* For ARM pre-v6, we use fstmiax and fldmiax. This adds one extra + * word after the registers, and a word of padding at the end for + * alignment. */ +#define VFP_MAGIC 0x56465001 +#define VFP_STORAGE_SIZE 152 +#else +#define VFP_MAGIC 0x56465002 +#define VFP_STORAGE_SIZE 144 +#endif + +struct vfp_sigframe +{ + unsigned long magic; + unsigned long size; + union vfp_state storage; +}; +#endif /* CONFIG_VFP */ + +/* + * Auxiliary signal frame. This saves stuff like FP state. + * The layout of this structure is not part of the user ABI, + * because the config options aren't. uc_regspace is really + * one of these. + */ +struct aux_sigframe { +#ifdef CONFIG_IWMMXT + struct iwmmxt_sigframe iwmmxt; +#endif +#if 0 && defined CONFIG_VFP /* Not yet saved. */ + struct vfp_sigframe vfp; +#endif + /* Something that isn't a valid magic number for any coprocessor. */ + unsigned long end_magic; +} __attribute__((__aligned__(8))); + +#endif + #endif /* !_ASMARM_UCONTEXT_H */ -- cgit v1.2.3-70-g09d2