Commit 96ce2385 authored by Ben Dooks's avatar Ben Dooks Committed by Russell King

[ARM] 3559/1: S3C2442: core and serial port

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: default avatarBen Dooks <ben-linux@fluff.org>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 66a9b49a
...@@ -70,6 +70,18 @@ config ARCH_S3C2440 ...@@ -70,6 +70,18 @@ config ARCH_S3C2440
help help
Say Y here if you are using the SMDK2440. 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 config MACH_VR1000
bool "Thorcom VR1000" bool "Thorcom VR1000"
select CPU_S3C2410 select CPU_S3C2410
...@@ -109,12 +121,26 @@ config CPU_S3C2410 ...@@ -109,12 +121,26 @@ config CPU_S3C2410
Support for S3C2410 and S3C2410A family from the S3C24XX line Support for S3C2410 and S3C2410A family from the S3C24XX line
of Samsung Mobile CPUs. 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 config CPU_S3C2440
bool bool
depends on ARCH_S3C2410 depends on ARCH_S3C2410
select CPU_S3C244X
help help
Support for S3C2440 Samsung Mobile CPU based systems. 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" comment "S3C2410 Boot"
config S3C2410_BOOT_WATCHDOG config S3C2410_BOOT_WATCHDOG
......
...@@ -24,6 +24,11 @@ obj-$(CONFIG_S3C2410_DMA) += dma.o ...@@ -24,6 +24,11 @@ obj-$(CONFIG_S3C2410_DMA) += dma.o
obj-$(CONFIG_PM) += pm.o sleep.o obj-$(CONFIG_PM) += pm.o sleep.o
obj-$(CONFIG_PM_SIMTEC) += pm-simtec.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 # S3C2440 support
obj-$(CONFIG_CPU_S3C2440) += s3c2440.o s3c2440-dsc.o obj-$(CONFIG_CPU_S3C2440) += s3c2440.o s3c2440-dsc.o
...@@ -31,6 +36,11 @@ obj-$(CONFIG_CPU_S3C2440) += s3c2440-irq.o ...@@ -31,6 +36,11 @@ obj-$(CONFIG_CPU_S3C2440) += s3c2440-irq.o
obj-$(CONFIG_CPU_S3C2440) += s3c2440-clock.o obj-$(CONFIG_CPU_S3C2440) += s3c2440-clock.o
obj-$(CONFIG_CPU_S3C2440) += s3c2410-gpio.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 # bast extras
obj-$(CONFIG_BAST_PC104_IRQ) += bast-irq.o obj-$(CONFIG_BAST_PC104_IRQ) += bast-irq.o
......
...@@ -70,7 +70,7 @@ void inline s3c24xx_clk_enable(unsigned int clocks, unsigned int enable) ...@@ -70,7 +70,7 @@ void inline s3c24xx_clk_enable(unsigned int clocks, unsigned int enable)
clkcon &= ~clocks; clkcon &= ~clocks;
/* ensure none of the special function bits set */ /* 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); __raw_writel(clkcon, S3C2410_CLKCON);
} }
......
...@@ -44,7 +44,9 @@ ...@@ -44,7 +44,9 @@
#include "clock.h" #include "clock.h"
#include "s3c2400.h" #include "s3c2400.h"
#include "s3c2410.h" #include "s3c2410.h"
#include "s3c244x.h"
#include "s3c2440.h" #include "s3c2440.h"
#include "s3c2442.h"
struct cpu_table { struct cpu_table {
unsigned long idcode; unsigned long idcode;
...@@ -61,6 +63,7 @@ struct cpu_table { ...@@ -61,6 +63,7 @@ struct cpu_table {
static const char name_s3c2400[] = "S3C2400"; static const char name_s3c2400[] = "S3C2400";
static const char name_s3c2410[] = "S3C2410"; static const char name_s3c2410[] = "S3C2410";
static const char name_s3c2440[] = "S3C2440"; static const char name_s3c2440[] = "S3C2440";
static const char name_s3c2442[] = "S3C2442";
static const char name_s3c2410a[] = "S3C2410A"; static const char name_s3c2410a[] = "S3C2410A";
static const char name_s3c2440a[] = "S3C2440A"; static const char name_s3c2440a[] = "S3C2440A";
...@@ -86,21 +89,30 @@ static struct cpu_table cpu_ids[] __initdata = { ...@@ -86,21 +89,30 @@ static struct cpu_table cpu_ids[] __initdata = {
{ {
.idcode = 0x32440000, .idcode = 0x32440000,
.idmask = 0xffffffff, .idmask = 0xffffffff,
.map_io = s3c2440_map_io, .map_io = s3c244x_map_io,
.init_clocks = s3c2440_init_clocks, .init_clocks = s3c244x_init_clocks,
.init_uarts = s3c2440_init_uarts, .init_uarts = s3c244x_init_uarts,
.init = s3c2440_init, .init = s3c2440_init,
.name = name_s3c2440 .name = name_s3c2440
}, },
{ {
.idcode = 0x32440001, .idcode = 0x32440001,
.idmask = 0xffffffff, .idmask = 0xffffffff,
.map_io = s3c2440_map_io, .map_io = s3c244x_map_io,
.init_clocks = s3c2440_init_clocks, .init_clocks = s3c244x_init_clocks,
.init_uarts = s3c2440_init_uarts, .init_uarts = s3c244x_init_uarts,
.init = s3c2440_init, .init = s3c2440_init,
.name = name_s3c2440a .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 */ .idcode = 0x0, /* S3C2400 doesn't have an idcode */
.idmask = 0xffffffff, .idmask = 0xffffffff,
......
...@@ -74,3 +74,4 @@ extern struct sys_timer s3c24xx_timer; ...@@ -74,3 +74,4 @@ extern struct sys_timer s3c24xx_timer;
/* system device classes */ /* system device classes */
extern struct sysdev_class s3c2440_sysclass; extern struct sysdev_class s3c2440_sysclass;
extern struct sysdev_class s3c2442_sysclass;
...@@ -100,73 +100,12 @@ static struct irqchip s3c_irq_wdtac97 = { ...@@ -100,73 +100,12 @@ static struct irqchip s3c_irq_wdtac97 = {
.ack = s3c_irq_wdtac97_ack, .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) static int s3c2440_irq_add(struct sys_device *sysdev)
{ {
unsigned int irqno; unsigned int irqno;
printk("S3C2440: IRQ Support\n"); 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 */ /* add new chained handler for wdt, ac7 */
set_irq_chip(IRQ_WDT, &s3c_irq_level_chip); set_irq_chip(IRQ_WDT, &s3c_irq_level_chip);
...@@ -179,18 +118,6 @@ static int s3c2440_irq_add(struct sys_device *sysdev) ...@@ -179,18 +118,6 @@ static int s3c2440_irq_add(struct sys_device *sysdev)
set_irq_flags(irqno, IRQF_VALID); 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; return 0;
} }
...@@ -198,10 +125,10 @@ static struct sysdev_driver s3c2440_irq_driver = { ...@@ -198,10 +125,10 @@ static struct sysdev_driver s3c2440_irq_driver = {
.add = s3c2440_irq_add, .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); return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_irq_driver);
} }
arch_initcall(s3c24xx_irq_driver); arch_initcall(s3c2440_irq_init);
/* linux/arch/arm/mach-s3c2410/s3c2440.c /* 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> * Ben Dooks <ben@simtec.co.uk>
* *
* Samsung S3C2440 Mobile CPU support * Samsung S3C2440 Mobile CPU support
...@@ -8,16 +8,6 @@ ...@@ -8,16 +8,6 @@
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * 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 <linux/kernel.h>
...@@ -50,144 +40,20 @@ ...@@ -50,144 +40,20 @@
#include "cpu.h" #include "cpu.h"
#include "pm.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 = { static struct sys_device s3c2440_sysdev = {
.cls = &s3c2440_sysclass, .cls = &s3c2440_sysclass,
}; };
void __init s3c2440_map_io(struct map_desc *mach_desc, int size) int __init s3c2440_init(void)
{ {
/* register our io-tables */ printk("S3C2440: Initialising architecture\n");
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";
/* change irq for watchdog */ /* change irq for watchdog */
s3c_device_wdt.resource[1].start = IRQ_S3C2440_WDT; s3c_device_wdt.resource[1].start = IRQ_S3C2440_WDT;
s3c_device_wdt.resource[1].end = IRQ_S3C2440_WDT; s3c_device_wdt.resource[1].end = IRQ_S3C2440_WDT;
}
void __init s3c2440_init_clocks(int xtal) /* register our system device for everything else */
{
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");
return sysdev_register(&s3c2440_sysdev); return sysdev_register(&s3c2440_sysdev);
} }
/* 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);
/* 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);
}
/* 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
/* 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);
/* 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);
/* 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
...@@ -1365,7 +1365,7 @@ static inline void s3c2410_serial_exit(void) ...@@ -1365,7 +1365,7 @@ static inline void s3c2410_serial_exit(void)
#endif /* CONFIG_CPU_S3C2410 */ #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, static int s3c2440_serial_setsource(struct uart_port *port,
struct s3c24xx_uart_clksrc *clk) struct s3c24xx_uart_clksrc *clk)
......
...@@ -114,7 +114,7 @@ s3c2410_get_pll(unsigned int pllval, unsigned int baseclk) ...@@ -114,7 +114,7 @@ s3c2410_get_pll(unsigned int pllval, unsigned int baseclk)
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */
#ifdef CONFIG_CPU_S3C2440 #if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442)
/* extra registers */ /* extra registers */
#define S3C2440_CAMDIVN S3C2410_CLKREG(0x18) #define S3C2440_CAMDIVN S3C2410_CLKREG(0x18)
...@@ -136,7 +136,9 @@ s3c2410_get_pll(unsigned int pllval, unsigned int baseclk) ...@@ -136,7 +136,9 @@ s3c2410_get_pll(unsigned int pllval, unsigned int baseclk)
#define S3C2440_CAMDIVN_HCLK4_HALF (1<<9) #define S3C2440_CAMDIVN_HCLK4_HALF (1<<9)
#define S3C2440_CAMDIVN_DVSEN (1<<12) #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 */ #endif /* __ASM_ARM_REGS_CLOCK */
...@@ -450,12 +450,14 @@ ...@@ -450,12 +450,14 @@
#define S3C2410_GPD0_OUTP (0x01 << 0) #define S3C2410_GPD0_OUTP (0x01 << 0)
#define S3C2410_GPD0_VD8 (0x02 << 0) #define S3C2410_GPD0_VD8 (0x02 << 0)
#define S3C2400_GPD0_VFRAME (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 S3C2410_GPIONO(S3C2410_GPIO_BANKD, 1)
#define S3C2410_GPD1_INP (0x00 << 2) #define S3C2410_GPD1_INP (0x00 << 2)
#define S3C2410_GPD1_OUTP (0x01 << 2) #define S3C2410_GPD1_OUTP (0x01 << 2)
#define S3C2410_GPD1_VD9 (0x02 << 2) #define S3C2410_GPD1_VD9 (0x02 << 2)
#define S3C2400_GPD1_VM (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 S3C2410_GPIONO(S3C2410_GPIO_BANKD, 2)
#define S3C2410_GPD2_INP (0x00 << 4) #define S3C2410_GPD2_INP (0x00 << 4)
...@@ -858,6 +860,7 @@ ...@@ -858,6 +860,7 @@
#define S3C2410_GPG12_OUTP (0x01 << 24) #define S3C2410_GPG12_OUTP (0x01 << 24)
#define S3C2410_GPG12_EINT20 (0x02 << 24) #define S3C2410_GPG12_EINT20 (0x02 << 24)
#define S3C2410_GPG12_XMON (0x03 << 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 S3C2410_GPIONO(S3C2410_GPIO_BANKG, 13)
#define S3C2410_GPG13_INP (0x00 << 26) #define S3C2410_GPG13_INP (0x00 << 26)
...@@ -943,6 +946,7 @@ ...@@ -943,6 +946,7 @@
#define S3C2410_GPH9_INP (0x00 << 18) #define S3C2410_GPH9_INP (0x00 << 18)
#define S3C2410_GPH9_OUTP (0x01 << 18) #define S3C2410_GPH9_OUTP (0x01 << 18)
#define S3C2410_GPH9_CLKOUT0 (0x02 << 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 S3C2410_GPIONO(S3C2410_GPIO_BANKH, 10)
#define S3C2410_GPH10_INP (0x00 << 20) #define S3C2410_GPH10_INP (0x00 << 20)
...@@ -1051,6 +1055,7 @@ ...@@ -1051,6 +1055,7 @@
#define S3C2410_GSTATUS1_IDMASK (0xffff0000) #define S3C2410_GSTATUS1_IDMASK (0xffff0000)
#define S3C2410_GSTATUS1_2410 (0x32410000) #define S3C2410_GSTATUS1_2410 (0x32410000)
#define S3C2410_GSTATUS1_2440 (0x32440000) #define S3C2410_GSTATUS1_2440 (0x32440000)
#define S3C2410_GSTATUS1_2442 (0x32440aaa)
#define S3C2410_GSTATUS2_WTRESET (1<<2) #define S3C2410_GSTATUS2_WTRESET (1<<2)
#define S3C2410_GSTATUS2_OFFRESET (1<<1) #define S3C2410_GSTATUS2_OFFRESET (1<<1)
......
...@@ -82,7 +82,8 @@ static void putc(int ch) ...@@ -82,7 +82,8 @@ static void putc(int ch)
while (1) { while (1) {
level = uart_rd(S3C2410_UFSTAT); 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_TXMASK;
level >>= S3C2440_UFSTAT_TXSHIFT; level >>= S3C2440_UFSTAT_TXSHIFT;
} else { } else {
...@@ -130,7 +131,7 @@ static void arch_decomp_wdog_start(void) ...@@ -130,7 +131,7 @@ static void arch_decomp_wdog_start(void)
{ {
__raw_writel(WDOG_COUNT, S3C2410_WTDAT); __raw_writel(WDOG_COUNT, S3C2410_WTDAT);
__raw_writel(WDOG_COUNT, S3C2410_WTCNT); __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 #else
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment