summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/kernel/iwmmxt.S2
-rw-r--r--arch/arm/kernel/signal.c207
-rw-r--r--arch/arm/mach-ep93xx/Makefile2
-rw-r--r--arch/arm/mach-ep93xx/clock.c156
-rw-r--r--arch/arm/mach-ep93xx/core.c28
-rw-r--r--arch/arm/mach-ixp2000/core.c1
-rw-r--r--arch/arm/mach-s3c2410/Kconfig20
-rw-r--r--arch/arm/mach-s3c2410/Makefile6
-rw-r--r--arch/arm/mach-s3c2410/clock.c21
-rw-r--r--arch/arm/mach-s3c2410/clock.h2
-rw-r--r--arch/arm/mach-s3c2410/cpu.c37
-rw-r--r--arch/arm/mach-s3c2410/cpu.h1
-rw-r--r--arch/arm/mach-s3c2410/irq.c57
-rw-r--r--arch/arm/mach-s3c2410/mach-smdk2413.c126
-rw-r--r--arch/arm/mach-s3c2410/pm-simtec.c3
-rw-r--r--arch/arm/mach-s3c2410/s3c2410-clock.c10
-rw-r--r--arch/arm/mach-s3c2410/s3c2410-gpio.c13
-rw-r--r--arch/arm/mach-s3c2410/s3c2412-clock.c711
-rw-r--r--arch/arm/mach-s3c2410/s3c2412.c195
-rw-r--r--arch/arm/mach-s3c2410/s3c2412.h29
-rw-r--r--arch/arm/mm/Kconfig10
21 files changed, 1466 insertions, 171 deletions
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.
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index f094277485c..1ce05ec086c 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;
@@ -177,70 +166,61 @@ 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 sigcontext sc;
- unsigned long extramask[_NSIG_WORDS-1];
+ struct ucontext uc;
unsigned long retcode[2];
- struct aux_sigframe aux __attribute__((aligned(8)));
};
struct rt_sigframe {
- struct siginfo __user *pinfo;
- void __user *puc;
struct siginfo info;
- struct ucontext uc;
- unsigned long retcode[2];
- struct aux_sigframe aux __attribute__((aligned(8)));
+ 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;
+ struct aux_sigframe __user *aux;
+ sigset_t set;
+ int err;
+
+ err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set));
+ if (err == 0) {
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sighand->siglock);
+ current->blocked = set;
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+ }
- __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);
+ __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);
+ 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(&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;
@@ -249,7 +229,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;
@@ -266,19 +245,8 @@ 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))))
- goto badframe;
-
- sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
- if (restore_sigcontext(regs, &frame->sc, &frame->aux))
+ if (restore_sigframe(regs, frame))
goto badframe;
/* Send SIGTRAP if we're single-stepping */
@@ -297,7 +265,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;
@@ -314,19 +281,11 @@ 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)))
- goto badframe;
- sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
-
- if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &frame->aux))
+ if (restore_sigframe(regs, &frame->sig))
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 */
@@ -343,42 +302,46 @@ 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)
{
+ struct aux_sigframe __user *aux;
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));
+
+ 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(&aux->iwmmxt);
#endif
#ifdef CONFIG_VFP
// if (err == 0)
-// err |= vfp_save_state(&aux->vfp);
+// err |= vfp_save_state(&sf->aux.vfp);
#endif
+ __put_user_error(0, &aux->end_magic, err);
return err;
}
@@ -487,13 +450,12 @@ 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]);
-
- if (_NSIG_WORDS > 1) {
- err |= __copy_to_user(frame->extramask, &set->sig[1],
- sizeof(frame->extramask));
- }
+ /*
+ * 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);
@@ -511,25 +473,20 @@ 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);
- __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 |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->aux,
- regs, set->sig[0]);
- err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+ err |= __copy_to_user(&frame->sig.uc.uc_stack, &stack, sizeof(stack));
+ err |= setup_sigframe(&frame->sig, regs, 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) {
/*
@@ -538,7 +495,7 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
* -- Peter Maydell <pmaydell@chiark.greenend.org.uk> 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;
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 <buytenh@wantstofly.org>
+ *
+ * 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 <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <asm/div64.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+
+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..1fe73c0a9d0 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -433,10 +433,37 @@ 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;
+ ep93xx_clock_init();
+
/*
* Disallow access to MaverickCrunch initially.
*/
@@ -450,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);
}
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);
/*************************************************************************
diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig
index 7b786d72563..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"
@@ -127,6 +133,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..0c7938645df 100644
--- a/arch/arm/mach-s3c2410/Makefile
+++ b/arch/arm/mach-s3c2410/Makefile
@@ -24,6 +24,11 @@ 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
+obj-$(CONFIG_CPU_S3C2412) += s3c2412-clock.o
+
+#
# S3C244X support
obj-$(CONFIG_CPU_S3C244X) += s3c244x.o
@@ -57,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/clock.c b/arch/arm/mach-s3c2410/clock.c
index c5c93c333ac..e13fb677889 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,
};
@@ -263,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;
}
@@ -289,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)
@@ -303,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;
}
@@ -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
*
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";
@@ -114,6 +116,15 @@ static struct cpu_table cpu_ids[] __initdata = {
.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,
.map_io = s3c2400_map_io,
@@ -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/irq.c b/arch/arm/mach-s3c2410/irq.c
index 66d8c068e94..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);
}
@@ -275,28 +271,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
@@ -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/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 <ben@simtec.co.uk>
+ *
+ * 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 <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/hardware.h>
+#include <asm/hardware/iomd.h>
+#include <asm/setup.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+//#include <asm/debug-ll.h>
+#include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-lcd.h>
+
+#include <asm/arch/idle.h>
+#include <asm/arch/fb.h>
+
+#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 <ben@fluff.org> */
+ .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
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");
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()
diff --git a/arch/arm/mach-s3c2410/s3c2410-gpio.c b/arch/arm/mach-s3c2410/s3c2410-gpio.c
index d5e1caea1d2..471a7149001 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 <linux/kernel.h>
@@ -38,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;
@@ -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);
@@ -61,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);
@@ -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)
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 <ben@simtec.co.uk>
+ *
+ * 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 <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/sysdev.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+
+#include <asm/arch/regs-clock.h>
+#include <asm/arch/regs-gpio.h>
+
+#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/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 <ben@simtec.co.uk>
+ *
+ * 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 <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/sysdev.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <asm/arch/regs-clock.h>
+#include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-gpioj.h>
+#include <asm/arch/regs-dsc.h>
+
+#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 <ben@simtec.co.uk>
+ *
+ * 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/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