[ARM] 3559/1: S3C2442: core and serial port
authorBen Dooks <ben-linux@fluff.org>
Sun, 18 Jun 2006 22:06:41 +0000 (23:06 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Sun, 18 Jun 2006 22:06:41 +0000 (23:06 +0100)
Patch from Ben Dooks

Core support for the Samsung S3C2442, and the
serial port driver update to allow the serial
port blocks to be used.

Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
17 files changed:
arch/arm/mach-s3c2410/Kconfig
arch/arm/mach-s3c2410/Makefile
arch/arm/mach-s3c2410/clock.c
arch/arm/mach-s3c2410/cpu.c
arch/arm/mach-s3c2410/cpu.h
arch/arm/mach-s3c2410/s3c2440-irq.c
arch/arm/mach-s3c2410/s3c2440.c
arch/arm/mach-s3c2410/s3c2442-clock.c [new file with mode: 0644]
arch/arm/mach-s3c2410/s3c2442.c [new file with mode: 0644]
arch/arm/mach-s3c2410/s3c2442.h [new file with mode: 0644]
arch/arm/mach-s3c2410/s3c244x-irq.c [new file with mode: 0644]
arch/arm/mach-s3c2410/s3c244x.c [new file with mode: 0644]
arch/arm/mach-s3c2410/s3c244x.h [new file with mode: 0644]
drivers/serial/s3c2410.c
include/asm-arm/arch-s3c2410/regs-clock.h
include/asm-arm/arch-s3c2410/regs-gpio.h
include/asm-arm/arch-s3c2410/uncompress.h

index 970f98d..0c33413 100644 (file)
@@ -70,6 +70,18 @@ config ARCH_S3C2440
        help
          Say Y here if you are using the SMDK2440.
 
+config SMDK2440_CPU2440
+       bool "SMDK2440 with S3C2440 cpu module"
+       depends on ARCH_S3C2440
+       default y if ARCH_S3C2440
+       select CPU_S3C2440
+
+config SMDK2440_CPU2442
+       bool "SMDM2440 with S3C2442 cpu module"
+       depends on ARCH_S3C2440
+       select CPU_S3C2442
+
+
 config MACH_VR1000
        bool "Thorcom VR1000"
        select CPU_S3C2410
@@ -109,12 +121,26 @@ config CPU_S3C2410
          Support for S3C2410 and S3C2410A family from the S3C24XX line
          of Samsung Mobile CPUs.
 
+config CPU_S3C244X
+       bool
+       depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442)
+       help
+         Support for S3C2440 and S3C2442 Samsung Mobile CPU based systems.
+
 config CPU_S3C2440
        bool
        depends on ARCH_S3C2410
+       select CPU_S3C244X
        help
          Support for S3C2440 Samsung Mobile CPU based systems.
 
+config CPU_S3C2442
+       bool
+       depends on ARCH_S3C2420
+       select CPU_S3C244X
+       help
+         Support for S3C2442 Samsung Mobile CPU based systems.
+
 comment "S3C2410 Boot"
 
 config S3C2410_BOOT_WATCHDOG
index 3e5712d..5e09355 100644 (file)
@@ -24,6 +24,11 @@ obj-$(CONFIG_S3C2410_DMA)  += dma.o
 obj-$(CONFIG_PM)          += pm.o sleep.o
 obj-$(CONFIG_PM_SIMTEC)           += pm-simtec.o
 
+# S3C244X support
+
+obj-$(CONFIG_CPU_S3C244X)  += s3c244x.o
+obj-$(CONFIG_CPU_S3C244X)  += s3c244x-irq.o
+
 # S3C2440 support
 
 obj-$(CONFIG_CPU_S3C2440)  += s3c2440.o s3c2440-dsc.o
@@ -31,6 +36,11 @@ obj-$(CONFIG_CPU_S3C2440)  += s3c2440-irq.o
 obj-$(CONFIG_CPU_S3C2440)  += s3c2440-clock.o
 obj-$(CONFIG_CPU_S3C2440)  += s3c2410-gpio.o
 
+# S3C2442 support
+
+obj-$(CONFIG_CPU_S3C2442)  += s3c2442.o
+obj-$(CONFIG_CPU_S3C2442)  += s3c2442-clock.o
+
 # bast extras
 
 obj-$(CONFIG_BAST_PC104_IRQ)   += bast-irq.o
index 6de713a..99d1746 100644 (file)
@@ -70,7 +70,7 @@ void inline s3c24xx_clk_enable(unsigned int clocks, unsigned int enable)
                clkcon &= ~clocks;
 
        /* ensure none of the special function bits set */
-       clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER);
+       clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER | 3);
 
        __raw_writel(clkcon, S3C2410_CLKCON);
 }
index acc58ad..52842e6 100644 (file)
@@ -44,7 +44,9 @@
 #include "clock.h"
 #include "s3c2400.h"
 #include "s3c2410.h"
+#include "s3c244x.h"
 #include "s3c2440.h"
+#include "s3c2442.h"
 
 struct cpu_table {
        unsigned long   idcode;
@@ -61,6 +63,7 @@ struct cpu_table {
 static const char name_s3c2400[]  = "S3C2400";
 static const char name_s3c2410[]  = "S3C2410";
 static const char name_s3c2440[]  = "S3C2440";
+static const char name_s3c2442[]  = "S3C2442";
 static const char name_s3c2410a[] = "S3C2410A";
 static const char name_s3c2440a[] = "S3C2440A";
 
@@ -86,21 +89,30 @@ static struct cpu_table cpu_ids[] __initdata = {
        {
                .idcode         = 0x32440000,
                .idmask         = 0xffffffff,
-               .map_io         = s3c2440_map_io,
-               .init_clocks    = s3c2440_init_clocks,
-               .init_uarts     = s3c2440_init_uarts,
+               .map_io         = s3c244x_map_io,
+               .init_clocks    = s3c244x_init_clocks,
+               .init_uarts     = s3c244x_init_uarts,
                .init           = s3c2440_init,
                .name           = name_s3c2440
        },
        {
                .idcode         = 0x32440001,
                .idmask         = 0xffffffff,
-               .map_io         = s3c2440_map_io,
-               .init_clocks    = s3c2440_init_clocks,
-               .init_uarts     = s3c2440_init_uarts,
+               .map_io         = s3c244x_map_io,
+               .init_clocks    = s3c244x_init_clocks,
+               .init_uarts     = s3c244x_init_uarts,
                .init           = s3c2440_init,
                .name           = name_s3c2440a
        },
+       {
+               .idcode         = 0x32440aaa,
+               .idmask         = 0xffffffff,
+               .map_io         = s3c244x_map_io,
+               .init_clocks    = s3c244x_init_clocks,
+               .init_uarts     = s3c244x_init_uarts,
+               .init           = s3c2442_init,
+               .name           = name_s3c2442
+       },
        {
                .idcode         = 0x0,   /* S3C2400 doesn't have an idcode */
                .idmask         = 0xffffffff,
index 0c776ac..4086289 100644 (file)
@@ -74,3 +74,4 @@ extern struct sys_timer s3c24xx_timer;
 /* system device classes */
 
 extern struct sysdev_class s3c2440_sysclass;
+extern struct sysdev_class s3c2442_sysclass;
index 278d004..acfe387 100644 (file)
@@ -100,73 +100,12 @@ static struct irqchip s3c_irq_wdtac97 = {
        .ack        = s3c_irq_wdtac97_ack,
 };
 
-/* camera irq */
-
-static void s3c_irq_demux_cam(unsigned int irq,
-                             struct irqdesc *desc,
-                             struct pt_regs *regs)
-{
-       unsigned int subsrc, submsk;
-       struct irqdesc *mydesc;
-
-       /* read the current pending interrupts, and the mask
-        * for what it is available */
-
-       subsrc = __raw_readl(S3C2410_SUBSRCPND);
-       submsk = __raw_readl(S3C2410_INTSUBMSK);
-
-       subsrc &= ~submsk;
-       subsrc >>= 11;
-       subsrc &= 3;
-
-       if (subsrc != 0) {
-               if (subsrc & 1) {
-                       mydesc = irq_desc + IRQ_S3C2440_CAM_C;
-                       desc_handle_irq(IRQ_S3C2440_CAM_C, mydesc, regs);
-               }
-               if (subsrc & 2) {
-                       mydesc = irq_desc + IRQ_S3C2440_CAM_P;
-                       desc_handle_irq(IRQ_S3C2440_CAM_P, mydesc, regs);
-               }
-       }
-}
-
-#define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0))
-
-static void
-s3c_irq_cam_mask(unsigned int irqno)
-{
-       s3c_irqsub_mask(irqno, INTMSK_CAM, 3<<11);
-}
-
-static void
-s3c_irq_cam_unmask(unsigned int irqno)
-{
-       s3c_irqsub_unmask(irqno, INTMSK_CAM);
-}
-
-static void
-s3c_irq_cam_ack(unsigned int irqno)
-{
-       s3c_irqsub_maskack(irqno, INTMSK_CAM, 3<<11);
-}
-
-static struct irqchip s3c_irq_cam = {
-       .mask       = s3c_irq_cam_mask,
-       .unmask     = s3c_irq_cam_unmask,
-       .ack        = s3c_irq_cam_ack,
-};
-
 static int s3c2440_irq_add(struct sys_device *sysdev)
 {
        unsigned int irqno;
 
        printk("S3C2440: IRQ Support\n");
 
-       set_irq_chip(IRQ_NFCON, &s3c_irq_level_chip);
-       set_irq_handler(IRQ_NFCON, do_level_IRQ);
-       set_irq_flags(IRQ_NFCON, IRQF_VALID);
-
        /* add new chained handler for wdt, ac7 */
 
        set_irq_chip(IRQ_WDT, &s3c_irq_level_chip);
@@ -179,18 +118,6 @@ static int s3c2440_irq_add(struct sys_device *sysdev)
                set_irq_flags(irqno, IRQF_VALID);
        }
 
-       /* add chained handler for camera */
-
-       set_irq_chip(IRQ_CAM, &s3c_irq_level_chip);
-       set_irq_handler(IRQ_CAM, do_level_IRQ);
-       set_irq_chained_handler(IRQ_CAM, s3c_irq_demux_cam);
-
-       for (irqno = IRQ_S3C2440_CAM_C; irqno <= IRQ_S3C2440_CAM_P; irqno++) {
-               set_irq_chip(irqno, &s3c_irq_cam);
-               set_irq_handler(irqno, do_level_IRQ);
-               set_irq_flags(irqno, IRQF_VALID);
-       }
-
        return 0;
 }
 
@@ -198,10 +125,10 @@ static struct sysdev_driver s3c2440_irq_driver = {
        .add    = s3c2440_irq_add,
 };
 
-static int s3c24xx_irq_driver(void)
+static int s3c2440_irq_init(void)
 {
        return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_irq_driver);
 }
 
-arch_initcall(s3c24xx_irq_driver);
+arch_initcall(s3c2440_irq_init);
 
index 5468174..0ab50f4 100644 (file)
@@ -1,6 +1,6 @@
 /* linux/arch/arm/mach-s3c2410/s3c2440.c
  *
- * Copyright (c) 2004-2005 Simtec Electronics
+ * Copyright (c) 2004-2006 Simtec Electronics
  *   Ben Dooks <ben@simtec.co.uk>
  *
  * Samsung S3C2440 Mobile CPU support
@@ -8,16 +8,6 @@
  * 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:
- *     24-Aug-2004 BJD  Start of s3c2440 support
- *     12-Oct-2004 BJD  Moved clock info out to clock.c
- *     01-Nov-2004 BJD  Fixed clock build code
- *     09-Nov-2004 BJD  Added sysdev for power management
- *     04-Nov-2004 BJD  New serial registration
- *     15-Nov-2004 BJD  Rename the i2c device for the s3c2440
- *     14-Jan-2005 BJD  Moved clock init code into seperate function
- *     14-Jan-2005 BJD  Removed un-used clock bits
 */
 
 #include <linux/kernel.h>
 #include "cpu.h"
 #include "pm.h"
 
-
-static struct map_desc s3c2440_iodesc[] __initdata = {
-       IODESC_ENT(USBHOST),
-       IODESC_ENT(CLKPWR),
-       IODESC_ENT(LCD),
-       IODESC_ENT(TIMER),
-       IODESC_ENT(ADC),
-       IODESC_ENT(WATCHDOG),
-};
-
-/* uart initialisation */
-
-void __init s3c2440_init_uarts(struct s3c2410_uartcfg *cfg, int no)
-{
-       s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);
-}
-
-#ifdef CONFIG_PM
-
-static struct sleep_save s3c2440_sleep[] = {
-       SAVE_ITEM(S3C2440_DSC0),
-       SAVE_ITEM(S3C2440_DSC1),
-       SAVE_ITEM(S3C2440_GPJDAT),
-       SAVE_ITEM(S3C2440_GPJCON),
-       SAVE_ITEM(S3C2440_GPJUP)
-};
-
-static int s3c2440_suspend(struct sys_device *dev, pm_message_t state)
-{
-       s3c2410_pm_do_save(s3c2440_sleep, ARRAY_SIZE(s3c2440_sleep));
-       return 0;
-}
-
-static int s3c2440_resume(struct sys_device *dev)
-{
-       s3c2410_pm_do_restore(s3c2440_sleep, ARRAY_SIZE(s3c2440_sleep));
-       return 0;
-}
-
-#else
-#define s3c2440_suspend NULL
-#define s3c2440_resume  NULL
-#endif
-
-struct sysdev_class s3c2440_sysclass = {
-       set_kset_name("s3c2440-core"),
-       .suspend        = s3c2440_suspend,
-       .resume         = s3c2440_resume
-};
-
 static struct sys_device s3c2440_sysdev = {
        .cls            = &s3c2440_sysclass,
 };
 
-void __init s3c2440_map_io(struct map_desc *mach_desc, int size)
+int __init s3c2440_init(void)
 {
-       /* register our io-tables */
-
-       iotable_init(s3c2440_iodesc, ARRAY_SIZE(s3c2440_iodesc));
-       iotable_init(mach_desc, size);
-
-       /* rename any peripherals used differing from the s3c2410 */
-
-       s3c_device_i2c.name  = "s3c2440-i2c";
-       s3c_device_nand.name = "s3c2440-nand";
+       printk("S3C2440: Initialising architecture\n");
 
        /* change irq for watchdog */
 
        s3c_device_wdt.resource[1].start = IRQ_S3C2440_WDT;
        s3c_device_wdt.resource[1].end   = IRQ_S3C2440_WDT;
-}
 
-void __init s3c2440_init_clocks(int xtal)
-{
-       unsigned long clkdiv;
-       unsigned long camdiv;
-       unsigned long hclk, fclk, pclk;
-       int hdiv = 1;
-
-       /* 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;
-
-       clkdiv = __raw_readl(S3C2410_CLKDIVN);
-       camdiv = __raw_readl(S3C2440_CAMDIVN);
-
-       /* work out clock scalings */
-
-       switch (clkdiv & S3C2440_CLKDIVN_HDIVN_MASK) {
-       case S3C2440_CLKDIVN_HDIVN_1:
-               hdiv = 1;
-               break;
-
-       case S3C2440_CLKDIVN_HDIVN_2:
-               hdiv = 2;
-               break;
-
-       case S3C2440_CLKDIVN_HDIVN_4_8:
-               hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4;
-               break;
-
-       case S3C2440_CLKDIVN_HDIVN_3_6:
-               hdiv = (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6 : 3;
-               break;
-       }
-
-       hclk = fclk / hdiv;
-       pclk = hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN)? 2:1);
-
-       /* print brief summary of clocks, etc */
-
-       printk("S3C2440: 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, and to add new ones after the initialisation
-        */
-
-       s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
-}
-
-/* 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 s3c2440 based system)
- * as a driver which may support both 2410 and 2440 may try and use it.
-*/
-
-static int __init s3c2440_core_init(void)
-{
-       return sysdev_class_register(&s3c2440_sysclass);
-}
-
-core_initcall(s3c2440_core_init);
-
-int __init s3c2440_init(void)
-{
-       printk("S3C2440: Initialising architecture\n");
+       /* register our system device for everything else */
 
        return sysdev_register(&s3c2440_sysdev);
 }
diff --git a/arch/arm/mach-s3c2410/s3c2442-clock.c b/arch/arm/mach-s3c2410/s3c2442-clock.c
new file mode 100644 (file)
index 0000000..5b7b301
--- /dev/null
@@ -0,0 +1,171 @@
+/* linux/arch/arm/mach-s3c2410/s3c2442-clock.c
+ *
+ * Copyright (c) 2004-2005 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2442 Clock 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/device.h>
+#include <linux/sysdev.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+
+#include <asm/hardware.h>
+#include <asm/atomic.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/arch/regs-clock.h>
+
+#include "clock.h"
+#include "cpu.h"
+
+/* S3C2442 extended clock support */
+
+static unsigned long s3c2442_camif_upll_round(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 == 3)
+               return parent_rate / 3;
+
+       /* note, we remove the +/- 1 calculations for the divisor */
+
+       div /= 2;
+
+       if (div < 1)
+               div = 1;
+       else if (div > 16)
+               div = 16;
+
+       return parent_rate / (div * 2);
+}
+
+static int s3c2442_camif_upll_setrate(struct clk *clk, unsigned long rate)
+{
+       unsigned long parent_rate = clk_get_rate(clk->parent);
+       unsigned long camdivn =  __raw_readl(S3C2440_CAMDIVN);
+
+       rate = s3c2442_camif_upll_round(clk, rate);
+
+       camdivn &= ~S3C2442_CAMDIVN_CAMCLK_DIV3;
+
+       if (rate == parent_rate) {
+               camdivn &= ~S3C2440_CAMDIVN_CAMCLK_SEL;
+       } else if ((parent_rate / rate) == 3) {
+               camdivn |= S3C2440_CAMDIVN_CAMCLK_SEL;
+               camdivn |= S3C2442_CAMDIVN_CAMCLK_DIV3;
+       } else {
+               camdivn &= ~S3C2440_CAMDIVN_CAMCLK_MASK;
+               camdivn |= S3C2440_CAMDIVN_CAMCLK_SEL;
+               camdivn |= (((parent_rate / rate) / 2) - 1);
+       }
+
+       __raw_writel(camdivn, S3C2440_CAMDIVN);
+
+       return 0;
+}
+
+/* Extra S3C2442 clocks */
+
+static struct clk s3c2442_clk_cam = {
+       .name           = "camif",
+       .id             = -1,
+       .enable         = s3c24xx_clkcon_enable,
+       .ctrlbit        = S3C2440_CLKCON_CAMERA,
+};
+
+static struct clk s3c2442_clk_cam_upll = {
+       .name           = "camif-upll",
+       .id             = -1,
+       .set_rate       = s3c2442_camif_upll_setrate,
+       .round_rate     = s3c2442_camif_upll_round,
+};
+
+static int s3c2442_clk_add(struct sys_device *sysdev)
+{
+       unsigned long camdivn = __raw_readl(S3C2440_CAMDIVN);
+       unsigned long clkdivn;
+       struct clk *clk_h;
+       struct clk *clk_p;
+       struct clk *clk_upll;
+
+       printk("S3C2442: Clock Support, DVS %s\n",
+              (camdivn & S3C2440_CAMDIVN_DVSEN) ? "on" : "off");
+
+       clk_p = clk_get(NULL, "pclk");
+       clk_h = clk_get(NULL, "hclk");
+       clk_upll = clk_get(NULL, "upll");
+
+       if (IS_ERR(clk_p) || IS_ERR(clk_h) || IS_ERR(clk_upll)) {
+               printk(KERN_ERR "S3C2442: Failed to get parent clocks\n");
+               return -EINVAL;
+       }
+
+       /* check rate of UPLL, and if it is near 96MHz, then change
+        * to using half the UPLL rate for the system */
+
+       if (clk_get_rate(clk_upll) > (94 * MHZ)) {
+               clk_usb_bus.rate = clk_get_rate(clk_upll) / 2;
+
+               mutex_lock(&clocks_mutex);
+
+               clkdivn = __raw_readl(S3C2410_CLKDIVN);
+               clkdivn |= S3C2440_CLKDIVN_UCLK;
+               __raw_writel(clkdivn, S3C2410_CLKDIVN);
+
+               mutex_unlock(&clocks_mutex);
+       }
+
+       s3c2442_clk_cam.parent = clk_h;
+       s3c2442_clk_cam_upll.parent = clk_upll;
+
+       s3c24xx_register_clock(&s3c2442_clk_cam);
+       s3c24xx_register_clock(&s3c2442_clk_cam_upll);
+
+       clk_disable(&s3c2442_clk_cam);
+
+       return 0;
+}
+
+static struct sysdev_driver s3c2442_clk_driver = {
+       .add    = s3c2442_clk_add,
+};
+
+static __init int s3c2442_clk_init(void)
+{
+       return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_clk_driver);
+}
+
+arch_initcall(s3c2442_clk_init);
diff --git a/arch/arm/mach-s3c2410/s3c2442.c b/arch/arm/mach-s3c2410/s3c2442.c
new file mode 100644 (file)
index 0000000..debae24
--- /dev/null
@@ -0,0 +1,52 @@
+/* linux/arch/arm/mach-s3c2410/s3c2440.c
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ *   Ben Dooks <ben@simtec.co.uk>
+ *
+ * Samsung S3C2442 Mobile 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.
+*/
+
+#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 <linux/sysdev.h>
+#include <linux/clk.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 "s3c2442.h"
+#include "clock.h"
+#include "devs.h"
+#include "cpu.h"
+#include "pm.h"
+
+static struct sys_device s3c2442_sysdev = {
+       .cls            = &s3c2442_sysclass,
+};
+
+int __init s3c2442_init(void)
+{
+       printk("S3C2442: Initialising architecture\n");
+
+       return sysdev_register(&s3c2442_sysdev);
+}
diff --git a/arch/arm/mach-s3c2410/s3c2442.h b/arch/arm/mach-s3c2410/s3c2442.h
new file mode 100644 (file)
index 0000000..0ae37d2
--- /dev/null
@@ -0,0 +1,17 @@
+/* arch/arm/mach-s3c2410/s3c2442.h
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * Header file for s3c2442 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_S3C2442
+extern  int s3c2442_init(void);
+#else
+#define s3c2442_init NULL
+#endif
diff --git a/arch/arm/mach-s3c2410/s3c244x-irq.c b/arch/arm/mach-s3c2410/s3c244x-irq.c
new file mode 100644 (file)
index 0000000..2aadca1
--- /dev/null
@@ -0,0 +1,142 @@
+/* linux/arch/arm/mach-s3c2410/s3c2440-irq.c
+ *
+ * Copyright (c) 2003,2004 Simtec Electronics
+ *     Ben Dooks <ben@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 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
+ *
+ * Changelog:
+ *     25-Jul-2005 BJD         Split from irq.c
+ *
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/ptrace.h>
+#include <linux/sysdev.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/mach/irq.h>
+
+#include <asm/arch/regs-irq.h>
+#include <asm/arch/regs-gpio.h>
+
+#include "cpu.h"
+#include "pm.h"
+#include "irq.h"
+
+/* camera irq */
+
+static void s3c_irq_demux_cam(unsigned int irq,
+                             struct irqdesc *desc,
+                             struct pt_regs *regs)
+{
+       unsigned int subsrc, submsk;
+       struct irqdesc *mydesc;
+
+       /* read the current pending interrupts, and the mask
+        * for what it is available */
+
+       subsrc = __raw_readl(S3C2410_SUBSRCPND);
+       submsk = __raw_readl(S3C2410_INTSUBMSK);
+
+       subsrc &= ~submsk;
+       subsrc >>= 11;
+       subsrc &= 3;
+
+       if (subsrc != 0) {
+               if (subsrc & 1) {
+                       mydesc = irq_desc + IRQ_S3C2440_CAM_C;
+                       desc_handle_irq(IRQ_S3C2440_CAM_C, mydesc, regs);
+               }
+               if (subsrc & 2) {
+                       mydesc = irq_desc + IRQ_S3C2440_CAM_P;
+                       desc_handle_irq(IRQ_S3C2440_CAM_P, mydesc, regs);
+               }
+       }
+}
+
+#define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0))
+
+static void
+s3c_irq_cam_mask(unsigned int irqno)
+{
+       s3c_irqsub_mask(irqno, INTMSK_CAM, 3<<11);
+}
+
+static void
+s3c_irq_cam_unmask(unsigned int irqno)
+{
+       s3c_irqsub_unmask(irqno, INTMSK_CAM);
+}
+
+static void
+s3c_irq_cam_ack(unsigned int irqno)
+{
+       s3c_irqsub_maskack(irqno, INTMSK_CAM, 3<<11);
+}
+
+static struct irqchip s3c_irq_cam = {
+       .mask       = s3c_irq_cam_mask,
+       .unmask     = s3c_irq_cam_unmask,
+       .ack        = s3c_irq_cam_ack,
+};
+
+static int s3c244x_irq_add(struct sys_device *sysdev)
+{
+       unsigned int irqno;
+
+       set_irq_chip(IRQ_NFCON, &s3c_irq_level_chip);
+       set_irq_handler(IRQ_NFCON, do_level_IRQ);
+       set_irq_flags(IRQ_NFCON, IRQF_VALID);
+
+       /* add chained handler for camera */
+
+       set_irq_chip(IRQ_CAM, &s3c_irq_level_chip);
+       set_irq_handler(IRQ_CAM, do_level_IRQ);
+       set_irq_chained_handler(IRQ_CAM, s3c_irq_demux_cam);
+
+       for (irqno = IRQ_S3C2440_CAM_C; irqno <= IRQ_S3C2440_CAM_P; irqno++) {
+               set_irq_chip(irqno, &s3c_irq_cam);
+               set_irq_handler(irqno, do_level_IRQ);
+               set_irq_flags(irqno, IRQF_VALID);
+       }
+
+       return 0;
+}
+
+static struct sysdev_driver s3c244x_irq_driver = {
+       .add    = s3c244x_irq_add,
+};
+
+static int s3c2440_irq_init(void)
+{
+       return sysdev_driver_register(&s3c2440_sysclass, &s3c244x_irq_driver);
+}
+
+arch_initcall(s3c2440_irq_init);
+
+
+static int s3c2442_irq_init(void)
+{
+       return sysdev_driver_register(&s3c2442_sysclass, &s3c244x_irq_driver);
+}
+
+arch_initcall(s3c2442_irq_init);
diff --git a/arch/arm/mach-s3c2410/s3c244x.c b/arch/arm/mach-s3c2410/s3c244x.c
new file mode 100644 (file)
index 0000000..96852a7
--- /dev/null
@@ -0,0 +1,182 @@
+/* linux/arch/arm/mach-s3c2410/s3c244x.c
+ *
+ * Copyright (c) 2004-2006 Simtec Electronics
+ *   Ben Dooks <ben@simtec.co.uk>
+ *
+ * Samsung S3C2440 and S3C2442 Mobile 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.
+*/
+
+#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 <linux/sysdev.h>
+#include <linux/clk.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 "s3c2440.h"
+#include "s3c244x.h"
+#include "clock.h"
+#include "devs.h"
+#include "cpu.h"
+#include "pm.h"
+
+static struct map_desc s3c244x_iodesc[] __initdata = {
+       IODESC_ENT(CLKPWR),
+       IODESC_ENT(TIMER),
+       IODESC_ENT(WATCHDOG),
+       IODESC_ENT(LCD),
+       IODESC_ENT(ADC),
+       IODESC_ENT(USBHOST),
+};
+
+/* uart initialisation */
+
+void __init s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no)
+{
+       s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);
+}
+
+void __init s3c244x_map_io(struct map_desc *mach_desc, int size)
+{
+       /* register our io-tables */
+
+       iotable_init(s3c244x_iodesc, ARRAY_SIZE(s3c244x_iodesc));
+       iotable_init(mach_desc, size);
+
+       /* rename any peripherals used differing from the s3c2410 */
+
+       s3c_device_i2c.name  = "s3c2440-i2c";
+       s3c_device_nand.name = "s3c2440-nand";
+}
+
+void __init s3c244x_init_clocks(int xtal)
+{
+       unsigned long clkdiv;
+       unsigned long camdiv;
+       unsigned long hclk, fclk, pclk;
+       int hdiv = 1;
+
+       /* 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;
+
+       clkdiv = __raw_readl(S3C2410_CLKDIVN);
+       camdiv = __raw_readl(S3C2440_CAMDIVN);
+
+       /* work out clock scalings */
+
+       switch (clkdiv & S3C2440_CLKDIVN_HDIVN_MASK) {
+       case S3C2440_CLKDIVN_HDIVN_1:
+               hdiv = 1;
+               break;
+
+       case S3C2440_CLKDIVN_HDIVN_2:
+               hdiv = 2;
+               break;
+
+       case S3C2440_CLKDIVN_HDIVN_4_8:
+               hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4;
+               break;
+
+       case S3C2440_CLKDIVN_HDIVN_3_6:
+               hdiv = (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6 : 3;
+               break;
+       }
+
+       hclk = fclk / hdiv;
+       pclk = hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN)? 2:1);
+
+       /* print brief summary of clocks, etc */
+
+       printk("S3C244X: 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, and to add new ones after the initialisation
+        */
+
+       s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
+}
+
+#ifdef CONFIG_PM
+
+static struct sleep_save s3c244x_sleep[] = {
+       SAVE_ITEM(S3C2440_DSC0),
+       SAVE_ITEM(S3C2440_DSC1),
+       SAVE_ITEM(S3C2440_GPJDAT),
+       SAVE_ITEM(S3C2440_GPJCON),
+       SAVE_ITEM(S3C2440_GPJUP)
+};
+
+static int s3c244x_suspend(struct sys_device *dev, pm_message_t state)
+{
+       s3c2410_pm_do_save(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep));
+       return 0;
+}
+
+static int s3c244x_resume(struct sys_device *dev)
+{
+       s3c2410_pm_do_restore(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep));
+       return 0;
+}
+
+#else
+#define s3c244x_suspend NULL
+#define s3c244x_resume  NULL
+#endif
+
+/* Since the S3C2442 and S3C2440 share  items, put both sysclasses here */
+
+struct sysdev_class s3c2440_sysclass = {
+       set_kset_name("s3c2440-core"),
+       .suspend        = s3c244x_suspend,
+       .resume         = s3c244x_resume
+};
+
+struct sysdev_class s3c2442_sysclass = {
+       set_kset_name("s3c2442-core"),
+       .suspend        = s3c244x_suspend,
+       .resume         = s3c244x_resume
+};
+
+/* 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 s3c2440 based system)
+ * as a driver which may support both 2410 and 2440 may try and use it.
+*/
+
+static int __init s3c2440_core_init(void)
+{
+       return sysdev_class_register(&s3c2440_sysclass);
+}
+
+core_initcall(s3c2440_core_init);
+
+static int __init s3c2442_core_init(void)
+{
+       return sysdev_class_register(&s3c2442_sysclass);
+}
+
+core_initcall(s3c2442_core_init);
diff --git a/arch/arm/mach-s3c2410/s3c244x.h b/arch/arm/mach-s3c2410/s3c244x.h
new file mode 100644 (file)
index 0000000..3e7f5f7
--- /dev/null
@@ -0,0 +1,25 @@
+/* arch/arm/mach-s3c2410/s3c2440.h
+ *
+ * Copyright (c) 2004-2005 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * Header file for S3C2440 and S3C2442 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.
+*/
+
+#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442)
+
+extern void s3c244x_map_io(struct map_desc *mach_desc, int size);
+
+extern void s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no);
+
+extern void s3c244x_init_clocks(int xtal);
+
+#else
+#define s3c244x_init_clocks NULL
+#define s3c244x_init_uarts NULL
+#define s3c244x_map_io NULL
+#endif
index f5aac92..53c2465 100644 (file)
@@ -1365,7 +1365,7 @@ static inline void s3c2410_serial_exit(void)
 
 #endif /* CONFIG_CPU_S3C2410 */
 
-#ifdef CONFIG_CPU_S3C2440
+#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442)
 
 static int s3c2440_serial_setsource(struct uart_port *port,
                                     struct s3c24xx_uart_clksrc *clk)
index 3436070..6c92faf 100644 (file)
@@ -114,7 +114,7 @@ s3c2410_get_pll(unsigned int pllval, unsigned int baseclk)
 
 #endif /* __ASSEMBLY__ */
 
-#ifdef CONFIG_CPU_S3C2440
+#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442)
 
 /* extra registers */
 #define S3C2440_CAMDIVN            S3C2410_CLKREG(0x18)
@@ -136,7 +136,9 @@ s3c2410_get_pll(unsigned int pllval, unsigned int baseclk)
 #define S3C2440_CAMDIVN_HCLK4_HALF   (1<<9)
 #define S3C2440_CAMDIVN_DVSEN        (1<<12)
 
-#endif /* CONFIG_CPU_S3C2440 */
+#define S3C2442_CAMDIVN_CAMCLK_DIV3  (1<<5)
+
+#endif /* CONFIG_CPU_S3C2440 or CONFIG_CPU_S3C2442 */
 
 
 #endif /* __ASM_ARM_REGS_CLOCK */
index d257408..5f10334 100644 (file)
 #define S3C2410_GPD0_OUTP      (0x01 << 0)
 #define S3C2410_GPD0_VD8       (0x02 << 0)
 #define S3C2400_GPD0_VFRAME    (0x02 << 0)
+#define S3C2442_GPD0_nSPICS1   (0x03 << 0)
 
 #define S3C2410_GPD1            S3C2410_GPIONO(S3C2410_GPIO_BANKD, 1)
 #define S3C2410_GPD1_INP       (0x00 << 2)
 #define S3C2410_GPD1_OUTP      (0x01 << 2)
 #define S3C2410_GPD1_VD9       (0x02 << 2)
 #define S3C2400_GPD1_VM                (0x02 << 2)
+#define S3C2442_GPD1_SPICLK1   (0x03 << 2)
 
 #define S3C2410_GPD2            S3C2410_GPIONO(S3C2410_GPIO_BANKD, 2)
 #define S3C2410_GPD2_INP       (0x00 << 4)
 #define S3C2410_GPG12_OUTP    (0x01 << 24)
 #define S3C2410_GPG12_EINT20  (0x02 << 24)
 #define S3C2410_GPG12_XMON    (0x03 << 24)
+#define S3C2442_GPG12_nSPICS0 (0x03 << 24)
 
 #define S3C2410_GPG13         S3C2410_GPIONO(S3C2410_GPIO_BANKG, 13)
 #define S3C2410_GPG13_INP     (0x00 << 26)
 #define S3C2410_GPH9_INP      (0x00 << 18)
 #define S3C2410_GPH9_OUTP     (0x01 << 18)
 #define S3C2410_GPH9_CLKOUT0  (0x02 << 18)
+#define S3C2442_GPH9_nSPICS0  (0x03 << 18)
 
 #define S3C2410_GPH10         S3C2410_GPIONO(S3C2410_GPIO_BANKH, 10)
 #define S3C2410_GPH10_INP     (0x00 << 20)
 #define S3C2410_GSTATUS1_IDMASK           (0xffff0000)
 #define S3C2410_GSTATUS1_2410     (0x32410000)
 #define S3C2410_GSTATUS1_2440     (0x32440000)
+#define S3C2410_GSTATUS1_2442     (0x32440aaa)
 
 #define S3C2410_GSTATUS2_WTRESET   (1<<2)
 #define S3C2410_GSTATUS2_OFFRESET  (1<<1)
index a6f6a0e..bbd9ee1 100644 (file)
@@ -82,7 +82,8 @@ static void putc(int ch)
                while (1) {
                        level = uart_rd(S3C2410_UFSTAT);
 
-                       if (cpuid == S3C2410_GSTATUS1_2440) {
+                       if (cpuid == S3C2410_GSTATUS1_2440 ||
+                           cpuid == S3C2410_GSTATUS1_2442) {
                                level &= S3C2440_UFSTAT_TXMASK;
                                level >>= S3C2440_UFSTAT_TXSHIFT;
                        } else {
@@ -130,7 +131,7 @@ static void arch_decomp_wdog_start(void)
 {
        __raw_writel(WDOG_COUNT, S3C2410_WTDAT);
        __raw_writel(WDOG_COUNT, S3C2410_WTCNT);
-       __raw_writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128 | S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x40), S3C2410_WTCON);
+       __raw_writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128 | S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x80), S3C2410_WTCON);
 }
 
 #else