[ARM] 4157/2: S3C24XX: move arch/arch/mach-s3c2410 into cpu components

The following patch and script moves the arch/arm/mach-s3c2410
directory into arch/arm/plat-s3c24xx for the generic core code
and inti arch/arm/mach-s3c{cpu} for the cpu/machine support files

Include directory include/asm-arm/plat-s3c24xx is added for the
core include files.

Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
Ben Dooks 2007-02-11 18:31:01 +01:00 committed by Russell King
parent d19494b187
commit a21765a70e
83 changed files with 4836 additions and 4742 deletions

View File

@ -363,7 +363,15 @@ source "arch/arm/mach-omap1/Kconfig"
source "arch/arm/mach-omap2/Kconfig" source "arch/arm/mach-omap2/Kconfig"
source "arch/arm/plat-s3c24xx/Kconfig"
if ARCH_S3C2410
source "arch/arm/mach-s3c2400/Kconfig"
source "arch/arm/mach-s3c2410/Kconfig" source "arch/arm/mach-s3c2410/Kconfig"
source "arch/arm/mach-s3c2412/Kconfig"
source "arch/arm/mach-s3c2440/Kconfig"
source "arch/arm/mach-s3c2442/Kconfig"
endif
source "arch/arm/mach-lh7a40x/Kconfig" source "arch/arm/mach-lh7a40x/Kconfig"

View File

@ -149,7 +149,7 @@ MACHINE := arch/arm/mach-$(machine-y)/
else else
MACHINE := MACHINE :=
endif endif
export TEXT_OFFSET GZFLAGS MMUEXT export TEXT_OFFSET GZFLAGS MMUEXT
# Do we have FASTFPE? # Do we have FASTFPE?
@ -161,6 +161,10 @@ endif
# If we have a machine-specific directory, then include it in the build. # If we have a machine-specific directory, then include it in the build.
core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/ core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
core-y += $(MACHINE) core-y += $(MACHINE)
core-$(CONFIG_ARCH_S3C2410) += arch/arm/mach-s3c2400/
core-$(CONFIG_ARCH_S3C2410) += arch/arm/mach-s3c2412/
core-$(CONFIG_ARCH_S3C2410) += arch/arm/mach-s3c2440/
core-$(CONFIG_ARCH_S3C2410) += arch/arm/mach-s3c2442/
core-$(CONFIG_FPE_NWFPE) += arch/arm/nwfpe/ core-$(CONFIG_FPE_NWFPE) += arch/arm/nwfpe/
core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ) core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ)
core-$(CONFIG_VFP) += arch/arm/vfp/ core-$(CONFIG_VFP) += arch/arm/vfp/
@ -168,6 +172,7 @@ core-$(CONFIG_VFP) += arch/arm/vfp/
# If we have a common platform directory, then include it in the build. # If we have a common platform directory, then include it in the build.
core-$(CONFIG_PLAT_IOP) += arch/arm/plat-iop/ core-$(CONFIG_PLAT_IOP) += arch/arm/plat-iop/
core-$(CONFIG_ARCH_OMAP) += arch/arm/plat-omap/ core-$(CONFIG_ARCH_OMAP) += arch/arm/plat-omap/
core-$(CONFIG_PLAT_S3C24XX) += arch/arm/plat-s3c24xx/
drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/ drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/
drivers-$(CONFIG_ARCH_CLPS7500) += drivers/acorn/char/ drivers-$(CONFIG_ARCH_CLPS7500) += drivers/acorn/char/

View File

@ -0,0 +1,13 @@
# arch/arm/mach-s3c2400/Kconfig
#
# Copyright 2007 Simtec Electronics
#
# Licensed under GPLv2
menu "S3C2400 Machines"
endmenu

View File

@ -0,0 +1,15 @@
# arch/arm/mach-s3c2400/Makefile
#
# Copyright 2007 Simtec Electronics
#
# Licensed under GPLv2
obj-y :=
obj-m :=
obj-n :=
obj- :=
obj-$(CONFIG_CPU_S3C2400) += gpio.o
# Machine support

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2410/s3c2400-gpio.c /* linux/arch/arm/mach-s3c2400/gpio.c
* *
* Copyright (c) 2006 Lucas Correia Villa Real <lucasvr@gobolinux.org> * Copyright (c) 2006 Lucas Correia Villa Real <lucasvr@gobolinux.org>
* *

View File

@ -1,179 +1,8 @@
if ARCH_S3C2410 # arch/arm/mach-s3c2410/Kconfig
#
menu "S3C24XX Implementations" # Copyright 2007 Simtec Electronics
#
config MACH_AML_M5900 # Licensed under GPLv2
bool "AML M5900 Series"
select CPU_S3C2410
select PM_SIMTEC if PM
help
Say Y here if you are using the American Microsystems M5900 Series
<http://www.amltd.com>
config MACH_ANUBIS
bool "Simtec Electronics ANUBIS"
select CPU_S3C2440
select PM_SIMTEC if PM
help
Say Y here if you are using the Simtec Electronics ANUBIS
development system
config MACH_OSIRIS
bool "Simtec IM2440D20 (OSIRIS) module"
select CPU_S3C2440
select PM_SIMTEC if PM
help
Say Y here if you are using the Simtec IM2440D20 module, also
known as the Osiris.
config ARCH_BAST
bool "Simtec Electronics BAST (EB2410ITX)"
select CPU_S3C2410
select PM_SIMTEC if PM
select ISA
help
Say Y here if you are using the Simtec Electronics EB2410ITX
development board (also known as BAST)
Product page: <http://www.simtec.co.uk/products/EB2410ITX/>.
config BAST_PC104_IRQ
bool "BAST PC104 IRQ support"
depends on ARCH_BAST
default y
help
Say Y here to enable the PC104 IRQ routing on the
Simtec BAST (EB2410ITX)
config PM_H1940
bool
help
Internal node for H1940 and related PM
config ARCH_H1940
bool "IPAQ H1940"
select CPU_S3C2410
select PM_H1940 if PM
help
Say Y here if you are using the HP IPAQ H1940
<http://www.handhelds.org/projects/h1940.html>.
config MACH_N30
bool "Acer N30"
select CPU_S3C2410
help
Say Y here if you are using the Acer N30
<http://zoo.weinigel.se/n30>.
config MACH_SMDK
bool
help
Common machine code for SMDK2410 and SMDK2440
config ARCH_SMDK2410
bool "SMDK2410/A9M2410"
select CPU_S3C2410
select MACH_SMDK
help
Say Y here if you are using the SMDK2410 or the derived module A9M2410
<http://www.fsforth.de>
config ARCH_S3C2440
bool "SMDK2440"
select CPU_S3C2440
select MACH_SMDK
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_S3C2413
bool
help
Internal node for S3C2413 version of SMDK2413, so that
machine_is_s3c2413() will work when MACH_SMDK2413 is
selected
config MACH_SMDK2413
bool "SMDK2413"
select CPU_S3C2412
select MACH_S3C2413
select MACH_SMDK
help
Say Y here if you are using an SMDK2413
config MACH_VR1000
bool "Thorcom VR1000"
select PM_SIMTEC if PM
select CPU_S3C2410
help
Say Y here if you are using the Thorcom VR1000 board.
This linux port is currently being maintained by Simtec, on behalf
of Thorcom. Any queries, please contact Thorcom first.
config MACH_RX3715
bool "HP iPAQ rx3715"
select CPU_S3C2440
select PM_H1940 if PM
help
Say Y here if you are using the HP iPAQ rx3715.
See <http://www.handhelds.org/projects/rx3715.html> for more
information on this project
config MACH_OTOM
bool "NexVision OTOM Board"
select CPU_S3C2410
help
Say Y here if you are using the Nex Vision OTOM board
config MACH_NEXCODER_2440
bool "NexVision NEXCODER 2440 Light Board"
select CPU_S3C2440
help
Say Y here if you are using the Nex Vision NEXCODER 2440 Light Board
config MACH_VSTMS
bool "VMSTMS"
select CPU_S3C2412
help
Say Y here if you are using an VSTMS board
endmenu
config S3C2410_CLOCK
bool
help
Clock code for the S3C2410, and similar processors
config S3C2410_GPIO
bool
help
GPIO code for S3C2410 and similar processors
config S3C2410_PM
bool
help
Power Management code common to S3C2410 and better
config CPU_S3C2410_DMA
bool
depends on S3C2410_DMA && (CPU_S3C2410 || CPU_S3C2442)
default y if CPU_S3C2410 || CPU_S3C2442
help
DMA device selection for S3C2410 and compatible CPUs
config CPU_S3C2410 config CPU_S3C2410
bool bool
@ -185,158 +14,95 @@ 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.
# internal node to signify if we are only dealing with an S3C2412 config CPU_S3C2410_DMA
config CPU_S3C2412_ONLY
bool bool
depends on ARCH_S3C2410 && !CPU_S3C2400 && !CPU_S3C2410 && \ depends on S3C2410_DMA && (CPU_S3C2410 || CPU_S3C2442)
!CPU_S3C2440 && !CPU_S3C2442 && CPU_S3C2412 default y if CPU_S3C2410 || CPU_S3C2442
default y if CPU_S3C2412 help
DMA device selection for S3C2410 and compatible CPUs
config S3C2412_PM config S3C2410_PM
bool bool
help help
Internal config node to apply S3C2412 power management Power Management code common to S3C2410 and better
config S3C2412_DMA config S3C2410_GPIO
bool
depends on CPU_S3C2412
help
Internal config node for S3C2412 DMA support
config CPU_S3C2412
bool
depends on ARCH_S3C2410
select S3C2412_PM if PM
select S3C2412_DMA if S3C2410_DMA
help
Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line
config CPU_S3C244X
bool
depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442)
help
Support for S3C2440 and S3C2442 Samsung Mobile CPU based systems.
config S3C2440_DMA
bool
depends on ARCH_S3C2410 && CPU_S3C24405B
help
Support for S3C2440 specific DMA code5A
config CPU_S3C2440
bool
depends on ARCH_S3C2410
select S3C2410_CLOCK
select S3C2410_PM if PM
select S3C2410_GPIO
select S3C2440_DMA if S3C2410_DMA
select CPU_S3C244X
help
Support for S3C2440 Samsung Mobile CPU based systems.
config CPU_S3C2442
bool
depends on ARCH_S3C2420
select S3C2410_CLOCK
select S3C2410_GPIO
select S3C2410_PM if PM
select CPU_S3C244X
help
Support for S3C2442 Samsung Mobile CPU based systems.
comment "S3C2410 Boot"
config S3C2410_BOOT_WATCHDOG
bool "S3C2410 Initialisation watchdog"
depends on ARCH_S3C2410 && S3C2410_WATCHDOG
help
Say y to enable the watchdog during the kernel decompression
stage. If the kernel fails to uncompress, then the watchdog
will trigger a reset and the system should restart.
Although this uses the same hardware unit as the kernel watchdog
driver, it is not a replacement for it. If you use this option,
you will have to use the watchdg driver to either stop the timeout
or restart it. If you do not, then your kernel will reboot after
startup.
The driver uses a fixed timeout value, so the exact time till the
system resets depends on the value of PCLK. The timeout on an
200MHz s3c2410 should be about 30 seconds.
config S3C2410_BOOT_ERROR_RESET
bool "S3C2410 Reboot on decompression error"
depends on ARCH_S3C2410
help
Say y here to use the watchdog to reset the system if the
kernel decompressor detects an error during decompression.
comment "S3C2410 Setup"
config S3C2410_DMA
bool "S3C2410 DMA support"
depends on ARCH_S3C2410
help
S3C2410 DMA support. This is needed for drivers like sound which
use the S3C2410's DMA system to move data to and from the
peripheral blocks.
config S3C2410_DMA_DEBUG
bool "S3C2410 DMA support debug"
depends on ARCH_S3C2410 && S3C2410_DMA
help
Enable debugging output for the DMA code. This option sends info
to the kernel log, at priority KERN_DEBUG.
Note, it is easy to create and fill the log buffer in a small
amount of time, as well as using an significant percentage of
the CPU time doing so.
config S3C2410_PM_DEBUG
bool "S3C2410 PM Suspend debug"
depends on ARCH_S3C2410 && PM
help
Say Y here if you want verbose debugging from the PM Suspend and
Resume code. See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt>
for more information.
config S3C2410_PM_CHECK
bool "S3C2410 PM Suspend Memory CRC"
depends on ARCH_S3C2410 && PM && CRC32
help
Enable the PM code's memory area checksum over sleep. This option
will generate CRCs of all blocks of memory, and store them before
going to sleep. The blocks are then checked on resume for any
errors.
config S3C2410_PM_CHECK_CHUNKSIZE
int "S3C2410 PM Suspend CRC Chunksize (KiB)"
depends on ARCH_S3C2410 && PM && S3C2410_PM_CHECK
default 64
help
Set the chunksize in Kilobytes of the CRC for checking memory
corruption over suspend and resume. A smaller value will mean that
the CRC data block will take more memory, but wil identify any
faults with better precision.
config PM_SIMTEC
bool bool
help help
Common power management code for systems that are GPIO code for S3C2410 and similar processors
compatible with the Simtec style of power management
config S3C2410_LOWLEVEL_UART_PORT config S3C2410_CLOCK
int "S3C2410 UART to use for low-level messages" bool
default 0
help help
Choice of which UART port to use for the low-level messages, Clock code for the S3C2410, and similar processors
such as the `Uncompressing...` at start time. The value of
this configuration should be between zero and two. The port
must have been initialised by the boot-loader before use.
Note, this does not affect the port used by the debug messages,
which is a separate configuration.
endif menu "S3C2410 Machines"
config ARCH_SMDK2410
bool "SMDK2410/A9M2410"
select CPU_S3C2410
select MACH_SMDK
help
Say Y here if you are using the SMDK2410 or the derived module A9M2410
<http://www.fsforth.de>
config ARCH_H1940
bool "IPAQ H1940"
select CPU_S3C2410
select PM_H1940 if PM
help
Say Y here if you are using the HP IPAQ H1940
config PM_H1940
bool
help
Internal node for H1940 and related PM
config MACH_N30
bool "Acer N30"
select CPU_S3C2410
help
Say Y here if you are using the Acer N30
config ARCH_BAST
bool "Simtec Electronics BAST (EB2410ITX)"
select CPU_S3C2410
select PM_SIMTEC if PM
select ISA
help
Say Y here if you are using the Simtec Electronics EB2410ITX
development board (also known as BAST)
config MACH_OTOM
bool "NexVision OTOM Board"
select CPU_S3C2410
help
Say Y here if you are using the Nex Vision OTOM board
config MACH_AML_M5900
bool "AML M5900 Series"
select CPU_S3C2410
select PM_SIMTEC if PM
help
Say Y here if you are using the American Microsystems M5900 Series
<http://www.amltd.com>
config BAST_PC104_IRQ
bool "BAST PC104 IRQ support"
depends on ARCH_BAST
default y
help
Say Y here to enable the PC104 IRQ routing on the
Simtec BAST (EB2410ITX)
config MACH_VR1000
bool "Thorcom VR1000"
select PM_SIMTEC if PM
select CPU_S3C2410
help
Say Y here if you are using the Thorcom VR1000 board.
endmenu

View File

@ -1,85 +1,30 @@
# arch/arm/mach-s3c2410/Makefile
# #
# Makefile for the linux kernel. # Copyright 2007 Simtec Electronics
# #
# Licensed under GPLv2
# Object file lists. obj-y :=
obj-m :=
obj-y := cpu.o irq.o time.o gpio.o clock.o devs.o obj-n :=
obj-m := obj- :=
obj-n :=
obj- :=
# DMA
obj-$(CONFIG_S3C2410_DMA) += dma.o
# S3C2400 support files
obj-$(CONFIG_CPU_S3C2400) += s3c2400-gpio.o
# S3C2410 support files
obj-$(CONFIG_CPU_S3C2410) += s3c2410.o obj-$(CONFIG_CPU_S3C2410) += s3c2410.o
obj-$(CONFIG_CPU_S3C2410) += s3c2410-irq.o obj-$(CONFIG_CPU_S3C2410) += irq.o
obj-$(CONFIG_CPU_S3C2410_DMA) += dma.o
obj-$(CONFIG_CPU_S3C2410_DMA) += dma.o
obj-$(CONFIG_S3C2410_PM) += pm.o sleep.o
obj-$(CONFIG_S3C2410_GPIO) += gpio.o
obj-$(CONFIG_S3C2410_CLOCK) += clock.o
obj-$(CONFIG_S3C2410_PM) += s3c2410-pm.o s3c2410-sleep.o # Machine support
obj-$(CONFIG_S3C2410_GPIO) += s3c2410-gpio.o
obj-$(CONFIG_CPU_S3C2410_DMA) += s3c2410-dma.o
# Power Management support
obj-$(CONFIG_PM) += pm.o sleep.o
obj-$(CONFIG_PM_SIMTEC) += pm-simtec.o
obj-$(CONFIG_PM_H1940) += pm-h1940.o
# S3C2412 support
obj-$(CONFIG_CPU_S3C2412) += s3c2412.o
obj-$(CONFIG_CPU_S3C2412) += s3c2412-irq.o
obj-$(CONFIG_CPU_S3C2412) += s3c2412-clock.o
obj-$(CONFIG_S3C2412_PM) += s3c2412-pm.o
obj-$(CONFIG_S3C2412_DMA) += s3c2412-dma.o
#
# S3C244X support
obj-$(CONFIG_CPU_S3C244X) += s3c244x.o
obj-$(CONFIG_CPU_S3C244X) += s3c244x-irq.o
# Clock control
obj-$(CONFIG_S3C2410_CLOCK) += s3c2410-clock.o
# S3C2440 support
obj-$(CONFIG_CPU_S3C2440) += s3c2440.o s3c2440-dsc.o
obj-$(CONFIG_CPU_S3C2440) += s3c2440-irq.o
obj-$(CONFIG_CPU_S3C2440) += s3c2440-clock.o
obj-$(CONFIG_S3C2440_DMA) += s3c2440-dma.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
# machine specific support
obj-$(CONFIG_MACH_AML_M5900) += mach-amlm5900.o
obj-$(CONFIG_MACH_ANUBIS) += mach-anubis.o
obj-$(CONFIG_MACH_OSIRIS) += mach-osiris.o
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_ARCH_SMDK2410) += mach-smdk2410.o
obj-$(CONFIG_MACH_SMDK2413) += mach-smdk2413.o obj-$(CONFIG_ARCH_H1940) += mach-h1940.o
obj-$(CONFIG_ARCH_S3C2440) += mach-smdk2440.o obj-$(CONFIG_PM_H1940) += pm-h1940.o
obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o usb-simtec.o obj-$(CONFIG_MACH_N30) += mach-n30.o
obj-$(CONFIG_MACH_RX3715) += mach-rx3715.o obj-$(CONFIG_ARCH_BAST) += mach-bast.o usb-simtec.o
obj-$(CONFIG_MACH_OTOM) += mach-otom.o obj-$(CONFIG_MACH_OTOM) += mach-otom.o
obj-$(CONFIG_MACH_NEXCODER_2440) += mach-nexcoder.o obj-$(CONFIG_MACH_AML_M5900) += mach-amlm5900.o
obj-$(CONFIG_MACH_VSTMS) += mach-vstms.o obj-$(CONFIG_BAST_PC104_IRQ) += bast-irq.o
obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o usb-simtec.o
obj-$(CONFIG_MACH_SMDK) += common-smdk.o

View File

@ -39,7 +39,7 @@
#include <asm/arch/bast-map.h> #include <asm/arch/bast-map.h>
#include <asm/arch/bast-irq.h> #include <asm/arch/bast-irq.h>
#include "irq.h" #include <asm/plat-s3c24xx/irq.h>
#if 0 #if 0
#include <asm/debug-ll.h> #include <asm/debug-ll.h>

View File

@ -1,2 +1,2 @@
/* linux/arch/arm/mach-s3c2410/bast.h
extern void bast_init_irq(void); extern void bast_init_irq(void);

View File

@ -1,15 +1,9 @@
/* linux/arch/arm/mach-s3c2410/clock.c /* linux/arch/arm/mach-s3c2410/clock.c
* *
* Copyright (c) 2004-2005 Simtec Electronics * Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>
* *
* S3C24XX Core clock control support * S3C2410,S3C2440,S3C2442 Clock control support
*
* Based on, and code from linux/arch/arm/mach-versatile/clock.c
**
** Copyright (C) 2004 ARM Limited.
** Written by Deep Blue Solutions Limited.
*
* *
* 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 as published by * it under the terms of the GNU General Public License as published by
@ -32,418 +26,251 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/sysdev.h> #include <linux/sysdev.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/serial_core.h>
#include <asm/mach/map.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/arch/regs-serial.h>
#include <asm/arch/regs-clock.h> #include <asm/arch/regs-clock.h>
#include <asm/arch/regs-gpio.h> #include <asm/arch/regs-gpio.h>
#include "clock.h" #include <asm/plat-s3c24xx/s3c2410.h>
#include "cpu.h" #include <asm/plat-s3c24xx/clock.h>
#include <asm/plat-s3c24xx/cpu.h>
/* clock information */ int s3c2410_clkcon_enable(struct clk *clk, int enable)
static LIST_HEAD(clocks);
DEFINE_MUTEX(clocks_mutex);
/* enable and disable calls for use with the clk struct */
static int clk_null_enable(struct clk *clk, int enable)
{ {
return 0; unsigned int clocks = clk->ctrlbit;
} unsigned long clkcon;
/* Clock API calls */ clkcon = __raw_readl(S3C2410_CLKCON);
struct clk *clk_get(struct device *dev, const char *id)
{
struct clk *p;
struct clk *clk = ERR_PTR(-ENOENT);
int idno;
if (dev == NULL || dev->bus != &platform_bus_type)
idno = -1;
else
idno = to_platform_device(dev)->id;
mutex_lock(&clocks_mutex);
list_for_each_entry(p, &clocks, list) {
if (p->id == idno &&
strcmp(id, p->name) == 0 &&
try_module_get(p->owner)) {
clk = p;
break;
}
}
/* check for the case where a device was supplied, but the
* clock that was being searched for is not device specific */
if (IS_ERR(clk)) {
list_for_each_entry(p, &clocks, list) {
if (p->id == -1 && strcmp(id, p->name) == 0 &&
try_module_get(p->owner)) {
clk = p;
break;
}
}
}
mutex_unlock(&clocks_mutex);
return clk;
}
void clk_put(struct clk *clk)
{
module_put(clk->owner);
}
int clk_enable(struct clk *clk)
{
if (IS_ERR(clk) || clk == NULL)
return -EINVAL;
clk_enable(clk->parent);
mutex_lock(&clocks_mutex);
if ((clk->usage++) == 0)
(clk->enable)(clk, 1);
mutex_unlock(&clocks_mutex);
return 0;
}
void clk_disable(struct clk *clk)
{
if (IS_ERR(clk) || clk == NULL)
return;
mutex_lock(&clocks_mutex);
if ((--clk->usage) == 0)
(clk->enable)(clk, 0);
mutex_unlock(&clocks_mutex);
clk_disable(clk->parent);
}
unsigned long clk_get_rate(struct clk *clk)
{
if (IS_ERR(clk))
return 0;
if (clk->rate != 0)
return clk->rate;
if (clk->get_rate != NULL)
return (clk->get_rate)(clk);
if (clk->parent != NULL)
return clk_get_rate(clk->parent);
return clk->rate;
}
long clk_round_rate(struct clk *clk, unsigned long rate)
{
if (!IS_ERR(clk) && clk->round_rate)
return (clk->round_rate)(clk, rate);
return rate;
}
int clk_set_rate(struct clk *clk, unsigned long rate)
{
int ret;
if (IS_ERR(clk))
return -EINVAL;
mutex_lock(&clocks_mutex);
ret = (clk->set_rate)(clk, rate);
mutex_unlock(&clocks_mutex);
return ret;
}
struct clk *clk_get_parent(struct clk *clk)
{
return clk->parent;
}
int clk_set_parent(struct clk *clk, struct clk *parent)
{
int ret = 0;
if (IS_ERR(clk))
return -EINVAL;
mutex_lock(&clocks_mutex);
if (clk->set_parent)
ret = (clk->set_parent)(clk, parent);
mutex_unlock(&clocks_mutex);
return ret;
}
EXPORT_SYMBOL(clk_get);
EXPORT_SYMBOL(clk_put);
EXPORT_SYMBOL(clk_enable);
EXPORT_SYMBOL(clk_disable);
EXPORT_SYMBOL(clk_get_rate);
EXPORT_SYMBOL(clk_round_rate);
EXPORT_SYMBOL(clk_set_rate);
EXPORT_SYMBOL(clk_get_parent);
EXPORT_SYMBOL(clk_set_parent);
/* base clocks */
struct clk clk_xtal = {
.name = "xtal",
.id = -1,
.rate = 0,
.parent = NULL,
.ctrlbit = 0,
};
struct clk clk_mpll = {
.name = "mpll",
.id = -1,
};
struct clk clk_upll = {
.name = "upll",
.id = -1,
.parent = NULL,
.ctrlbit = 0,
};
struct clk clk_f = {
.name = "fclk",
.id = -1,
.rate = 0,
.parent = &clk_mpll,
.ctrlbit = 0,
};
struct clk clk_h = {
.name = "hclk",
.id = -1,
.rate = 0,
.parent = NULL,
.ctrlbit = 0,
};
struct clk clk_p = {
.name = "pclk",
.id = -1,
.rate = 0,
.parent = NULL,
.ctrlbit = 0,
};
struct clk clk_usb_bus = {
.name = "usb-bus",
.id = -1,
.rate = 0,
.parent = &clk_upll,
};
/* clocks that could be registered by external code */
static int s3c24xx_dclk_enable(struct clk *clk, int enable)
{
unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON);
if (enable) if (enable)
dclkcon |= clk->ctrlbit; clkcon |= clocks;
else else
dclkcon &= ~clk->ctrlbit; clkcon &= ~clocks;
__raw_writel(dclkcon, S3C24XX_DCLKCON); /* ensure none of the special function bits set */
clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER);
__raw_writel(clkcon, S3C2410_CLKCON);
return 0; return 0;
} }
static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent) static int s3c2410_upll_enable(struct clk *clk, int enable)
{ {
unsigned long dclkcon; unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
unsigned int uclk; unsigned long orig = clkslow;
if (parent == &clk_upll) if (enable)
uclk = 1; clkslow &= ~S3C2410_CLKSLOW_UCLK_OFF;
else if (parent == &clk_p)
uclk = 0;
else else
return -EINVAL; clkslow |= S3C2410_CLKSLOW_UCLK_OFF;
clk->parent = parent; __raw_writel(clkslow, S3C2410_CLKSLOW);
dclkcon = __raw_readl(S3C24XX_DCLKCON); /* if we started the UPLL, then allow to settle */
if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) { if (enable && (orig & S3C2410_CLKSLOW_UCLK_OFF))
if (uclk) udelay(200);
dclkcon |= S3C2410_DCLKCON_DCLK0_UCLK;
else return 0;
dclkcon &= ~S3C2410_DCLKCON_DCLK0_UCLK; }
} else {
if (uclk) /* standard clock definitions */
dclkcon |= S3C2410_DCLKCON_DCLK1_UCLK;
else static struct clk init_clocks_disable[] = {
dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK; {
.name = "nand",
.id = -1,
.parent = &clk_h,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_NAND,
}, {
.name = "sdi",
.id = -1,
.parent = &clk_p,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_SDI,
}, {
.name = "adc",
.id = -1,
.parent = &clk_p,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_ADC,
}, {
.name = "i2c",
.id = -1,
.parent = &clk_p,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_IIC,
}, {
.name = "iis",
.id = -1,
.parent = &clk_p,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_IIS,
}, {
.name = "spi",
.id = -1,
.parent = &clk_p,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_SPI,
}
};
static struct clk init_clocks[] = {
{
.name = "lcd",
.id = -1,
.parent = &clk_h,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_LCDC,
}, {
.name = "gpio",
.id = -1,
.parent = &clk_p,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_GPIO,
}, {
.name = "usb-host",
.id = -1,
.parent = &clk_h,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_USBH,
}, {
.name = "usb-device",
.id = -1,
.parent = &clk_h,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_USBD,
}, {
.name = "timers",
.id = -1,
.parent = &clk_p,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_PWMT,
}, {
.name = "uart",
.id = 0,
.parent = &clk_p,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_UART0,
}, {
.name = "uart",
.id = 1,
.parent = &clk_p,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_UART1,
}, {
.name = "uart",
.id = 2,
.parent = &clk_p,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_UART2,
}, {
.name = "rtc",
.id = -1,
.parent = &clk_p,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_RTC,
}, {
.name = "watchdog",
.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()
*
* Add all the clocks used by the s3c2410 or compatible CPUs
* such as the S3C2440 and S3C2442.
*
* We cannot use a system device as we are needed before any
* of the init-calls that initialise the devices are actually
* done.
*/
int __init s3c2410_baseclk_add(void)
{
unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
unsigned long clkcon = __raw_readl(S3C2410_CLKCON);
struct clk *clkp;
struct clk *xtal;
int ret;
int ptr;
clk_upll.enable = s3c2410_upll_enable;
if (s3c24xx_register_clock(&clk_usb_bus) < 0)
printk(KERN_ERR "failed to register usb bus clock\n");
/* 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);
}
} }
__raw_writel(dclkcon, S3C24XX_DCLKCON); /* 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.
*/
return 0; /* 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++) {
static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent) ret = s3c24xx_register_clock(clkp);
{ if (ret < 0) {
unsigned long mask; printk(KERN_ERR "Failed to register clock %s (%d)\n",
unsigned long source; clkp->name, ret);
}
/* calculate the MISCCR setting for the clock */ s3c2410_clkcon_enable(clkp, 0);
if (parent == &clk_xtal)
source = S3C2410_MISCCR_CLK0_MPLL;
else if (parent == &clk_upll)
source = S3C2410_MISCCR_CLK0_UPLL;
else if (parent == &clk_f)
source = S3C2410_MISCCR_CLK0_FCLK;
else if (parent == &clk_h)
source = S3C2410_MISCCR_CLK0_HCLK;
else if (parent == &clk_p)
source = S3C2410_MISCCR_CLK0_PCLK;
else if (clk == &s3c24xx_clkout0 && parent == &s3c24xx_dclk0)
source = S3C2410_MISCCR_CLK0_DCLK0;
else if (clk == &s3c24xx_clkout1 && parent == &s3c24xx_dclk1)
source = S3C2410_MISCCR_CLK0_DCLK0;
else
return -EINVAL;
clk->parent = parent;
if (clk == &s3c24xx_dclk0)
mask = S3C2410_MISCCR_CLK0_MASK;
else {
source <<= 4;
mask = S3C2410_MISCCR_CLK1_MASK;
} }
s3c2410_modify_misccr(mask, source); /* show the clock-slow value */
return 0;
}
/* external clock definitions */ xtal = clk_get(NULL, "xtal");
struct clk s3c24xx_dclk0 = { printk("CLOCK: Slow mode (%ld.%ld MHz), %s, MPLL %s, UPLL %s\n",
.name = "dclk0", print_mhz(clk_get_rate(xtal) /
.id = -1, ( 2 * S3C2410_CLKSLOW_GET_SLOWVAL(clkslow))),
.ctrlbit = S3C2410_DCLKCON_DCLK0EN, (clkslow & S3C2410_CLKSLOW_SLOW) ? "slow" : "fast",
.enable = s3c24xx_dclk_enable, (clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on",
.set_parent = s3c24xx_dclk_setparent, (clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on");
};
struct clk s3c24xx_dclk1 = {
.name = "dclk1",
.id = -1,
.ctrlbit = S3C2410_DCLKCON_DCLK0EN,
.enable = s3c24xx_dclk_enable,
.set_parent = s3c24xx_dclk_setparent,
};
struct clk s3c24xx_clkout0 = {
.name = "clkout0",
.id = -1,
.set_parent = s3c24xx_clkout_setparent,
};
struct clk s3c24xx_clkout1 = {
.name = "clkout1",
.id = -1,
.set_parent = s3c24xx_clkout_setparent,
};
struct clk s3c24xx_uclk = {
.name = "uclk",
.id = -1,
};
/* initialise the clock system */
int s3c24xx_register_clock(struct clk *clk)
{
clk->owner = THIS_MODULE;
if (clk->enable == NULL)
clk->enable = clk_null_enable;
/* add to the list of available clocks */
mutex_lock(&clocks_mutex);
list_add(&clk->list, &clocks);
mutex_unlock(&clocks_mutex);
return 0;
}
/* initalise all the clocks */
int __init s3c24xx_setup_clocks(unsigned long xtal,
unsigned long fclk,
unsigned long hclk,
unsigned long pclk)
{
printk(KERN_INFO "S3C24XX Clocks, (c) 2004 Simtec Electronics\n");
/* initialise the main system clocks */
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;
/* assume uart clocks are correctly setup */
/* register our clocks */
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");
if (s3c24xx_register_clock(&clk_f) < 0)
printk(KERN_ERR "failed to register cpu fclk\n");
if (s3c24xx_register_clock(&clk_h) < 0)
printk(KERN_ERR "failed to register cpu hclk\n");
if (s3c24xx_register_clock(&clk_p) < 0)
printk(KERN_ERR "failed to register cpu pclk\n");
return 0; return 0;
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,9 @@
/* linux/arch/arm/mach-s3c2410/gpio.c /* linux/arch/arm/mach-s3c2410/gpio.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>
* *
* S3C24XX GPIO support * S3C2410 GPIO support
* *
* 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 as published by * it under the terms of the GNU General Public License as published by
@ -18,8 +18,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
@ -33,156 +32,40 @@
#include <asm/arch/regs-gpio.h> #include <asm/arch/regs-gpio.h>
void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function) int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
unsigned int config)
{ {
void __iomem *base = S3C24XX_GPIO_BASE(pin); void __iomem *reg = S3C24XX_EINFLT0;
unsigned long mask;
unsigned long con;
unsigned long flags; unsigned long flags;
unsigned long val;
if (pin < S3C2410_GPIO_BANKB) { if (pin < S3C2410_GPG8 || pin > S3C2410_GPG15)
mask = 1 << S3C2410_GPIO_OFFSET(pin); return -1;
} else {
mask = 3 << S3C2410_GPIO_OFFSET(pin)*2;
}
switch (function) { config &= 0xff;
case S3C2410_GPIO_LEAVE:
mask = 0;
function = 0;
break;
case S3C2410_GPIO_INPUT: pin -= S3C2410_GPG8;
case S3C2410_GPIO_OUTPUT: reg += pin & ~3;
case S3C2410_GPIO_SFN2:
case S3C2410_GPIO_SFN3:
if (pin < S3C2410_GPIO_BANKB) {
function -= 1;
function &= 1;
function <<= S3C2410_GPIO_OFFSET(pin);
} else {
function &= 3;
function <<= S3C2410_GPIO_OFFSET(pin)*2;
}
}
/* modify the specified register wwith IRQs off */
local_irq_save(flags); local_irq_save(flags);
con = __raw_readl(base + 0x00); /* update filter width and clock source */
con &= ~mask;
con |= function;
__raw_writel(con, base + 0x00); val = __raw_readl(reg);
val &= ~(0xff << ((pin & 3) * 8));
val |= config << ((pin & 3) * 8);
__raw_writel(val, reg);
/* update filter enable */
val = __raw_readl(S3C24XX_EXTINT2);
val &= ~(1 << ((pin * 4) + 3));
val |= on << ((pin * 4) + 3);
__raw_writel(val, S3C24XX_EXTINT2);
local_irq_restore(flags); local_irq_restore(flags);
return 0;
} }
EXPORT_SYMBOL(s3c2410_gpio_cfgpin); EXPORT_SYMBOL(s3c2410_gpio_irqfilter);
unsigned int s3c2410_gpio_getcfg(unsigned int pin)
{
void __iomem *base = S3C24XX_GPIO_BASE(pin);
unsigned long val = __raw_readl(base);
if (pin < S3C2410_GPIO_BANKB) {
val >>= S3C2410_GPIO_OFFSET(pin);
val &= 1;
val += 1;
} else {
val >>= S3C2410_GPIO_OFFSET(pin)*2;
val &= 3;
}
return val | S3C2410_GPIO_INPUT;
}
EXPORT_SYMBOL(s3c2410_gpio_getcfg);
void s3c2410_gpio_pullup(unsigned int pin, unsigned int to)
{
void __iomem *base = S3C24XX_GPIO_BASE(pin);
unsigned long offs = S3C2410_GPIO_OFFSET(pin);
unsigned long flags;
unsigned long up;
if (pin < S3C2410_GPIO_BANKB)
return;
local_irq_save(flags);
up = __raw_readl(base + 0x08);
up &= ~(1L << offs);
up |= to << offs;
__raw_writel(up, base + 0x08);
local_irq_restore(flags);
}
EXPORT_SYMBOL(s3c2410_gpio_pullup);
void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)
{
void __iomem *base = S3C24XX_GPIO_BASE(pin);
unsigned long offs = S3C2410_GPIO_OFFSET(pin);
unsigned long flags;
unsigned long dat;
local_irq_save(flags);
dat = __raw_readl(base + 0x04);
dat &= ~(1 << offs);
dat |= to << offs;
__raw_writel(dat, base + 0x04);
local_irq_restore(flags);
}
EXPORT_SYMBOL(s3c2410_gpio_setpin);
unsigned int s3c2410_gpio_getpin(unsigned int pin)
{
void __iomem *base = S3C24XX_GPIO_BASE(pin);
unsigned long offs = S3C2410_GPIO_OFFSET(pin);
return __raw_readl(base + 0x04) & (1<< offs);
}
EXPORT_SYMBOL(s3c2410_gpio_getpin);
unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change)
{
unsigned long flags;
unsigned long misccr;
local_irq_save(flags);
misccr = __raw_readl(S3C24XX_MISCCR);
misccr &= ~clear;
misccr ^= change;
__raw_writel(misccr, S3C24XX_MISCCR);
local_irq_restore(flags);
return misccr;
}
EXPORT_SYMBOL(s3c2410_modify_misccr);
int s3c2410_gpio_getirq(unsigned int pin)
{
if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15)
return -1; /* not valid interrupts */
if (pin < S3C2410_GPG0 && pin > S3C2410_GPF7)
return -1; /* not valid pin */
if (pin < S3C2410_GPF4)
return (pin - S3C2410_GPF0) + IRQ_EINT0;
if (pin < S3C2410_GPG0)
return (pin - S3C2410_GPF4) + IRQ_EINT4;
return (pin - S3C2410_GPG0) + IRQ_EINT8;
}
EXPORT_SYMBOL(s3c2410_gpio_getirq);

View File

@ -1,6 +1,6 @@
/* linux/arch/arm/mach-s3c2410/irq.c /* linux/arch/arm/mach-s3c2410/irq.c
* *
* Copyright (c) 2003,2004 Simtec Electronics * Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -17,37 +17,6 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* Changelog:
*
* 22-Jul-2004 Ben Dooks <ben@simtec.co.uk>
* Fixed compile warnings
*
* 22-Jul-2004 Roc Wu <cooloney@yahoo.com.cn>
* Fixed s3c_extirq_type
*
* 21-Jul-2004 Arnaud Patard (Rtp) <arnaud.patard@rtp-net.org>
* Addition of ADC/TC demux
*
* 04-Oct-2004 Klaus Fetscher <k.fetscher@fetron.de>
* Fix for set_irq_type() on low EINT numbers
*
* 05-Oct-2004 Ben Dooks <ben@simtec.co.uk>
* Tidy up KF's patch and sort out new release
*
* 05-Oct-2004 Ben Dooks <ben@simtec.co.uk>
* Add support for power management controls
*
* 04-Nov-2004 Ben Dooks
* Fix standard IRQ wake for EINT0..4 and RTC
*
* 22-Feb-2005 Ben Dooks
* Fixed edge-triggering on ADC IRQ
*
* 28-Jun-2005 Ben Dooks
* Mark IRQ_LCD valid
*
* 25-Jul-2005 Ben Dooks
* Split the S3C2440 IRQ code to seperate file
*/ */
#include <linux/init.h> #include <linux/init.h>
@ -57,745 +26,23 @@
#include <linux/ptrace.h> #include <linux/ptrace.h>
#include <linux/sysdev.h> #include <linux/sysdev.h>
#include <asm/hardware.h> #include <asm/plat-s3c24xx/cpu.h>
#include <asm/irq.h> #include <asm/plat-s3c24xx/pm.h>
#include <asm/io.h>
#include <asm/mach/irq.h> static int s3c2410_irq_add(struct sys_device *sysdev)
#include <asm/arch/regs-irq.h>
#include <asm/arch/regs-gpio.h>
#include "cpu.h"
#include "pm.h"
#include "irq.h"
/* wakeup irq control */
#ifdef CONFIG_PM
/* state for IRQs over sleep */
/* default is to allow for EINT0..EINT15, and IRQ_RTC as wakeup sources
*
* set bit to 1 in allow bitfield to enable the wakeup settings on it
*/
unsigned long s3c_irqwake_intallow = 1L << (IRQ_RTC - IRQ_EINT0) | 0xfL;
unsigned long s3c_irqwake_intmask = 0xffffffffL;
unsigned long s3c_irqwake_eintallow = 0x0000fff0L;
unsigned long s3c_irqwake_eintmask = 0xffffffffL;
int
s3c_irq_wake(unsigned int irqno, unsigned int state)
{ {
unsigned long irqbit = 1 << (irqno - IRQ_EINT0);
if (!(s3c_irqwake_intallow & irqbit))
return -ENOENT;
printk(KERN_INFO "wake %s for irq %d\n",
state ? "enabled" : "disabled", irqno);
if (!state)
s3c_irqwake_intmask |= irqbit;
else
s3c_irqwake_intmask &= ~irqbit;
return 0; return 0;
} }
static int static struct sysdev_driver s3c2410_irq_driver = {
s3c_irqext_wake(unsigned int irqno, unsigned int state) .add = s3c2410_irq_add,
{ .suspend = s3c24xx_irq_suspend,
unsigned long bit = 1L << (irqno - EXTINT_OFF); .resume = s3c24xx_irq_resume,
if (!(s3c_irqwake_eintallow & bit))
return -ENOENT;
printk(KERN_INFO "wake %s for irq %d\n",
state ? "enabled" : "disabled", irqno);
if (!state)
s3c_irqwake_eintmask |= bit;
else
s3c_irqwake_eintmask &= ~bit;
return 0;
}
#else
#define s3c_irqext_wake NULL
#define s3c_irq_wake NULL
#endif
static void
s3c_irq_mask(unsigned int irqno)
{
unsigned long mask;
irqno -= IRQ_EINT0;
mask = __raw_readl(S3C2410_INTMSK);
mask |= 1UL << irqno;
__raw_writel(mask, S3C2410_INTMSK);
}
static inline void
s3c_irq_ack(unsigned int irqno)
{
unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
__raw_writel(bitval, S3C2410_SRCPND);
__raw_writel(bitval, S3C2410_INTPND);
}
static inline void
s3c_irq_maskack(unsigned int irqno)
{
unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
unsigned long mask;
mask = __raw_readl(S3C2410_INTMSK);
__raw_writel(mask|bitval, S3C2410_INTMSK);
__raw_writel(bitval, S3C2410_SRCPND);
__raw_writel(bitval, S3C2410_INTPND);
}
static void
s3c_irq_unmask(unsigned int irqno)
{
unsigned long mask;
if (irqno != IRQ_TIMER4 && irqno != IRQ_EINT8t23)
irqdbf2("s3c_irq_unmask %d\n", irqno);
irqno -= IRQ_EINT0;
mask = __raw_readl(S3C2410_INTMSK);
mask &= ~(1UL << irqno);
__raw_writel(mask, S3C2410_INTMSK);
}
struct irq_chip s3c_irq_level_chip = {
.name = "s3c-level",
.ack = s3c_irq_maskack,
.mask = s3c_irq_mask,
.unmask = s3c_irq_unmask,
.set_wake = s3c_irq_wake
}; };
static struct irq_chip s3c_irq_chip = { static int s3c2410_irq_init(void)
.name = "s3c",
.ack = s3c_irq_ack,
.mask = s3c_irq_mask,
.unmask = s3c_irq_unmask,
.set_wake = s3c_irq_wake
};
static void
s3c_irqext_mask(unsigned int irqno)
{ {
unsigned long mask; return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_irq_driver);
irqno -= EXTINT_OFF;
mask = __raw_readl(S3C24XX_EINTMASK);
mask |= ( 1UL << irqno);
__raw_writel(mask, S3C24XX_EINTMASK);
} }
static void arch_initcall(s3c2410_irq_init);
s3c_irqext_ack(unsigned int irqno)
{
unsigned long req;
unsigned long bit;
unsigned long mask;
bit = 1UL << (irqno - EXTINT_OFF);
mask = __raw_readl(S3C24XX_EINTMASK);
__raw_writel(bit, S3C24XX_EINTPEND);
req = __raw_readl(S3C24XX_EINTPEND);
req &= ~mask;
/* not sure if we should be acking the parent irq... */
if (irqno <= IRQ_EINT7 ) {
if ((req & 0xf0) == 0)
s3c_irq_ack(IRQ_EINT4t7);
} else {
if ((req >> 8) == 0)
s3c_irq_ack(IRQ_EINT8t23);
}
}
static void
s3c_irqext_unmask(unsigned int irqno)
{
unsigned long mask;
irqno -= EXTINT_OFF;
mask = __raw_readl(S3C24XX_EINTMASK);
mask &= ~( 1UL << irqno);
__raw_writel(mask, S3C24XX_EINTMASK);
}
int
s3c_irqext_type(unsigned int irq, unsigned int type)
{
void __iomem *extint_reg;
void __iomem *gpcon_reg;
unsigned long gpcon_offset, extint_offset;
unsigned long newvalue = 0, value;
if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3))
{
gpcon_reg = S3C2410_GPFCON;
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 = 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 = 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 = S3C24XX_EXTINT2;
gpcon_offset = (irq - IRQ_EINT8) * 2;
extint_offset = (irq - IRQ_EINT16) * 4;
} else
return -1;
/* Set the GPIO to external interrupt mode */
value = __raw_readl(gpcon_reg);
value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset);
__raw_writel(value, gpcon_reg);
/* Set the external interrupt to pointed trigger type */
switch (type)
{
case IRQT_NOEDGE:
printk(KERN_WARNING "No edge setting!\n");
break;
case IRQT_RISING:
newvalue = S3C2410_EXTINT_RISEEDGE;
break;
case IRQT_FALLING:
newvalue = S3C2410_EXTINT_FALLEDGE;
break;
case IRQT_BOTHEDGE:
newvalue = S3C2410_EXTINT_BOTHEDGE;
break;
case IRQT_LOW:
newvalue = S3C2410_EXTINT_LOWLEV;
break;
case IRQT_HIGH:
newvalue = S3C2410_EXTINT_HILEV;
break;
default:
printk(KERN_ERR "No such irq type %d", type);
return -1;
}
value = __raw_readl(extint_reg);
value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset);
__raw_writel(value, extint_reg);
return 0;
}
static struct irq_chip s3c_irqext_chip = {
.name = "s3c-ext",
.mask = s3c_irqext_mask,
.unmask = s3c_irqext_unmask,
.ack = s3c_irqext_ack,
.set_type = s3c_irqext_type,
.set_wake = s3c_irqext_wake
};
static struct irq_chip s3c_irq_eint0t4 = {
.name = "s3c-ext0",
.ack = s3c_irq_ack,
.mask = s3c_irq_mask,
.unmask = s3c_irq_unmask,
.set_wake = s3c_irq_wake,
.set_type = s3c_irqext_type,
};
/* mask values for the parent registers for each of the interrupt types */
#define INTMSK_UART0 (1UL << (IRQ_UART0 - IRQ_EINT0))
#define INTMSK_UART1 (1UL << (IRQ_UART1 - IRQ_EINT0))
#define INTMSK_UART2 (1UL << (IRQ_UART2 - IRQ_EINT0))
#define INTMSK_ADCPARENT (1UL << (IRQ_ADCPARENT - IRQ_EINT0))
/* UART0 */
static void
s3c_irq_uart0_mask(unsigned int irqno)
{
s3c_irqsub_mask(irqno, INTMSK_UART0, 7);
}
static void
s3c_irq_uart0_unmask(unsigned int irqno)
{
s3c_irqsub_unmask(irqno, INTMSK_UART0);
}
static void
s3c_irq_uart0_ack(unsigned int irqno)
{
s3c_irqsub_maskack(irqno, INTMSK_UART0, 7);
}
static struct irq_chip s3c_irq_uart0 = {
.name = "s3c-uart0",
.mask = s3c_irq_uart0_mask,
.unmask = s3c_irq_uart0_unmask,
.ack = s3c_irq_uart0_ack,
};
/* UART1 */
static void
s3c_irq_uart1_mask(unsigned int irqno)
{
s3c_irqsub_mask(irqno, INTMSK_UART1, 7 << 3);
}
static void
s3c_irq_uart1_unmask(unsigned int irqno)
{
s3c_irqsub_unmask(irqno, INTMSK_UART1);
}
static void
s3c_irq_uart1_ack(unsigned int irqno)
{
s3c_irqsub_maskack(irqno, INTMSK_UART1, 7 << 3);
}
static struct irq_chip s3c_irq_uart1 = {
.name = "s3c-uart1",
.mask = s3c_irq_uart1_mask,
.unmask = s3c_irq_uart1_unmask,
.ack = s3c_irq_uart1_ack,
};
/* UART2 */
static void
s3c_irq_uart2_mask(unsigned int irqno)
{
s3c_irqsub_mask(irqno, INTMSK_UART2, 7 << 6);
}
static void
s3c_irq_uart2_unmask(unsigned int irqno)
{
s3c_irqsub_unmask(irqno, INTMSK_UART2);
}
static void
s3c_irq_uart2_ack(unsigned int irqno)
{
s3c_irqsub_maskack(irqno, INTMSK_UART2, 7 << 6);
}
static struct irq_chip s3c_irq_uart2 = {
.name = "s3c-uart2",
.mask = s3c_irq_uart2_mask,
.unmask = s3c_irq_uart2_unmask,
.ack = s3c_irq_uart2_ack,
};
/* ADC and Touchscreen */
static void
s3c_irq_adc_mask(unsigned int irqno)
{
s3c_irqsub_mask(irqno, INTMSK_ADCPARENT, 3 << 9);
}
static void
s3c_irq_adc_unmask(unsigned int irqno)
{
s3c_irqsub_unmask(irqno, INTMSK_ADCPARENT);
}
static void
s3c_irq_adc_ack(unsigned int irqno)
{
s3c_irqsub_ack(irqno, INTMSK_ADCPARENT, 3 << 9);
}
static struct irq_chip s3c_irq_adc = {
.name = "s3c-adc",
.mask = s3c_irq_adc_mask,
.unmask = s3c_irq_adc_unmask,
.ack = s3c_irq_adc_ack,
};
/* irq demux for adc */
static void s3c_irq_demux_adc(unsigned int irq,
struct irq_desc *desc)
{
unsigned int subsrc, submsk;
unsigned int offset = 9;
struct irq_desc *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 >>= offset;
subsrc &= 3;
if (subsrc != 0) {
if (subsrc & 1) {
mydesc = irq_desc + IRQ_TC;
desc_handle_irq(IRQ_TC, mydesc);
}
if (subsrc & 2) {
mydesc = irq_desc + IRQ_ADC;
desc_handle_irq(IRQ_ADC, mydesc);
}
}
}
static void s3c_irq_demux_uart(unsigned int start)
{
unsigned int subsrc, submsk;
unsigned int offset = start - IRQ_S3CUART_RX0;
struct irq_desc *desc;
/* read the current pending interrupts, and the mask
* for what it is available */
subsrc = __raw_readl(S3C2410_SUBSRCPND);
submsk = __raw_readl(S3C2410_INTSUBMSK);
irqdbf2("s3c_irq_demux_uart: start=%d (%d), subsrc=0x%08x,0x%08x\n",
start, offset, subsrc, submsk);
subsrc &= ~submsk;
subsrc >>= offset;
subsrc &= 7;
if (subsrc != 0) {
desc = irq_desc + start;
if (subsrc & 1)
desc_handle_irq(start, desc);
desc++;
if (subsrc & 2)
desc_handle_irq(start+1, desc);
desc++;
if (subsrc & 4)
desc_handle_irq(start+2, desc);
}
}
/* uart demux entry points */
static void
s3c_irq_demux_uart0(unsigned int irq,
struct irq_desc *desc)
{
irq = irq;
s3c_irq_demux_uart(IRQ_S3CUART_RX0);
}
static void
s3c_irq_demux_uart1(unsigned int irq,
struct irq_desc *desc)
{
irq = irq;
s3c_irq_demux_uart(IRQ_S3CUART_RX1);
}
static void
s3c_irq_demux_uart2(unsigned int irq,
struct irq_desc *desc)
{
irq = irq;
s3c_irq_demux_uart(IRQ_S3CUART_RX2);
}
static void
s3c_irq_demux_extint8(unsigned int irq,
struct irq_desc *desc)
{
unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);
eintpnd &= ~eintmsk;
eintpnd &= ~0xff; /* ignore lower irqs */
/* we may as well handle all the pending IRQs here */
while (eintpnd) {
irq = __ffs(eintpnd);
eintpnd &= ~(1<<irq);
irq += (IRQ_EINT4 - 4);
desc_handle_irq(irq, irq_desc + irq);
}
}
static void
s3c_irq_demux_extint4t7(unsigned int irq,
struct irq_desc *desc)
{
unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);
eintpnd &= ~eintmsk;
eintpnd &= 0xff; /* only lower irqs */
/* we may as well handle all the pending IRQs here */
while (eintpnd) {
irq = __ffs(eintpnd);
eintpnd &= ~(1<<irq);
irq += (IRQ_EINT4 - 4);
desc_handle_irq(irq, irq_desc + irq);
}
}
#ifdef CONFIG_PM
static struct sleep_save irq_save[] = {
SAVE_ITEM(S3C2410_INTMSK),
SAVE_ITEM(S3C2410_INTSUBMSK),
};
/* the extint values move between the s3c2410/s3c2440 and the s3c2412
* so we use an array to hold them, and to calculate the address of
* the register at run-time
*/
static unsigned long save_extint[3];
static unsigned long save_eintflt[4];
static unsigned long save_eintmask;
int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(save_extint); i++)
save_extint[i] = __raw_readl(S3C24XX_EXTINT0 + (i*4));
for (i = 0; i < ARRAY_SIZE(save_eintflt); i++)
save_eintflt[i] = __raw_readl(S3C24XX_EINFLT0 + (i*4));
s3c2410_pm_do_save(irq_save, ARRAY_SIZE(irq_save));
save_eintmask = __raw_readl(S3C24XX_EINTMASK);
return 0;
}
int s3c24xx_irq_resume(struct sys_device *dev)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(save_extint); i++)
__raw_writel(save_extint[i], S3C24XX_EXTINT0 + (i*4));
for (i = 0; i < ARRAY_SIZE(save_eintflt); i++)
__raw_writel(save_eintflt[i], S3C24XX_EINFLT0 + (i*4));
s3c2410_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));
__raw_writel(save_eintmask, S3C24XX_EINTMASK);
return 0;
}
#else
#define s3c24xx_irq_suspend NULL
#define s3c24xx_irq_resume NULL
#endif
/* s3c24xx_init_irq
*
* Initialise S3C2410 IRQ system
*/
void __init s3c24xx_init_irq(void)
{
unsigned long pend;
unsigned long last;
int irqno;
int i;
irqdbf("s3c2410_init_irq: clearing interrupt status flags\n");
/* first, clear all interrupts pending... */
last = 0;
for (i = 0; i < 4; i++) {
pend = __raw_readl(S3C24XX_EINTPEND);
if (pend == 0 || pend == last)
break;
__raw_writel(pend, S3C24XX_EINTPEND);
printk("irq: clearing pending ext status %08x\n", (int)pend);
last = pend;
}
last = 0;
for (i = 0; i < 4; i++) {
pend = __raw_readl(S3C2410_INTPND);
if (pend == 0 || pend == last)
break;
__raw_writel(pend, S3C2410_SRCPND);
__raw_writel(pend, S3C2410_INTPND);
printk("irq: clearing pending status %08x\n", (int)pend);
last = pend;
}
last = 0;
for (i = 0; i < 4; i++) {
pend = __raw_readl(S3C2410_SUBSRCPND);
if (pend == 0 || pend == last)
break;
printk("irq: clearing subpending status %08x\n", (int)pend);
__raw_writel(pend, S3C2410_SUBSRCPND);
last = pend;
}
/* register the main interrupts */
irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n");
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:
case IRQ_ADCPARENT:
set_irq_chip(irqno, &s3c_irq_level_chip);
set_irq_handler(irqno, handle_level_irq);
break;
case IRQ_RESERVED6:
case IRQ_RESERVED24:
/* no IRQ here */
break;
default:
//irqdbf("registering irq %d (s3c irq)\n", irqno);
set_irq_chip(irqno, &s3c_irq_chip);
set_irq_handler(irqno, handle_edge_irq);
set_irq_flags(irqno, IRQF_VALID);
}
}
/* setup the cascade irq handlers */
set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint4t7);
set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint8);
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++) {
irqdbf("registering irq %d (ext int)\n", irqno);
set_irq_chip(irqno, &s3c_irq_eint0t4);
set_irq_handler(irqno, handle_edge_irq);
set_irq_flags(irqno, IRQF_VALID);
}
for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) {
irqdbf("registering irq %d (extended s3c irq)\n", irqno);
set_irq_chip(irqno, &s3c_irqext_chip);
set_irq_handler(irqno, handle_edge_irq);
set_irq_flags(irqno, IRQF_VALID);
}
/* register the uart interrupts */
irqdbf("s3c2410: registering external interrupts\n");
for (irqno = IRQ_S3CUART_RX0; irqno <= IRQ_S3CUART_ERR0; irqno++) {
irqdbf("registering irq %d (s3c uart0 irq)\n", irqno);
set_irq_chip(irqno, &s3c_irq_uart0);
set_irq_handler(irqno, handle_level_irq);
set_irq_flags(irqno, IRQF_VALID);
}
for (irqno = IRQ_S3CUART_RX1; irqno <= IRQ_S3CUART_ERR1; irqno++) {
irqdbf("registering irq %d (s3c uart1 irq)\n", irqno);
set_irq_chip(irqno, &s3c_irq_uart1);
set_irq_handler(irqno, handle_level_irq);
set_irq_flags(irqno, IRQF_VALID);
}
for (irqno = IRQ_S3CUART_RX2; irqno <= IRQ_S3CUART_ERR2; irqno++) {
irqdbf("registering irq %d (s3c uart2 irq)\n", irqno);
set_irq_chip(irqno, &s3c_irq_uart2);
set_irq_handler(irqno, handle_level_irq);
set_irq_flags(irqno, IRQF_VALID);
}
for (irqno = IRQ_TC; irqno <= IRQ_ADC; irqno++) {
irqdbf("registering irq %d (s3c adc irq)\n", irqno);
set_irq_chip(irqno, &s3c_irq_adc);
set_irq_handler(irqno, handle_edge_irq);
set_irq_flags(irqno, IRQF_VALID);
}
irqdbf("s3c2410: registered interrupt handlers\n");
}

View File

@ -1,4 +1,4 @@
/*********************************************************************** /* linux/arch/arm/mach-s3c2410/mach-amlm5900.c
* *
* linux/arch/arm/mach-s3c2410/mach-amlm5900.c * linux/arch/arm/mach-s3c2410/mach-amlm5900.c
* *
@ -52,8 +52,8 @@
#include <asm/arch/regs-lcd.h> #include <asm/arch/regs-lcd.h>
#include <asm/arch/regs-gpio.h> #include <asm/arch/regs-gpio.h>
#include "devs.h" #include <asm/plat-s3c24xx/devs.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
#ifdef CONFIG_MTD_PARTITIONS #ifdef CONFIG_MTD_PARTITIONS

View File

@ -50,9 +50,9 @@
#include <linux/serial_8250.h> #include <linux/serial_8250.h>
#include "clock.h" #include <asm/plat-s3c24xx/clock.h>
#include "devs.h" #include <asm/plat-s3c24xx/devs.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
#include "usb-simtec.h" #include "usb-simtec.h"
#define COPYRIGHT ", (c) 2004-2005 Simtec Electronics" #define COPYRIGHT ", (c) 2004-2005 Simtec Electronics"

View File

@ -38,10 +38,10 @@
#include <asm/arch/h1940-latch.h> #include <asm/arch/h1940-latch.h>
#include <asm/arch/fb.h> #include <asm/arch/fb.h>
#include "clock.h" #include <asm/plat-s3c24xx/clock.h>
#include "devs.h" #include <asm/plat-s3c24xx/devs.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
#include "pm.h" #include <asm/plat-s3c24xx/pm.h>
static struct map_desc h1940_iodesc[] __initdata = { static struct map_desc h1940_iodesc[] __initdata = {
[0] = { [0] = {

View File

@ -38,10 +38,10 @@
#include <asm/arch/regs-gpio.h> #include <asm/arch/regs-gpio.h>
#include <asm/arch/iic.h> #include <asm/arch/iic.h>
#include "s3c2410.h" #include <asm/plat-s3c24xx/s3c2410.h>
#include "clock.h" #include <asm/plat-s3c24xx/clock.h>
#include "devs.h" #include <asm/plat-s3c24xx/devs.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
static struct map_desc n30_iodesc[] __initdata = { static struct map_desc n30_iodesc[] __initdata = {
/* nothing here yet */ /* nothing here yet */

View File

@ -32,10 +32,10 @@
#include <asm/arch/regs-serial.h> #include <asm/arch/regs-serial.h>
#include <asm/arch/regs-gpio.h> #include <asm/arch/regs-gpio.h>
#include "s3c2410.h" #include <asm/plat-s3c24xx/s3c2410.h>
#include "clock.h" #include <asm/plat-s3c24xx/clock.h>
#include "devs.h" #include <asm/plat-s3c24xx/devs.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
static struct map_desc otom11_iodesc[] __initdata = { static struct map_desc otom11_iodesc[] __initdata = {
/* Device area */ /* Device area */

View File

@ -1,4 +1,4 @@
/*********************************************************************** /* linux/arch/arm/mach-s3c2410/mach-smdk2410.c
* *
* linux/arch/arm/mach-s3c2410/mach-smdk2410.c * linux/arch/arm/mach-s3c2410/mach-smdk2410.c
* *
@ -49,10 +49,10 @@
#include <asm/arch/regs-serial.h> #include <asm/arch/regs-serial.h>
#include "devs.h" #include <asm/plat-s3c24xx/devs.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
#include "common-smdk.h" #include <asm/plat-s3c24xx/common-smdk.h>
static struct map_desc smdk2410_iodesc[] __initdata = { static struct map_desc smdk2410_iodesc[] __initdata = {
/* nothing here yet */ /* nothing here yet */

View File

@ -43,9 +43,9 @@
#include <asm/arch/regs-gpio.h> #include <asm/arch/regs-gpio.h>
#include <asm/arch/leds-gpio.h> #include <asm/arch/leds-gpio.h>
#include "clock.h" #include <asm/plat-s3c24xx/clock.h>
#include "devs.h" #include <asm/plat-s3c24xx/devs.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
#include "usb-simtec.h" #include "usb-simtec.h"
/* macros for virtual address mods for the io space entries */ /* macros for virtual address mods for the io space entries */

View File

@ -1,11 +1,9 @@
/* linux/arch/arm/mach-s3c2410/pm.c /* linux/arch/arm/mach-s3c2410/pm.c
* *
* Copyright (c) 2004,2006 Simtec Electronics * Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>
* *
* S3C24XX Power Manager (Suspend-To-RAM) support * S3C2410 (and compatible) Power Manager (Suspend-To-RAM) support
*
* See Documentation/arm/Samsung-S3C24XX/Suspend.txt for more information
* *
* 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 as published by * it under the terms of the GNU General Public License as published by
@ -20,640 +18,139 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Parts based on arch/arm/mach-pxa/pm.c
*
* Thanks to Dimitry Andric for debugging
*/ */
#include <linux/init.h> #include <linux/init.h>
#include <linux/suspend.h> #include <linux/suspend.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/interrupt.h> #include <linux/sysdev.h>
#include <linux/crc32.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/serial_core.h>
#include <asm/cacheflush.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/arch/regs-serial.h> #include <asm/mach-types.h>
#include <asm/arch/regs-clock.h>
#include <asm/arch/regs-gpio.h> #include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-mem.h> #include <asm/arch/h1940.h>
#include <asm/arch/regs-irq.h>
#include <asm/mach/time.h> #include <asm/plat-s3c24xx/cpu.h>
#include <asm/plat-s3c24xx/pm.h>
#include "pm.h"
/* for external use */
unsigned long s3c_pm_flags;
#define PFX "s3c24xx-pm: "
static struct sleep_save core_save[] = {
SAVE_ITEM(S3C2410_LOCKTIME),
SAVE_ITEM(S3C2410_CLKCON),
/* we restore the timings here, with the proviso that the board
* brings the system up in an slower, or equal frequency setting
* to the original system.
*
* if we cannot guarantee this, then things are going to go very
* wrong here, as we modify the refresh and both pll settings.
*/
SAVE_ITEM(S3C2410_BWSCON),
SAVE_ITEM(S3C2410_BANKCON0),
SAVE_ITEM(S3C2410_BANKCON1),
SAVE_ITEM(S3C2410_BANKCON2),
SAVE_ITEM(S3C2410_BANKCON3),
SAVE_ITEM(S3C2410_BANKCON4),
SAVE_ITEM(S3C2410_BANKCON5),
SAVE_ITEM(S3C2410_CLKDIVN),
SAVE_ITEM(S3C2410_MPLLCON),
SAVE_ITEM(S3C2410_UPLLCON),
SAVE_ITEM(S3C2410_CLKSLOW),
SAVE_ITEM(S3C2410_REFRESH),
};
static struct sleep_save gpio_save[] = {
SAVE_ITEM(S3C2410_GPACON),
SAVE_ITEM(S3C2410_GPADAT),
SAVE_ITEM(S3C2410_GPBCON),
SAVE_ITEM(S3C2410_GPBDAT),
SAVE_ITEM(S3C2410_GPBUP),
SAVE_ITEM(S3C2410_GPCCON),
SAVE_ITEM(S3C2410_GPCDAT),
SAVE_ITEM(S3C2410_GPCUP),
SAVE_ITEM(S3C2410_GPDCON),
SAVE_ITEM(S3C2410_GPDDAT),
SAVE_ITEM(S3C2410_GPDUP),
SAVE_ITEM(S3C2410_GPECON),
SAVE_ITEM(S3C2410_GPEDAT),
SAVE_ITEM(S3C2410_GPEUP),
SAVE_ITEM(S3C2410_GPFCON),
SAVE_ITEM(S3C2410_GPFDAT),
SAVE_ITEM(S3C2410_GPFUP),
SAVE_ITEM(S3C2410_GPGCON),
SAVE_ITEM(S3C2410_GPGDAT),
SAVE_ITEM(S3C2410_GPGUP),
SAVE_ITEM(S3C2410_GPHCON),
SAVE_ITEM(S3C2410_GPHDAT),
SAVE_ITEM(S3C2410_GPHUP),
SAVE_ITEM(S3C2410_DCLKCON),
};
#ifdef CONFIG_S3C2410_PM_DEBUG #ifdef CONFIG_S3C2410_PM_DEBUG
extern void pm_dbg(const char *fmt, ...);
#define SAVE_UART(va) \
SAVE_ITEM((va) + S3C2410_ULCON), \
SAVE_ITEM((va) + S3C2410_UCON), \
SAVE_ITEM((va) + S3C2410_UFCON), \
SAVE_ITEM((va) + S3C2410_UMCON), \
SAVE_ITEM((va) + S3C2410_UBRDIV)
static struct sleep_save uart_save[] = {
SAVE_UART(S3C24XX_VA_UART0),
SAVE_UART(S3C24XX_VA_UART1),
#ifndef CONFIG_CPU_S3C2400
SAVE_UART(S3C24XX_VA_UART2),
#endif
};
/* debug
*
* we send the debug to printascii() to allow it to be seen if the
* system never wakes up from the sleep
*/
extern void printascii(const char *);
void pm_dbg(const char *fmt, ...)
{
va_list va;
char buff[256];
va_start(va, fmt);
vsprintf(buff, fmt, va);
va_end(va);
printascii(buff);
}
static void s3c2410_pm_debug_init(void)
{
unsigned long tmp = __raw_readl(S3C2410_CLKCON);
/* re-start uart clocks */
tmp |= S3C2410_CLKCON_UART0;
tmp |= S3C2410_CLKCON_UART1;
tmp |= S3C2410_CLKCON_UART2;
__raw_writel(tmp, S3C2410_CLKCON);
udelay(10);
}
#define DBG(fmt...) pm_dbg(fmt) #define DBG(fmt...) pm_dbg(fmt)
#else #else
#define DBG(fmt...) printk(KERN_DEBUG fmt) #define DBG(fmt...) printk(KERN_DEBUG fmt)
#define s3c2410_pm_debug_init() do { } while(0)
static struct sleep_save uart_save[] = {};
#endif #endif
#if defined(CONFIG_S3C2410_PM_CHECK) && CONFIG_S3C2410_PM_CHECK_CHUNKSIZE != 0 static void s3c2410_pm_prepare(void)
/* suspend checking code...
*
* this next area does a set of crc checks over all the installed
* memory, so the system can verify if the resume was ok.
*
* CONFIG_S3C2410_PM_CHECK_CHUNKSIZE defines the block-size for the CRC,
* increasing it will mean that the area corrupted will be less easy to spot,
* and reducing the size will cause the CRC save area to grow
*/
#define CHECK_CHUNKSIZE (CONFIG_S3C2410_PM_CHECK_CHUNKSIZE * 1024)
static u32 crc_size; /* size needed for the crc block */
static u32 *crcs; /* allocated over suspend/resume */
typedef u32 *(run_fn_t)(struct resource *ptr, u32 *arg);
/* s3c2410_pm_run_res
*
* go thorugh the given resource list, and look for system ram
*/
static void s3c2410_pm_run_res(struct resource *ptr, run_fn_t fn, u32 *arg)
{ {
while (ptr != NULL) { /* ensure at least GSTATUS3 has the resume address */
if (ptr->child != NULL)
s3c2410_pm_run_res(ptr->child, fn, arg);
if ((ptr->flags & IORESOURCE_MEM) && __raw_writel(virt_to_phys(s3c2410_cpu_resume), S3C2410_GSTATUS3);
strcmp(ptr->name, "System RAM") == 0) {
DBG("Found system RAM at %08lx..%08lx\n",
ptr->start, ptr->end);
arg = (fn)(ptr, arg);
}
ptr = ptr->sibling; DBG("GSTATUS3 0x%08x\n", __raw_readl(S3C2410_GSTATUS3));
} DBG("GSTATUS4 0x%08x\n", __raw_readl(S3C2410_GSTATUS4));
}
static void s3c2410_pm_run_sysram(run_fn_t fn, u32 *arg) if (machine_is_h1940()) {
{ void *base = phys_to_virt(H1940_SUSPEND_CHECK);
s3c2410_pm_run_res(&iomem_resource, fn, arg); unsigned long ptr;
} unsigned long calc = 0;
static u32 *s3c2410_pm_countram(struct resource *res, u32 *val) /* generate check for the bootloader to check on resume */
{
u32 size = (u32)(res->end - res->start)+1;
size += CHECK_CHUNKSIZE-1; for (ptr = 0; ptr < 0x40000; ptr += 0x400)
size /= CHECK_CHUNKSIZE; calc += __raw_readl(base+ptr);
DBG("Area %08lx..%08lx, %d blocks\n", res->start, res->end, size); __raw_writel(calc, phys_to_virt(H1940_SUSPEND_CHECKSUM));
*val += size * sizeof(u32);
return val;
}
/* s3c2410_pm_prepare_check
*
* prepare the necessary information for creating the CRCs. This
* must be done before the final save, as it will require memory
* allocating, and thus touching bits of the kernel we do not
* know about.
*/
static void s3c2410_pm_check_prepare(void)
{
crc_size = 0;
s3c2410_pm_run_sysram(s3c2410_pm_countram, &crc_size);
DBG("s3c2410_pm_prepare_check: %u checks needed\n", crc_size);
crcs = kmalloc(crc_size+4, GFP_KERNEL);
if (crcs == NULL)
printk(KERN_ERR "Cannot allocated CRC save area\n");
}
static u32 *s3c2410_pm_makecheck(struct resource *res, u32 *val)
{
unsigned long addr, left;
for (addr = res->start; addr < res->end;
addr += CHECK_CHUNKSIZE) {
left = res->end - addr;
if (left > CHECK_CHUNKSIZE)
left = CHECK_CHUNKSIZE;
*val = crc32_le(~0, phys_to_virt(addr), left);
val++;
} }
return val; /* the RX3715 uses similar code and the same H1940 and the
* same offsets for resume and checksum pointers */
if (machine_is_rx3715()) {
void *base = phys_to_virt(H1940_SUSPEND_CHECK);
unsigned long ptr;
unsigned long calc = 0;
/* generate check for the bootloader to check on resume */
for (ptr = 0; ptr < 0x40000; ptr += 0x4)
calc += __raw_readl(base+ptr);
__raw_writel(calc, phys_to_virt(H1940_SUSPEND_CHECKSUM));
}
if ( machine_is_aml_m5900() )
s3c2410_gpio_setpin(S3C2410_GPF2, 1);
} }
/* s3c2410_pm_check_store static int s3c2410_pm_resume(struct sys_device *dev)
*
* compute the CRC values for the memory blocks before the final
* sleep.
*/
static void s3c2410_pm_check_store(void)
{ {
if (crcs != NULL) unsigned long tmp;
s3c2410_pm_run_sysram(s3c2410_pm_makecheck, crcs);
}
/* in_region /* unset the return-from-sleep flag, to ensure reset */
*
* return TRUE if the area defined by ptr..ptr+size contatins the
* what..what+whatsz
*/
static inline int in_region(void *ptr, int size, void *what, size_t whatsz) tmp = __raw_readl(S3C2410_GSTATUS2);
{ tmp &= S3C2410_GSTATUS2_OFFRESET;
if ((what+whatsz) < ptr) __raw_writel(tmp, S3C2410_GSTATUS2);
return 0;
if (what > (ptr+size)) if ( machine_is_aml_m5900() )
return 0; s3c2410_gpio_setpin(S3C2410_GPF2, 0);
return 1;
}
static u32 *s3c2410_pm_runcheck(struct resource *res, u32 *val)
{
void *save_at = phys_to_virt(s3c2410_sleep_save_phys);
unsigned long addr;
unsigned long left;
void *ptr;
u32 calc;
for (addr = res->start; addr < res->end;
addr += CHECK_CHUNKSIZE) {
left = res->end - addr;
if (left > CHECK_CHUNKSIZE)
left = CHECK_CHUNKSIZE;
ptr = phys_to_virt(addr);
if (in_region(ptr, left, crcs, crc_size)) {
DBG("skipping %08lx, has crc block in\n", addr);
goto skip_check;
}
if (in_region(ptr, left, save_at, 32*4 )) {
DBG("skipping %08lx, has save block in\n", addr);
goto skip_check;
}
/* calculate and check the checksum */
calc = crc32_le(~0, ptr, left);
if (calc != *val) {
printk(KERN_ERR PFX "Restore CRC error at "
"%08lx (%08x vs %08x)\n", addr, calc, *val);
DBG("Restore CRC error at %08lx (%08x vs %08x)\n",
addr, calc, *val);
}
skip_check:
val++;
}
return val;
}
/* s3c2410_pm_check_restore
*
* check the CRCs after the restore event and free the memory used
* to hold them
*/
static void s3c2410_pm_check_restore(void)
{
if (crcs != NULL) {
s3c2410_pm_run_sysram(s3c2410_pm_runcheck, crcs);
kfree(crcs);
crcs = NULL;
}
}
#else
#define s3c2410_pm_check_prepare() do { } while(0)
#define s3c2410_pm_check_restore() do { } while(0)
#define s3c2410_pm_check_store() do { } while(0)
#endif
/* helper functions to save and restore register state */
void s3c2410_pm_do_save(struct sleep_save *ptr, int count)
{
for (; count > 0; count--, ptr++) {
ptr->val = __raw_readl(ptr->reg);
DBG("saved %p value %08lx\n", ptr->reg, ptr->val);
}
}
/* s3c2410_pm_do_restore
*
* restore the system from the given list of saved registers
*
* Note, we do not use DBG() in here, as the system may not have
* restore the UARTs state yet
*/
void s3c2410_pm_do_restore(struct sleep_save *ptr, int count)
{
for (; count > 0; count--, ptr++) {
printk(KERN_DEBUG "restore %p (restore %08lx, was %08x)\n",
ptr->reg, ptr->val, __raw_readl(ptr->reg));
__raw_writel(ptr->val, ptr->reg);
}
}
/* s3c2410_pm_do_restore_core
*
* similar to s3c2410_pm_do_restore_core
*
* WARNING: Do not put any debug in here that may effect memory or use
* peripherals, as things may be changing!
*/
static void s3c2410_pm_do_restore_core(struct sleep_save *ptr, int count)
{
for (; count > 0; count--, ptr++) {
__raw_writel(ptr->val, ptr->reg);
}
}
/* s3c2410_pm_show_resume_irqs
*
* print any IRQs asserted at resume time (ie, we woke from)
*/
static void s3c2410_pm_show_resume_irqs(int start, unsigned long which,
unsigned long mask)
{
int i;
which &= ~mask;
for (i = 0; i <= 31; i++) {
if ((which) & (1L<<i)) {
DBG("IRQ %d asserted at resume\n", start+i);
}
}
}
/* s3c2410_pm_check_resume_pin
*
* check to see if the pin is configured correctly for sleep mode, and
* make any necessary adjustments if it is not
*/
static void s3c2410_pm_check_resume_pin(unsigned int pin, unsigned int irqoffs)
{
unsigned long irqstate;
unsigned long pinstate;
int irq = s3c2410_gpio_getirq(pin);
if (irqoffs < 4)
irqstate = s3c_irqwake_intmask & (1L<<irqoffs);
else
irqstate = s3c_irqwake_eintmask & (1L<<irqoffs);
pinstate = s3c2410_gpio_getcfg(pin);
if (!irqstate) {
if (pinstate == S3C2410_GPIO_IRQ)
DBG("Leaving IRQ %d (pin %d) enabled\n", irq, pin);
} else {
if (pinstate == S3C2410_GPIO_IRQ) {
DBG("Disabling IRQ %d (pin %d)\n", irq, pin);
s3c2410_gpio_cfgpin(pin, S3C2410_GPIO_INPUT);
}
}
}
/* s3c2410_pm_configure_extint
*
* configure all external interrupt pins
*/
static void s3c2410_pm_configure_extint(void)
{
int pin;
/* for each of the external interrupts (EINT0..EINT15) we
* need to check wether it is an external interrupt source,
* and then configure it as an input if it is not
*/
for (pin = S3C2410_GPF0; pin <= S3C2410_GPF7; pin++) {
s3c2410_pm_check_resume_pin(pin, pin - S3C2410_GPF0);
}
for (pin = S3C2410_GPG0; pin <= S3C2410_GPG7; pin++) {
s3c2410_pm_check_resume_pin(pin, (pin - S3C2410_GPG0)+8);
}
}
void (*pm_cpu_prep)(void);
void (*pm_cpu_sleep)(void);
#define any_allowed(mask, allow) (((mask) & (allow)) != (allow))
/* s3c2410_pm_enter
*
* central control for sleep/resume process
*/
static int s3c2410_pm_enter(suspend_state_t state)
{
unsigned long regs_save[16];
/* ensure the debug is initialised (if enabled) */
s3c2410_pm_debug_init();
DBG("s3c2410_pm_enter(%d)\n", state);
if (pm_cpu_prep == NULL || pm_cpu_sleep == NULL) {
printk(KERN_ERR PFX "error: no cpu sleep functions set\n");
return -EINVAL;
}
if (state != PM_SUSPEND_MEM) {
printk(KERN_ERR PFX "error: only PM_SUSPEND_MEM supported\n");
return -EINVAL;
}
/* check if we have anything to wake-up with... bad things seem
* to happen if you suspend with no wakeup (system will often
* require a full power-cycle)
*/
if (!any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) &&
!any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) {
printk(KERN_ERR PFX "No sources enabled for wake-up!\n");
printk(KERN_ERR PFX "Aborting sleep\n");
return -EINVAL;
}
/* prepare check area if configured */
s3c2410_pm_check_prepare();
/* store the physical address of the register recovery block */
s3c2410_sleep_save_phys = virt_to_phys(regs_save);
DBG("s3c2410_sleep_save_phys=0x%08lx\n", s3c2410_sleep_save_phys);
/* save all necessary core registers not covered by the drivers */
s3c2410_pm_do_save(gpio_save, ARRAY_SIZE(gpio_save));
s3c2410_pm_do_save(core_save, ARRAY_SIZE(core_save));
s3c2410_pm_do_save(uart_save, ARRAY_SIZE(uart_save));
/* set the irq configuration for wake */
s3c2410_pm_configure_extint();
DBG("sleep: irq wakeup masks: %08lx,%08lx\n",
s3c_irqwake_intmask, s3c_irqwake_eintmask);
__raw_writel(s3c_irqwake_intmask, S3C2410_INTMSK);
__raw_writel(s3c_irqwake_eintmask, S3C2410_EINTMASK);
/* ack any outstanding external interrupts before we go to sleep */
__raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND);
__raw_writel(__raw_readl(S3C2410_INTPND), S3C2410_INTPND);
__raw_writel(__raw_readl(S3C2410_SRCPND), S3C2410_SRCPND);
/* call cpu specific preperation */
pm_cpu_prep();
/* flush cache back to ram */
flush_cache_all();
s3c2410_pm_check_store();
/* send the cpu to sleep... */
__raw_writel(0x00, S3C2410_CLKCON); /* turn off clocks over sleep */
/* s3c2410_cpu_save will also act as our return point from when
* we resume as it saves its own register state, so use the return
* code to differentiate return from save and return from sleep */
if (s3c2410_cpu_save(regs_save) == 0) {
flush_cache_all();
pm_cpu_sleep();
}
/* restore the cpu state */
cpu_init();
/* restore the system state */
s3c2410_pm_do_restore_core(core_save, ARRAY_SIZE(core_save));
s3c2410_pm_do_restore(gpio_save, ARRAY_SIZE(gpio_save));
s3c2410_pm_do_restore(uart_save, ARRAY_SIZE(uart_save));
s3c2410_pm_debug_init();
/* check what irq (if any) restored the system */
DBG("post sleep: IRQs 0x%08x, 0x%08x\n",
__raw_readl(S3C2410_SRCPND),
__raw_readl(S3C2410_EINTPEND));
s3c2410_pm_show_resume_irqs(IRQ_EINT0, __raw_readl(S3C2410_SRCPND),
s3c_irqwake_intmask);
s3c2410_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND),
s3c_irqwake_eintmask);
DBG("post sleep, preparing to return\n");
s3c2410_pm_check_restore();
/* ok, let's return from sleep */
DBG("S3C2410 PM Resume (post-restore)\n");
return 0; return 0;
} }
/* static int s3c2410_pm_add(struct sys_device *dev)
* Called after processes are frozen, but before we shut down devices.
*/
static int s3c2410_pm_prepare(suspend_state_t state)
{ {
pm_cpu_prep = s3c2410_pm_prepare;
pm_cpu_sleep = s3c2410_cpu_suspend;
return 0; return 0;
} }
/* #if defined(CONFIG_CPU_S3C2410)
* Called after devices are re-setup, but before processes are thawed. static struct sysdev_driver s3c2410_pm_driver = {
*/ .add = s3c2410_pm_add,
static int s3c2410_pm_finish(suspend_state_t state) .resume = s3c2410_pm_resume,
{
return 0;
}
/*
* Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
*/
static struct pm_ops s3c2410_pm_ops = {
.pm_disk_mode = PM_DISK_FIRMWARE,
.prepare = s3c2410_pm_prepare,
.enter = s3c2410_pm_enter,
.finish = s3c2410_pm_finish,
}; };
/* s3c2410_pm_init /* register ourselves */
*
* Attach the power management functions. This should be called
* from the board specific initialisation if the board supports
* it.
*/
int __init s3c2410_pm_init(void) static int __init s3c2410_pm_drvinit(void)
{ {
printk("S3C2410 Power Management, (c) 2004 Simtec Electronics\n"); return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_pm_driver);
pm_set_ops(&s3c2410_pm_ops);
return 0;
} }
arch_initcall(s3c2410_pm_drvinit);
#endif
#if defined(CONFIG_CPU_S3C2440)
static struct sysdev_driver s3c2440_pm_driver = {
.add = s3c2410_pm_add,
.resume = s3c2410_pm_resume,
};
static int __init s3c2440_pm_drvinit(void)
{
return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_pm_driver);
}
arch_initcall(s3c2440_pm_drvinit);
#endif
#if defined(CONFIG_CPU_S3C2442)
static struct sysdev_driver s3c2442_pm_driver = {
.add = s3c2410_pm_add,
.resume = s3c2410_pm_resume,
};
static int __init s3c2442_pm_drvinit(void)
{
return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_pm_driver);
}
arch_initcall(s3c2442_pm_drvinit);
#endif

View File

@ -1,276 +0,0 @@
/* linux/arch/arm/mach-s3c2410/s3c2410-clock.c
*
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* S3C2410,S3C2440,S3C2442 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 <linux/serial_core.h>
#include <asm/mach/map.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/arch/regs-serial.h>
#include <asm/arch/regs-clock.h>
#include <asm/arch/regs-gpio.h>
#include "s3c2410.h"
#include "clock.h"
#include "cpu.h"
int s3c2410_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;
/* ensure none of the special function bits set */
clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER);
__raw_writel(clkcon, S3C2410_CLKCON);
return 0;
}
static int s3c2410_upll_enable(struct clk *clk, int enable)
{
unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
unsigned long orig = clkslow;
if (enable)
clkslow &= ~S3C2410_CLKSLOW_UCLK_OFF;
else
clkslow |= S3C2410_CLKSLOW_UCLK_OFF;
__raw_writel(clkslow, S3C2410_CLKSLOW);
/* if we started the UPLL, then allow to settle */
if (enable && (orig & S3C2410_CLKSLOW_UCLK_OFF))
udelay(200);
return 0;
}
/* standard clock definitions */
static struct clk init_clocks_disable[] = {
{
.name = "nand",
.id = -1,
.parent = &clk_h,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_NAND,
}, {
.name = "sdi",
.id = -1,
.parent = &clk_p,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_SDI,
}, {
.name = "adc",
.id = -1,
.parent = &clk_p,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_ADC,
}, {
.name = "i2c",
.id = -1,
.parent = &clk_p,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_IIC,
}, {
.name = "iis",
.id = -1,
.parent = &clk_p,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_IIS,
}, {
.name = "spi",
.id = -1,
.parent = &clk_p,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_SPI,
}
};
static struct clk init_clocks[] = {
{
.name = "lcd",
.id = -1,
.parent = &clk_h,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_LCDC,
}, {
.name = "gpio",
.id = -1,
.parent = &clk_p,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_GPIO,
}, {
.name = "usb-host",
.id = -1,
.parent = &clk_h,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_USBH,
}, {
.name = "usb-device",
.id = -1,
.parent = &clk_h,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_USBD,
}, {
.name = "timers",
.id = -1,
.parent = &clk_p,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_PWMT,
}, {
.name = "uart",
.id = 0,
.parent = &clk_p,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_UART0,
}, {
.name = "uart",
.id = 1,
.parent = &clk_p,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_UART1,
}, {
.name = "uart",
.id = 2,
.parent = &clk_p,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_UART2,
}, {
.name = "rtc",
.id = -1,
.parent = &clk_p,
.enable = s3c2410_clkcon_enable,
.ctrlbit = S3C2410_CLKCON_RTC,
}, {
.name = "watchdog",
.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()
*
* Add all the clocks used by the s3c2410 or compatible CPUs
* such as the S3C2440 and S3C2442.
*
* We cannot use a system device as we are needed before any
* of the init-calls that initialise the devices are actually
* done.
*/
int __init s3c2410_baseclk_add(void)
{
unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
unsigned long clkcon = __raw_readl(S3C2410_CLKCON);
struct clk *clkp;
struct clk *xtal;
int ret;
int ptr;
clk_upll.enable = s3c2410_upll_enable;
if (s3c24xx_register_clock(&clk_usb_bus) < 0)
printk(KERN_ERR "failed to register usb bus clock\n");
/* 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);
}
s3c2410_clkcon_enable(clkp, 0);
}
/* show the clock-slow value */
xtal = clk_get(NULL, "xtal");
printk("CLOCK: Slow mode (%ld.%ld MHz), %s, MPLL %s, UPLL %s\n",
print_mhz(clk_get_rate(xtal) /
( 2 * S3C2410_CLKSLOW_GET_SLOWVAL(clkslow))),
(clkslow & S3C2410_CLKSLOW_SLOW) ? "slow" : "fast",
(clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on",
(clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on");
return 0;
}

View File

@ -1,161 +0,0 @@
/* linux/arch/arm/mach-s3c2410/s3c2410-dma.c
*
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* S3C2410 DMA selection
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sysdev.h>
#include <linux/serial_core.h>
#include <asm/dma.h>
#include <asm/arch/dma.h>
#include "dma.h"
#include "cpu.h"
#include <asm/arch/regs-serial.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-ac97.h>
#include <asm/arch/regs-mem.h>
#include <asm/arch/regs-lcd.h>
#include <asm/arch/regs-sdi.h>
#include <asm/arch/regs-iis.h>
#include <asm/arch/regs-spi.h>
static struct s3c24xx_dma_map __initdata s3c2410_dma_mappings[] = {
[DMACH_XD0] = {
.name = "xdreq0",
.channels[0] = S3C2410_DCON_CH0_XDREQ0 | DMA_CH_VALID,
},
[DMACH_XD1] = {
.name = "xdreq1",
.channels[1] = S3C2410_DCON_CH1_XDREQ1 | DMA_CH_VALID,
},
[DMACH_SDI] = {
.name = "sdi",
.channels[0] = S3C2410_DCON_CH0_SDI | DMA_CH_VALID,
.channels[2] = S3C2410_DCON_CH2_SDI | DMA_CH_VALID,
.channels[3] = S3C2410_DCON_CH3_SDI | DMA_CH_VALID,
.hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO,
.hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO,
},
[DMACH_SPI0] = {
.name = "spi0",
.channels[1] = S3C2410_DCON_CH1_SPI | DMA_CH_VALID,
.hw_addr.to = S3C2410_PA_SPI + S3C2410_SPTDAT,
.hw_addr.from = S3C2410_PA_SPI + S3C2410_SPRDAT,
},
[DMACH_SPI1] = {
.name = "spi1",
.channels[3] = S3C2410_DCON_CH3_SPI | DMA_CH_VALID,
.hw_addr.to = S3C2410_PA_SPI + 0x20 + S3C2410_SPTDAT,
.hw_addr.from = S3C2410_PA_SPI + 0x20 + S3C2410_SPRDAT,
},
[DMACH_UART0] = {
.name = "uart0",
.channels[0] = S3C2410_DCON_CH0_UART0 | DMA_CH_VALID,
.hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH,
.hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH,
},
[DMACH_UART1] = {
.name = "uart1",
.channels[1] = S3C2410_DCON_CH1_UART1 | DMA_CH_VALID,
.hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH,
.hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH,
},
[DMACH_UART2] = {
.name = "uart2",
.channels[3] = S3C2410_DCON_CH3_UART2 | DMA_CH_VALID,
.hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH,
.hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH,
},
[DMACH_TIMER] = {
.name = "timer",
.channels[0] = S3C2410_DCON_CH0_TIMER | DMA_CH_VALID,
.channels[2] = S3C2410_DCON_CH2_TIMER | DMA_CH_VALID,
.channels[3] = S3C2410_DCON_CH3_TIMER | DMA_CH_VALID,
},
[DMACH_I2S_IN] = {
.name = "i2s-sdi",
.channels[1] = S3C2410_DCON_CH1_I2SSDI | DMA_CH_VALID,
.channels[2] = S3C2410_DCON_CH2_I2SSDI | DMA_CH_VALID,
.hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO,
},
[DMACH_I2S_OUT] = {
.name = "i2s-sdo",
.channels[2] = S3C2410_DCON_CH2_I2SSDO | DMA_CH_VALID,
.hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO,
},
[DMACH_USB_EP1] = {
.name = "usb-ep1",
.channels[0] = S3C2410_DCON_CH0_USBEP1 | DMA_CH_VALID,
},
[DMACH_USB_EP2] = {
.name = "usb-ep2",
.channels[1] = S3C2410_DCON_CH1_USBEP2 | DMA_CH_VALID,
},
[DMACH_USB_EP3] = {
.name = "usb-ep3",
.channels[2] = S3C2410_DCON_CH2_USBEP3 | DMA_CH_VALID,
},
[DMACH_USB_EP4] = {
.name = "usb-ep4",
.channels[3] =S3C2410_DCON_CH3_USBEP4 | DMA_CH_VALID,
},
};
static void s3c2410_dma_select(struct s3c2410_dma_chan *chan,
struct s3c24xx_dma_map *map)
{
chan->dcon = map->channels[chan->number] & ~DMA_CH_VALID;
}
static struct s3c24xx_dma_selection __initdata s3c2410_dma_sel = {
.select = s3c2410_dma_select,
.dcon_mask = 7 << 24,
.map = s3c2410_dma_mappings,
.map_size = ARRAY_SIZE(s3c2410_dma_mappings),
};
static int s3c2410_dma_add(struct sys_device *sysdev)
{
return s3c24xx_dma_init_map(&s3c2410_dma_sel);
}
#if defined(CONFIG_CPU_S3C2410)
static struct sysdev_driver s3c2410_dma_driver = {
.add = s3c2410_dma_add,
};
static int __init s3c2410_dma_init(void)
{
return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_dma_driver);
}
arch_initcall(s3c2410_dma_init);
#endif
#if defined(CONFIG_CPU_S3C2442)
/* S3C2442 DMA contains the same selection table as the S3C2410 */
static struct sysdev_driver s3c2442_dma_driver = {
.add = s3c2410_dma_add,
};
static int __init s3c2442_dma_init(void)
{
return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_dma_driver);
}
arch_initcall(s3c2442_dma_init);
#endif

View File

@ -1,71 +0,0 @@
/* linux/arch/arm/mach-s3c2410/s3c2410-gpio.c
*
* Copyright (c) 2004-2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* S3C2410 GPIO 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/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
unsigned int config)
{
void __iomem *reg = S3C24XX_EINFLT0;
unsigned long flags;
unsigned long val;
if (pin < S3C2410_GPG8 || pin > S3C2410_GPG15)
return -1;
config &= 0xff;
pin -= S3C2410_GPG8;
reg += pin & ~3;
local_irq_save(flags);
/* update filter width and clock source */
val = __raw_readl(reg);
val &= ~(0xff << ((pin & 3) * 8));
val |= config << ((pin & 3) * 8);
__raw_writel(val, reg);
/* update filter enable */
val = __raw_readl(S3C24XX_EXTINT2);
val &= ~(1 << ((pin * 4) + 3));
val |= on << ((pin * 4) + 3);
__raw_writel(val, S3C24XX_EXTINT2);
local_irq_restore(flags);
return 0;
}
EXPORT_SYMBOL(s3c2410_gpio_irqfilter);

View File

@ -1,48 +0,0 @@
/* linux/arch/arm/mach-s3c2410/s3c2410-irq.c
*
* Copyright (c) 2006 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
*
*/
#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 "cpu.h"
#include "pm.h"
static int s3c2410_irq_add(struct sys_device *sysdev)
{
return 0;
}
static struct sysdev_driver s3c2410_irq_driver = {
.add = s3c2410_irq_add,
.suspend = s3c24xx_irq_suspend,
.resume = s3c24xx_irq_resume,
};
static int s3c2410_irq_init(void)
{
return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_irq_driver);
}
arch_initcall(s3c2410_irq_init);

View File

@ -1,156 +0,0 @@
/* linux/arch/arm/mach-s3c2410/s3c2410-pm.c
*
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* S3C2410 (and compatible) Power Manager (Suspend-To-RAM) 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/suspend.h>
#include <linux/errno.h>
#include <linux/time.h>
#include <linux/sysdev.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/mach-types.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/h1940.h>
#include "cpu.h"
#include "pm.h"
#ifdef CONFIG_S3C2410_PM_DEBUG
extern void pm_dbg(const char *fmt, ...);
#define DBG(fmt...) pm_dbg(fmt)
#else
#define DBG(fmt...) printk(KERN_DEBUG fmt)
#endif
static void s3c2410_pm_prepare(void)
{
/* ensure at least GSTATUS3 has the resume address */
__raw_writel(virt_to_phys(s3c2410_cpu_resume), S3C2410_GSTATUS3);
DBG("GSTATUS3 0x%08x\n", __raw_readl(S3C2410_GSTATUS3));
DBG("GSTATUS4 0x%08x\n", __raw_readl(S3C2410_GSTATUS4));
if (machine_is_h1940()) {
void *base = phys_to_virt(H1940_SUSPEND_CHECK);
unsigned long ptr;
unsigned long calc = 0;
/* generate check for the bootloader to check on resume */
for (ptr = 0; ptr < 0x40000; ptr += 0x400)
calc += __raw_readl(base+ptr);
__raw_writel(calc, phys_to_virt(H1940_SUSPEND_CHECKSUM));
}
/* the RX3715 uses similar code and the same H1940 and the
* same offsets for resume and checksum pointers */
if (machine_is_rx3715()) {
void *base = phys_to_virt(H1940_SUSPEND_CHECK);
unsigned long ptr;
unsigned long calc = 0;
/* generate check for the bootloader to check on resume */
for (ptr = 0; ptr < 0x40000; ptr += 0x4)
calc += __raw_readl(base+ptr);
__raw_writel(calc, phys_to_virt(H1940_SUSPEND_CHECKSUM));
}
if ( machine_is_aml_m5900() )
s3c2410_gpio_setpin(S3C2410_GPF2, 1);
}
static int s3c2410_pm_resume(struct sys_device *dev)
{
unsigned long tmp;
/* unset the return-from-sleep flag, to ensure reset */
tmp = __raw_readl(S3C2410_GSTATUS2);
tmp &= S3C2410_GSTATUS2_OFFRESET;
__raw_writel(tmp, S3C2410_GSTATUS2);
if ( machine_is_aml_m5900() )
s3c2410_gpio_setpin(S3C2410_GPF2, 0);
return 0;
}
static int s3c2410_pm_add(struct sys_device *dev)
{
pm_cpu_prep = s3c2410_pm_prepare;
pm_cpu_sleep = s3c2410_cpu_suspend;
return 0;
}
#if defined(CONFIG_CPU_S3C2410)
static struct sysdev_driver s3c2410_pm_driver = {
.add = s3c2410_pm_add,
.resume = s3c2410_pm_resume,
};
/* register ourselves */
static int __init s3c2410_pm_drvinit(void)
{
return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_pm_driver);
}
arch_initcall(s3c2410_pm_drvinit);
#endif
#if defined(CONFIG_CPU_S3C2440)
static struct sysdev_driver s3c2440_pm_driver = {
.add = s3c2410_pm_add,
.resume = s3c2410_pm_resume,
};
static int __init s3c2440_pm_drvinit(void)
{
return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_pm_driver);
}
arch_initcall(s3c2440_pm_drvinit);
#endif
#if defined(CONFIG_CPU_S3C2442)
static struct sysdev_driver s3c2442_pm_driver = {
.add = s3c2410_pm_add,
.resume = s3c2410_pm_resume,
};
static int __init s3c2442_pm_drvinit(void)
{
return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_pm_driver);
}
arch_initcall(s3c2442_pm_drvinit);
#endif

View File

@ -1,68 +0,0 @@
/* linux/arch/arm/mach-s3c2410/s3c2410-sleep.S
*
* Copyright (c) 2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* S3C2410 Power Manager (Suspend-To-RAM) support
*
* Based on PXA/SA1100 sleep code by:
* Nicolas Pitre, (c) 2002 Monta Vista Software Inc
* Cliff Brake, (c) 2001
*
* 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/linkage.h>
#include <asm/assembler.h>
#include <asm/hardware.h>
#include <asm/arch/map.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-clock.h>
#include <asm/arch/regs-mem.h>
#include <asm/arch/regs-serial.h>
/* s3c2410_cpu_suspend
*
* put the cpu into sleep mode
*/
ENTRY(s3c2410_cpu_suspend)
@@ prepare cpu to sleep
ldr r4, =S3C2410_REFRESH
ldr r5, =S3C24XX_MISCCR
ldr r6, =S3C2410_CLKCON
ldr r7, [ r4 ] @ get REFRESH (and ensure in TLB)
ldr r8, [ r5 ] @ get MISCCR (and ensure in TLB)
ldr r9, [ r6 ] @ get CLKCON (and ensure in TLB)
orr r7, r7, #S3C2410_REFRESH_SELF @ SDRAM sleep command
orr r8, r8, #S3C2410_MISCCR_SDSLEEP @ SDRAM power-down signals
orr r9, r9, #S3C2410_CLKCON_POWER @ power down command
teq pc, #0 @ first as a trial-run to load cache
bl s3c2410_do_sleep
teq r0, r0 @ now do it for real
b s3c2410_do_sleep @
@@ align next bit of code to cache line
.align 8
s3c2410_do_sleep:
streq r7, [ r4 ] @ SDRAM sleep command
streq r8, [ r5 ] @ SDRAM power-down config
streq r9, [ r6 ] @ CPU sleep
1: beq 1b
mov pc, r14

View File

@ -31,10 +31,10 @@
#include <asm/arch/regs-clock.h> #include <asm/arch/regs-clock.h>
#include <asm/arch/regs-serial.h> #include <asm/arch/regs-serial.h>
#include "s3c2410.h" #include <asm/plat-s3c24xx/s3c2410.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
#include "devs.h" #include <asm/plat-s3c24xx/devs.h>
#include "clock.h" #include <asm/plat-s3c24xx/clock.h>
/* Initial IO mappings */ /* Initial IO mappings */

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2410/sleep.S /* linux/arch/arm/mach-s3c2410/s3c2410-sleep.S
* *
* Copyright (c) 2004 Simtec Electronics * Copyright (c) 2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>
@ -34,126 +34,35 @@
#include <asm/arch/regs-mem.h> #include <asm/arch/regs-mem.h>
#include <asm/arch/regs-serial.h> #include <asm/arch/regs-serial.h>
/* CONFIG_DEBUG_RESUME is dangerous if your bootloader does not /* s3c2410_cpu_suspend
* reset the UART configuration, only enable if you really need this!
*/
//#define CONFIG_DEBUG_RESUME
.text
/* s3c2410_cpu_save
* *
* save enough of the CPU state to allow us to re-start * put the cpu into sleep mode
* pm.c code. as we store items like the sp/lr, we will
* end up returning from this function when the cpu resumes
* so the return value is set to mark this.
*
* This arangement means we avoid having to flush the cache
* from this code.
*
* entry:
* r0 = pointer to save block
*
* exit:
* r0 = 0 => we stored everything
* 1 => resumed from sleep
*/ */
ENTRY(s3c2410_cpu_save) ENTRY(s3c2410_cpu_suspend)
stmfd sp!, { r4 - r12, lr } @@ prepare cpu to sleep
@@ store co-processor registers ldr r4, =S3C2410_REFRESH
ldr r5, =S3C24XX_MISCCR
ldr r6, =S3C2410_CLKCON
ldr r7, [ r4 ] @ get REFRESH (and ensure in TLB)
ldr r8, [ r5 ] @ get MISCCR (and ensure in TLB)
ldr r9, [ r6 ] @ get CLKCON (and ensure in TLB)
mrc p15, 0, r4, c15, c1, 0 @ CP access register orr r7, r7, #S3C2410_REFRESH_SELF @ SDRAM sleep command
mrc p15, 0, r5, c13, c0, 0 @ PID orr r8, r8, #S3C2410_MISCCR_SDSLEEP @ SDRAM power-down signals
mrc p15, 0, r6, c3, c0, 0 @ Domain ID orr r9, r9, #S3C2410_CLKCON_POWER @ power down command
mrc p15, 0, r7, c2, c0, 0 @ translation table base address
mrc p15, 0, r8, c1, c0, 0 @ control register
stmia r0, { r4 - r13 } teq pc, #0 @ first as a trial-run to load cache
bl s3c2410_do_sleep
teq r0, r0 @ now do it for real
b s3c2410_do_sleep @
mov r0, #0 @@ align next bit of code to cache line
ldmfd sp, { r4 - r12, pc } .align 8
s3c2410_do_sleep:
@@ return to the caller, after having the MMU streq r7, [ r4 ] @ SDRAM sleep command
@@ turned on, this restores the last bits from the streq r8, [ r5 ] @ SDRAM power-down config
@@ stack streq r9, [ r6 ] @ CPU sleep
resume_with_mmu: 1: beq 1b
mov r0, #1 mov pc, r14
ldmfd sp!, { r4 - r12, pc }
.ltorg
@@ the next bits sit in the .data segment, even though they
@@ happen to be code... the s3c2410_sleep_save_phys needs to be
@@ accessed by the resume code before it can restore the MMU.
@@ This means that the variable has to be close enough for the
@@ code to read it... since the .text segment needs to be RO,
@@ the data segment can be the only place to put this code.
.data
.global s3c2410_sleep_save_phys
s3c2410_sleep_save_phys:
.word 0
/* s3c2410_cpu_resume
*
* resume code entry for bootloader to call
*
* we must put this code here in the data segment as we have no
* other way of restoring the stack pointer after sleep, and we
* must not write to the code segment (code is read-only)
*/
ENTRY(s3c2410_cpu_resume)
mov r0, #PSR_I_BIT | PSR_F_BIT | SVC_MODE
msr cpsr_c, r0
@@ load UART to allow us to print the two characters for
@@ resume debug
mov r2, #S3C24XX_PA_UART & 0xff000000
orr r2, r2, #S3C24XX_PA_UART & 0xff000
#if 0
/* SMDK2440 LED set */
mov r14, #S3C24XX_PA_GPIO
ldr r12, [ r14, #0x54 ]
bic r12, r12, #3<<4
orr r12, r12, #1<<7
str r12, [ r14, #0x54 ]
#endif
#ifdef CONFIG_DEBUG_RESUME
mov r3, #'L'
strb r3, [ r2, #S3C2410_UTXH ]
1001:
ldrb r14, [ r3, #S3C2410_UTRSTAT ]
tst r14, #S3C2410_UTRSTAT_TXE
beq 1001b
#endif /* CONFIG_DEBUG_RESUME */
mov r1, #0
mcr p15, 0, r1, c8, c7, 0 @@ invalidate I & D TLBs
mcr p15, 0, r1, c7, c7, 0 @@ invalidate I & D caches
ldr r0, s3c2410_sleep_save_phys @ address of restore block
ldmia r0, { r4 - r13 }
mcr p15, 0, r4, c15, c1, 0 @ CP access register
mcr p15, 0, r5, c13, c0, 0 @ PID
mcr p15, 0, r6, c3, c0, 0 @ Domain ID
mcr p15, 0, r7, c2, c0, 0 @ translation table base
#ifdef CONFIG_DEBUG_RESUME
mov r3, #'R'
strb r3, [ r2, #S3C2410_UTXH ]
#endif
ldr r2, =resume_with_mmu
mcr p15, 0, r8, c1, c0, 0 @ turn on MMU, etc
nop @ second-to-last before mmu
mov pc, r2 @ go back to virtual address
.ltorg

View File

@ -35,7 +35,7 @@
#include <asm/io.h> #include <asm/io.h>
#include <asm/irq.h> #include <asm/irq.h>
#include "devs.h" #include <asm/plat-s3c24xx/devs.h>
#include "usb-simtec.h" #include "usb-simtec.h"
/* control power and monitor over-current events on various Simtec /* control power and monitor over-current events on various Simtec

View File

@ -0,0 +1,58 @@
# arch/arm/mach-s3c2412/Kconfig
#
# Copyright 2007 Simtec Electronics
#
# Licensed under GPLv2
config CPU_S3C2412
bool
depends on ARCH_S3C2410
select S3C2412_PM if PM
select S3C2412_DMA if S3C2410_DMA
help
Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line
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 S3C2412_DMA
bool
depends on CPU_S3C2412
help
Internal config node for S3C2412 DMA support
config S3C2412_PM
bool
help
Internal config node to apply S3C2412 power management
menu "S3C2412 Machines"
config MACH_SMDK2413
bool "SMDK2413"
select CPU_S3C2412
select MACH_S3C2413
select MACH_SMDK
help
Say Y here if you are using an SMDK2413
config MACH_S3C2413
bool
help
Internal node for S3C2413 version of SMDK2413, so that
machine_is_s3c2413() will work when MACH_SMDK2413 is
selected
config MACH_VSTMS
bool "VMSTMS"
select CPU_S3C2412
help
Say Y here if you are using an VSTMS board
endmenu

View File

@ -0,0 +1,21 @@
# arch/arm/mach-s3c2412/Makefile
#
# Copyright 2007 Simtec Electronics
#
# Licensed under GPLv2
obj-y :=
obj-m :=
obj-n :=
obj- :=
obj-$(CONFIG_CPU_S3C2412) += s3c2412.o
obj-$(CONFIG_CPU_S3C2412) += irq.o
obj-$(CONFIG_CPU_S3C2412) += clock.o
obj-$(CONFIG_S3C2412_DMA) += dma.o
obj-$(CONFIG_S3C2412_PM) += pm.o
# Machine support
obj-$(CONFIG_MACH_SMDK2413) += mach-smdk2413.o
obj-$(CONFIG_MACH_VSTMS) += mach-vstms.o

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2410/s3c2412-clock.c /* linux/arch/arm/mach-s3c2412/clock.c
* *
* Copyright (c) 2006 Simtec Electronics * Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>
@ -41,9 +41,9 @@
#include <asm/arch/regs-clock.h> #include <asm/arch/regs-clock.h>
#include <asm/arch/regs-gpio.h> #include <asm/arch/regs-gpio.h>
#include "s3c2412.h" #include <asm/plat-s3c24xx/s3c2412.h>
#include "clock.h" #include <asm/plat-s3c24xx/clock.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
/* We currently have to assume that the system is running /* We currently have to assume that the system is running
* from the XTPll input, and that all ***REFCLKs are being * from the XTPll input, and that all ***REFCLKs are being

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2410/s3c2412-dma.c /* linux/arch/arm/mach-s3c2412/dma.c
* *
* Copyright (c) 2006 Simtec Electronics * Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>
@ -21,8 +21,8 @@
#include <asm/arch/dma.h> #include <asm/arch/dma.h>
#include <asm/io.h> #include <asm/io.h>
#include "dma.h" #include <asm/plat-s3c24xx/dma.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
#include <asm/arch/regs-serial.h> #include <asm/arch/regs-serial.h>
#include <asm/arch/regs-gpio.h> #include <asm/arch/regs-gpio.h>

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2412/s3c2412-irq.c /* linux/arch/arm/mach-s3c2412/irq.c
* *
* Copyright (c) 2006 Simtec Electronics * Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>
@ -35,9 +35,9 @@
#include <asm/arch/regs-irq.h> #include <asm/arch/regs-irq.h>
#include <asm/arch/regs-gpio.h> #include <asm/arch/regs-gpio.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
#include "irq.h" #include <asm/plat-s3c24xx/irq.h>
#include "pm.h" #include <asm/plat-s3c24xx/pm.h>
/* the s3c2412 changes the behaviour of IRQ_EINT0 through IRQ_EINT3 by /* the s3c2412 changes the behaviour of IRQ_EINT0 through IRQ_EINT3 by
* having them turn up in both the INT* and the EINT* registers. Whilst * having them turn up in both the INT* and the EINT* registers. Whilst

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2410/mach-smdk2413.c /* linux/arch/arm/mach-s3c2412/mach-smdk2413.c
* *
* Copyright (c) 2006 Simtec Electronics * Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>
@ -39,13 +39,13 @@
#include <asm/arch/idle.h> #include <asm/arch/idle.h>
#include <asm/arch/fb.h> #include <asm/arch/fb.h>
#include "s3c2410.h" #include <asm/plat-s3c24xx/s3c2410.h>
#include "s3c2412.h" #include <asm/plat-s3c24xx/s3c2412.h>
#include "clock.h" #include <asm/plat-s3c24xx/clock.h>
#include "devs.h" #include <asm/plat-s3c24xx/devs.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
#include "common-smdk.h" #include <asm/plat-s3c24xx/common-smdk.h>
static struct map_desc smdk2413_iodesc[] __initdata = { static struct map_desc smdk2413_iodesc[] __initdata = {
}; };

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2410/mach-vstms.c /* linux/arch/arm/mach-s3c2412/mach-vstms.c
* *
* (C) 2006 Thomas Gleixner <tglx@linutronix.de> * (C) 2006 Thomas Gleixner <tglx@linutronix.de>
* *
@ -43,11 +43,11 @@
#include <asm/arch/nand.h> #include <asm/arch/nand.h>
#include "s3c2410.h" #include <asm/plat-s3c24xx/s3c2410.h>
#include "s3c2412.h" #include <asm/plat-s3c24xx/s3c2412.h>
#include "clock.h" #include <asm/plat-s3c24xx/clock.h>
#include "devs.h" #include <asm/plat-s3c24xx/devs.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
static struct map_desc vstms_iodesc[] __initdata = { static struct map_desc vstms_iodesc[] __initdata = {

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2410/s3c2412-pm.c /* linux/arch/arm/mach-s3c2412/pm.c
* *
* Copyright (c) 2006 Simtec Electronics * Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>
@ -28,10 +28,10 @@
#include <asm/arch/regs-gpio.h> #include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-dsc.h> #include <asm/arch/regs-dsc.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
#include "pm.h" #include <asm/plat-s3c24xx/pm.h>
#include "s3c2412.h" #include <asm/plat-s3c24xx/s3c2412.h>
static void s3c2412_cpu_suspend(void) static void s3c2412_cpu_suspend(void)
{ {

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2410/s3c2412.c /* linux/arch/arm/mach-s3c2412/s3c2412.c
* *
* Copyright (c) 2006 Simtec Electronics * Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>
@ -38,11 +38,11 @@
#include <asm/arch/regs-gpioj.h> #include <asm/arch/regs-gpioj.h>
#include <asm/arch/regs-dsc.h> #include <asm/arch/regs-dsc.h>
#include "s3c2412.h" #include <asm/plat-s3c24xx/s3c2412.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
#include "devs.h" #include <asm/plat-s3c24xx/devs.h>
#include "clock.h" #include <asm/plat-s3c24xx/clock.h>
#include "pm.h" #include <asm/plat-s3c24xx/pm.h>
#ifndef CONFIG_CPU_S3C2412_ONLY #ifndef CONFIG_CPU_S3C2412_ONLY
void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO; void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO;

View File

@ -0,0 +1,71 @@
# arch/arm/mach-s3c2440/Kconfig
#
# Copyright 2007 Simtec Electronics
#
# Licensed under GPLv2
config CPU_S3C2440
bool
depends on ARCH_S3C2410
select S3C2410_CLOCK
select S3C2410_PM if PM
select S3C2410_GPIO
select S3C2440_DMA if S3C2410_DMA
select CPU_S3C244X
help
Support for S3C2440 Samsung Mobile CPU based systems.
config S3C2440_DMA
bool
depends on ARCH_S3C2410 && CPU_S3C24405B
help
Support for S3C2440 specific DMA code5A
menu "S3C2440 Machines"
config MACH_ANUBIS
bool "Simtec Electronics ANUBIS"
select CPU_S3C2440
select PM_SIMTEC if PM
help
Say Y here if you are using the Simtec Electronics ANUBIS
development system
config MACH_OSIRIS
bool "Simtec IM2440D20 (OSIRIS) module"
select CPU_S3C2440
select PM_SIMTEC if PM
help
Say Y here if you are using the Simtec IM2440D20 module, also
known as the Osiris.
config MACH_RX3715
bool "HP iPAQ rx3715"
select CPU_S3C2440
select PM_H1940 if PM
help
Say Y here if you are using the HP iPAQ rx3715.
config ARCH_S3C2440
bool "SMDK2440"
select CPU_S3C2440
select MACH_SMDK
help
Say Y here if you are using the SMDK2440.
config MACH_NEXCODER_2440
bool "NexVision NEXCODER 2440 Light Board"
select CPU_S3C2440
help
Say Y here if you are using the Nex Vision NEXCODER 2440 Light Board
config SMDK2440_CPU2440
bool "SMDK2440 with S3C2440 CPU module"
depends on ARCH_S3C2440
default y if ARCH_S3C2440
select CPU_S3C2440
endmenu

View File

@ -0,0 +1,23 @@
# arch/arm/mach-s3c2440/Makefile
#
# Copyright 2007 Simtec Electronics
#
# Licensed under GPLv2
obj-y :=
obj-m :=
obj-n :=
obj- :=
obj-$(CONFIG_CPU_S3C2440) += s3c2440.o dsc.o
obj-$(CONFIG_CPU_S3C2440) += irq.o
obj-$(CONFIG_CPU_S3C2440) += clock.o
obj-$(CONFIG_S3C2440_DMA) += dma.o
# Machine support
obj-$(CONFIG_MACH_ANUBIS) += mach-anubis.o
obj-$(CONFIG_MACH_OSIRIS) += mach-osiris.o
obj-$(CONFIG_MACH_RX3715) += mach-rx3715.o
obj-$(CONFIG_ARCH_S3C2440) += mach-smdk2440.o
obj-$(CONFIG_MACH_NEXCODER_2440) += mach-nexcoder.o

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2410/s3c2440-clock.c /* linux/arch/arm/mach-s3c2440/clock.c
* *
* Copyright (c) 2004-2005 Simtec Electronics * Copyright (c) 2004-2005 Simtec Electronics
* http://armlinux.simtec.co.uk/ * http://armlinux.simtec.co.uk/
@ -41,8 +41,8 @@
#include <asm/arch/regs-clock.h> #include <asm/arch/regs-clock.h>
#include "clock.h" #include <asm/plat-s3c24xx/clock.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
/* S3C2440 extended clock support */ /* S3C2440 extended clock support */

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2410/s3c2440-dma.c /* linux/arch/arm/mach-s3c2440/dma.c
* *
* Copyright (c) 2006 Simtec Electronics * Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>
@ -19,9 +19,9 @@
#include <asm/dma.h> #include <asm/dma.h>
#include <asm/arch/dma.h> #include <asm/arch/dma.h>
#include "dma.h" #include <asm/plat-s3c24xx/dma.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
#include <asm/arch/regs-serial.h> #include <asm/arch/regs-serial.h>
#include <asm/arch/regs-gpio.h> #include <asm/arch/regs-gpio.h>

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2410/s3c2440-dsc.c /* linux/arch/arm/mach-s3c2440/dsc.c
* *
* Copyright (c) 2004-2005 Simtec Electronics * Copyright (c) 2004-2005 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>
@ -27,8 +27,8 @@
#include <asm/arch/regs-gpio.h> #include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-dsc.h> #include <asm/arch/regs-dsc.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
#include "s3c2440.h" #include <asm/plat-s3c24xx/s3c2440.h>
int s3c2440_set_dsc(unsigned int pin, unsigned int value) int s3c2440_set_dsc(unsigned int pin, unsigned int value)
{ {

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2410/s3c2440-irq.c /* linux/arch/arm/mach-s3c2440/irq.c
* *
* Copyright (c) 2003,2004 Simtec Electronics * Copyright (c) 2003,2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>
@ -35,9 +35,9 @@
#include <asm/arch/regs-irq.h> #include <asm/arch/regs-irq.h>
#include <asm/arch/regs-gpio.h> #include <asm/arch/regs-gpio.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
#include "pm.h" #include <asm/plat-s3c24xx/pm.h>
#include "irq.h" #include <asm/plat-s3c24xx/irq.h>
/* WDT/AC97 */ /* WDT/AC97 */

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2410/mach-anubis.c /* linux/arch/arm/mach-s3c2440/mach-anubis.c
* *
* Copyright (c) 2003-2005 Simtec Electronics * Copyright (c) 2003-2005 Simtec Electronics
* http://armlinux.simtec.co.uk/ * http://armlinux.simtec.co.uk/
@ -42,9 +42,9 @@
#include <linux/mtd/nand_ecc.h> #include <linux/mtd/nand_ecc.h>
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
#include "clock.h" #include <asm/plat-s3c24xx/clock.h>
#include "devs.h" #include <asm/plat-s3c24xx/devs.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
#define COPYRIGHT ", (c) 2005 Simtec Electronics" #define COPYRIGHT ", (c) 2005 Simtec Electronics"

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2410/mach-nexcoder.c /* linux/arch/arm/mach-s3c2440/mach-nexcoder.c
* *
* Copyright (c) 2004 Nex Vision * Copyright (c) 2004 Nex Vision
* Guillaume GOURAT <guillaume.gourat@nexvision.tv> * Guillaume GOURAT <guillaume.gourat@nexvision.tv>
@ -38,11 +38,11 @@
#include <asm/arch/regs-gpio.h> #include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-serial.h> #include <asm/arch/regs-serial.h>
#include "s3c2410.h" #include <asm/plat-s3c24xx/s3c2410.h>
#include "s3c2440.h" #include <asm/plat-s3c24xx/s3c2440.h>
#include "clock.h" #include <asm/plat-s3c24xx/clock.h>
#include "devs.h" #include <asm/plat-s3c24xx/devs.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
static struct map_desc nexcoder_iodesc[] __initdata = { static struct map_desc nexcoder_iodesc[] __initdata = {
/* nothing here yet */ /* nothing here yet */

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2410/mach-osiris.c /* linux/arch/arm/mach-s3c2440/mach-osiris.c
* *
* Copyright (c) 2005 Simtec Electronics * Copyright (c) 2005 Simtec Electronics
* http://armlinux.simtec.co.uk/ * http://armlinux.simtec.co.uk/
@ -41,9 +41,9 @@
#include <linux/mtd/nand_ecc.h> #include <linux/mtd/nand_ecc.h>
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
#include "clock.h" #include <asm/plat-s3c24xx/clock.h>
#include "devs.h" #include <asm/plat-s3c24xx/devs.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
/* onboard perihpheral map */ /* onboard perihpheral map */

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2410/mach-rx3715.c /* linux/arch/arm/mach-s3c2440/mach-rx3715.c
* *
* Copyright (c) 2003,2004 Simtec Electronics * Copyright (c) 2003,2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>
@ -46,10 +46,10 @@
#include <asm/arch/nand.h> #include <asm/arch/nand.h>
#include <asm/arch/fb.h> #include <asm/arch/fb.h>
#include "clock.h" #include <asm/plat-s3c24xx/clock.h>
#include "devs.h" #include <asm/plat-s3c24xx/devs.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
#include "pm.h" #include <asm/plat-s3c24xx/pm.h>
static struct map_desc rx3715_iodesc[] __initdata = { static struct map_desc rx3715_iodesc[] __initdata = {
/* dump ISA space somewhere unused */ /* dump ISA space somewhere unused */

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2410/mach-smdk2440.c /* linux/arch/arm/mach-s3c2440/mach-smdk2440.c
* *
* Copyright (c) 2004,2005 Simtec Electronics * Copyright (c) 2004,2005 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>
@ -40,13 +40,13 @@
#include <asm/arch/idle.h> #include <asm/arch/idle.h>
#include <asm/arch/fb.h> #include <asm/arch/fb.h>
#include "s3c2410.h" #include <asm/plat-s3c24xx/s3c2410.h>
#include "s3c2440.h" #include <asm/plat-s3c24xx/s3c2440.h>
#include "clock.h" #include <asm/plat-s3c24xx/clock.h>
#include "devs.h" #include <asm/plat-s3c24xx/devs.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
#include "common-smdk.h" #include <asm/plat-s3c24xx/common-smdk.h>
static struct map_desc smdk2440_iodesc[] __initdata = { static struct map_desc smdk2440_iodesc[] __initdata = {
/* ISA IO Space map (memory space selected by A24) */ /* ISA IO Space map (memory space selected by A24) */

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2410/s3c2440.c /* linux/arch/arm/mach-s3c2440/s3c2440.c
* *
* Copyright (c) 2004-2006 Simtec Electronics * Copyright (c) 2004-2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>
@ -29,9 +29,9 @@
#include <asm/io.h> #include <asm/io.h>
#include <asm/irq.h> #include <asm/irq.h>
#include "s3c2440.h" #include <asm/plat-s3c24xx/s3c2440.h>
#include "devs.h" #include <asm/plat-s3c24xx/devs.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
static struct sys_device s3c2440_sysdev = { static struct sys_device s3c2440_sysdev = {
.cls = &s3c2440_sysclass, .cls = &s3c2440_sysclass,

View File

@ -0,0 +1,27 @@
# arch/arm/mach-s3c2442/Kconfig
#
# Copyright 2007 Simtec Electronics
#
# Licensed under GPLv2
config CPU_S3C2442
bool
depends on ARCH_S3C2420
select S3C2410_CLOCK
select S3C2410_GPIO
select S3C2410_PM if PM
select CPU_S3C244X
help
Support for S3C2442 Samsung Mobile CPU based systems.
menu "S3C2442 Machines"
config SMDK2440_CPU2442
bool "SMDM2440 with S3C2442 CPU module"
depends on ARCH_S3C2440
select CPU_S3C2442
endmenu

View File

@ -0,0 +1,16 @@
# arch/arm/mach-s3c2442/Makefile
#
# Copyright 2007 Simtec Electronics
#
# Licensed under GPLv2
obj-y :=
obj-m :=
obj-n :=
obj- :=
obj-$(CONFIG_CPU_S3C2442) += s3c2442.o
obj-$(CONFIG_CPU_S3C2442) += clock.o
# Machine support

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2410/s3c2442-clock.c /* linux/arch/arm/mach-s3c2442/clock.c
* *
* Copyright (c) 2004-2005 Simtec Electronics * Copyright (c) 2004-2005 Simtec Electronics
* http://armlinux.simtec.co.uk/ * http://armlinux.simtec.co.uk/
@ -41,8 +41,8 @@
#include <asm/arch/regs-clock.h> #include <asm/arch/regs-clock.h>
#include "clock.h" #include <asm/plat-s3c24xx/clock.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
/* S3C2442 extended clock support */ /* S3C2442 extended clock support */

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2410/s3c2442.c /* linux/arch/arm/mach-s3c2442/s3c2442.c
* *
* Copyright (c) 2006 Simtec Electronics * Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>
@ -19,8 +19,8 @@
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <linux/sysdev.h> #include <linux/sysdev.h>
#include "s3c2442.h" #include <asm/plat-s3c24xx/s3c2442.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
static struct sys_device s3c2442_sysdev = { static struct sys_device s3c2442_sysdev = {
.cls = &s3c2442_sysclass, .cls = &s3c2442_sysclass,

View File

@ -0,0 +1,96 @@
# arch/arm/plat-s3c24xx/Kconfig
#
# Copyright 2007 Simtec Electronics
#
# Licensed under GPLv2
config PLAT_S3C24XX
bool
depends on ARCH_S3C2410
default y
help
Base platform code for any Samsung S3C device
config CPU_S3C244X
bool
depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442)
help
Support for S3C2440 and S3C2442 Samsung Mobile CPU based systems.
config PM_SIMTEC
bool
help
Common power management code for systems that are
compatible with the Simtec style of power management
config S3C2410_BOOT_WATCHDOG
bool "S3C2410 Initialisation watchdog"
depends on ARCH_S3C2410 && S3C2410_WATCHDOG
help
Say y to enable the watchdog during the kernel decompression
stage. If the kernel fails to uncompress, then the watchdog
will trigger a reset and the system should restart.
config S3C2410_BOOT_ERROR_RESET
bool "S3C2410 Reboot on decompression error"
depends on ARCH_S3C2410
help
Say y here to use the watchdog to reset the system if the
kernel decompressor detects an error during decompression.
config S3C2410_PM_DEBUG
bool "S3C2410 PM Suspend debug"
depends on ARCH_S3C2410 && PM
help
Say Y here if you want verbose debugging from the PM Suspend and
Resume code. See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt>
for more information.
config S3C2410_PM_CHECK
bool "S3C2410 PM Suspend Memory CRC"
depends on ARCH_S3C2410 && PM && CRC32
help
Enable the PM code's memory area checksum over sleep. This option
will generate CRCs of all blocks of memory, and store them before
going to sleep. The blocks are then checked on resume for any
errors.
config S3C2410_PM_CHECK_CHUNKSIZE
int "S3C2410 PM Suspend CRC Chunksize (KiB)"
depends on ARCH_S3C2410 && PM && S3C2410_PM_CHECK
default 64
help
Set the chunksize in Kilobytes of the CRC for checking memory
corruption over suspend and resume. A smaller value will mean that
the CRC data block will take more memory, but wil identify any
faults with better precision.
config S3C2410_LOWLEVEL_UART_PORT
int "S3C2410 UART to use for low-level messages"
default 0
help
Choice of which UART port to use for the low-level messages,
such as the `Uncompressing...` at start time. The value of
this configuration should be between zero and two. The port
must have been initialised by the boot-loader before use.
config S3C2410_DMA
bool "S3C2410 DMA support"
depends on ARCH_S3C2410
help
S3C2410 DMA support. This is needed for drivers like sound which
use the S3C2410's DMA system to move data to and from the
peripheral blocks.
config S3C2410_DMA_DEBUG
bool "S3C2410 DMA support debug"
depends on ARCH_S3C2410 && S3C2410_DMA
help
Enable debugging output for the DMA code. This option sends info
to the kernel log, at priority KERN_DEBUG.
config MACH_SMDK
bool
help
Common machine code for SMDK2410 and SMDK2440

View File

@ -0,0 +1,30 @@
# arch/arm/plat-s3c24xx/Makefile
#
# Copyright 2007 Simtec Electronics
#
# Licensed under GPLv2
obj-y :=
obj-m :=
obj-n :=
obj- :=
# Core files
obj-y += cpu.o
obj-y += irq.o
obj-y += devs.o
obj-y += gpio.o
obj-y += time.o
obj-y += clock.o
# Architecture dependant builds
obj-$(CONFIG_CPU_S3C244X) += s3c244x.o
obj-$(CONFIG_CPU_S3C244X) += s3c244x-irq.o
obj-$(CONFIG_PM_SIMTEC) += pm-simtec.o
obj-$(CONFIG_PM) += pm.o
obj-$(CONFIG_PM) += sleep.o
obj-$(CONFIG_S3C2410_DMA) += dma.o
obj-$(CONFIG_MACH_SMDK) += common-smdk.o

View File

@ -0,0 +1,449 @@
/* linux/arch/arm/plat-s3c24xx/clock.c
*
* Copyright (c) 2004-2005 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* S3C24XX Core clock control support
*
* Based on, and code from linux/arch/arm/mach-versatile/clock.c
**
** Copyright (C) 2004 ARM Limited.
** Written by Deep Blue Solutions Limited.
*
*
* 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/platform_device.h>
#include <linux/sysdev.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/clk.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-clock.h>
#include <asm/arch/regs-gpio.h>
#include <asm/plat-s3c24xx/clock.h>
#include <asm/plat-s3c24xx/cpu.h>
/* clock information */
static LIST_HEAD(clocks);
DEFINE_MUTEX(clocks_mutex);
/* enable and disable calls for use with the clk struct */
static int clk_null_enable(struct clk *clk, int enable)
{
return 0;
}
/* Clock API calls */
struct clk *clk_get(struct device *dev, const char *id)
{
struct clk *p;
struct clk *clk = ERR_PTR(-ENOENT);
int idno;
if (dev == NULL || dev->bus != &platform_bus_type)
idno = -1;
else
idno = to_platform_device(dev)->id;
mutex_lock(&clocks_mutex);
list_for_each_entry(p, &clocks, list) {
if (p->id == idno &&
strcmp(id, p->name) == 0 &&
try_module_get(p->owner)) {
clk = p;
break;
}
}
/* check for the case where a device was supplied, but the
* clock that was being searched for is not device specific */
if (IS_ERR(clk)) {
list_for_each_entry(p, &clocks, list) {
if (p->id == -1 && strcmp(id, p->name) == 0 &&
try_module_get(p->owner)) {
clk = p;
break;
}
}
}
mutex_unlock(&clocks_mutex);
return clk;
}
void clk_put(struct clk *clk)
{
module_put(clk->owner);
}
int clk_enable(struct clk *clk)
{
if (IS_ERR(clk) || clk == NULL)
return -EINVAL;
clk_enable(clk->parent);
mutex_lock(&clocks_mutex);
if ((clk->usage++) == 0)
(clk->enable)(clk, 1);
mutex_unlock(&clocks_mutex);
return 0;
}
void clk_disable(struct clk *clk)
{
if (IS_ERR(clk) || clk == NULL)
return;
mutex_lock(&clocks_mutex);
if ((--clk->usage) == 0)
(clk->enable)(clk, 0);
mutex_unlock(&clocks_mutex);
clk_disable(clk->parent);
}
unsigned long clk_get_rate(struct clk *clk)
{
if (IS_ERR(clk))
return 0;
if (clk->rate != 0)
return clk->rate;
if (clk->get_rate != NULL)
return (clk->get_rate)(clk);
if (clk->parent != NULL)
return clk_get_rate(clk->parent);
return clk->rate;
}
long clk_round_rate(struct clk *clk, unsigned long rate)
{
if (!IS_ERR(clk) && clk->round_rate)
return (clk->round_rate)(clk, rate);
return rate;
}
int clk_set_rate(struct clk *clk, unsigned long rate)
{
int ret;
if (IS_ERR(clk))
return -EINVAL;
mutex_lock(&clocks_mutex);
ret = (clk->set_rate)(clk, rate);
mutex_unlock(&clocks_mutex);
return ret;
}
struct clk *clk_get_parent(struct clk *clk)
{
return clk->parent;
}
int clk_set_parent(struct clk *clk, struct clk *parent)
{
int ret = 0;
if (IS_ERR(clk))
return -EINVAL;
mutex_lock(&clocks_mutex);
if (clk->set_parent)
ret = (clk->set_parent)(clk, parent);
mutex_unlock(&clocks_mutex);
return ret;
}
EXPORT_SYMBOL(clk_get);
EXPORT_SYMBOL(clk_put);
EXPORT_SYMBOL(clk_enable);
EXPORT_SYMBOL(clk_disable);
EXPORT_SYMBOL(clk_get_rate);
EXPORT_SYMBOL(clk_round_rate);
EXPORT_SYMBOL(clk_set_rate);
EXPORT_SYMBOL(clk_get_parent);
EXPORT_SYMBOL(clk_set_parent);
/* base clocks */
struct clk clk_xtal = {
.name = "xtal",
.id = -1,
.rate = 0,
.parent = NULL,
.ctrlbit = 0,
};
struct clk clk_mpll = {
.name = "mpll",
.id = -1,
};
struct clk clk_upll = {
.name = "upll",
.id = -1,
.parent = NULL,
.ctrlbit = 0,
};
struct clk clk_f = {
.name = "fclk",
.id = -1,
.rate = 0,
.parent = &clk_mpll,
.ctrlbit = 0,
};
struct clk clk_h = {
.name = "hclk",
.id = -1,
.rate = 0,
.parent = NULL,
.ctrlbit = 0,
};
struct clk clk_p = {
.name = "pclk",
.id = -1,
.rate = 0,
.parent = NULL,
.ctrlbit = 0,
};
struct clk clk_usb_bus = {
.name = "usb-bus",
.id = -1,
.rate = 0,
.parent = &clk_upll,
};
/* clocks that could be registered by external code */
static int s3c24xx_dclk_enable(struct clk *clk, int enable)
{
unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON);
if (enable)
dclkcon |= clk->ctrlbit;
else
dclkcon &= ~clk->ctrlbit;
__raw_writel(dclkcon, S3C24XX_DCLKCON);
return 0;
}
static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent)
{
unsigned long dclkcon;
unsigned int uclk;
if (parent == &clk_upll)
uclk = 1;
else if (parent == &clk_p)
uclk = 0;
else
return -EINVAL;
clk->parent = parent;
dclkcon = __raw_readl(S3C24XX_DCLKCON);
if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) {
if (uclk)
dclkcon |= S3C2410_DCLKCON_DCLK0_UCLK;
else
dclkcon &= ~S3C2410_DCLKCON_DCLK0_UCLK;
} else {
if (uclk)
dclkcon |= S3C2410_DCLKCON_DCLK1_UCLK;
else
dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK;
}
__raw_writel(dclkcon, S3C24XX_DCLKCON);
return 0;
}
static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent)
{
unsigned long mask;
unsigned long source;
/* calculate the MISCCR setting for the clock */
if (parent == &clk_xtal)
source = S3C2410_MISCCR_CLK0_MPLL;
else if (parent == &clk_upll)
source = S3C2410_MISCCR_CLK0_UPLL;
else if (parent == &clk_f)
source = S3C2410_MISCCR_CLK0_FCLK;
else if (parent == &clk_h)
source = S3C2410_MISCCR_CLK0_HCLK;
else if (parent == &clk_p)
source = S3C2410_MISCCR_CLK0_PCLK;
else if (clk == &s3c24xx_clkout0 && parent == &s3c24xx_dclk0)
source = S3C2410_MISCCR_CLK0_DCLK0;
else if (clk == &s3c24xx_clkout1 && parent == &s3c24xx_dclk1)
source = S3C2410_MISCCR_CLK0_DCLK0;
else
return -EINVAL;
clk->parent = parent;
if (clk == &s3c24xx_dclk0)
mask = S3C2410_MISCCR_CLK0_MASK;
else {
source <<= 4;
mask = S3C2410_MISCCR_CLK1_MASK;
}
s3c2410_modify_misccr(mask, source);
return 0;
}
/* external clock definitions */
struct clk s3c24xx_dclk0 = {
.name = "dclk0",
.id = -1,
.ctrlbit = S3C2410_DCLKCON_DCLK0EN,
.enable = s3c24xx_dclk_enable,
.set_parent = s3c24xx_dclk_setparent,
};
struct clk s3c24xx_dclk1 = {
.name = "dclk1",
.id = -1,
.ctrlbit = S3C2410_DCLKCON_DCLK0EN,
.enable = s3c24xx_dclk_enable,
.set_parent = s3c24xx_dclk_setparent,
};
struct clk s3c24xx_clkout0 = {
.name = "clkout0",
.id = -1,
.set_parent = s3c24xx_clkout_setparent,
};
struct clk s3c24xx_clkout1 = {
.name = "clkout1",
.id = -1,
.set_parent = s3c24xx_clkout_setparent,
};
struct clk s3c24xx_uclk = {
.name = "uclk",
.id = -1,
};
/* initialise the clock system */
int s3c24xx_register_clock(struct clk *clk)
{
clk->owner = THIS_MODULE;
if (clk->enable == NULL)
clk->enable = clk_null_enable;
/* add to the list of available clocks */
mutex_lock(&clocks_mutex);
list_add(&clk->list, &clocks);
mutex_unlock(&clocks_mutex);
return 0;
}
/* initalise all the clocks */
int __init s3c24xx_setup_clocks(unsigned long xtal,
unsigned long fclk,
unsigned long hclk,
unsigned long pclk)
{
printk(KERN_INFO "S3C24XX Clocks, (c) 2004 Simtec Electronics\n");
/* initialise the main system clocks */
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;
/* assume uart clocks are correctly setup */
/* register our clocks */
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");
if (s3c24xx_register_clock(&clk_f) < 0)
printk(KERN_ERR "failed to register cpu fclk\n");
if (s3c24xx_register_clock(&clk_h) < 0)
printk(KERN_ERR "failed to register cpu hclk\n");
if (s3c24xx_register_clock(&clk_p) < 0)
printk(KERN_ERR "failed to register cpu pclk\n");
return 0;
}

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2410/common-smdk.c /* linux/arch/arm/plat-s3c24xx/common-smdk.c
* *
* Copyright (c) 2006 Simtec Electronics * Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>
@ -38,9 +38,9 @@
#include <asm/arch/nand.h> #include <asm/arch/nand.h>
#include "common-smdk.h" #include <asm/plat-s3c24xx/common-smdk.h>
#include "devs.h" #include <asm/plat-s3c24xx/devs.h>
#include "pm.h" #include <asm/plat-s3c24xx/pm.h>
/* LED devices */ /* LED devices */

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2410/cpu.c /* linux/arch/arm/plat-s3c24xx/cpu.c
* *
* Copyright (c) 2004-2005 Simtec Electronics * Copyright (c) 2004-2005 Simtec Electronics
* http://www.simtec.co.uk/products/SWLINUX/ * http://www.simtec.co.uk/products/SWLINUX/
@ -40,15 +40,15 @@
#include <asm/arch/regs-gpio.h> #include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-serial.h> #include <asm/arch/regs-serial.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
#include "devs.h" #include <asm/plat-s3c24xx/devs.h>
#include "clock.h" #include <asm/plat-s3c24xx/clock.h>
#include "s3c2400.h" #include <asm/plat-s3c24xx/s3c2400.h>
#include "s3c2410.h" #include <asm/plat-s3c24xx/s3c2410.h>
#include "s3c2412.h" #include <asm/plat-s3c24xx/s3c2412.h>
#include "s3c244x.h" #include "s3c244x.h"
#include "s3c2440.h" #include <asm/plat-s3c24xx/s3c2440.h>
#include "s3c2442.h" #include <asm/plat-s3c24xx/s3c2442.h>
struct cpu_table { struct cpu_table {
unsigned long idcode; unsigned long idcode;

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2410/devs.c /* linux/arch/arm/plat-s3c24xx/devs.c
* *
* Copyright (c) 2004 Simtec Electronics * Copyright (c) 2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>
@ -30,8 +30,8 @@
#include <asm/arch/regs-serial.h> #include <asm/arch/regs-serial.h>
#include "devs.h" #include <asm/plat-s3c24xx/devs.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
/* Serial port registrations */ /* Serial port registrations */

1441
arch/arm/plat-s3c24xx/dma.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,188 @@
/* linux/arch/arm/plat-s3c24xx/gpio.c
*
* Copyright (c) 2004-2005 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* S3C24XX GPIO 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/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)
{
void __iomem *base = S3C24XX_GPIO_BASE(pin);
unsigned long mask;
unsigned long con;
unsigned long flags;
if (pin < S3C2410_GPIO_BANKB) {
mask = 1 << S3C2410_GPIO_OFFSET(pin);
} else {
mask = 3 << S3C2410_GPIO_OFFSET(pin)*2;
}
switch (function) {
case S3C2410_GPIO_LEAVE:
mask = 0;
function = 0;
break;
case S3C2410_GPIO_INPUT:
case S3C2410_GPIO_OUTPUT:
case S3C2410_GPIO_SFN2:
case S3C2410_GPIO_SFN3:
if (pin < S3C2410_GPIO_BANKB) {
function -= 1;
function &= 1;
function <<= S3C2410_GPIO_OFFSET(pin);
} else {
function &= 3;
function <<= S3C2410_GPIO_OFFSET(pin)*2;
}
}
/* modify the specified register wwith IRQs off */
local_irq_save(flags);
con = __raw_readl(base + 0x00);
con &= ~mask;
con |= function;
__raw_writel(con, base + 0x00);
local_irq_restore(flags);
}
EXPORT_SYMBOL(s3c2410_gpio_cfgpin);
unsigned int s3c2410_gpio_getcfg(unsigned int pin)
{
void __iomem *base = S3C24XX_GPIO_BASE(pin);
unsigned long val = __raw_readl(base);
if (pin < S3C2410_GPIO_BANKB) {
val >>= S3C2410_GPIO_OFFSET(pin);
val &= 1;
val += 1;
} else {
val >>= S3C2410_GPIO_OFFSET(pin)*2;
val &= 3;
}
return val | S3C2410_GPIO_INPUT;
}
EXPORT_SYMBOL(s3c2410_gpio_getcfg);
void s3c2410_gpio_pullup(unsigned int pin, unsigned int to)
{
void __iomem *base = S3C24XX_GPIO_BASE(pin);
unsigned long offs = S3C2410_GPIO_OFFSET(pin);
unsigned long flags;
unsigned long up;
if (pin < S3C2410_GPIO_BANKB)
return;
local_irq_save(flags);
up = __raw_readl(base + 0x08);
up &= ~(1L << offs);
up |= to << offs;
__raw_writel(up, base + 0x08);
local_irq_restore(flags);
}
EXPORT_SYMBOL(s3c2410_gpio_pullup);
void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)
{
void __iomem *base = S3C24XX_GPIO_BASE(pin);
unsigned long offs = S3C2410_GPIO_OFFSET(pin);
unsigned long flags;
unsigned long dat;
local_irq_save(flags);
dat = __raw_readl(base + 0x04);
dat &= ~(1 << offs);
dat |= to << offs;
__raw_writel(dat, base + 0x04);
local_irq_restore(flags);
}
EXPORT_SYMBOL(s3c2410_gpio_setpin);
unsigned int s3c2410_gpio_getpin(unsigned int pin)
{
void __iomem *base = S3C24XX_GPIO_BASE(pin);
unsigned long offs = S3C2410_GPIO_OFFSET(pin);
return __raw_readl(base + 0x04) & (1<< offs);
}
EXPORT_SYMBOL(s3c2410_gpio_getpin);
unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change)
{
unsigned long flags;
unsigned long misccr;
local_irq_save(flags);
misccr = __raw_readl(S3C24XX_MISCCR);
misccr &= ~clear;
misccr ^= change;
__raw_writel(misccr, S3C24XX_MISCCR);
local_irq_restore(flags);
return misccr;
}
EXPORT_SYMBOL(s3c2410_modify_misccr);
int s3c2410_gpio_getirq(unsigned int pin)
{
if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15)
return -1; /* not valid interrupts */
if (pin < S3C2410_GPG0 && pin > S3C2410_GPF7)
return -1; /* not valid pin */
if (pin < S3C2410_GPF4)
return (pin - S3C2410_GPF0) + IRQ_EINT0;
if (pin < S3C2410_GPG0)
return (pin - S3C2410_GPF4) + IRQ_EINT4;
return (pin - S3C2410_GPG0) + IRQ_EINT8;
}
EXPORT_SYMBOL(s3c2410_gpio_getirq);

801
arch/arm/plat-s3c24xx/irq.c Normal file
View File

@ -0,0 +1,801 @@
/* linux/arch/arm/plat-s3c24xx/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:
*
* 22-Jul-2004 Ben Dooks <ben@simtec.co.uk>
* Fixed compile warnings
*
* 22-Jul-2004 Roc Wu <cooloney@yahoo.com.cn>
* Fixed s3c_extirq_type
*
* 21-Jul-2004 Arnaud Patard (Rtp) <arnaud.patard@rtp-net.org>
* Addition of ADC/TC demux
*
* 04-Oct-2004 Klaus Fetscher <k.fetscher@fetron.de>
* Fix for set_irq_type() on low EINT numbers
*
* 05-Oct-2004 Ben Dooks <ben@simtec.co.uk>
* Tidy up KF's patch and sort out new release
*
* 05-Oct-2004 Ben Dooks <ben@simtec.co.uk>
* Add support for power management controls
*
* 04-Nov-2004 Ben Dooks
* Fix standard IRQ wake for EINT0..4 and RTC
*
* 22-Feb-2005 Ben Dooks
* Fixed edge-triggering on ADC IRQ
*
* 28-Jun-2005 Ben Dooks
* Mark IRQ_LCD valid
*
* 25-Jul-2005 Ben Dooks
* Split the S3C2440 IRQ code to seperate file
*/
#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 <asm/plat-s3c24xx/cpu.h>
#include <asm/plat-s3c24xx/pm.h>
#include <asm/plat-s3c24xx/irq.h>
/* wakeup irq control */
#ifdef CONFIG_PM
/* state for IRQs over sleep */
/* default is to allow for EINT0..EINT15, and IRQ_RTC as wakeup sources
*
* set bit to 1 in allow bitfield to enable the wakeup settings on it
*/
unsigned long s3c_irqwake_intallow = 1L << (IRQ_RTC - IRQ_EINT0) | 0xfL;
unsigned long s3c_irqwake_intmask = 0xffffffffL;
unsigned long s3c_irqwake_eintallow = 0x0000fff0L;
unsigned long s3c_irqwake_eintmask = 0xffffffffL;
int
s3c_irq_wake(unsigned int irqno, unsigned int state)
{
unsigned long irqbit = 1 << (irqno - IRQ_EINT0);
if (!(s3c_irqwake_intallow & irqbit))
return -ENOENT;
printk(KERN_INFO "wake %s for irq %d\n",
state ? "enabled" : "disabled", irqno);
if (!state)
s3c_irqwake_intmask |= irqbit;
else
s3c_irqwake_intmask &= ~irqbit;
return 0;
}
static int
s3c_irqext_wake(unsigned int irqno, unsigned int state)
{
unsigned long bit = 1L << (irqno - EXTINT_OFF);
if (!(s3c_irqwake_eintallow & bit))
return -ENOENT;
printk(KERN_INFO "wake %s for irq %d\n",
state ? "enabled" : "disabled", irqno);
if (!state)
s3c_irqwake_eintmask |= bit;
else
s3c_irqwake_eintmask &= ~bit;
return 0;
}
#else
#define s3c_irqext_wake NULL
#define s3c_irq_wake NULL
#endif
static void
s3c_irq_mask(unsigned int irqno)
{
unsigned long mask;
irqno -= IRQ_EINT0;
mask = __raw_readl(S3C2410_INTMSK);
mask |= 1UL << irqno;
__raw_writel(mask, S3C2410_INTMSK);
}
static inline void
s3c_irq_ack(unsigned int irqno)
{
unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
__raw_writel(bitval, S3C2410_SRCPND);
__raw_writel(bitval, S3C2410_INTPND);
}
static inline void
s3c_irq_maskack(unsigned int irqno)
{
unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
unsigned long mask;
mask = __raw_readl(S3C2410_INTMSK);
__raw_writel(mask|bitval, S3C2410_INTMSK);
__raw_writel(bitval, S3C2410_SRCPND);
__raw_writel(bitval, S3C2410_INTPND);
}
static void
s3c_irq_unmask(unsigned int irqno)
{
unsigned long mask;
if (irqno != IRQ_TIMER4 && irqno != IRQ_EINT8t23)
irqdbf2("s3c_irq_unmask %d\n", irqno);
irqno -= IRQ_EINT0;
mask = __raw_readl(S3C2410_INTMSK);
mask &= ~(1UL << irqno);
__raw_writel(mask, S3C2410_INTMSK);
}
struct irq_chip s3c_irq_level_chip = {
.name = "s3c-level",
.ack = s3c_irq_maskack,
.mask = s3c_irq_mask,
.unmask = s3c_irq_unmask,
.set_wake = s3c_irq_wake
};
static struct irq_chip s3c_irq_chip = {
.name = "s3c",
.ack = s3c_irq_ack,
.mask = s3c_irq_mask,
.unmask = s3c_irq_unmask,
.set_wake = s3c_irq_wake
};
static void
s3c_irqext_mask(unsigned int irqno)
{
unsigned long mask;
irqno -= EXTINT_OFF;
mask = __raw_readl(S3C24XX_EINTMASK);
mask |= ( 1UL << irqno);
__raw_writel(mask, S3C24XX_EINTMASK);
}
static void
s3c_irqext_ack(unsigned int irqno)
{
unsigned long req;
unsigned long bit;
unsigned long mask;
bit = 1UL << (irqno - EXTINT_OFF);
mask = __raw_readl(S3C24XX_EINTMASK);
__raw_writel(bit, S3C24XX_EINTPEND);
req = __raw_readl(S3C24XX_EINTPEND);
req &= ~mask;
/* not sure if we should be acking the parent irq... */
if (irqno <= IRQ_EINT7 ) {
if ((req & 0xf0) == 0)
s3c_irq_ack(IRQ_EINT4t7);
} else {
if ((req >> 8) == 0)
s3c_irq_ack(IRQ_EINT8t23);
}
}
static void
s3c_irqext_unmask(unsigned int irqno)
{
unsigned long mask;
irqno -= EXTINT_OFF;
mask = __raw_readl(S3C24XX_EINTMASK);
mask &= ~( 1UL << irqno);
__raw_writel(mask, S3C24XX_EINTMASK);
}
int
s3c_irqext_type(unsigned int irq, unsigned int type)
{
void __iomem *extint_reg;
void __iomem *gpcon_reg;
unsigned long gpcon_offset, extint_offset;
unsigned long newvalue = 0, value;
if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3))
{
gpcon_reg = S3C2410_GPFCON;
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 = 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 = 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 = S3C24XX_EXTINT2;
gpcon_offset = (irq - IRQ_EINT8) * 2;
extint_offset = (irq - IRQ_EINT16) * 4;
} else
return -1;
/* Set the GPIO to external interrupt mode */
value = __raw_readl(gpcon_reg);
value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset);
__raw_writel(value, gpcon_reg);
/* Set the external interrupt to pointed trigger type */
switch (type)
{
case IRQT_NOEDGE:
printk(KERN_WARNING "No edge setting!\n");
break;
case IRQT_RISING:
newvalue = S3C2410_EXTINT_RISEEDGE;
break;
case IRQT_FALLING:
newvalue = S3C2410_EXTINT_FALLEDGE;
break;
case IRQT_BOTHEDGE:
newvalue = S3C2410_EXTINT_BOTHEDGE;
break;
case IRQT_LOW:
newvalue = S3C2410_EXTINT_LOWLEV;
break;
case IRQT_HIGH:
newvalue = S3C2410_EXTINT_HILEV;
break;
default:
printk(KERN_ERR "No such irq type %d", type);
return -1;
}
value = __raw_readl(extint_reg);
value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset);
__raw_writel(value, extint_reg);
return 0;
}
static struct irq_chip s3c_irqext_chip = {
.name = "s3c-ext",
.mask = s3c_irqext_mask,
.unmask = s3c_irqext_unmask,
.ack = s3c_irqext_ack,
.set_type = s3c_irqext_type,
.set_wake = s3c_irqext_wake
};
static struct irq_chip s3c_irq_eint0t4 = {
.name = "s3c-ext0",
.ack = s3c_irq_ack,
.mask = s3c_irq_mask,
.unmask = s3c_irq_unmask,
.set_wake = s3c_irq_wake,
.set_type = s3c_irqext_type,
};
/* mask values for the parent registers for each of the interrupt types */
#define INTMSK_UART0 (1UL << (IRQ_UART0 - IRQ_EINT0))
#define INTMSK_UART1 (1UL << (IRQ_UART1 - IRQ_EINT0))
#define INTMSK_UART2 (1UL << (IRQ_UART2 - IRQ_EINT0))
#define INTMSK_ADCPARENT (1UL << (IRQ_ADCPARENT - IRQ_EINT0))
/* UART0 */
static void
s3c_irq_uart0_mask(unsigned int irqno)
{
s3c_irqsub_mask(irqno, INTMSK_UART0, 7);
}
static void
s3c_irq_uart0_unmask(unsigned int irqno)
{
s3c_irqsub_unmask(irqno, INTMSK_UART0);
}
static void
s3c_irq_uart0_ack(unsigned int irqno)
{
s3c_irqsub_maskack(irqno, INTMSK_UART0, 7);
}
static struct irq_chip s3c_irq_uart0 = {
.name = "s3c-uart0",
.mask = s3c_irq_uart0_mask,
.unmask = s3c_irq_uart0_unmask,
.ack = s3c_irq_uart0_ack,
};
/* UART1 */
static void
s3c_irq_uart1_mask(unsigned int irqno)
{
s3c_irqsub_mask(irqno, INTMSK_UART1, 7 << 3);
}
static void
s3c_irq_uart1_unmask(unsigned int irqno)
{
s3c_irqsub_unmask(irqno, INTMSK_UART1);
}
static void
s3c_irq_uart1_ack(unsigned int irqno)
{
s3c_irqsub_maskack(irqno, INTMSK_UART1, 7 << 3);
}
static struct irq_chip s3c_irq_uart1 = {
.name = "s3c-uart1",
.mask = s3c_irq_uart1_mask,
.unmask = s3c_irq_uart1_unmask,
.ack = s3c_irq_uart1_ack,
};
/* UART2 */
static void
s3c_irq_uart2_mask(unsigned int irqno)
{
s3c_irqsub_mask(irqno, INTMSK_UART2, 7 << 6);
}
static void
s3c_irq_uart2_unmask(unsigned int irqno)
{
s3c_irqsub_unmask(irqno, INTMSK_UART2);
}
static void
s3c_irq_uart2_ack(unsigned int irqno)
{
s3c_irqsub_maskack(irqno, INTMSK_UART2, 7 << 6);
}
static struct irq_chip s3c_irq_uart2 = {
.name = "s3c-uart2",
.mask = s3c_irq_uart2_mask,
.unmask = s3c_irq_uart2_unmask,
.ack = s3c_irq_uart2_ack,
};
/* ADC and Touchscreen */
static void
s3c_irq_adc_mask(unsigned int irqno)
{
s3c_irqsub_mask(irqno, INTMSK_ADCPARENT, 3 << 9);
}
static void
s3c_irq_adc_unmask(unsigned int irqno)
{
s3c_irqsub_unmask(irqno, INTMSK_ADCPARENT);
}
static void
s3c_irq_adc_ack(unsigned int irqno)
{
s3c_irqsub_ack(irqno, INTMSK_ADCPARENT, 3 << 9);
}
static struct irq_chip s3c_irq_adc = {
.name = "s3c-adc",
.mask = s3c_irq_adc_mask,
.unmask = s3c_irq_adc_unmask,
.ack = s3c_irq_adc_ack,
};
/* irq demux for adc */
static void s3c_irq_demux_adc(unsigned int irq,
struct irq_desc *desc)
{
unsigned int subsrc, submsk;
unsigned int offset = 9;
struct irq_desc *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 >>= offset;
subsrc &= 3;
if (subsrc != 0) {
if (subsrc & 1) {
mydesc = irq_desc + IRQ_TC;
desc_handle_irq(IRQ_TC, mydesc);
}
if (subsrc & 2) {
mydesc = irq_desc + IRQ_ADC;
desc_handle_irq(IRQ_ADC, mydesc);
}
}
}
static void s3c_irq_demux_uart(unsigned int start)
{
unsigned int subsrc, submsk;
unsigned int offset = start - IRQ_S3CUART_RX0;
struct irq_desc *desc;
/* read the current pending interrupts, and the mask
* for what it is available */
subsrc = __raw_readl(S3C2410_SUBSRCPND);
submsk = __raw_readl(S3C2410_INTSUBMSK);
irqdbf2("s3c_irq_demux_uart: start=%d (%d), subsrc=0x%08x,0x%08x\n",
start, offset, subsrc, submsk);
subsrc &= ~submsk;
subsrc >>= offset;
subsrc &= 7;
if (subsrc != 0) {
desc = irq_desc + start;
if (subsrc & 1)
desc_handle_irq(start, desc);
desc++;
if (subsrc & 2)
desc_handle_irq(start+1, desc);
desc++;
if (subsrc & 4)
desc_handle_irq(start+2, desc);
}
}
/* uart demux entry points */
static void
s3c_irq_demux_uart0(unsigned int irq,
struct irq_desc *desc)
{
irq = irq;
s3c_irq_demux_uart(IRQ_S3CUART_RX0);
}
static void
s3c_irq_demux_uart1(unsigned int irq,
struct irq_desc *desc)
{
irq = irq;
s3c_irq_demux_uart(IRQ_S3CUART_RX1);
}
static void
s3c_irq_demux_uart2(unsigned int irq,
struct irq_desc *desc)
{
irq = irq;
s3c_irq_demux_uart(IRQ_S3CUART_RX2);
}
static void
s3c_irq_demux_extint8(unsigned int irq,
struct irq_desc *desc)
{
unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);
eintpnd &= ~eintmsk;
eintpnd &= ~0xff; /* ignore lower irqs */
/* we may as well handle all the pending IRQs here */
while (eintpnd) {
irq = __ffs(eintpnd);
eintpnd &= ~(1<<irq);
irq += (IRQ_EINT4 - 4);
desc_handle_irq(irq, irq_desc + irq);
}
}
static void
s3c_irq_demux_extint4t7(unsigned int irq,
struct irq_desc *desc)
{
unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);
eintpnd &= ~eintmsk;
eintpnd &= 0xff; /* only lower irqs */
/* we may as well handle all the pending IRQs here */
while (eintpnd) {
irq = __ffs(eintpnd);
eintpnd &= ~(1<<irq);
irq += (IRQ_EINT4 - 4);
desc_handle_irq(irq, irq_desc + irq);
}
}
#ifdef CONFIG_PM
static struct sleep_save irq_save[] = {
SAVE_ITEM(S3C2410_INTMSK),
SAVE_ITEM(S3C2410_INTSUBMSK),
};
/* the extint values move between the s3c2410/s3c2440 and the s3c2412
* so we use an array to hold them, and to calculate the address of
* the register at run-time
*/
static unsigned long save_extint[3];
static unsigned long save_eintflt[4];
static unsigned long save_eintmask;
int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(save_extint); i++)
save_extint[i] = __raw_readl(S3C24XX_EXTINT0 + (i*4));
for (i = 0; i < ARRAY_SIZE(save_eintflt); i++)
save_eintflt[i] = __raw_readl(S3C24XX_EINFLT0 + (i*4));
s3c2410_pm_do_save(irq_save, ARRAY_SIZE(irq_save));
save_eintmask = __raw_readl(S3C24XX_EINTMASK);
return 0;
}
int s3c24xx_irq_resume(struct sys_device *dev)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(save_extint); i++)
__raw_writel(save_extint[i], S3C24XX_EXTINT0 + (i*4));
for (i = 0; i < ARRAY_SIZE(save_eintflt); i++)
__raw_writel(save_eintflt[i], S3C24XX_EINFLT0 + (i*4));
s3c2410_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));
__raw_writel(save_eintmask, S3C24XX_EINTMASK);
return 0;
}
#else
#define s3c24xx_irq_suspend NULL
#define s3c24xx_irq_resume NULL
#endif
/* s3c24xx_init_irq
*
* Initialise S3C2410 IRQ system
*/
void __init s3c24xx_init_irq(void)
{
unsigned long pend;
unsigned long last;
int irqno;
int i;
irqdbf("s3c2410_init_irq: clearing interrupt status flags\n");
/* first, clear all interrupts pending... */
last = 0;
for (i = 0; i < 4; i++) {
pend = __raw_readl(S3C24XX_EINTPEND);
if (pend == 0 || pend == last)
break;
__raw_writel(pend, S3C24XX_EINTPEND);
printk("irq: clearing pending ext status %08x\n", (int)pend);
last = pend;
}
last = 0;
for (i = 0; i < 4; i++) {
pend = __raw_readl(S3C2410_INTPND);
if (pend == 0 || pend == last)
break;
__raw_writel(pend, S3C2410_SRCPND);
__raw_writel(pend, S3C2410_INTPND);
printk("irq: clearing pending status %08x\n", (int)pend);
last = pend;
}
last = 0;
for (i = 0; i < 4; i++) {
pend = __raw_readl(S3C2410_SUBSRCPND);
if (pend == 0 || pend == last)
break;
printk("irq: clearing subpending status %08x\n", (int)pend);
__raw_writel(pend, S3C2410_SUBSRCPND);
last = pend;
}
/* register the main interrupts */
irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n");
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:
case IRQ_ADCPARENT:
set_irq_chip(irqno, &s3c_irq_level_chip);
set_irq_handler(irqno, handle_level_irq);
break;
case IRQ_RESERVED6:
case IRQ_RESERVED24:
/* no IRQ here */
break;
default:
//irqdbf("registering irq %d (s3c irq)\n", irqno);
set_irq_chip(irqno, &s3c_irq_chip);
set_irq_handler(irqno, handle_edge_irq);
set_irq_flags(irqno, IRQF_VALID);
}
}
/* setup the cascade irq handlers */
set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint4t7);
set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint8);
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++) {
irqdbf("registering irq %d (ext int)\n", irqno);
set_irq_chip(irqno, &s3c_irq_eint0t4);
set_irq_handler(irqno, handle_edge_irq);
set_irq_flags(irqno, IRQF_VALID);
}
for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) {
irqdbf("registering irq %d (extended s3c irq)\n", irqno);
set_irq_chip(irqno, &s3c_irqext_chip);
set_irq_handler(irqno, handle_edge_irq);
set_irq_flags(irqno, IRQF_VALID);
}
/* register the uart interrupts */
irqdbf("s3c2410: registering external interrupts\n");
for (irqno = IRQ_S3CUART_RX0; irqno <= IRQ_S3CUART_ERR0; irqno++) {
irqdbf("registering irq %d (s3c uart0 irq)\n", irqno);
set_irq_chip(irqno, &s3c_irq_uart0);
set_irq_handler(irqno, handle_level_irq);
set_irq_flags(irqno, IRQF_VALID);
}
for (irqno = IRQ_S3CUART_RX1; irqno <= IRQ_S3CUART_ERR1; irqno++) {
irqdbf("registering irq %d (s3c uart1 irq)\n", irqno);
set_irq_chip(irqno, &s3c_irq_uart1);
set_irq_handler(irqno, handle_level_irq);
set_irq_flags(irqno, IRQF_VALID);
}
for (irqno = IRQ_S3CUART_RX2; irqno <= IRQ_S3CUART_ERR2; irqno++) {
irqdbf("registering irq %d (s3c uart2 irq)\n", irqno);
set_irq_chip(irqno, &s3c_irq_uart2);
set_irq_handler(irqno, handle_level_irq);
set_irq_flags(irqno, IRQF_VALID);
}
for (irqno = IRQ_TC; irqno <= IRQ_ADC; irqno++) {
irqdbf("registering irq %d (s3c adc irq)\n", irqno);
set_irq_chip(irqno, &s3c_irq_adc);
set_irq_handler(irqno, handle_edge_irq);
set_irq_flags(irqno, IRQF_VALID);
}
irqdbf("s3c2410: registered interrupt handlers\n");
}

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2410/pm-simtec.c /* linux/arch/arm/plat-s3c24xx/pm-simtec.c
* *
* Copyright (c) 2004 Simtec Electronics * Copyright (c) 2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>
@ -32,7 +32,7 @@
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include "pm.h" #include <asm/plat-s3c24xx/pm.h>
#define COPYRIGHT ", (c) 2005 Simtec Electronics" #define COPYRIGHT ", (c) 2005 Simtec Electronics"

659
arch/arm/plat-s3c24xx/pm.c Normal file
View File

@ -0,0 +1,659 @@
/* linux/arch/arm/plat-s3c24xx/pm.c
*
* Copyright (c) 2004,2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* S3C24XX Power Manager (Suspend-To-RAM) support
*
* See Documentation/arm/Samsung-S3C24XX/Suspend.txt for more information
*
* 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
*
* Parts based on arch/arm/mach-pxa/pm.c
*
* Thanks to Dimitry Andric for debugging
*/
#include <linux/init.h>
#include <linux/suspend.h>
#include <linux/errno.h>
#include <linux/time.h>
#include <linux/interrupt.h>
#include <linux/crc32.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/serial_core.h>
#include <asm/cacheflush.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/arch/regs-serial.h>
#include <asm/arch/regs-clock.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-mem.h>
#include <asm/arch/regs-irq.h>
#include <asm/mach/time.h>
#include <asm/plat-s3c24xx/pm.h>
/* for external use */
unsigned long s3c_pm_flags;
#define PFX "s3c24xx-pm: "
static struct sleep_save core_save[] = {
SAVE_ITEM(S3C2410_LOCKTIME),
SAVE_ITEM(S3C2410_CLKCON),
/* we restore the timings here, with the proviso that the board
* brings the system up in an slower, or equal frequency setting
* to the original system.
*
* if we cannot guarantee this, then things are going to go very
* wrong here, as we modify the refresh and both pll settings.
*/
SAVE_ITEM(S3C2410_BWSCON),
SAVE_ITEM(S3C2410_BANKCON0),
SAVE_ITEM(S3C2410_BANKCON1),
SAVE_ITEM(S3C2410_BANKCON2),
SAVE_ITEM(S3C2410_BANKCON3),
SAVE_ITEM(S3C2410_BANKCON4),
SAVE_ITEM(S3C2410_BANKCON5),
SAVE_ITEM(S3C2410_CLKDIVN),
SAVE_ITEM(S3C2410_MPLLCON),
SAVE_ITEM(S3C2410_UPLLCON),
SAVE_ITEM(S3C2410_CLKSLOW),
SAVE_ITEM(S3C2410_REFRESH),
};
static struct sleep_save gpio_save[] = {
SAVE_ITEM(S3C2410_GPACON),
SAVE_ITEM(S3C2410_GPADAT),
SAVE_ITEM(S3C2410_GPBCON),
SAVE_ITEM(S3C2410_GPBDAT),
SAVE_ITEM(S3C2410_GPBUP),
SAVE_ITEM(S3C2410_GPCCON),
SAVE_ITEM(S3C2410_GPCDAT),
SAVE_ITEM(S3C2410_GPCUP),
SAVE_ITEM(S3C2410_GPDCON),
SAVE_ITEM(S3C2410_GPDDAT),
SAVE_ITEM(S3C2410_GPDUP),
SAVE_ITEM(S3C2410_GPECON),
SAVE_ITEM(S3C2410_GPEDAT),
SAVE_ITEM(S3C2410_GPEUP),
SAVE_ITEM(S3C2410_GPFCON),
SAVE_ITEM(S3C2410_GPFDAT),
SAVE_ITEM(S3C2410_GPFUP),
SAVE_ITEM(S3C2410_GPGCON),
SAVE_ITEM(S3C2410_GPGDAT),
SAVE_ITEM(S3C2410_GPGUP),
SAVE_ITEM(S3C2410_GPHCON),
SAVE_ITEM(S3C2410_GPHDAT),
SAVE_ITEM(S3C2410_GPHUP),
SAVE_ITEM(S3C2410_DCLKCON),
};
#ifdef CONFIG_S3C2410_PM_DEBUG
#define SAVE_UART(va) \
SAVE_ITEM((va) + S3C2410_ULCON), \
SAVE_ITEM((va) + S3C2410_UCON), \
SAVE_ITEM((va) + S3C2410_UFCON), \
SAVE_ITEM((va) + S3C2410_UMCON), \
SAVE_ITEM((va) + S3C2410_UBRDIV)
static struct sleep_save uart_save[] = {
SAVE_UART(S3C24XX_VA_UART0),
SAVE_UART(S3C24XX_VA_UART1),
#ifndef CONFIG_CPU_S3C2400
SAVE_UART(S3C24XX_VA_UART2),
#endif
};
/* debug
*
* we send the debug to printascii() to allow it to be seen if the
* system never wakes up from the sleep
*/
extern void printascii(const char *);
void pm_dbg(const char *fmt, ...)
{
va_list va;
char buff[256];
va_start(va, fmt);
vsprintf(buff, fmt, va);
va_end(va);
printascii(buff);
}
static void s3c2410_pm_debug_init(void)
{
unsigned long tmp = __raw_readl(S3C2410_CLKCON);
/* re-start uart clocks */
tmp |= S3C2410_CLKCON_UART0;
tmp |= S3C2410_CLKCON_UART1;
tmp |= S3C2410_CLKCON_UART2;
__raw_writel(tmp, S3C2410_CLKCON);
udelay(10);
}
#define DBG(fmt...) pm_dbg(fmt)
#else
#define DBG(fmt...) printk(KERN_DEBUG fmt)
#define s3c2410_pm_debug_init() do { } while(0)
static struct sleep_save uart_save[] = {};
#endif
#if defined(CONFIG_S3C2410_PM_CHECK) && CONFIG_S3C2410_PM_CHECK_CHUNKSIZE != 0
/* suspend checking code...
*
* this next area does a set of crc checks over all the installed
* memory, so the system can verify if the resume was ok.
*
* CONFIG_S3C2410_PM_CHECK_CHUNKSIZE defines the block-size for the CRC,
* increasing it will mean that the area corrupted will be less easy to spot,
* and reducing the size will cause the CRC save area to grow
*/
#define CHECK_CHUNKSIZE (CONFIG_S3C2410_PM_CHECK_CHUNKSIZE * 1024)
static u32 crc_size; /* size needed for the crc block */
static u32 *crcs; /* allocated over suspend/resume */
typedef u32 *(run_fn_t)(struct resource *ptr, u32 *arg);
/* s3c2410_pm_run_res
*
* go thorugh the given resource list, and look for system ram
*/
static void s3c2410_pm_run_res(struct resource *ptr, run_fn_t fn, u32 *arg)
{
while (ptr != NULL) {
if (ptr->child != NULL)
s3c2410_pm_run_res(ptr->child, fn, arg);
if ((ptr->flags & IORESOURCE_MEM) &&
strcmp(ptr->name, "System RAM") == 0) {
DBG("Found system RAM at %08lx..%08lx\n",
ptr->start, ptr->end);
arg = (fn)(ptr, arg);
}
ptr = ptr->sibling;
}
}
static void s3c2410_pm_run_sysram(run_fn_t fn, u32 *arg)
{
s3c2410_pm_run_res(&iomem_resource, fn, arg);
}
static u32 *s3c2410_pm_countram(struct resource *res, u32 *val)
{
u32 size = (u32)(res->end - res->start)+1;
size += CHECK_CHUNKSIZE-1;
size /= CHECK_CHUNKSIZE;
DBG("Area %08lx..%08lx, %d blocks\n", res->start, res->end, size);
*val += size * sizeof(u32);
return val;
}
/* s3c2410_pm_prepare_check
*
* prepare the necessary information for creating the CRCs. This
* must be done before the final save, as it will require memory
* allocating, and thus touching bits of the kernel we do not
* know about.
*/
static void s3c2410_pm_check_prepare(void)
{
crc_size = 0;
s3c2410_pm_run_sysram(s3c2410_pm_countram, &crc_size);
DBG("s3c2410_pm_prepare_check: %u checks needed\n", crc_size);
crcs = kmalloc(crc_size+4, GFP_KERNEL);
if (crcs == NULL)
printk(KERN_ERR "Cannot allocated CRC save area\n");
}
static u32 *s3c2410_pm_makecheck(struct resource *res, u32 *val)
{
unsigned long addr, left;
for (addr = res->start; addr < res->end;
addr += CHECK_CHUNKSIZE) {
left = res->end - addr;
if (left > CHECK_CHUNKSIZE)
left = CHECK_CHUNKSIZE;
*val = crc32_le(~0, phys_to_virt(addr), left);
val++;
}
return val;
}
/* s3c2410_pm_check_store
*
* compute the CRC values for the memory blocks before the final
* sleep.
*/
static void s3c2410_pm_check_store(void)
{
if (crcs != NULL)
s3c2410_pm_run_sysram(s3c2410_pm_makecheck, crcs);
}
/* in_region
*
* return TRUE if the area defined by ptr..ptr+size contatins the
* what..what+whatsz
*/
static inline int in_region(void *ptr, int size, void *what, size_t whatsz)
{
if ((what+whatsz) < ptr)
return 0;
if (what > (ptr+size))
return 0;
return 1;
}
static u32 *s3c2410_pm_runcheck(struct resource *res, u32 *val)
{
void *save_at = phys_to_virt(s3c2410_sleep_save_phys);
unsigned long addr;
unsigned long left;
void *ptr;
u32 calc;
for (addr = res->start; addr < res->end;
addr += CHECK_CHUNKSIZE) {
left = res->end - addr;
if (left > CHECK_CHUNKSIZE)
left = CHECK_CHUNKSIZE;
ptr = phys_to_virt(addr);
if (in_region(ptr, left, crcs, crc_size)) {
DBG("skipping %08lx, has crc block in\n", addr);
goto skip_check;
}
if (in_region(ptr, left, save_at, 32*4 )) {
DBG("skipping %08lx, has save block in\n", addr);
goto skip_check;
}
/* calculate and check the checksum */
calc = crc32_le(~0, ptr, left);
if (calc != *val) {
printk(KERN_ERR PFX "Restore CRC error at "
"%08lx (%08x vs %08x)\n", addr, calc, *val);
DBG("Restore CRC error at %08lx (%08x vs %08x)\n",
addr, calc, *val);
}
skip_check:
val++;
}
return val;
}
/* s3c2410_pm_check_restore
*
* check the CRCs after the restore event and free the memory used
* to hold them
*/
static void s3c2410_pm_check_restore(void)
{
if (crcs != NULL) {
s3c2410_pm_run_sysram(s3c2410_pm_runcheck, crcs);
kfree(crcs);
crcs = NULL;
}
}
#else
#define s3c2410_pm_check_prepare() do { } while(0)
#define s3c2410_pm_check_restore() do { } while(0)
#define s3c2410_pm_check_store() do { } while(0)
#endif
/* helper functions to save and restore register state */
void s3c2410_pm_do_save(struct sleep_save *ptr, int count)
{
for (; count > 0; count--, ptr++) {
ptr->val = __raw_readl(ptr->reg);
DBG("saved %p value %08lx\n", ptr->reg, ptr->val);
}
}
/* s3c2410_pm_do_restore
*
* restore the system from the given list of saved registers
*
* Note, we do not use DBG() in here, as the system may not have
* restore the UARTs state yet
*/
void s3c2410_pm_do_restore(struct sleep_save *ptr, int count)
{
for (; count > 0; count--, ptr++) {
printk(KERN_DEBUG "restore %p (restore %08lx, was %08x)\n",
ptr->reg, ptr->val, __raw_readl(ptr->reg));
__raw_writel(ptr->val, ptr->reg);
}
}
/* s3c2410_pm_do_restore_core
*
* similar to s3c2410_pm_do_restore_core
*
* WARNING: Do not put any debug in here that may effect memory or use
* peripherals, as things may be changing!
*/
static void s3c2410_pm_do_restore_core(struct sleep_save *ptr, int count)
{
for (; count > 0; count--, ptr++) {
__raw_writel(ptr->val, ptr->reg);
}
}
/* s3c2410_pm_show_resume_irqs
*
* print any IRQs asserted at resume time (ie, we woke from)
*/
static void s3c2410_pm_show_resume_irqs(int start, unsigned long which,
unsigned long mask)
{
int i;
which &= ~mask;
for (i = 0; i <= 31; i++) {
if ((which) & (1L<<i)) {
DBG("IRQ %d asserted at resume\n", start+i);
}
}
}
/* s3c2410_pm_check_resume_pin
*
* check to see if the pin is configured correctly for sleep mode, and
* make any necessary adjustments if it is not
*/
static void s3c2410_pm_check_resume_pin(unsigned int pin, unsigned int irqoffs)
{
unsigned long irqstate;
unsigned long pinstate;
int irq = s3c2410_gpio_getirq(pin);
if (irqoffs < 4)
irqstate = s3c_irqwake_intmask & (1L<<irqoffs);
else
irqstate = s3c_irqwake_eintmask & (1L<<irqoffs);
pinstate = s3c2410_gpio_getcfg(pin);
if (!irqstate) {
if (pinstate == S3C2410_GPIO_IRQ)
DBG("Leaving IRQ %d (pin %d) enabled\n", irq, pin);
} else {
if (pinstate == S3C2410_GPIO_IRQ) {
DBG("Disabling IRQ %d (pin %d)\n", irq, pin);
s3c2410_gpio_cfgpin(pin, S3C2410_GPIO_INPUT);
}
}
}
/* s3c2410_pm_configure_extint
*
* configure all external interrupt pins
*/
static void s3c2410_pm_configure_extint(void)
{
int pin;
/* for each of the external interrupts (EINT0..EINT15) we
* need to check wether it is an external interrupt source,
* and then configure it as an input if it is not
*/
for (pin = S3C2410_GPF0; pin <= S3C2410_GPF7; pin++) {
s3c2410_pm_check_resume_pin(pin, pin - S3C2410_GPF0);
}
for (pin = S3C2410_GPG0; pin <= S3C2410_GPG7; pin++) {
s3c2410_pm_check_resume_pin(pin, (pin - S3C2410_GPG0)+8);
}
}
void (*pm_cpu_prep)(void);
void (*pm_cpu_sleep)(void);
#define any_allowed(mask, allow) (((mask) & (allow)) != (allow))
/* s3c2410_pm_enter
*
* central control for sleep/resume process
*/
static int s3c2410_pm_enter(suspend_state_t state)
{
unsigned long regs_save[16];
/* ensure the debug is initialised (if enabled) */
s3c2410_pm_debug_init();
DBG("s3c2410_pm_enter(%d)\n", state);
if (pm_cpu_prep == NULL || pm_cpu_sleep == NULL) {
printk(KERN_ERR PFX "error: no cpu sleep functions set\n");
return -EINVAL;
}
if (state != PM_SUSPEND_MEM) {
printk(KERN_ERR PFX "error: only PM_SUSPEND_MEM supported\n");
return -EINVAL;
}
/* check if we have anything to wake-up with... bad things seem
* to happen if you suspend with no wakeup (system will often
* require a full power-cycle)
*/
if (!any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) &&
!any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) {
printk(KERN_ERR PFX "No sources enabled for wake-up!\n");
printk(KERN_ERR PFX "Aborting sleep\n");
return -EINVAL;
}
/* prepare check area if configured */
s3c2410_pm_check_prepare();
/* store the physical address of the register recovery block */
s3c2410_sleep_save_phys = virt_to_phys(regs_save);
DBG("s3c2410_sleep_save_phys=0x%08lx\n", s3c2410_sleep_save_phys);
/* save all necessary core registers not covered by the drivers */
s3c2410_pm_do_save(gpio_save, ARRAY_SIZE(gpio_save));
s3c2410_pm_do_save(core_save, ARRAY_SIZE(core_save));
s3c2410_pm_do_save(uart_save, ARRAY_SIZE(uart_save));
/* set the irq configuration for wake */
s3c2410_pm_configure_extint();
DBG("sleep: irq wakeup masks: %08lx,%08lx\n",
s3c_irqwake_intmask, s3c_irqwake_eintmask);
__raw_writel(s3c_irqwake_intmask, S3C2410_INTMSK);
__raw_writel(s3c_irqwake_eintmask, S3C2410_EINTMASK);
/* ack any outstanding external interrupts before we go to sleep */
__raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND);
__raw_writel(__raw_readl(S3C2410_INTPND), S3C2410_INTPND);
__raw_writel(__raw_readl(S3C2410_SRCPND), S3C2410_SRCPND);
/* call cpu specific preperation */
pm_cpu_prep();
/* flush cache back to ram */
flush_cache_all();
s3c2410_pm_check_store();
/* send the cpu to sleep... */
__raw_writel(0x00, S3C2410_CLKCON); /* turn off clocks over sleep */
/* s3c2410_cpu_save will also act as our return point from when
* we resume as it saves its own register state, so use the return
* code to differentiate return from save and return from sleep */
if (s3c2410_cpu_save(regs_save) == 0) {
flush_cache_all();
pm_cpu_sleep();
}
/* restore the cpu state */
cpu_init();
/* restore the system state */
s3c2410_pm_do_restore_core(core_save, ARRAY_SIZE(core_save));
s3c2410_pm_do_restore(gpio_save, ARRAY_SIZE(gpio_save));
s3c2410_pm_do_restore(uart_save, ARRAY_SIZE(uart_save));
s3c2410_pm_debug_init();
/* check what irq (if any) restored the system */
DBG("post sleep: IRQs 0x%08x, 0x%08x\n",
__raw_readl(S3C2410_SRCPND),
__raw_readl(S3C2410_EINTPEND));
s3c2410_pm_show_resume_irqs(IRQ_EINT0, __raw_readl(S3C2410_SRCPND),
s3c_irqwake_intmask);
s3c2410_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND),
s3c_irqwake_eintmask);
DBG("post sleep, preparing to return\n");
s3c2410_pm_check_restore();
/* ok, let's return from sleep */
DBG("S3C2410 PM Resume (post-restore)\n");
return 0;
}
/*
* Called after processes are frozen, but before we shut down devices.
*/
static int s3c2410_pm_prepare(suspend_state_t state)
{
return 0;
}
/*
* Called after devices are re-setup, but before processes are thawed.
*/
static int s3c2410_pm_finish(suspend_state_t state)
{
return 0;
}
/*
* Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
*/
static struct pm_ops s3c2410_pm_ops = {
.pm_disk_mode = PM_DISK_FIRMWARE,
.prepare = s3c2410_pm_prepare,
.enter = s3c2410_pm_enter,
.finish = s3c2410_pm_finish,
};
/* s3c2410_pm_init
*
* Attach the power management functions. This should be called
* from the board specific initialisation if the board supports
* it.
*/
int __init s3c2410_pm_init(void)
{
printk("S3C2410 Power Management, (c) 2004 Simtec Electronics\n");
pm_set_ops(&s3c2410_pm_ops);
return 0;
}

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2410/s3c244x-irq.c /* linux/arch/arm/plat-s3c24xx/s3c244x-irq.c
* *
* Copyright (c) 2003,2004 Simtec Electronics * Copyright (c) 2003,2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>
@ -35,9 +35,9 @@
#include <asm/arch/regs-irq.h> #include <asm/arch/regs-irq.h>
#include <asm/arch/regs-gpio.h> #include <asm/arch/regs-gpio.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
#include "pm.h" #include <asm/plat-s3c24xx/pm.h>
#include "irq.h" #include <asm/plat-s3c24xx/irq.h>
/* camera irq */ /* camera irq */

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2410/s3c244x.c /* linux/arch/arm/plat-s3c24xx/s3c244x.c
* *
* Copyright (c) 2004-2006 Simtec Electronics * Copyright (c) 2004-2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>
@ -35,13 +35,13 @@
#include <asm/arch/regs-gpioj.h> #include <asm/arch/regs-gpioj.h>
#include <asm/arch/regs-dsc.h> #include <asm/arch/regs-dsc.h>
#include "s3c2410.h" #include <asm/plat-s3c24xx/s3c2410.h>
#include "s3c2440.h" #include <asm/plat-s3c24xx/s3c2440.h>
#include "s3c244x.h" #include "s3c244x.h"
#include "clock.h" #include <asm/plat-s3c24xx/clock.h>
#include "devs.h" #include <asm/plat-s3c24xx/devs.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
#include "pm.h" #include <asm/plat-s3c24xx/pm.h>
static struct map_desc s3c244x_iodesc[] __initdata = { static struct map_desc s3c244x_iodesc[] __initdata = {
IODESC_ENT(CLKPWR), IODESC_ENT(CLKPWR),

View File

@ -1,4 +1,4 @@
/* arch/arm/mach-s3c2410/s3c244x.h /* linux/arch/arm/plat-s3c24xx/s3c244x.h
* *
* Copyright (c) 2004-2005 Simtec Electronics * Copyright (c) 2004-2005 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>

View File

@ -0,0 +1,159 @@
/* linux/arch/arm/mach-s3c2410/sleep.S
*
* Copyright (c) 2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* S3C2410 Power Manager (Suspend-To-RAM) support
*
* Based on PXA/SA1100 sleep code by:
* Nicolas Pitre, (c) 2002 Monta Vista Software Inc
* Cliff Brake, (c) 2001
*
* 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/linkage.h>
#include <asm/assembler.h>
#include <asm/hardware.h>
#include <asm/arch/map.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-clock.h>
#include <asm/arch/regs-mem.h>
#include <asm/arch/regs-serial.h>
/* CONFIG_DEBUG_RESUME is dangerous if your bootloader does not
* reset the UART configuration, only enable if you really need this!
*/
//#define CONFIG_DEBUG_RESUME
.text
/* s3c2410_cpu_save
*
* save enough of the CPU state to allow us to re-start
* pm.c code. as we store items like the sp/lr, we will
* end up returning from this function when the cpu resumes
* so the return value is set to mark this.
*
* This arangement means we avoid having to flush the cache
* from this code.
*
* entry:
* r0 = pointer to save block
*
* exit:
* r0 = 0 => we stored everything
* 1 => resumed from sleep
*/
ENTRY(s3c2410_cpu_save)
stmfd sp!, { r4 - r12, lr }
@@ store co-processor registers
mrc p15, 0, r4, c15, c1, 0 @ CP access register
mrc p15, 0, r5, c13, c0, 0 @ PID
mrc p15, 0, r6, c3, c0, 0 @ Domain ID
mrc p15, 0, r7, c2, c0, 0 @ translation table base address
mrc p15, 0, r8, c1, c0, 0 @ control register
stmia r0, { r4 - r13 }
mov r0, #0
ldmfd sp, { r4 - r12, pc }
@@ return to the caller, after having the MMU
@@ turned on, this restores the last bits from the
@@ stack
resume_with_mmu:
mov r0, #1
ldmfd sp!, { r4 - r12, pc }
.ltorg
@@ the next bits sit in the .data segment, even though they
@@ happen to be code... the s3c2410_sleep_save_phys needs to be
@@ accessed by the resume code before it can restore the MMU.
@@ This means that the variable has to be close enough for the
@@ code to read it... since the .text segment needs to be RO,
@@ the data segment can be the only place to put this code.
.data
.global s3c2410_sleep_save_phys
s3c2410_sleep_save_phys:
.word 0
/* s3c2410_cpu_resume
*
* resume code entry for bootloader to call
*
* we must put this code here in the data segment as we have no
* other way of restoring the stack pointer after sleep, and we
* must not write to the code segment (code is read-only)
*/
ENTRY(s3c2410_cpu_resume)
mov r0, #PSR_I_BIT | PSR_F_BIT | SVC_MODE
msr cpsr_c, r0
@@ load UART to allow us to print the two characters for
@@ resume debug
mov r2, #S3C24XX_PA_UART & 0xff000000
orr r2, r2, #S3C24XX_PA_UART & 0xff000
#if 0
/* SMDK2440 LED set */
mov r14, #S3C24XX_PA_GPIO
ldr r12, [ r14, #0x54 ]
bic r12, r12, #3<<4
orr r12, r12, #1<<7
str r12, [ r14, #0x54 ]
#endif
#ifdef CONFIG_DEBUG_RESUME
mov r3, #'L'
strb r3, [ r2, #S3C2410_UTXH ]
1001:
ldrb r14, [ r3, #S3C2410_UTRSTAT ]
tst r14, #S3C2410_UTRSTAT_TXE
beq 1001b
#endif /* CONFIG_DEBUG_RESUME */
mov r1, #0
mcr p15, 0, r1, c8, c7, 0 @@ invalidate I & D TLBs
mcr p15, 0, r1, c7, c7, 0 @@ invalidate I & D caches
ldr r0, s3c2410_sleep_save_phys @ address of restore block
ldmia r0, { r4 - r13 }
mcr p15, 0, r4, c15, c1, 0 @ CP access register
mcr p15, 0, r5, c13, c0, 0 @ PID
mcr p15, 0, r6, c3, c0, 0 @ Domain ID
mcr p15, 0, r7, c2, c0, 0 @ translation table base
#ifdef CONFIG_DEBUG_RESUME
mov r3, #'R'
strb r3, [ r2, #S3C2410_UTXH ]
#endif
ldr r2, =resume_with_mmu
mcr p15, 0, r8, c1, c0, 0 @ turn on MMU, etc
nop @ second-to-last before mmu
mov pc, r2 @ go back to virtual address
.ltorg

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2410/time.c /* linux/arch/arm/plat-s3c24xx/time.c
* *
* Copyright (C) 2003-2005 Simtec Electronics * Copyright (C) 2003-2005 Simtec Electronics
* Ben Dooks, <ben@simtec.co.uk> * Ben Dooks, <ben@simtec.co.uk>
@ -37,8 +37,8 @@
#include <asm/arch/regs-irq.h> #include <asm/arch/regs-irq.h>
#include <asm/mach/time.h> #include <asm/mach/time.h>
#include "clock.h" #include <asm/plat-s3c24xx/clock.h>
#include "cpu.h" #include <asm/plat-s3c24xx/cpu.h>
static unsigned long timer_startval; static unsigned long timer_startval;
static unsigned long timer_usec_ticks; static unsigned long timer_usec_ticks;

View File

@ -1,4 +1,4 @@
/* /* linux/include/asm-arm/plat-s3c24xx/clock.h
* linux/arch/arm/mach-s3c2410/clock.h * linux/arch/arm/mach-s3c2410/clock.h
* *
* Copyright (c) 2004-2005 Simtec Electronics * Copyright (c) 2004-2005 Simtec Electronics

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2410/common-smdk.h /* linux/include/asm-arm/plat-s3c24xx/common-smdk.h
* *
* Copyright (c) 2006 Simtec Electronics * Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>

View File

@ -1,4 +1,4 @@
/* arch/arm/mach-s3c2410/cpu.h /* linux/include/asm-arm/plat-s3c24xx/cpu.h
* *
* Copyright (c) 2004-2005 Simtec Electronics * Copyright (c) 2004-2005 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>

View File

@ -1,4 +1,4 @@
/* arch/arm/mach-s3c2410/devs.h /* linux/include/asm-arm/plat-s3c24xx/devs.h
* *
* Copyright (c) 2004 Simtec Electronics * Copyright (c) 2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>

View File

@ -1,4 +1,4 @@
/* arch/arm/mach-s3c2410/dma.h /* linux/include/asm-arm/plat-s3c24xx/dma.h
* *
* Copyright (C) 2006 Simtec Electronics * Copyright (C) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>

View File

@ -1,4 +1,4 @@
/* arch/arm/mach-s3c2410/irq.h /* linux/include/asm-arm/plat-s3c24xx/irq.h
* *
* Copyright (c) 2004-2005 Simtec Electronics * Copyright (c) 2004-2005 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>

View File

@ -1,4 +1,4 @@
/* linux/arch/arm/mach-s3c2410/pm.h /* linux/include/asm-arm/plat-s3c24xx/pm.h
* *
* Copyright (c) 2004 Simtec Electronics * Copyright (c) 2004 Simtec Electronics
* Written by Ben Dooks, <ben@simtec.co.uk> * Written by Ben Dooks, <ben@simtec.co.uk>

View File

@ -1,4 +1,4 @@
/* arch/arm/mach-s3c2410/s3c2400.h /* linux/include/asm-arm/plat-s3c24xx/s3c2400.h
* *
* Copyright (c) 2004 Simtec Electronics * Copyright (c) 2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>

View File

@ -1,4 +1,4 @@
/* arch/arm/mach-s3c2410/s3c2410.h /* linux/include/asm-arm/plat-s3c24xx/s3c2410.h
* *
* Copyright (c) 2004 Simtec Electronics * Copyright (c) 2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>

View File

@ -1,4 +1,4 @@
/* arch/arm/mach-s3c2410/s3c2412.h /* linux/include/asm-arm/plat-s3c24xx/s3c2412.h
* *
* Copyright (c) 2006 Simtec Electronics * Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>

View File

@ -1,4 +1,4 @@
/* arch/arm/mach-s3c2410/s3c2440.h /* linux/include/asm-arm/plat-s3c24xx/s3c2440.h
* *
* Copyright (c) 2004-2005 Simtec Electronics * Copyright (c) 2004-2005 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>

View File

@ -1,4 +1,4 @@
/* arch/arm/mach-s3c2410/s3c2442.h /* linux/include/asm-arm/plat-s3c24xx/s3c2442.h
* *
* Copyright (c) 2006 Simtec Electronics * Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk> * Ben Dooks <ben@simtec.co.uk>