From c133c290118bfc99cd7a23b5a00b5252d2be90c8 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 19 Mar 2009 15:02:37 +0000 Subject: [ARM] S3C: Make common header Move the common information from the header into a new shareable header for re-use on the s3c64xx. Signed-off-by: Ben Dooks Signed-off-by: Ben Dooks --- arch/arm/plat-s3c/include/plat/dma.h | 127 +++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 arch/arm/plat-s3c/include/plat/dma.h (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/plat-s3c/include/plat/dma.h b/arch/arm/plat-s3c/include/plat/dma.h new file mode 100644 index 000000000000..34dba98f08e1 --- /dev/null +++ b/arch/arm/plat-s3c/include/plat/dma.h @@ -0,0 +1,127 @@ +/* arch/arm/plat-s3c/include/plat/dma.h + * + * Copyright (C) 2003,2004,2006 Simtec Electronics + * Ben Dooks + * + * Samsung S3C DMA support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +enum s3c2410_dma_buffresult { + S3C2410_RES_OK, + S3C2410_RES_ERR, + S3C2410_RES_ABORT +}; + +enum s3c2410_dmasrc { + S3C2410_DMASRC_HW, /* source is memory */ + S3C2410_DMASRC_MEM /* source is hardware */ +}; + +/* enum s3c2410_chan_op + * + * operation codes passed to the DMA code by the user, and also used + * to inform the current channel owner of any changes to the system state +*/ + +enum s3c2410_chan_op { + S3C2410_DMAOP_START, + S3C2410_DMAOP_STOP, + S3C2410_DMAOP_PAUSE, + S3C2410_DMAOP_RESUME, + S3C2410_DMAOP_FLUSH, + S3C2410_DMAOP_TIMEOUT, /* internal signal to handler */ + S3C2410_DMAOP_STARTED, /* indicate channel started */ +}; + +struct s3c2410_dma_client { + char *name; +}; + +struct s3c2410_dma_chan; + +/* s3c2410_dma_cbfn_t + * + * buffer callback routine type +*/ + +typedef void (*s3c2410_dma_cbfn_t)(struct s3c2410_dma_chan *, + void *buf, int size, + enum s3c2410_dma_buffresult result); + +typedef int (*s3c2410_dma_opfn_t)(struct s3c2410_dma_chan *, + enum s3c2410_chan_op ); + + + +/* s3c2410_dma_request + * + * request a dma channel exclusivley +*/ + +extern int s3c2410_dma_request(unsigned int channel, + struct s3c2410_dma_client *, void *dev); + + +/* s3c2410_dma_ctrl + * + * change the state of the dma channel +*/ + +extern int s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op); + +/* s3c2410_dma_setflags + * + * set the channel's flags to a given state +*/ + +extern int s3c2410_dma_setflags(unsigned int channel, + unsigned int flags); + +/* s3c2410_dma_free + * + * free the dma channel (will also abort any outstanding operations) +*/ + +extern int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *); + +/* s3c2410_dma_enqueue + * + * place the given buffer onto the queue of operations for the channel. + * The buffer must be allocated from dma coherent memory, or the Dcache/WB + * drained before the buffer is given to the DMA system. +*/ + +extern int s3c2410_dma_enqueue(unsigned int channel, void *id, + dma_addr_t data, int size); + +/* s3c2410_dma_config + * + * configure the dma channel +*/ + +extern int s3c2410_dma_config(unsigned int channel, int xferunit); + +/* s3c2410_dma_devconfig + * + * configure the device we're talking to +*/ + +extern int s3c2410_dma_devconfig(int channel, enum s3c2410_dmasrc source, + unsigned long devaddr); + +/* s3c2410_dma_getposition + * + * get the position that the dma transfer is currently at +*/ + +extern int s3c2410_dma_getposition(unsigned int channel, + dma_addr_t *src, dma_addr_t *dest); + +extern int s3c2410_dma_set_opfn(unsigned int, s3c2410_dma_opfn_t rtn); +extern int s3c2410_dma_set_buffdone_fn(unsigned int, s3c2410_dma_cbfn_t rtn); + + -- cgit v1.2.3 From 97c1b145231730e62dd71921ec653315a1da3aad Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 19 Mar 2009 15:02:39 +0000 Subject: [ARM] S3C: Move DMA channel management code to plat-s3c Change the name of S3C2410_DMA_CHANNELS to S3C_DMA_CHANNELS in the process. Signed-off-by: Ben Dooks Signed-off-by: Ben Dooks --- arch/arm/mach-s3c2410/include/mach/dma.h | 8 +-- arch/arm/plat-s3c/Kconfig | 7 +++ arch/arm/plat-s3c/Makefile | 4 ++ arch/arm/plat-s3c/dma.c | 86 ++++++++++++++++++++++++++ arch/arm/plat-s3c/include/plat/dma-core.h | 22 +++++++ arch/arm/plat-s3c24xx/Kconfig | 1 + arch/arm/plat-s3c24xx/dma.c | 87 +++------------------------ arch/arm/plat-s3c24xx/include/plat/dma-plat.h | 10 +-- 8 files changed, 136 insertions(+), 89 deletions(-) create mode 100644 arch/arm/plat-s3c/dma.c create mode 100644 arch/arm/plat-s3c/include/plat/dma-core.h (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/mach-s3c2410/include/mach/dma.h b/arch/arm/mach-s3c2410/include/mach/dma.h index 1648311c7b47..c3a2629e0ded 100644 --- a/arch/arm/mach-s3c2410/include/mach/dma.h +++ b/arch/arm/mach-s3c2410/include/mach/dma.h @@ -55,9 +55,9 @@ enum dma_ch { /* we have 4 dma channels */ #ifndef CONFIG_CPU_S3C2443 -#define S3C2410_DMA_CHANNELS (4) +#define S3C_DMA_CHANNELS (4) #else -#define S3C2410_DMA_CHANNELS (6) +#define S3C_DMA_CHANNELS (6) #endif /* types */ @@ -192,10 +192,6 @@ struct s3c2410_dma_chan { struct sys_device dev; }; -/* the currently allocated channel information */ -extern struct s3c2410_dma_chan s3c2410_chans[]; - -/* note, we don't really use dma_device_t at the moment */ typedef unsigned long dma_device_t; #endif /* __ASM_ARCH_DMA_H */ diff --git a/arch/arm/plat-s3c/Kconfig b/arch/arm/plat-s3c/Kconfig index de9383814e5e..d4fc89fc5f45 100644 --- a/arch/arm/plat-s3c/Kconfig +++ b/arch/arm/plat-s3c/Kconfig @@ -150,6 +150,13 @@ config S3C_GPIO_CFG_S3C64XX Internal configuration to enable S3C64XX style GPIO configuration functions. +# DMA + +config S3C_DMA + bool + help + Internal configuration for S3C DMA core + # device definitions to compile in config S3C_DEV_HSMMC diff --git a/arch/arm/plat-s3c/Makefile b/arch/arm/plat-s3c/Makefile index 8d7815d25a51..e8b23fc8fba2 100644 --- a/arch/arm/plat-s3c/Makefile +++ b/arch/arm/plat-s3c/Makefile @@ -18,6 +18,10 @@ obj-y += pwm-clock.o obj-y += gpio.o obj-y += gpio-config.o +# DMA support + +obj-$(CONFIG_S3C_DMA) += dma.o + # PM support obj-$(CONFIG_PM) += pm.o diff --git a/arch/arm/plat-s3c/dma.c b/arch/arm/plat-s3c/dma.c new file mode 100644 index 000000000000..c9db75c06af5 --- /dev/null +++ b/arch/arm/plat-s3c/dma.c @@ -0,0 +1,86 @@ +/* linux/arch/arm/plat-s3c/dma.c + * + * Copyright (c) 2003-2005,2006,2009 Simtec Electronics + * Ben Dooks + * http://armlinux.simtec.co.uk/ + * + * S3C DMA core + * + * 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. +*/ + +struct s3c2410_dma_buf; + +#include +#include +#include + +#include +#include + +#include + +/* dma channel state information */ +struct s3c2410_dma_chan s3c2410_chans[S3C_DMA_CHANNELS]; +struct s3c2410_dma_chan *s3c_dma_chan_map[DMACH_MAX]; + +/* s3c_dma_lookup_channel + * + * change the dma channel number given into a real dma channel id +*/ + +struct s3c2410_dma_chan *s3c_dma_lookup_channel(unsigned int channel) +{ + if (channel & DMACH_LOW_LEVEL) + return &s3c2410_chans[channel & ~DMACH_LOW_LEVEL]; + else + return s3c_dma_chan_map[channel]; +} + +/* do we need to protect the settings of the fields from + * irq? +*/ + +int s3c2410_dma_set_opfn(unsigned int channel, s3c2410_dma_opfn_t rtn) +{ + struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); + + if (chan == NULL) + return -EINVAL; + + pr_debug("%s: chan=%p, op rtn=%p\n", __func__, chan, rtn); + + chan->op_fn = rtn; + + return 0; +} +EXPORT_SYMBOL(s3c2410_dma_set_opfn); + +int s3c2410_dma_set_buffdone_fn(unsigned int channel, s3c2410_dma_cbfn_t rtn) +{ + struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); + + if (chan == NULL) + return -EINVAL; + + pr_debug("%s: chan=%p, callback rtn=%p\n", __func__, chan, rtn); + + chan->callback_fn = rtn; + + return 0; +} +EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn); + +int s3c2410_dma_setflags(unsigned int channel, unsigned int flags) +{ + struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); + + if (chan == NULL) + return -EINVAL; + + chan->flags = flags; + return 0; +} +EXPORT_SYMBOL(s3c2410_dma_setflags); diff --git a/arch/arm/plat-s3c/include/plat/dma-core.h b/arch/arm/plat-s3c/include/plat/dma-core.h new file mode 100644 index 000000000000..32ff2a92cb3c --- /dev/null +++ b/arch/arm/plat-s3c/include/plat/dma-core.h @@ -0,0 +1,22 @@ +/* arch/arm/plat-s3c/include/plat/dma.h + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * Ben Dooks + * http://armlinux.simtec.co.uk/ + * + * Samsung S3C DMA core support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +extern struct s3c2410_dma_chan *s3c_dma_lookup_channel(unsigned int channel); + +extern struct s3c2410_dma_chan *s3c_dma_chan_map[]; + +/* the currently allocated channel information */ +extern struct s3c2410_dma_chan s3c2410_chans[]; + + diff --git a/arch/arm/plat-s3c24xx/Kconfig b/arch/arm/plat-s3c24xx/Kconfig index 2c8a2f5d75ff..5b0bc914f58e 100644 --- a/arch/arm/plat-s3c24xx/Kconfig +++ b/arch/arm/plat-s3c24xx/Kconfig @@ -71,6 +71,7 @@ config PM_SIMTEC config S3C2410_DMA bool "S3C2410 DMA support" depends on ARCH_S3C2410 + select S3C_DMA 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 diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c index 7c37c9a75323..b07fec01ab47 100644 --- a/arch/arm/plat-s3c24xx/dma.c +++ b/arch/arm/plat-s3c24xx/dma.c @@ -44,8 +44,6 @@ static int dma_channels; static struct s3c24xx_dma_selection dma_sel; -/* dma channel state information */ -struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS]; /* debugging functions */ @@ -135,21 +133,6 @@ dmadbg_showregs(const char *fname, int line, struct s3c2410_dma_chan *chan) #define dbg_showchan(chan) do { } while(0) #endif /* CONFIG_S3C2410_DMA_DEBUG */ -static struct s3c2410_dma_chan *dma_chan_map[DMACH_MAX]; - -/* lookup_dma_channel - * - * change the dma channel number given into a real dma channel id -*/ - -static struct s3c2410_dma_chan *lookup_dma_channel(unsigned int channel) -{ - if (channel & DMACH_LOW_LEVEL) - return &s3c2410_chans[channel & ~DMACH_LOW_LEVEL]; - else - return dma_chan_map[channel]; -} - /* s3c2410_dma_stats_timeout * * Update DMA stats from timeout info @@ -214,8 +197,6 @@ s3c2410_dma_waitforload(struct s3c2410_dma_chan *chan, int line) return 0; } - - /* s3c2410_dma_loadbuffer * * load a buffer, and update the channel state @@ -453,7 +434,7 @@ s3c2410_dma_canload(struct s3c2410_dma_chan *chan) int s3c2410_dma_enqueue(unsigned int channel, void *id, dma_addr_t data, int size) { - struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); + struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); struct s3c2410_dma_buf *buf; unsigned long flags; @@ -804,7 +785,7 @@ EXPORT_SYMBOL(s3c2410_dma_request); int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *client) { - struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); + struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); unsigned long flags; if (chan == NULL) @@ -836,7 +817,7 @@ int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *client) chan->irq_claimed = 0; if (!(channel & DMACH_LOW_LEVEL)) - dma_chan_map[channel] = NULL; + s3c_dma_chan_map[channel] = NULL; local_irq_restore(flags); @@ -995,7 +976,7 @@ static int s3c2410_dma_started(struct s3c2410_dma_chan *chan) int s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op) { - struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); + struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); if (chan == NULL) return -EINVAL; @@ -1043,7 +1024,7 @@ EXPORT_SYMBOL(s3c2410_dma_ctrl); int s3c2410_dma_config(unsigned int channel, int xferunit) { - struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); + struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); unsigned int dcon; pr_debug("%s: chan=%d, xfer_unit=%d, dcon=%08x\n", @@ -1112,58 +1093,6 @@ int s3c2410_dma_config(unsigned int channel, EXPORT_SYMBOL(s3c2410_dma_config); -int s3c2410_dma_setflags(unsigned int channel, unsigned int flags) -{ - struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); - - if (chan == NULL) - return -EINVAL; - - pr_debug("%s: chan=%p, flags=%08x\n", __func__, chan, flags); - - chan->flags = flags; - - return 0; -} - -EXPORT_SYMBOL(s3c2410_dma_setflags); - - -/* do we need to protect the settings of the fields from - * irq? -*/ - -int s3c2410_dma_set_opfn(unsigned int channel, s3c2410_dma_opfn_t rtn) -{ - struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); - - if (chan == NULL) - return -EINVAL; - - pr_debug("%s: chan=%p, op rtn=%p\n", __func__, chan, rtn); - - chan->op_fn = rtn; - - return 0; -} - -EXPORT_SYMBOL(s3c2410_dma_set_opfn); - -int s3c2410_dma_set_buffdone_fn(unsigned int channel, s3c2410_dma_cbfn_t rtn) -{ - struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); - - if (chan == NULL) - return -EINVAL; - - pr_debug("%s: chan=%p, callback rtn=%p\n", __func__, chan, rtn); - - chan->callback_fn = rtn; - - return 0; -} - -EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn); /* s3c2410_dma_devconfig * @@ -1179,7 +1108,7 @@ int s3c2410_dma_devconfig(int channel, enum s3c2410_dmasrc source, unsigned long devaddr) { - struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); + struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); unsigned int hwcfg; if (chan == NULL) @@ -1250,7 +1179,7 @@ EXPORT_SYMBOL(s3c2410_dma_devconfig); int s3c2410_dma_getposition(unsigned int channel, dma_addr_t *src, dma_addr_t *dst) { - struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); + struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); if (chan == NULL) return -EINVAL; @@ -1508,7 +1437,7 @@ static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel) dmach = &s3c2410_chans[ch]; dmach->map = ch_map; dmach->req_ch = channel; - dma_chan_map[channel] = dmach; + s3c_dma_chan_map[channel] = dmach; /* select the channel */ diff --git a/arch/arm/plat-s3c24xx/include/plat/dma-plat.h b/arch/arm/plat-s3c24xx/include/plat/dma-plat.h index fbe84afe2d90..9565ead1bc9b 100644 --- a/arch/arm/plat-s3c24xx/include/plat/dma-plat.h +++ b/arch/arm/plat-s3c24xx/include/plat/dma-plat.h @@ -10,8 +10,10 @@ * published by the Free Software Foundation. */ +#include + extern struct sysdev_class dma_sysclass; -extern struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS]; +extern struct s3c2410_dma_chan s3c2410_chans[S3C_DMA_CHANNELS]; #define DMA_CH_VALID (1<<31) #define DMA_CH_NEVER (1<<30) @@ -31,8 +33,8 @@ struct s3c24xx_dma_map { const char *name; struct s3c24xx_dma_addr hw_addr; - unsigned long channels[S3C2410_DMA_CHANNELS]; - unsigned long channels_rx[S3C2410_DMA_CHANNELS]; + unsigned long channels[S3C_DMA_CHANNELS]; + unsigned long channels_rx[S3C_DMA_CHANNELS]; }; struct s3c24xx_dma_selection { @@ -58,7 +60,7 @@ extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel); */ struct s3c24xx_dma_order_ch { - unsigned int list[S3C2410_DMA_CHANNELS]; /* list of channels */ + unsigned int list[S3C_DMA_CHANNELS]; /* list of channels */ unsigned int flags; /* flags */ }; -- cgit v1.2.3 From eca8655ffa1ffb23c8f6f1485c1315a3087c8f38 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Fri, 6 Mar 2009 19:49:48 +0000 Subject: [ARM] S3C: Add common USB OHCI device definition Add common definition for USB OHCI platform device, add a Kconfig to selectively compile it and add update all the users. Signed-off-by: Ben Dooks Signed-off-by: Ben Dooks --- arch/arm/mach-s3c2410/Kconfig | 8 +++++++ arch/arm/mach-s3c2412/Kconfig | 3 +++ arch/arm/mach-s3c2440/Kconfig | 5 +++++ arch/arm/plat-s3c/Kconfig | 5 +++++ arch/arm/plat-s3c/Makefile | 1 + arch/arm/plat-s3c/dev-usb.c | 50 +++++++++++++++++++++++++++++++++++++++++++ arch/arm/plat-s3c24xx/devs.c | 30 -------------------------- 7 files changed, 72 insertions(+), 30 deletions(-) create mode 100644 arch/arm/plat-s3c/dev-usb.c (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig index 63a30d1dd425..41bb65d5b91f 100644 --- a/arch/arm/mach-s3c2410/Kconfig +++ b/arch/arm/mach-s3c2410/Kconfig @@ -59,6 +59,7 @@ config ARCH_H1940 bool "IPAQ H1940" select CPU_S3C2410 select PM_H1940 if PM + select S3C_DEV_USB_HOST help Say Y here if you are using the HP IPAQ H1940 @@ -70,6 +71,7 @@ config PM_H1940 config MACH_N30 bool "Acer N30 family" select CPU_S3C2410 + select S3C_DEV_USB_HOST help Say Y here if you want suppt for the Acer N30, Acer N35, Navman PiN570, Yakumo AlphaX or Airis NC05 PDAs. @@ -82,6 +84,7 @@ config ARCH_BAST select MACH_BAST_IDE select S3C24XX_DCLK select ISA + select S3C_DEV_USB_HOST help Say Y here if you are using the Simtec Electronics EB2410ITX development board (also known as BAST) @@ -89,6 +92,7 @@ config ARCH_BAST config MACH_OTOM bool "NexVision OTOM Board" select CPU_S3C2410 + select S3C_DEV_USB_HOST help Say Y here if you are using the Nex Vision OTOM board @@ -96,6 +100,7 @@ config MACH_AML_M5900 bool "AML M5900 Series" select CPU_S3C2410 select PM_SIMTEC if PM + select S3C_DEV_USB_HOST help Say Y here if you are using the American Microsystems M5900 Series @@ -111,6 +116,7 @@ config BAST_PC104_IRQ config MACH_TCT_HAMMER bool "TCT Hammer Board" select CPU_S3C2410 + select S3C_DEV_USB_HOST help Say Y here if you are using the TinCanTools Hammer Board @@ -122,12 +128,14 @@ config MACH_VR1000 select SIMTEC_NOR select MACH_BAST_IDE select CPU_S3C2410 + select S3C_DEV_USB_HOST help Say Y here if you are using the Thorcom VR1000 board. config MACH_QT2410 bool "QT2410" select CPU_S3C2410 + select S3C_DEV_USB_HOST help Say Y here if you are using the Armzone QT2410 diff --git a/arch/arm/mach-s3c2412/Kconfig b/arch/arm/mach-s3c2412/Kconfig index ca99564ae4b5..63586ffd0ae7 100644 --- a/arch/arm/mach-s3c2412/Kconfig +++ b/arch/arm/mach-s3c2412/Kconfig @@ -38,6 +38,7 @@ menu "S3C2412 Machines" config MACH_JIVE bool "Logitech Jive" select CPU_S3C2412 + select S3C_DEV_USB_HOST help Say Y here if you are using the Logitech Jive. @@ -50,6 +51,7 @@ config MACH_SMDK2413 select CPU_S3C2412 select MACH_S3C2413 select MACH_SMDK + select S3C_DEV_USB_HOST help Say Y here if you are using an SMDK2413 @@ -72,6 +74,7 @@ config MACH_SMDK2412 config MACH_VSTMS bool "VMSTMS" select CPU_S3C2412 + select S3C_DEV_USB_HOST help Say Y here if you are using an VSTMS board diff --git a/arch/arm/mach-s3c2440/Kconfig b/arch/arm/mach-s3c2440/Kconfig index cde5ae9a4340..5df73cbf2b40 100644 --- a/arch/arm/mach-s3c2440/Kconfig +++ b/arch/arm/mach-s3c2440/Kconfig @@ -33,6 +33,7 @@ config MACH_ANUBIS select PM_SIMTEC if PM select HAVE_PATA_PLATFORM select S3C24XX_GPIO_EXTRA64 + select S3C_DEV_USB_HOST help Say Y here if you are using the Simtec Electronics ANUBIS development system @@ -43,6 +44,7 @@ config MACH_OSIRIS select S3C24XX_DCLK select PM_SIMTEC if PM select S3C24XX_GPIO_EXTRA128 + select S3C_DEV_USB_HOST help Say Y here if you are using the Simtec IM2440D20 module, also known as the Osiris. @@ -58,12 +60,14 @@ config ARCH_S3C2440 bool "SMDK2440" select CPU_S3C2440 select MACH_SMDK + select S3C_DEV_USB_HOST help Say Y here if you are using the SMDK2440. config MACH_NEXCODER_2440 bool "NexVision NEXCODER 2440 Light Board" select CPU_S3C2440 + select S3C_DEV_USB_HOST help Say Y here if you are using the Nex Vision NEXCODER 2440 Light Board @@ -76,6 +80,7 @@ config SMDK2440_CPU2440 config MACH_AT2440EVB bool "Avantech AT2440EVB development board" select CPU_S3C2440 + select S3C_DEV_USB_HOST help Say Y here if you are using the AT2440EVB development board diff --git a/arch/arm/plat-s3c/Kconfig b/arch/arm/plat-s3c/Kconfig index de9383814e5e..042d34a6f815 100644 --- a/arch/arm/plat-s3c/Kconfig +++ b/arch/arm/plat-s3c/Kconfig @@ -172,4 +172,9 @@ config S3C_DEV_FB help Compile in platform device definition for framebuffer +config S3C_DEV_USB_HOST + bool + help + Compile in platform device definition for USB host. + endif diff --git a/arch/arm/plat-s3c/Makefile b/arch/arm/plat-s3c/Makefile index 8d7815d25a51..aa995a49e567 100644 --- a/arch/arm/plat-s3c/Makefile +++ b/arch/arm/plat-s3c/Makefile @@ -30,3 +30,4 @@ obj-$(CONFIG_S3C_DEV_HSMMC1) += dev-hsmmc1.o obj-y += dev-i2c0.o obj-$(CONFIG_S3C_DEV_I2C1) += dev-i2c1.o obj-$(CONFIG_S3C_DEV_FB) += dev-fb.o +obj-$(CONFIG_S3C_DEV_USB_HOST) += dev-usb.o diff --git a/arch/arm/plat-s3c/dev-usb.c b/arch/arm/plat-s3c/dev-usb.c new file mode 100644 index 000000000000..a997d952816b --- /dev/null +++ b/arch/arm/plat-s3c/dev-usb.c @@ -0,0 +1,50 @@ +/* linux/arch/arm/plat-s3c/dev-usb.c + * + * Copyright 2008 Simtec Electronics + * Ben Dooks + * http://armlinux.simtec.co.uk/ + * + * S3C series device definition for USB host + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include +#include +#include + +#include +#include + +#include + + +static struct resource s3c_usb_resource[] = { + [0] = { + .start = S3C24XX_PA_USBHOST, + .end = S3C24XX_PA_USBHOST + S3C24XX_SZ_USBHOST - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_USBH, + .end = IRQ_USBH, + .flags = IORESOURCE_IRQ, + } +}; + +static u64 s3c_device_usb_dmamask = 0xffffffffUL; + +struct platform_device s3c_device_usb = { + .name = "s3c2410-ohci", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_usb_resource), + .resource = s3c_usb_resource, + .dev = { + .dma_mask = &s3c_device_usb_dmamask, + .coherent_dma_mask = 0xffffffffUL + } +}; + +EXPORT_SYMBOL(s3c_device_usb); diff --git a/arch/arm/plat-s3c24xx/devs.c b/arch/arm/plat-s3c24xx/devs.c index 16ac01d9b8ab..4eb378c89a39 100644 --- a/arch/arm/plat-s3c24xx/devs.c +++ b/arch/arm/plat-s3c24xx/devs.c @@ -136,36 +136,6 @@ struct platform_device *s3c24xx_uart_src[4] = { struct platform_device *s3c24xx_uart_devs[4] = { }; -/* USB Host Controller */ - -static struct resource s3c_usb_resource[] = { - [0] = { - .start = S3C24XX_PA_USBHOST, - .end = S3C24XX_PA_USBHOST + S3C24XX_SZ_USBHOST - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_USBH, - .end = IRQ_USBH, - .flags = IORESOURCE_IRQ, - } -}; - -static u64 s3c_device_usb_dmamask = 0xffffffffUL; - -struct platform_device s3c_device_usb = { - .name = "s3c2410-ohci", - .id = -1, - .num_resources = ARRAY_SIZE(s3c_usb_resource), - .resource = s3c_usb_resource, - .dev = { - .dma_mask = &s3c_device_usb_dmamask, - .coherent_dma_mask = 0xffffffffUL - } -}; - -EXPORT_SYMBOL(s3c_device_usb); - /* LCD Controller */ static struct resource s3c_lcd_resource[] = { -- cgit v1.2.3 From e6a2a9ce69400a8109e01030aec0d5e1e2bc73c2 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Fri, 6 Mar 2009 19:51:50 +0000 Subject: [ARM] S3C: Rename S3C24XX_PA_USBHOST to S3C_PA_USBHOST The USB host base address is available on both the S3C24XX and S3C64XX ranges. Signed-off-by: Ben Dooks Signed-off-by: Ben Dooks --- arch/arm/mach-s3c2410/include/mach/map.h | 2 +- arch/arm/plat-s3c/dev-usb.c | 4 ++-- arch/arm/plat-s3c24xx/include/plat/map.h | 1 - 3 files changed, 3 insertions(+), 4 deletions(-) (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/mach-s3c2410/include/mach/map.h b/arch/arm/mach-s3c2410/include/mach/map.h index 255fdfeaf957..e99b212cb1ca 100644 --- a/arch/arm/mach-s3c2410/include/mach/map.h +++ b/arch/arm/mach-s3c2410/include/mach/map.h @@ -84,7 +84,6 @@ #define S3C24XX_PA_IRQ S3C2410_PA_IRQ #define S3C24XX_PA_MEMCTRL S3C2410_PA_MEMCTRL -#define S3C24XX_PA_USBHOST S3C2410_PA_USBHOST #define S3C24XX_PA_DMA S3C2410_PA_DMA #define S3C24XX_PA_CLKPWR S3C2410_PA_CLKPWR #define S3C24XX_PA_LCD S3C2410_PA_LCD @@ -102,6 +101,7 @@ #define S3C_PA_IIC S3C2410_PA_IIC #define S3C_PA_UART S3C24XX_PA_UART +#define S3C_PA_USBHOST S3C2410_PA_USBHOST #define S3C_PA_HSMMC0 S3C2443_PA_HSMMC #endif /* __ASM_ARCH_MAP_H */ diff --git a/arch/arm/plat-s3c/dev-usb.c b/arch/arm/plat-s3c/dev-usb.c index a997d952816b..2ee85abed6d9 100644 --- a/arch/arm/plat-s3c/dev-usb.c +++ b/arch/arm/plat-s3c/dev-usb.c @@ -23,8 +23,8 @@ static struct resource s3c_usb_resource[] = { [0] = { - .start = S3C24XX_PA_USBHOST, - .end = S3C24XX_PA_USBHOST + S3C24XX_SZ_USBHOST - 1, + .start = S3C_PA_USBHOST, + .end = S3C_PA_USBHOST + 0x100 - 1, .flags = IORESOURCE_MEM, }, [1] = { diff --git a/arch/arm/plat-s3c24xx/include/plat/map.h b/arch/arm/plat-s3c24xx/include/plat/map.h index eed8f78e7593..c4d133436fc7 100644 --- a/arch/arm/plat-s3c24xx/include/plat/map.h +++ b/arch/arm/plat-s3c24xx/include/plat/map.h @@ -58,7 +58,6 @@ #define S3C24XX_SZ_SPI SZ_1M #define S3C24XX_SZ_SDI SZ_1M #define S3C24XX_SZ_NAND SZ_1M -#define S3C24XX_SZ_USBHOST SZ_1M /* GPIO ports */ -- cgit v1.2.3 From 57699e9adf1b44f281d808609b47816804763bfa Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Fri, 12 Dec 2008 00:24:23 +0000 Subject: [ARM] S3C: Add debug to UART save and a per-arch callback pre-restore Add a simple debug message on saving the UART state and add a per-arch pre-restore function to be used by the s3c64xx restore code to ensure the UARTs control registers do not go through any illegal state changes. Signed-off-by: Ben Dooks --- arch/arm/plat-s3c/pm.c | 5 +++++ arch/arm/plat-s3c24xx/include/plat/pm-core.h | 5 +++++ 2 files changed, 10 insertions(+) (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/plat-s3c/pm.c b/arch/arm/plat-s3c/pm.c index 061182ca66e3..de4c4aa22468 100644 --- a/arch/arm/plat-s3c/pm.c +++ b/arch/arm/plat-s3c/pm.c @@ -83,6 +83,9 @@ static void s3c_pm_save_uart(unsigned int uart, struct pm_uart_save *save) save->ufcon = __raw_readl(regs + S3C2410_UFCON); save->umcon = __raw_readl(regs + S3C2410_UMCON); save->ubrdiv = __raw_readl(regs + S3C2410_UBRDIV); + + S3C_PMDBG("UART[%d]: ULCON=%04x, UCON=%04x, UFCON=%04x, UBRDIV=%04x\n", + uart, save->ulcon, save->ucon, save->ufcon, save->ubrdiv); } static void s3c_pm_save_uarts(void) @@ -98,6 +101,8 @@ static void s3c_pm_restore_uart(unsigned int uart, struct pm_uart_save *save) { void __iomem *regs = S3C_VA_UARTx(uart); + s3c_pm_arch_update_uart(regs, save); + __raw_writel(save->ulcon, regs + S3C2410_ULCON); __raw_writel(save->ucon, regs + S3C2410_UCON); __raw_writel(save->ufcon, regs + S3C2410_UFCON); diff --git a/arch/arm/plat-s3c24xx/include/plat/pm-core.h b/arch/arm/plat-s3c24xx/include/plat/pm-core.h index c75882113e04..fb45dd9adca5 100644 --- a/arch/arm/plat-s3c24xx/include/plat/pm-core.h +++ b/arch/arm/plat-s3c24xx/include/plat/pm-core.h @@ -57,3 +57,8 @@ static inline void s3c_pm_arch_show_resume_irqs(void) s3c_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND), s3c_irqwake_eintmask); } + +static inline void s3c_pm_arch_update_uart(void __iomem *regs, + struct pm_uart_save *save) +{ +} -- cgit v1.2.3 From 4b637dc231a96a151ea70c27d86b35c7891e2a7c Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Fri, 12 Dec 2008 00:24:24 +0000 Subject: [ARM] S3C: PM save UART UDIVSLOT if doing PM Add the facility to save the UART UDIVSLOT register if the UART state is being saved over suspend. Signed-off-by: Ben Dooks --- arch/arm/plat-s3c/include/plat/pm.h | 3 +++ arch/arm/plat-s3c/pm.c | 8 ++++++++ 2 files changed, 11 insertions(+) (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/plat-s3c/include/plat/pm.h b/arch/arm/plat-s3c/include/plat/pm.h index 3779775133a9..5f8707e2a09c 100644 --- a/arch/arm/plat-s3c/include/plat/pm.h +++ b/arch/arm/plat-s3c/include/plat/pm.h @@ -44,6 +44,8 @@ extern void (*pm_cpu_sleep)(void); extern unsigned long s3c_pm_flags; +extern unsigned char pm_uart_udivslot; /* true to save UART UDIVSLOT */ + /* from sleep.S */ extern int s3c_cpu_save(unsigned long *saveblk); @@ -88,6 +90,7 @@ struct pm_uart_save { u32 ufcon; u32 umcon; u32 ubrdiv; + u32 udivslot; }; /* helper functions to save/restore lists of registers. */ diff --git a/arch/arm/plat-s3c/pm.c b/arch/arm/plat-s3c/pm.c index de4c4aa22468..9957b539600f 100644 --- a/arch/arm/plat-s3c/pm.c +++ b/arch/arm/plat-s3c/pm.c @@ -70,6 +70,8 @@ static inline void s3c_pm_debug_init(void) /* Save the UART configurations if we are configured for debug. */ +unsigned char pm_uart_udivslot; + #ifdef CONFIG_S3C2410_PM_DEBUG struct pm_uart_save uart_save[CONFIG_SERIAL_SAMSUNG_UARTS]; @@ -84,6 +86,9 @@ static void s3c_pm_save_uart(unsigned int uart, struct pm_uart_save *save) save->umcon = __raw_readl(regs + S3C2410_UMCON); save->ubrdiv = __raw_readl(regs + S3C2410_UBRDIV); + if (pm_uart_udivslot) + save->udivslot = __raw_readl(regs + S3C2443_DIVSLOT); + S3C_PMDBG("UART[%d]: ULCON=%04x, UCON=%04x, UFCON=%04x, UBRDIV=%04x\n", uart, save->ulcon, save->ucon, save->ufcon, save->ubrdiv); } @@ -108,6 +113,9 @@ static void s3c_pm_restore_uart(unsigned int uart, struct pm_uart_save *save) __raw_writel(save->ufcon, regs + S3C2410_UFCON); __raw_writel(save->umcon, regs + S3C2410_UMCON); __raw_writel(save->ubrdiv, regs + S3C2410_UBRDIV); + + if (pm_uart_udivslot) + __raw_writel(save->udivslot, regs + S3C2443_DIVSLOT); } static void s3c_pm_restore_uarts(void) -- cgit v1.2.3 From bd117bd161ea99826494983aef8c8e236ac129bd Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 10 Mar 2009 18:19:35 +0000 Subject: [ARM] S3C64XX: Initial support for PM (suspend to RAM) Add the initial support for the S3C64XX based systems to use suspend-to-RAM to sleep. Includes basic debugging for use with the SMDK6410 usign the LEDs on the baseboard. Signed-off-by: Ben Dooks --- arch/arm/mach-s3c6400/include/mach/regs-clock.h | 16 ++ arch/arm/plat-s3c/Kconfig | 9 ++ arch/arm/plat-s3c/include/plat/pm.h | 12 ++ arch/arm/plat-s3c/pm.c | 6 +- arch/arm/plat-s3c64xx/Makefile | 5 + arch/arm/plat-s3c64xx/include/plat/irqs.h | 1 + arch/arm/plat-s3c64xx/include/plat/pm-core.h | 98 +++++++++++++ arch/arm/plat-s3c64xx/include/plat/regs-clock.h | 1 + arch/arm/plat-s3c64xx/irq-eint.c | 3 + arch/arm/plat-s3c64xx/pm.c | 186 ++++++++++++++++++++++++ arch/arm/plat-s3c64xx/sleep.S | 144 ++++++++++++++++++ 11 files changed, 479 insertions(+), 2 deletions(-) create mode 100644 arch/arm/mach-s3c6400/include/mach/regs-clock.h create mode 100644 arch/arm/plat-s3c64xx/include/plat/pm-core.h create mode 100644 arch/arm/plat-s3c64xx/pm.c create mode 100644 arch/arm/plat-s3c64xx/sleep.S (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/mach-s3c6400/include/mach/regs-clock.h b/arch/arm/mach-s3c6400/include/mach/regs-clock.h new file mode 100644 index 000000000000..a6c7f4eb3a1b --- /dev/null +++ b/arch/arm/mach-s3c6400/include/mach/regs-clock.h @@ -0,0 +1,16 @@ +/* linux/arch/arm/mach-s3c6400/include/mach/regs-clock.h + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks + * + * S3C64XX - clock register compatibility with s3c24xx + * + * 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 + diff --git a/arch/arm/plat-s3c/Kconfig b/arch/arm/plat-s3c/Kconfig index 042d34a6f815..a4c5027421d3 100644 --- a/arch/arm/plat-s3c/Kconfig +++ b/arch/arm/plat-s3c/Kconfig @@ -71,6 +71,15 @@ config S3C2410_PM_DEBUG Resume code. See for more information. +config S3C_PM_DEBUG_LED_SMDK + bool "SMDK LED suspend/resume debugging" + depends on PM && (MACH_SMDK6410) + help + Say Y here to enable the use of the SMDK LEDs on the baseboard + for debugging of the state of the suspend and resume process. + + Note, this currently only works for S3C64XX based SMDK boards. + config S3C2410_PM_CHECK bool "S3C2410 PM Suspend Memory CRC" depends on PM && CRC32 diff --git a/arch/arm/plat-s3c/include/plat/pm.h b/arch/arm/plat-s3c/include/plat/pm.h index 5f8707e2a09c..7a797192fcf3 100644 --- a/arch/arm/plat-s3c/include/plat/pm.h +++ b/arch/arm/plat-s3c/include/plat/pm.h @@ -127,6 +127,18 @@ extern void s3c_pm_dbg(const char *msg, ...); #define S3C_PMDBG(fmt...) printk(KERN_DEBUG fmt) #endif +#ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK +/** + * s3c_pm_debug_smdkled() - Debug PM suspend/resume via SMDK Board LEDs + * @set: set bits for the state of the LEDs + * @clear: clear bits for the state of the LEDs. + */ +extern void s3c_pm_debug_smdkled(u32 set, u32 clear); + +#else +static inline void s3c_pm_debug_smdkled(u32 set, u32 clear) { } +#endif /* CONFIG_S3C_PM_DEBUG_LED_SMDK */ + /* suspend memory checking */ #ifdef CONFIG_S3C2410_PM_CHECK diff --git a/arch/arm/plat-s3c/pm.c b/arch/arm/plat-s3c/pm.c index 9957b539600f..8d97db2c7a0d 100644 --- a/arch/arm/plat-s3c/pm.c +++ b/arch/arm/plat-s3c/pm.c @@ -21,11 +21,10 @@ #include #include +#include #include #include -#include -#include #include #include @@ -326,6 +325,9 @@ static int s3c_pm_enter(suspend_state_t state) S3C_PMDBG("%s: post sleep, preparing to return\n", __func__); + /* LEDs should now be 1110 */ + s3c_pm_debug_smdkled(1 << 1, 0); + s3c_pm_check_restore(); /* ok, let's return from sleep */ diff --git a/arch/arm/plat-s3c64xx/Makefile b/arch/arm/plat-s3c64xx/Makefile index 2e6d79bf8f33..b2bc2a9ed46b 100644 --- a/arch/arm/plat-s3c64xx/Makefile +++ b/arch/arm/plat-s3c64xx/Makefile @@ -24,6 +24,11 @@ obj-y += gpiolib.o obj-$(CONFIG_CPU_S3C6400_INIT) += s3c6400-init.o obj-$(CONFIG_CPU_S3C6400_CLOCK) += s3c6400-clock.o +# PM support + +obj-$(CONFIG_PM) += pm.o +obj-$(CONFIG_PM) += sleep.o + # Device setup obj-$(CONFIG_S3C64XX_SETUP_I2C0) += setup-i2c0.o diff --git a/arch/arm/plat-s3c64xx/include/plat/irqs.h b/arch/arm/plat-s3c64xx/include/plat/irqs.h index f865bf4d709e..743a70094d04 100644 --- a/arch/arm/plat-s3c64xx/include/plat/irqs.h +++ b/arch/arm/plat-s3c64xx/include/plat/irqs.h @@ -157,6 +157,7 @@ #define S3C_EINT(x) ((x) + S3C_IRQ_EINT_BASE) #define IRQ_EINT(x) S3C_EINT(x) +#define IRQ_EINT_BIT(x) ((x) - S3C_EINT(0)) /* Next the external interrupt groups. These are similar to the IRQ_EINT(x) * that they are sourced from the GPIO pins but with a different scheme for diff --git a/arch/arm/plat-s3c64xx/include/plat/pm-core.h b/arch/arm/plat-s3c64xx/include/plat/pm-core.h new file mode 100644 index 000000000000..d347de3ba0dc --- /dev/null +++ b/arch/arm/plat-s3c64xx/include/plat/pm-core.h @@ -0,0 +1,98 @@ +/* linux/arch/arm/plat-s3c64xx/include/plat/pm-core.h + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * Ben Dooks + * http://armlinux.simtec.co.uk/ + * + * S3C64XX - PM core support for arch/arm/plat-s3c/pm.c + * + * 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 + +static inline void s3c_pm_debug_init_uart(void) +{ + u32 tmp = __raw_readl(S3C_PCLK_GATE); + + /* As a note, since the S3C64XX UARTs generally have multiple + * clock sources, we simply enable PCLK at the moment and hope + * that the resume settings for the UART are suitable for the + * use with PCLK. + */ + + tmp |= S3C_CLKCON_PCLK_UART0; + tmp |= S3C_CLKCON_PCLK_UART1; + tmp |= S3C_CLKCON_PCLK_UART2; + tmp |= S3C_CLKCON_PCLK_UART3; + + __raw_writel(tmp, S3C_PCLK_GATE); + udelay(10); +} + +static inline void s3c_pm_arch_prepare_irqs(void) +{ + /* VIC should have already been taken care of */ + + /* clear any pending EINT0 interrupts */ + __raw_writel(__raw_readl(S3C64XX_EINT0PEND), S3C64XX_EINT0PEND); +} + +static inline void s3c_pm_arch_stop_clocks(void) +{ +} + +static inline void s3c_pm_arch_show_resume_irqs(void) +{ +} + +/* make these defines, we currently do not have any need to change + * the IRQ wake controls depending on the CPU we are running on */ + +#define s3c_irqwake_eintallow ((1 << 28) - 1) +#define s3c_irqwake_intallow (0) + +static inline void s3c_pm_arch_update_uart(void __iomem *regs, + struct pm_uart_save *save) +{ + u32 ucon = __raw_readl(regs + S3C2410_UCON); + u32 ucon_clk = ucon & S3C6400_UCON_CLKMASK; + u32 save_clk = save->ucon & S3C6400_UCON_CLKMASK; + u32 new_ucon; + u32 delta; + + /* S3C64XX UART blocks only support level interrupts, so ensure that + * when we restore unused UART blocks we force the level interrupt + * settigs. */ + save->ucon |= S3C2410_UCON_TXILEVEL | S3C2410_UCON_RXILEVEL; + + /* We have a constraint on changing the clock type of the UART + * between UCLKx and PCLK, so ensure that when we restore UCON + * that the CLK field is correctly modified if the bootloader + * has changed anything. + */ + if (ucon_clk != save_clk) { + new_ucon = save->ucon; + delta = ucon_clk ^ save_clk; + + /* change from UCLKx => wrong PCLK, + * either UCLK can be tested for by a bit-test + * with UCLK0 */ + if (ucon_clk & S3C6400_UCON_UCLK0 && + !(save_clk & S3C6400_UCON_UCLK0) && + delta & S3C6400_UCON_PCLK2) { + new_ucon &= ~S3C6400_UCON_UCLK0; + } else if (delta == S3C6400_UCON_PCLK2) { + /* as an precaution, don't change from + * PCLK2 => PCLK or vice-versa */ + new_ucon ^= S3C6400_UCON_PCLK2; + } + + S3C_PMDBG("ucon change %04x => %04x (save=%04x)\n", + ucon, new_ucon, save->ucon); + save->ucon = new_ucon; + } +} diff --git a/arch/arm/plat-s3c64xx/include/plat/regs-clock.h b/arch/arm/plat-s3c64xx/include/plat/regs-clock.h index b1082c163247..52836d41e333 100644 --- a/arch/arm/plat-s3c64xx/include/plat/regs-clock.h +++ b/arch/arm/plat-s3c64xx/include/plat/regs-clock.h @@ -32,6 +32,7 @@ #define S3C_HCLK_GATE S3C_CLKREG(0x30) #define S3C_PCLK_GATE S3C_CLKREG(0x34) #define S3C_SCLK_GATE S3C_CLKREG(0x38) +#define S3C_MEM0_GATE S3C_CLKREG(0x3C) /* CLKDIV0 */ #define S3C6400_CLKDIV0_MFC_MASK (0xf << 28) diff --git a/arch/arm/plat-s3c64xx/irq-eint.c b/arch/arm/plat-s3c64xx/irq-eint.c index 47e5155bb13e..f81b7b818ba0 100644 --- a/arch/arm/plat-s3c64xx/irq-eint.c +++ b/arch/arm/plat-s3c64xx/irq-eint.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -26,6 +27,7 @@ #include #include +#include #define eint_offset(irq) ((irq) - IRQ_EINT(0)) #define eint_irq_to_bit(irq) (1 << eint_offset(irq)) @@ -134,6 +136,7 @@ static struct irq_chip s3c_irq_eint = { .mask_ack = s3c_irq_eint_maskack, .ack = s3c_irq_eint_ack, .set_type = s3c_irq_eint_set_type, + .set_wake = s3c_irqext_wake, }; /* s3c_irq_demux_eint diff --git a/arch/arm/plat-s3c64xx/pm.c b/arch/arm/plat-s3c64xx/pm.c new file mode 100644 index 000000000000..98190aa364ae --- /dev/null +++ b/arch/arm/plat-s3c64xx/pm.c @@ -0,0 +1,186 @@ +/* linux/arch/arm/plat-s3c64xx/pm.c + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * Ben Dooks + * http://armlinux.simtec.co.uk/ + * + * S3C64XX CPU PM support. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK +#include + +void s3c_pm_debug_smdkled(u32 set, u32 clear) +{ + unsigned long flags; + u32 reg; + + local_irq_save(flags); + reg = __raw_readl(S3C64XX_GPNCON); + reg &= ~(S3C64XX_GPN_CONMASK(12) | S3C64XX_GPN_CONMASK(13) | + S3C64XX_GPN_CONMASK(14) | S3C64XX_GPN_CONMASK(15)); + reg |= S3C64XX_GPN_OUTPUT(12) | S3C64XX_GPN_OUTPUT(13) | + S3C64XX_GPN_OUTPUT(14) | S3C64XX_GPN_OUTPUT(15); + __raw_writel(reg, S3C64XX_GPNCON); + + reg = __raw_readl(S3C64XX_GPNDAT); + reg &= ~(clear << 12); + reg |= set << 12; + __raw_writel(reg, S3C64XX_GPNDAT); + + local_irq_restore(flags); +} +#endif + +static struct sleep_save core_save[] = { + SAVE_ITEM(S3C_APLL_LOCK), + SAVE_ITEM(S3C_MPLL_LOCK), + SAVE_ITEM(S3C_EPLL_LOCK), + SAVE_ITEM(S3C_CLK_SRC), + SAVE_ITEM(S3C_CLK_DIV0), + SAVE_ITEM(S3C_CLK_DIV1), + SAVE_ITEM(S3C_CLK_DIV2), + SAVE_ITEM(S3C_CLK_OUT), + SAVE_ITEM(S3C_HCLK_GATE), + SAVE_ITEM(S3C_PCLK_GATE), + SAVE_ITEM(S3C_SCLK_GATE), + SAVE_ITEM(S3C_MEM0_GATE), + + SAVE_ITEM(S3C_EPLL_CON1), + SAVE_ITEM(S3C_EPLL_CON0), + + SAVE_ITEM(S3C64XX_MEM0DRVCON), + SAVE_ITEM(S3C64XX_MEM1DRVCON), + +#ifndef CONFIG_CPU_FREQ + SAVE_ITEM(S3C_APLL_CON), + SAVE_ITEM(S3C_MPLL_CON), +#endif +}; + +static struct sleep_save misc_save[] = { + SAVE_ITEM(S3C64XX_AHB_CON0), + SAVE_ITEM(S3C64XX_AHB_CON1), + SAVE_ITEM(S3C64XX_AHB_CON2), + + SAVE_ITEM(S3C64XX_SPCON), + + SAVE_ITEM(S3C64XX_MEM0CONSTOP), + SAVE_ITEM(S3C64XX_MEM1CONSTOP), + SAVE_ITEM(S3C64XX_MEM0CONSLP0), + SAVE_ITEM(S3C64XX_MEM0CONSLP1), + SAVE_ITEM(S3C64XX_MEM1CONSLP), +}; + +void s3c_pm_configure_extint(void) +{ + __raw_writel(s3c_irqwake_eintmask, S3C64XX_EINT_MASK); +} + +void s3c_pm_save_gpios(void) +{ + /* currently, unless the bootloader does something really stupid + * the gpio blocks should be maintained over their sleep. + */ +} + +void s3c_pm_restore_gpios(void) +{ +} + +void s3c_pm_restore_core(void) +{ + __raw_writel(0, S3C64XX_EINT_MASK); + + s3c_pm_debug_smdkled(1 << 2, 0); + + s3c_pm_do_restore_core(core_save, ARRAY_SIZE(core_save)); + s3c_pm_do_restore(misc_save, ARRAY_SIZE(misc_save)); +} + +void s3c_pm_save_core(void) +{ + s3c_pm_do_save(misc_save, ARRAY_SIZE(misc_save)); + s3c_pm_do_save(core_save, ARRAY_SIZE(core_save)); +} + +/* since both s3c6400 and s3c6410 share the same sleep pm calls, we + * put the per-cpu code in here until any new cpu comes along and changes + * this. + */ + +#include + +static void s3c64xx_cpu_suspend(void) +{ + unsigned long tmp; + + /* set our standby method to sleep */ + + tmp = __raw_readl(S3C64XX_PWR_CFG); + tmp &= ~S3C64XX_PWRCFG_CFG_WFI_MASK; + tmp |= S3C64XX_PWRCFG_CFG_WFI_SLEEP; + __raw_writel(tmp, S3C64XX_PWR_CFG); + + /* clear any old wakeup */ + + __raw_writel(__raw_readl(S3C64XX_WAKEUP_STAT), + S3C64XX_WAKEUP_STAT); + + /* set the LED state to 0110 over sleep */ + s3c_pm_debug_smdkled(3 << 1, 0xf); + + /* issue the standby signal into the pm unit. Note, we + * issue a write-buffer drain just in case */ + + tmp = 0; + + asm("b 1f\n\t" + ".align 5\n\t" + "1:\n\t" + "mcr p15, 0, %0, c7, c10, 5\n\t" + "mcr p15, 0, %0, c7, c10, 4\n\t" + "mcr p15, 0, %0, c7, c0, 4" :: "r" (tmp)); + + /* we should never get past here */ + + panic("sleep resumed to originator?"); +} + +static void s3c64xx_pm_prepare(void) +{ + /* store address of resume. */ + __raw_writel(virt_to_phys(s3c_cpu_resume), S3C64XX_INFORM0); + + /* ensure previous wakeup state is cleared before sleeping */ + __raw_writel(__raw_readl(S3C64XX_WAKEUP_STAT), S3C64XX_WAKEUP_STAT); +} + +static int s3c64xx_pm_init(void) +{ + pm_cpu_prep = s3c64xx_pm_prepare; + pm_cpu_sleep = s3c64xx_cpu_suspend; + pm_uart_udivslot = 1; + return 0; +} + +arch_initcall(s3c64xx_pm_init); diff --git a/arch/arm/plat-s3c64xx/sleep.S b/arch/arm/plat-s3c64xx/sleep.S new file mode 100644 index 000000000000..8e71fe90a373 --- /dev/null +++ b/arch/arm/plat-s3c64xx/sleep.S @@ -0,0 +1,144 @@ +/* linux/0arch/arm/plat-s3c64xx/sleep.S + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * Ben Dooks + * http://armlinux.simtec.co.uk/ + * + * S3C64XX CPU sleep code + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include +#include +#include + +#undef S3C64XX_VA_GPIO +#define S3C64XX_VA_GPIO (0x0) + +#include +#include + +#define LL_UART (S3C_PA_UART + (0x400 * CONFIG_S3C_LOWLEVEL_UART_PORT)) + + .text + + /* s3c_cpu_save + * + * Save enough processor state to allow the restart of the pm.c + * code after resume. + * + * entry: + * r0 = pointer to the save block + */ + +ENTRY(s3c_cpu_save) + stmfd sp!, { r4 - r12, lr } + + mrc p15, 0, r4, c13, c0, 0 @ FCSE/PID + mrc p15, 0, r5, c3, c0, 0 @ Domain ID + mrc p15, 0, r6, c2, c0, 0 @ Translation Table BASE0 + mrc p15, 0, r7, c2, c0, 1 @ Translation Table BASE1 + mrc p15, 0, r8, c2, c0, 2 @ Translation Table Control + mrc p15, 0, r9, c1, c0, 0 @ Control register + mrc p15, 0, r10, c1, c0, 1 @ Auxiliary control register + mrc p15, 0, r11, c1, c0, 2 @ Co-processor access controls + + stmia r0, { r4 - r13 } @ Save CP registers and SP + + @@ save our state to ram + bl s3c_pm_cb_flushcache + + @@ call final suspend code + ldr r0, =pm_cpu_sleep + ldr pc, [r0] + + @@ return to the caller, after the MMU is turned on. + @@ restore the last bits of the stack and return. +resume_with_mmu: + ldmfd sp!, { r4 - r12, pc } @ return, from sp from s3c_cpu_save + + .data + + /* the next bit is code, but it requires easy access to the + * s3c_sleep_save_phys data before the MMU is switched on, so + * we store the code that needs this variable in the .data where + * the value can be written to (the .text segment is RO). + */ + + .global s3c_sleep_save_phys +s3c_sleep_save_phys: + .word 0 + + /* Sleep magic, the word before the resume entry point so that the + * bootloader can check for a resumeable image. */ + + .word 0x2bedf00d + + /* s3c_cpu_reusme + * + * This is the entry point, stored by whatever method the bootloader + * requires to get the kernel runnign again. This code expects to be + * entered with no caches live and the MMU disabled. It will then + * restore the MMU and other basic CP registers saved and restart + * the kernel C code to finish the resume code. + */ + +ENTRY(s3c_cpu_resume) + msr cpsr_c, #PSR_I_BIT | PSR_F_BIT | SVC_MODE + ldr r2, =LL_UART /* for debug */ + +#ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK + /* Initialise the GPIO state if we are debugging via the SMDK LEDs, + * as the uboot version supplied resets these to inputs during the + * resume checks. + */ + + ldr r3, =S3C64XX_PA_GPIO + ldr r0, [ r3, #S3C64XX_GPNCON ] + bic r0, r0, #(S3C64XX_GPN_CONMASK(12) | S3C64XX_GPN_CONMASK(13) | \ + S3C64XX_GPN_CONMASK(14) | S3C64XX_GPN_CONMASK(15)) + orr r0, r0, #(S3C64XX_GPN_OUTPUT(12) | S3C64XX_GPN_OUTPUT(13) | \ + S3C64XX_GPN_OUTPUT(14) | S3C64XX_GPN_OUTPUT(15)) + str r0, [ r3, #S3C64XX_GPNCON ] + + ldr r0, [ r3, #S3C64XX_GPNDAT ] + bic r0, r0, #0xf << 12 @ GPN12..15 + orr r0, r0, #1 << 15 @ GPN15 + str r0, [ r3, #S3C64XX_GPNDAT ] +#endif + + /* __v6_setup from arch/arm/mm/proc-v6.S, ensure that the caches + * are thoroughly cleaned just in case the bootloader didn't do it + * for us. */ + mov r0, #0 + mcr p15, 0, r0, c7, c14, 0 @ clean+invalidate D cache + mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache + mcr p15, 0, r0, c7, c15, 0 @ clean+invalidate cache + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer + @@mcr p15, 0, r0, c8, c7, 0 @ invalidate I + D TLBs + @@mcr p15, 0, r0, c7, c7, 0 @ Invalidate I + D caches + + ldr r0, s3c_sleep_save_phys + ldmia r0, { r4 - r13 } + + mcr p15, 0, r4, c13, c0, 0 @ FCSE/PID + mcr p15, 0, r5, c3, c0, 0 @ Domain ID + mcr p15, 0, r6, c2, c0, 0 @ Translation Table BASE0 + mcr p15, 0, r7, c2, c0, 1 @ Translation Table BASE1 + mcr p15, 0, r8, c2, c0, 2 @ Translation Table Control + mcr p15, 0, r10, c1, c0, 1 @ Auxiliary control register + + mov r0, #0 @ restore copro access controls + mcr p15, 0, r11, c1, c0, 2 @ Co-processor access controls + mcr p15, 0, r0, c7, c5, 4 + + ldr r2, =resume_with_mmu + mcr p15, 0, r9, c1, c0, 0 /* turn mmu back on */ + nop + mov pc, r2 /* jump back */ + + .end -- cgit v1.2.3 From 0abfe9aab1867abd96b44a425ad27ce021891e4f Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Fri, 12 Dec 2008 00:24:28 +0000 Subject: [ARM] S3C64XX: Add s3c6410_sysclass export Add definition for s3c6410_sysclass which was missing from arch/arm/plat-s3c/include/plat/cpu.h. Signed-off-by: Ben Dooks --- arch/arm/plat-s3c/include/plat/cpu.h | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/plat-s3c/include/plat/cpu.h b/arch/arm/plat-s3c/include/plat/cpu.h index e62ae0fcfe56..f878cf6673ce 100644 --- a/arch/arm/plat-s3c/include/plat/cpu.h +++ b/arch/arm/plat-s3c/include/plat/cpu.h @@ -69,3 +69,4 @@ extern struct sysdev_class s3c2412_sysclass; extern struct sysdev_class s3c2440_sysclass; extern struct sysdev_class s3c2442_sysclass; extern struct sysdev_class s3c2443_sysclass; +extern struct sysdev_class s3c6410_sysclass; -- cgit v1.2.3 From 1deb507dc7612e6c81b7953e827d1c859c1d8c0b Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Fri, 12 Dec 2008 00:24:31 +0000 Subject: [ARM] S3C64XX: Add generic s3c64xx sys device. Add an s3c64xx_sysclass and device for items that currently want to bind to any s3c64xx processor. The first user of this will be parts of the s3c64xx suspend support which need to save device state over suspend/resume. Signed-off-by: Ben Dooks --- arch/arm/plat-s3c/include/plat/cpu.h | 2 ++ arch/arm/plat-s3c64xx/cpu.c | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/plat-s3c/include/plat/cpu.h b/arch/arm/plat-s3c/include/plat/cpu.h index f878cf6673ce..be541cbba070 100644 --- a/arch/arm/plat-s3c/include/plat/cpu.h +++ b/arch/arm/plat-s3c/include/plat/cpu.h @@ -70,3 +70,5 @@ extern struct sysdev_class s3c2440_sysclass; extern struct sysdev_class s3c2442_sysclass; extern struct sysdev_class s3c2443_sysclass; extern struct sysdev_class s3c6410_sysclass; +extern struct sysdev_class s3c64xx_sysclass; + diff --git a/arch/arm/plat-s3c64xx/cpu.c b/arch/arm/plat-s3c64xx/cpu.c index 91f49a3a665d..f9fdaab32ab4 100644 --- a/arch/arm/plat-s3c64xx/cpu.c +++ b/arch/arm/plat-s3c64xx/cpu.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -104,6 +105,16 @@ static struct map_desc s3c_iodesc[] __initdata = { }, }; + +struct sysdev_class s3c64xx_sysclass = { + .name = "s3c64xx-core", +}; + +static struct sys_device s3c64xx_sysdev = { + .cls = &s3c64xx_sysclass, +}; + + /* read cpu identification code */ void __init s3c64xx_init_io(struct map_desc *mach_desc, int size) @@ -117,3 +128,11 @@ void __init s3c64xx_init_io(struct map_desc *mach_desc, int size) idcode = __raw_readl(S3C_VA_SYS + 0x118); s3c_init_cpu(idcode, cpu_ids, ARRAY_SIZE(cpu_ids)); } + +static __init int s3c64xx_sysdev_init(void) +{ + sysdev_class_register(&s3c64xx_sysclass); + return sysdev_register(&s3c64xx_sysdev); +} + +core_initcall(s3c64xx_sysdev_init); -- cgit v1.2.3 From 966bcc14386000e8b4dc7bbb426910bcb55a8588 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Fri, 12 Dec 2008 00:24:32 +0000 Subject: [ARM] S3C64XX: Add IRQ PM code Add support for saving the state of the IRQ registers over suspend. This requires moving the S3C64XX UART registers into and adding irq-pm.c which saves the state of all the IRQ registers. The irq-pm.c saves all the IRQ registers, including the IRQ_EINT and IRQ_EINT_GROUP registers as it was easier than adding three different files. Also ensuring that all the registers are restored to the same state as before suspend is considered to be the best thing to do. Note, we do not suspend the VIC here, this is done by the VIC driver itself. Signed-off-by: Ben Dooks --- arch/arm/plat-s3c/include/plat/regs-serial.h | 5 ++ arch/arm/plat-s3c64xx/Makefile | 1 + arch/arm/plat-s3c64xx/irq-pm.c | 111 +++++++++++++++++++++++++++ arch/arm/plat-s3c64xx/irq.c | 5 +- 4 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 arch/arm/plat-s3c64xx/irq-pm.c (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/plat-s3c/include/plat/regs-serial.h b/arch/arm/plat-s3c/include/plat/regs-serial.h index 487d7d2a7e1d..66af75a5cdd1 100644 --- a/arch/arm/plat-s3c/include/plat/regs-serial.h +++ b/arch/arm/plat-s3c/include/plat/regs-serial.h @@ -189,6 +189,11 @@ #define S3C2443_DIVSLOT (0x2C) +/* S3C64XX interrupt registers. */ +#define S3C64XX_UINTP 0x30 +#define S3C64XX_UINTSP 0x34 +#define S3C64XX_UINTM 0x38 + #ifndef __ASSEMBLY__ /* struct s3c24xx_uart_clksrc diff --git a/arch/arm/plat-s3c64xx/Makefile b/arch/arm/plat-s3c64xx/Makefile index b2bc2a9ed46b..12ac7a50ab74 100644 --- a/arch/arm/plat-s3c64xx/Makefile +++ b/arch/arm/plat-s3c64xx/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_CPU_S3C6400_CLOCK) += s3c6400-clock.o obj-$(CONFIG_PM) += pm.o obj-$(CONFIG_PM) += sleep.o +obj-$(CONFIG_PM) += irq-pm.o # Device setup diff --git a/arch/arm/plat-s3c64xx/irq-pm.c b/arch/arm/plat-s3c64xx/irq-pm.c new file mode 100644 index 000000000000..ca523b5d4c17 --- /dev/null +++ b/arch/arm/plat-s3c64xx/irq-pm.c @@ -0,0 +1,111 @@ +/* arch/arm/plat-s3c64xx/irq-pm.c + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * Ben Dooks + * http://armlinux.simtec.co.uk/ + * + * S3C64XX - Interrupt handling Power Management + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +/* We handled all the IRQ types in this code, to save having to make several + * small files to handle each different type separately. Having the EINT_GRP + * code here shouldn't be as much bloat as the IRQ table space needed when + * they are enabled. The added benefit is we ensure that these registers are + * in the same state as we suspended. + */ + +static struct sleep_save irq_save[] = { + SAVE_ITEM(S3C64XX_PRIORITY), + SAVE_ITEM(S3C64XX_EINT0CON0), + SAVE_ITEM(S3C64XX_EINT0CON1), + SAVE_ITEM(S3C64XX_EINT0FLTCON0), + SAVE_ITEM(S3C64XX_EINT0FLTCON1), + SAVE_ITEM(S3C64XX_EINT0FLTCON2), + SAVE_ITEM(S3C64XX_EINT0FLTCON3), + SAVE_ITEM(S3C64XX_EINT0MASK), + SAVE_ITEM(S3C64XX_TINT_CSTAT), +}; + +static struct irq_grp_save { + u32 fltcon; + u32 con; + u32 mask; +} eint_grp_save[5]; + +static u32 irq_uart_mask[CONFIG_SERIAL_SAMSUNG_UARTS]; + +static int s3c64xx_irq_pm_suspend(struct sys_device *dev, pm_message_t state) +{ + struct irq_grp_save *grp = eint_grp_save; + int i; + + S3C_PMDBG("%s: suspending IRQs\n", __func__); + + s3c_pm_do_save(irq_save, ARRAY_SIZE(irq_save)); + + for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++) + irq_uart_mask[i] = __raw_readl(S3C_VA_UARTx(i) + S3C64XX_UINTM); + + for (i = 0; i < ARRAY_SIZE(eint_grp_save); i++, grp++) { + grp->con = __raw_readl(S3C64XX_EINT12CON + (i * 4)); + grp->mask = __raw_readl(S3C64XX_EINT12MASK + (i * 4)); + grp->fltcon = __raw_readl(S3C64XX_EINT12FLTCON + (i * 4)); + } + + return 0; +} + +static int s3c64xx_irq_pm_resume(struct sys_device *dev) +{ + struct irq_grp_save *grp = eint_grp_save; + int i; + + S3C_PMDBG("%s: resuming IRQs\n", __func__); + + s3c_pm_do_restore(irq_save, ARRAY_SIZE(irq_save)); + + for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++) + __raw_writel(irq_uart_mask[i], S3C_VA_UARTx(i) + S3C64XX_UINTM); + + for (i = 0; i < ARRAY_SIZE(eint_grp_save); i++, grp++) { + __raw_writel(grp->con, S3C64XX_EINT12CON + (i * 4)); + __raw_writel(grp->mask, S3C64XX_EINT12MASK + (i * 4)); + __raw_writel(grp->fltcon, S3C64XX_EINT12FLTCON + (i * 4)); + } + + S3C_PMDBG("%s: IRQ configuration restored\n", __func__); + return 0; +} + +static struct sysdev_driver s3c64xx_irq_driver = { + .suspend = s3c64xx_irq_pm_suspend, + .resume = s3c64xx_irq_pm_resume, +}; + +static int __init s3c64xx_irq_pm_init(void) +{ + return sysdev_driver_register(&s3c64xx_sysclass, &s3c64xx_irq_driver); +} + +arch_initcall(s3c64xx_irq_pm_init); + diff --git a/arch/arm/plat-s3c64xx/irq.c b/arch/arm/plat-s3c64xx/irq.c index f22edf7c2d2d..f4c4844f9fdb 100644 --- a/arch/arm/plat-s3c64xx/irq.c +++ b/arch/arm/plat-s3c64xx/irq.c @@ -14,12 +14,14 @@ #include #include +#include #include #include #include #include +#include #include #include @@ -135,9 +137,6 @@ static inline unsigned int s3c_irq_uart_bit(unsigned int irq) } /* UART interrupt registers, not worth adding to seperate include header */ -#define S3C64XX_UINTP 0x30 -#define S3C64XX_UINTSP 0x34 -#define S3C64XX_UINTM 0x38 static void s3c_irq_uart_mask(unsigned int irq) { -- cgit v1.2.3 From d87964c46005ccb04754f6309df0fd8f67b08c6d Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Fri, 12 Dec 2008 00:24:30 +0000 Subject: [ARM] S3C: GPIO PM core GPIOlib integration Move the GPIO suspend/resume support inline with the gpiolib support so that it will work with both the S3C24XX and S3C64XX series. The s3c_gpio_chip is extended to have a pm callback and a save block to keep the state of the GPIO over suspend, and the code from the s3c24xx implementation is added to a new common file. The suspend process now uses the list of registered chips to go through saving and restoring each one as appropriate, using the pm callback to select the appropriate routine depending on the type of control register present. This change also means that any additional GPIO added should not require changes to the PM. Signed-off-by: Ben Dooks --- arch/arm/plat-s3c/Makefile | 1 + arch/arm/plat-s3c/gpio.c | 11 +- arch/arm/plat-s3c/include/plat/gpio-core.h | 30 +++ arch/arm/plat-s3c/pm-gpio.c | 380 +++++++++++++++++++++++++++++ arch/arm/plat-s3c24xx/gpiolib.c | 8 + arch/arm/plat-s3c24xx/pm.c | 213 ---------------- arch/arm/plat-s3c64xx/gpiolib.c | 10 +- arch/arm/plat-s3c64xx/pm.c | 11 - 8 files changed, 438 insertions(+), 226 deletions(-) create mode 100644 arch/arm/plat-s3c/pm-gpio.c (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/plat-s3c/Makefile b/arch/arm/plat-s3c/Makefile index aa995a49e567..bfc8f537db18 100644 --- a/arch/arm/plat-s3c/Makefile +++ b/arch/arm/plat-s3c/Makefile @@ -21,6 +21,7 @@ obj-y += gpio-config.o # PM support obj-$(CONFIG_PM) += pm.o +obj-$(CONFIG_PM) += pm-gpio.o obj-$(CONFIG_S3C2410_PM_CHECK) += pm-check.o # devices diff --git a/arch/arm/plat-s3c/gpio.c b/arch/arm/plat-s3c/gpio.c index d71dd6d9ce5c..260fdc6ad685 100644 --- a/arch/arm/plat-s3c/gpio.c +++ b/arch/arm/plat-s3c/gpio.c @@ -16,7 +16,7 @@ #include #include -#include +#include #ifdef CONFIG_S3C_GPIO_TRACK struct s3c_gpio_chip *s3c_gpios[S3C_GPIO_END]; @@ -140,6 +140,15 @@ __init void s3c_gpiolib_add(struct s3c_gpio_chip *chip) if (!gc->get) gc->get = s3c_gpiolib_get; +#ifdef CONFIG_PM + if (chip->pm != NULL) { + if (!chip->pm->save || !chip->pm->resume) + printk(KERN_ERR "gpio: %s has missing PM functions\n", + gc->label); + } else + printk(KERN_ERR "gpio: %s has no PM function\n", gc->label); +#endif + /* gpiochip_add() prints own failure message on error. */ ret = gpiochip_add(gc); if (ret >= 0) diff --git a/arch/arm/plat-s3c/include/plat/gpio-core.h b/arch/arm/plat-s3c/include/plat/gpio-core.h index 2fc60a580ac8..32af612767aa 100644 --- a/arch/arm/plat-s3c/include/plat/gpio-core.h +++ b/arch/arm/plat-s3c/include/plat/gpio-core.h @@ -20,6 +20,18 @@ * specific code. */ +struct s3c_gpio_chip; + +/** + * struct s3c_gpio_pm - power management (suspend/resume) information + * @save: Routine to save the state of the GPIO block + * @resume: Routine to resume the GPIO block. + */ +struct s3c_gpio_pm { + void (*save)(struct s3c_gpio_chip *chip); + void (*resume)(struct s3c_gpio_chip *chip); +}; + struct s3c_gpio_cfg; /** @@ -27,6 +39,7 @@ struct s3c_gpio_cfg; * @chip: The chip structure to be exported via gpiolib. * @base: The base pointer to the gpio configuration registers. * @config: special function and pull-resistor control information. + * @pm_save: Save information for suspend/resume support. * * This wrapper provides the necessary information for the Samsung * specific gpios being registered with gpiolib. @@ -34,7 +47,11 @@ struct s3c_gpio_cfg; struct s3c_gpio_chip { struct gpio_chip chip; struct s3c_gpio_cfg *config; + struct s3c_gpio_pm *pm; void __iomem *base; +#ifdef CONFIG_PM + u32 pm_save[4]; +#endif }; static inline struct s3c_gpio_chip *to_s3c_gpio(struct gpio_chip *gpc) @@ -75,3 +92,16 @@ static inline struct s3c_gpio_chip *s3c_gpiolib_getchip(unsigned int chip) static inline void s3c_gpiolib_track(struct s3c_gpio_chip *chip) { } #endif + +#ifdef CONFIG_PM +extern struct s3c_gpio_pm s3c_gpio_pm_1bit; +extern struct s3c_gpio_pm s3c_gpio_pm_2bit; +extern struct s3c_gpio_pm s3c_gpio_pm_4bit; +#define __gpio_pm(x) x +#else +#define s3c_gpio_pm_1bit NULL +#define s3c_gpio_pm_2bit NULL +#define s3c_gpio_pm_4bit NULL +#define __gpio_pm(x) NULL + +#endif /* CONFIG_PM */ diff --git a/arch/arm/plat-s3c/pm-gpio.c b/arch/arm/plat-s3c/pm-gpio.c new file mode 100644 index 000000000000..cfd326a8b693 --- /dev/null +++ b/arch/arm/plat-s3c/pm-gpio.c @@ -0,0 +1,380 @@ + +/* linux/arch/arm/plat-s3c/pm-gpio.c + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * Ben Dooks + * http://armlinux.simtec.co.uk/ + * + * S3C series GPIO PM code + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include +#include +#include +#include +#include + +#include +#include + +/* PM GPIO helpers */ + +#define OFFS_CON (0x00) +#define OFFS_DAT (0x04) +#define OFFS_UP (0x08) + +static void s3c_gpio_pm_1bit_save(struct s3c_gpio_chip *chip) +{ + chip->pm_save[0] = __raw_readl(chip->base + OFFS_CON); + chip->pm_save[1] = __raw_readl(chip->base + OFFS_DAT); +} + +static void s3c_gpio_pm_1bit_resume(struct s3c_gpio_chip *chip) +{ + void __iomem *base = chip->base; + u32 old_gpcon = __raw_readl(base + OFFS_CON); + u32 old_gpdat = __raw_readl(base + OFFS_DAT); + u32 gps_gpcon = chip->pm_save[0]; + u32 gps_gpdat = chip->pm_save[1]; + u32 gpcon; + + /* GPACON only has one bit per control / data and no PULLUPs. + * GPACON[x] = 0 => Output, 1 => SFN */ + + /* first set all SFN bits to SFN */ + + gpcon = old_gpcon | gps_gpcon; + __raw_writel(gpcon, base + OFFS_CON); + + /* now set all the other bits */ + + __raw_writel(gps_gpdat, base + OFFS_DAT); + __raw_writel(gps_gpcon, base + OFFS_CON); + + S3C_PMDBG("%s: CON %08x => %08x, DAT %08x => %08x\n", + chip->chip.label, old_gpcon, gps_gpcon, old_gpdat, gps_gpdat); +} + +struct s3c_gpio_pm s3c_gpio_pm_1bit = { + .save = s3c_gpio_pm_1bit_save, + .resume = s3c_gpio_pm_1bit_resume, +}; + +static void s3c_gpio_pm_2bit_save(struct s3c_gpio_chip *chip) +{ + chip->pm_save[0] = __raw_readl(chip->base + OFFS_CON); + chip->pm_save[1] = __raw_readl(chip->base + OFFS_DAT); + chip->pm_save[2] = __raw_readl(chip->base + OFFS_UP); +} + +/* Test whether the given masked+shifted bits of an GPIO configuration + * are one of the SFN (special function) modes. */ + +static inline int is_sfn(unsigned long con) +{ + return con >= 2; +} + +/* Test if the given masked+shifted GPIO configuration is an input */ + +static inline int is_in(unsigned long con) +{ + return con == 0; +} + +/* Test if the given masked+shifted GPIO configuration is an output */ + +static inline int is_out(unsigned long con) +{ + return con == 1; +} + +/** + * s3c_gpio_pm_2bit_resume() - restore the given GPIO bank + * @chip: The chip information to resume. + * + * Restore one of the GPIO banks that was saved during suspend. This is + * not as simple as once thought, due to the possibility of glitches + * from the order that the CON and DAT registers are set in. + * + * The three states the pin can be are {IN,OUT,SFN} which gives us 9 + * combinations of changes to check. Three of these, if the pin stays + * in the same configuration can be discounted. This leaves us with + * the following: + * + * { IN => OUT } Change DAT first + * { IN => SFN } Change CON first + * { OUT => SFN } Change CON first, so new data will not glitch + * { OUT => IN } Change CON first, so new data will not glitch + * { SFN => IN } Change CON first + * { SFN => OUT } Change DAT first, so new data will not glitch [1] + * + * We do not currently deal with the UP registers as these control + * weak resistors, so a small delay in change should not need to bring + * these into the calculations. + * + * [1] this assumes that writing to a pin DAT whilst in SFN will set the + * state for when it is next output. + */ +static void s3c_gpio_pm_2bit_resume(struct s3c_gpio_chip *chip) +{ + void __iomem *base = chip->base; + u32 old_gpcon = __raw_readl(base + OFFS_CON); + u32 old_gpdat = __raw_readl(base + OFFS_DAT); + u32 gps_gpcon = chip->pm_save[0]; + u32 gps_gpdat = chip->pm_save[1]; + u32 gpcon, old, new, mask; + u32 change_mask = 0x0; + int nr; + + /* restore GPIO pull-up settings */ + __raw_writel(chip->pm_save[2], base + OFFS_UP); + + /* Create a change_mask of all the items that need to have + * their CON value changed before their DAT value, so that + * we minimise the work between the two settings. + */ + + for (nr = 0, mask = 0x03; nr < 32; nr += 2, mask <<= 2) { + old = (old_gpcon & mask) >> nr; + new = (gps_gpcon & mask) >> nr; + + /* If there is no change, then skip */ + + if (old == new) + continue; + + /* If both are special function, then skip */ + + if (is_sfn(old) && is_sfn(new)) + continue; + + /* Change is IN => OUT, do not change now */ + + if (is_in(old) && is_out(new)) + continue; + + /* Change is SFN => OUT, do not change now */ + + if (is_sfn(old) && is_out(new)) + continue; + + /* We should now be at the case of IN=>SFN, + * OUT=>SFN, OUT=>IN, SFN=>IN. */ + + change_mask |= mask; + } + + + /* Write the new CON settings */ + + gpcon = old_gpcon & ~change_mask; + gpcon |= gps_gpcon & change_mask; + + __raw_writel(gpcon, base + OFFS_CON); + + /* Now change any items that require DAT,CON */ + + __raw_writel(gps_gpdat, base + OFFS_DAT); + __raw_writel(gps_gpcon, base + OFFS_CON); + + S3C_PMDBG("%s: CON %08x => %08x, DAT %08x => %08x\n", + chip->chip.label, old_gpcon, gps_gpcon, old_gpdat, gps_gpdat); +} + +struct s3c_gpio_pm s3c_gpio_pm_2bit = { + .save = s3c_gpio_pm_2bit_save, + .resume = s3c_gpio_pm_2bit_resume, +}; + +#ifdef CONFIG_ARCH_S3C64XX +static void s3c_gpio_pm_4bit_save(struct s3c_gpio_chip *chip) +{ + chip->pm_save[1] = __raw_readl(chip->base + OFFS_CON); + chip->pm_save[2] = __raw_readl(chip->base + OFFS_DAT); + chip->pm_save[3] = __raw_readl(chip->base + OFFS_UP); + + if (chip->chip.ngpio > 8) + chip->pm_save[0] = __raw_readl(chip->base - 4); +} + +static u32 s3c_gpio_pm_4bit_mask(u32 old_gpcon, u32 gps_gpcon) +{ + u32 old, new, mask; + u32 change_mask = 0x0; + int nr; + + for (nr = 0, mask = 0x0f; nr < 16; nr += 4, mask <<= 4) { + old = (old_gpcon & mask) >> nr; + new = (gps_gpcon & mask) >> nr; + + /* If there is no change, then skip */ + + if (old == new) + continue; + + /* If both are special function, then skip */ + + if (is_sfn(old) && is_sfn(new)) + continue; + + /* Change is IN => OUT, do not change now */ + + if (is_in(old) && is_out(new)) + continue; + + /* Change is SFN => OUT, do not change now */ + + if (is_sfn(old) && is_out(new)) + continue; + + /* We should now be at the case of IN=>SFN, + * OUT=>SFN, OUT=>IN, SFN=>IN. */ + + change_mask |= mask; + } + + return change_mask; +} + +static void s3c_gpio_pm_4bit_con(struct s3c_gpio_chip *chip, int index) +{ + void __iomem *con = chip->base + (index * 4); + u32 old_gpcon = __raw_readl(con); + u32 gps_gpcon = chip->pm_save[index + 1]; + u32 gpcon, mask; + + mask = s3c_gpio_pm_4bit_mask(old_gpcon, gps_gpcon); + + gpcon = old_gpcon & ~mask; + gpcon |= gps_gpcon & mask; + + __raw_writel(gpcon, con); +} + +static void s3c_gpio_pm_4bit_resume(struct s3c_gpio_chip *chip) +{ + void __iomem *base = chip->base; + u32 old_gpcon[2]; + u32 old_gpdat = __raw_readl(base + OFFS_DAT); + u32 gps_gpdat = chip->pm_save[2]; + + /* First, modify the CON settings */ + + old_gpcon[0] = 0; + old_gpcon[1] = __raw_readl(base + OFFS_CON); + + s3c_gpio_pm_4bit_con(chip, 0); + if (chip->chip.ngpio > 8) { + old_gpcon[0] = __raw_readl(base - 4); + s3c_gpio_pm_4bit_con(chip, -1); + } + + /* Now change the configurations that require DAT,CON */ + + __raw_writel(chip->pm_save[2], base + OFFS_DAT); + __raw_writel(chip->pm_save[1], base + OFFS_CON); + if (chip->chip.ngpio > 8) + __raw_writel(chip->pm_save[0], base - 4); + + __raw_writel(chip->pm_save[2], base + OFFS_DAT); + __raw_writel(chip->pm_save[3], base + OFFS_UP); + + if (chip->chip.ngpio > 8) { + S3C_PMDBG("%s: CON4 %08x,%08x => %08x,%08x, DAT %08x => %08x\n", + chip->chip.label, old_gpcon[0], old_gpcon[1], + __raw_readl(base - 4), + __raw_readl(base + OFFS_CON), + old_gpdat, gps_gpdat); + } else + S3C_PMDBG("%s: CON4 %08x => %08x, DAT %08x => %08x\n", + chip->chip.label, old_gpcon[1], + __raw_readl(base + OFFS_CON), + old_gpdat, gps_gpdat); +} + +struct s3c_gpio_pm s3c_gpio_pm_4bit = { + .save = s3c_gpio_pm_4bit_save, + .resume = s3c_gpio_pm_4bit_resume, +}; +#endif /* CONFIG_ARCH_S3C64XX */ + +/** + * s3c_pm_save_gpio() - save gpio chip data for suspend + * @ourchip: The chip for suspend. + */ +static void s3c_pm_save_gpio(struct s3c_gpio_chip *ourchip) +{ + struct s3c_gpio_pm *pm = ourchip->pm; + + if (pm == NULL || pm->save == NULL) + S3C_PMDBG("%s: no pm for %s\n", __func__, ourchip->chip.label); + else + pm->save(ourchip); +} + +/** + * s3c_pm_save_gpios() - Save the state of the GPIO banks. + * + * For all the GPIO banks, save the state of each one ready for going + * into a suspend mode. + */ +void s3c_pm_save_gpios(void) +{ + struct s3c_gpio_chip *ourchip; + unsigned int gpio_nr; + + for (gpio_nr = 0; gpio_nr < S3C_GPIO_END; gpio_nr++) { + ourchip = s3c_gpiolib_getchip(gpio_nr); + if (!ourchip) + continue; + + s3c_pm_save_gpio(ourchip); + + S3C_PMDBG("%s: save %08x,%08x,%08x,%08x\n", + ourchip->chip.label, + ourchip->pm_save[0], + ourchip->pm_save[1], + ourchip->pm_save[2], + ourchip->pm_save[3]); + + gpio_nr += ourchip->chip.ngpio; + gpio_nr += CONFIG_S3C_GPIO_SPACE; + } +} + +/** + * s3c_pm_resume_gpio() - restore gpio chip data after suspend + * @ourchip: The suspended chip. + */ +static void s3c_pm_resume_gpio(struct s3c_gpio_chip *ourchip) +{ + struct s3c_gpio_pm *pm = ourchip->pm; + + if (pm == NULL || pm->resume == NULL) + S3C_PMDBG("%s: no pm for %s\n", __func__, ourchip->chip.label); + else + pm->resume(ourchip); +} + +void s3c_pm_restore_gpios(void) +{ + struct s3c_gpio_chip *ourchip; + unsigned int gpio_nr; + + for (gpio_nr = 0; gpio_nr < S3C_GPIO_END; gpio_nr++) { + ourchip = s3c_gpiolib_getchip(gpio_nr); + if (!ourchip) + continue; + + s3c_pm_resume_gpio(ourchip); + + gpio_nr += ourchip->chip.ngpio; + gpio_nr += CONFIG_S3C_GPIO_SPACE; + } +} diff --git a/arch/arm/plat-s3c24xx/gpiolib.c b/arch/arm/plat-s3c24xx/gpiolib.c index 5c0491bf738b..4bac12dc0733 100644 --- a/arch/arm/plat-s3c24xx/gpiolib.c +++ b/arch/arm/plat-s3c24xx/gpiolib.c @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -78,6 +79,7 @@ static int s3c24xx_gpiolib_bankg_toirq(struct gpio_chip *chip, unsigned offset) struct s3c_gpio_chip s3c24xx_gpios[] = { [0] = { .base = S3C24XX_GPIO_BASE(S3C2410_GPA0), + .pm = __gpio_pm(&s3c_gpio_pm_1bit), .chip = { .base = S3C2410_GPA0, .owner = THIS_MODULE, @@ -89,6 +91,7 @@ struct s3c_gpio_chip s3c24xx_gpios[] = { }, [1] = { .base = S3C24XX_GPIO_BASE(S3C2410_GPB0), + .pm = __gpio_pm(&s3c_gpio_pm_2bit), .chip = { .base = S3C2410_GPB0, .owner = THIS_MODULE, @@ -98,6 +101,7 @@ struct s3c_gpio_chip s3c24xx_gpios[] = { }, [2] = { .base = S3C24XX_GPIO_BASE(S3C2410_GPC0), + .pm = __gpio_pm(&s3c_gpio_pm_2bit), .chip = { .base = S3C2410_GPC0, .owner = THIS_MODULE, @@ -107,6 +111,7 @@ struct s3c_gpio_chip s3c24xx_gpios[] = { }, [3] = { .base = S3C24XX_GPIO_BASE(S3C2410_GPD0), + .pm = __gpio_pm(&s3c_gpio_pm_2bit), .chip = { .base = S3C2410_GPD0, .owner = THIS_MODULE, @@ -116,6 +121,7 @@ struct s3c_gpio_chip s3c24xx_gpios[] = { }, [4] = { .base = S3C24XX_GPIO_BASE(S3C2410_GPE0), + .pm = __gpio_pm(&s3c_gpio_pm_2bit), .chip = { .base = S3C2410_GPE0, .label = "GPIOE", @@ -125,6 +131,7 @@ struct s3c_gpio_chip s3c24xx_gpios[] = { }, [5] = { .base = S3C24XX_GPIO_BASE(S3C2410_GPF0), + .pm = __gpio_pm(&s3c_gpio_pm_2bit), .chip = { .base = S3C2410_GPF0, .owner = THIS_MODULE, @@ -135,6 +142,7 @@ struct s3c_gpio_chip s3c24xx_gpios[] = { }, [6] = { .base = S3C24XX_GPIO_BASE(S3C2410_GPG0), + .pm = __gpio_pm(&s3c_gpio_pm_2bit), .chip = { .base = S3C2410_GPG0, .owner = THIS_MODULE, diff --git a/arch/arm/plat-s3c24xx/pm.c b/arch/arm/plat-s3c24xx/pm.c index 062a29339a91..5135c40a1b90 100644 --- a/arch/arm/plat-s3c24xx/pm.c +++ b/arch/arm/plat-s3c24xx/pm.c @@ -75,43 +75,10 @@ static struct sleep_save core_save[] = { SAVE_ITEM(S3C2410_CLKSLOW), }; -static struct gpio_sleep { - void __iomem *base; - unsigned int gpcon; - unsigned int gpdat; - unsigned int gpup; -} gpio_save[] = { - [0] = { - .base = S3C2410_GPACON, - }, - [1] = { - .base = S3C2410_GPBCON, - }, - [2] = { - .base = S3C2410_GPCCON, - }, - [3] = { - .base = S3C2410_GPDCON, - }, - [4] = { - .base = S3C2410_GPECON, - }, - [5] = { - .base = S3C2410_GPFCON, - }, - [6] = { - .base = S3C2410_GPGCON, - }, - [7] = { - .base = S3C2410_GPHCON, - }, -}; - static struct sleep_save misc_save[] = { SAVE_ITEM(S3C2410_DCLKCON), }; - /* s3c_pm_check_resume_pin * * check to see if the pin is configured correctly for sleep mode, and @@ -165,186 +132,6 @@ void s3c_pm_configure_extint(void) } } -/* offsets for CON/DAT/UP registers */ - -#define OFFS_CON (S3C2410_GPACON - S3C2410_GPACON) -#define OFFS_DAT (S3C2410_GPADAT - S3C2410_GPACON) -#define OFFS_UP (S3C2410_GPBUP - S3C2410_GPBCON) - -/* s3c_pm_save_gpios() - * - * Save the state of the GPIOs - */ - -void s3c_pm_save_gpios(void) -{ - struct gpio_sleep *gps = gpio_save; - unsigned int gpio; - - for (gpio = 0; gpio < ARRAY_SIZE(gpio_save); gpio++, gps++) { - void __iomem *base = gps->base; - - gps->gpcon = __raw_readl(base + OFFS_CON); - gps->gpdat = __raw_readl(base + OFFS_DAT); - - if (gpio > 0) - gps->gpup = __raw_readl(base + OFFS_UP); - - } -} - -/* Test whether the given masked+shifted bits of an GPIO configuration - * are one of the SFN (special function) modes. */ - -static inline int is_sfn(unsigned long con) -{ - return (con == 2 || con == 3); -} - -/* Test if the given masked+shifted GPIO configuration is an input */ - -static inline int is_in(unsigned long con) -{ - return con == 0; -} - -/* Test if the given masked+shifted GPIO configuration is an output */ - -static inline int is_out(unsigned long con) -{ - return con == 1; -} - -/** - * s3c2410_pm_restore_gpio() - restore the given GPIO bank - * @index: The number of the GPIO bank being resumed. - * @gps: The sleep confgiuration for the bank. - * - * Restore one of the GPIO banks that was saved during suspend. This is - * not as simple as once thought, due to the possibility of glitches - * from the order that the CON and DAT registers are set in. - * - * The three states the pin can be are {IN,OUT,SFN} which gives us 9 - * combinations of changes to check. Three of these, if the pin stays - * in the same configuration can be discounted. This leaves us with - * the following: - * - * { IN => OUT } Change DAT first - * { IN => SFN } Change CON first - * { OUT => SFN } Change CON first, so new data will not glitch - * { OUT => IN } Change CON first, so new data will not glitch - * { SFN => IN } Change CON first - * { SFN => OUT } Change DAT first, so new data will not glitch [1] - * - * We do not currently deal with the UP registers as these control - * weak resistors, so a small delay in change should not need to bring - * these into the calculations. - * - * [1] this assumes that writing to a pin DAT whilst in SFN will set the - * state for when it is next output. - */ - -static void s3c2410_pm_restore_gpio(int index, struct gpio_sleep *gps) -{ - void __iomem *base = gps->base; - unsigned long gps_gpcon = gps->gpcon; - unsigned long gps_gpdat = gps->gpdat; - unsigned long old_gpcon; - unsigned long old_gpdat; - unsigned long old_gpup = 0x0; - unsigned long gpcon; - int nr; - - old_gpcon = __raw_readl(base + OFFS_CON); - old_gpdat = __raw_readl(base + OFFS_DAT); - - if (base == S3C2410_GPACON) { - /* GPACON only has one bit per control / data and no PULLUPs. - * GPACON[x] = 0 => Output, 1 => SFN */ - - /* first set all SFN bits to SFN */ - - gpcon = old_gpcon | gps->gpcon; - __raw_writel(gpcon, base + OFFS_CON); - - /* now set all the other bits */ - - __raw_writel(gps_gpdat, base + OFFS_DAT); - __raw_writel(gps_gpcon, base + OFFS_CON); - } else { - unsigned long old, new, mask; - unsigned long change_mask = 0x0; - - old_gpup = __raw_readl(base + OFFS_UP); - - /* Create a change_mask of all the items that need to have - * their CON value changed before their DAT value, so that - * we minimise the work between the two settings. - */ - - for (nr = 0, mask = 0x03; nr < 32; nr += 2, mask <<= 2) { - old = (old_gpcon & mask) >> nr; - new = (gps_gpcon & mask) >> nr; - - /* If there is no change, then skip */ - - if (old == new) - continue; - - /* If both are special function, then skip */ - - if (is_sfn(old) && is_sfn(new)) - continue; - - /* Change is IN => OUT, do not change now */ - - if (is_in(old) && is_out(new)) - continue; - - /* Change is SFN => OUT, do not change now */ - - if (is_sfn(old) && is_out(new)) - continue; - - /* We should now be at the case of IN=>SFN, - * OUT=>SFN, OUT=>IN, SFN=>IN. */ - - change_mask |= mask; - } - - /* Write the new CON settings */ - - gpcon = old_gpcon & ~change_mask; - gpcon |= gps_gpcon & change_mask; - - __raw_writel(gpcon, base + OFFS_CON); - - /* Now change any items that require DAT,CON */ - - __raw_writel(gps_gpdat, base + OFFS_DAT); - __raw_writel(gps_gpcon, base + OFFS_CON); - __raw_writel(gps->gpup, base + OFFS_UP); - } - - S3C_PMDBG("GPIO[%d] CON %08lx => %08lx, DAT %08lx => %08lx\n", - index, old_gpcon, gps_gpcon, old_gpdat, gps_gpdat); -} - - -/** s3c2410_pm_restore_gpios() - * - * Restore the state of the GPIOs - */ - -void s3c_pm_restore_gpios(void) -{ - struct gpio_sleep *gps = gpio_save; - int gpio; - - for (gpio = 0; gpio < ARRAY_SIZE(gpio_save); gpio++, gps++) { - s3c2410_pm_restore_gpio(gpio, gps); - } -} void s3c_pm_restore_core(void) { diff --git a/arch/arm/plat-s3c64xx/gpiolib.c b/arch/arm/plat-s3c64xx/gpiolib.c index ee9188add8fb..ccb82e854962 100644 --- a/arch/arm/plat-s3c64xx/gpiolib.c +++ b/arch/arm/plat-s3c64xx/gpiolib.c @@ -385,12 +385,19 @@ static __init void s3c64xx_gpiolib_add_4bit(struct s3c_gpio_chip *chip) { chip->chip.direction_input = s3c64xx_gpiolib_4bit_input; chip->chip.direction_output = s3c64xx_gpiolib_4bit_output; + chip->pm = __gpio_pm(&s3c_gpio_pm_4bit); } static __init void s3c64xx_gpiolib_add_4bit2(struct s3c_gpio_chip *chip) { chip->chip.direction_input = s3c64xx_gpiolib_4bit2_input; chip->chip.direction_output = s3c64xx_gpiolib_4bit2_output; + chip->pm = __gpio_pm(&s3c_gpio_pm_4bit); +} + +static __init void s3c64xx_gpiolib_add_2bit(struct s3c_gpio_chip *chip) +{ + chip->pm = __gpio_pm(&s3c_gpio_pm_2bit); } static __init void s3c64xx_gpiolib_add(struct s3c_gpio_chip *chips, @@ -412,7 +419,8 @@ static __init int s3c64xx_gpiolib_init(void) s3c64xx_gpiolib_add(gpio_4bit2, ARRAY_SIZE(gpio_4bit2), s3c64xx_gpiolib_add_4bit2); - s3c64xx_gpiolib_add(gpio_2bit, ARRAY_SIZE(gpio_2bit), NULL); + s3c64xx_gpiolib_add(gpio_2bit, ARRAY_SIZE(gpio_2bit), + s3c64xx_gpiolib_add_2bit); return 0; } diff --git a/arch/arm/plat-s3c64xx/pm.c b/arch/arm/plat-s3c64xx/pm.c index 98190aa364ae..07a6516a4f3c 100644 --- a/arch/arm/plat-s3c64xx/pm.c +++ b/arch/arm/plat-s3c64xx/pm.c @@ -96,17 +96,6 @@ void s3c_pm_configure_extint(void) __raw_writel(s3c_irqwake_eintmask, S3C64XX_EINT_MASK); } -void s3c_pm_save_gpios(void) -{ - /* currently, unless the bootloader does something really stupid - * the gpio blocks should be maintained over their sleep. - */ -} - -void s3c_pm_restore_gpios(void) -{ -} - void s3c_pm_restore_core(void) { __raw_writel(0, S3C64XX_EINT_MASK); -- cgit v1.2.3 From 4faf6867638cc21aa43b4ca4ed0bdf14a2d29762 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 25 Mar 2009 11:01:24 +0000 Subject: [ARM] S3C64XX: Add S3C6400 SDHCI setup support Add support for S3C6400 SDHCI channels 0 and 1, making the GPIO code common to both S3C6400 and S3C6410. Signed-off-by: Ben Dooks --- arch/arm/mach-s3c6400/Kconfig | 7 ++++ arch/arm/mach-s3c6400/Makefile | 4 ++ arch/arm/mach-s3c6400/s3c6400.c | 7 +++- arch/arm/mach-s3c6400/setup-sdhci.c | 63 ++++++++++++++++++++++++++++++++ arch/arm/mach-s3c6410/Kconfig | 1 + arch/arm/mach-s3c6410/setup-sdhci.c | 34 ----------------- arch/arm/plat-s3c/include/plat/sdhci.h | 50 ++++++++++++++++++++++--- arch/arm/plat-s3c64xx/Kconfig | 5 +++ arch/arm/plat-s3c64xx/Makefile | 1 + arch/arm/plat-s3c64xx/setup-sdhci-gpio.c | 55 ++++++++++++++++++++++++++++ 10 files changed, 187 insertions(+), 40 deletions(-) create mode 100644 arch/arm/mach-s3c6400/setup-sdhci.c create mode 100644 arch/arm/plat-s3c64xx/setup-sdhci-gpio.c (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/mach-s3c6400/Kconfig b/arch/arm/mach-s3c6400/Kconfig index f0292a8cddde..f5af212066c3 100644 --- a/arch/arm/mach-s3c6400/Kconfig +++ b/arch/arm/mach-s3c6400/Kconfig @@ -14,11 +14,18 @@ config CPU_S3C6400 help Enable S3C6400 CPU support +config S3C6400_SETUP_SDHCI + bool + help + Internal configuration for default SDHCI + setup for S3C6400. + # S36400 Macchine support config MACH_SMDK6400 bool "SMDK6400" select CPU_S3C6400 select S3C_DEV_HSMMC + select S3C6400_SETUP_SDHCI help Machine support for the Samsung SMDK6400 diff --git a/arch/arm/mach-s3c6400/Makefile b/arch/arm/mach-s3c6400/Makefile index 07eac2be6f6f..df1ce4aa03e5 100644 --- a/arch/arm/mach-s3c6400/Makefile +++ b/arch/arm/mach-s3c6400/Makefile @@ -14,6 +14,10 @@ obj- := obj-$(CONFIG_CPU_S3C6400) += s3c6400.o +# setup support + +obj-$(CONFIG_S3C6400_SETUP_SDHCI) += setup-sdhci.o + # Machine support obj-$(CONFIG_MACH_SMDK6400) += mach-smdk6400.o diff --git a/arch/arm/mach-s3c6400/s3c6400.c b/arch/arm/mach-s3c6400/s3c6400.c index d11a4272b94c..bd17f3db2c21 100644 --- a/arch/arm/mach-s3c6400/s3c6400.c +++ b/arch/arm/mach-s3c6400/s3c6400.c @@ -40,7 +40,12 @@ void __init s3c6400_map_io(void) { - /* the i2c device is directly compatible with s3c2440 */ + /* setup SDHCI */ + + s3c6400_default_sdhci0(); + s3c6400_default_sdhci1(); + + /* the i2c devices are directly compatible with s3c2440 */ s3c_i2c0_setname("s3c2440-i2c"); } diff --git a/arch/arm/mach-s3c6400/setup-sdhci.c b/arch/arm/mach-s3c6400/setup-sdhci.c new file mode 100644 index 000000000000..b93dafbee1f4 --- /dev/null +++ b/arch/arm/mach-s3c6400/setup-sdhci.c @@ -0,0 +1,63 @@ +/* linux/arch/arm/mach-s3c6410/setup-sdhci.c + * + * Copyright 2008 Simtec Electronics + * Copyright 2008 Simtec Electronics + * Ben Dooks + * http://armlinux.simtec.co.uk/ + * + * S3C6410 - Helper functions for settign up SDHCI device(s) (HSMMC) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +/* clock sources for the mmc bus clock, order as for the ctrl2[5..4] */ + +char *s3c6400_hsmmc_clksrcs[4] = { + [0] = "hsmmc", + [1] = "hsmmc", + [2] = "mmc_bus", + /* [3] = "48m", - note not succesfully used yet */ +}; + +void s3c6400_setup_sdhci_cfg_card(struct platform_device *dev, + void __iomem *r, + struct mmc_ios *ios, + struct mmc_card *card) +{ + u32 ctrl2, ctrl3; + + ctrl2 = readl(r + S3C_SDHCI_CONTROL2); + ctrl2 &= S3C_SDHCI_CTRL2_SELBASECLK_MASK; + ctrl2 |= (S3C64XX_SDHCI_CTRL2_ENSTAASYNCCLR | + S3C64XX_SDHCI_CTRL2_ENCMDCNFMSK | + S3C_SDHCI_CTRL2_ENFBCLKRX | + S3C_SDHCI_CTRL2_DFCNT_NONE | + S3C_SDHCI_CTRL2_ENCLKOUTHOLD); + + if (ios->clock < 25 * 1000000) + ctrl3 = (S3C_SDHCI_CTRL3_FCSEL3 | + S3C_SDHCI_CTRL3_FCSEL2 | + S3C_SDHCI_CTRL3_FCSEL1 | + S3C_SDHCI_CTRL3_FCSEL0); + else + ctrl3 = (S3C_SDHCI_CTRL3_FCSEL1 | S3C_SDHCI_CTRL3_FCSEL0); + + printk(KERN_INFO "%s: CTRL 2=%08x, 3=%08x\n", __func__, ctrl2, ctrl3); + writel(ctrl2, r + S3C_SDHCI_CONTROL2); + writel(ctrl3, r + S3C_SDHCI_CONTROL3); +} + diff --git a/arch/arm/mach-s3c6410/Kconfig b/arch/arm/mach-s3c6410/Kconfig index 0c8df9797e55..4f7ffc7ce859 100644 --- a/arch/arm/mach-s3c6410/Kconfig +++ b/arch/arm/mach-s3c6410/Kconfig @@ -16,6 +16,7 @@ config CPU_S3C6410 config S3C6410_SETUP_SDHCI bool + select S3C64XX_SETUP_SDHCI_GPIO help Internal helper functions for S3C6410 based SDHCI systems diff --git a/arch/arm/mach-s3c6410/setup-sdhci.c b/arch/arm/mach-s3c6410/setup-sdhci.c index 0b5788bd5985..20666f3bd478 100644 --- a/arch/arm/mach-s3c6410/setup-sdhci.c +++ b/arch/arm/mach-s3c6410/setup-sdhci.c @@ -21,8 +21,6 @@ #include #include -#include -#include #include #include @@ -35,22 +33,6 @@ char *s3c6410_hsmmc_clksrcs[4] = { /* [3] = "48m", - note not succesfully used yet */ }; -void s3c6410_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width) -{ - unsigned int gpio; - unsigned int end; - - end = S3C64XX_GPG(2 + width); - - /* Set all the necessary GPG pins to special-function 0 */ - for (gpio = S3C64XX_GPG(0); gpio < end; gpio++) { - s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); - s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); - } - - s3c_gpio_setpull(S3C64XX_GPG(6), S3C_GPIO_PULL_UP); - s3c_gpio_cfgpin(S3C64XX_GPG(6), S3C_GPIO_SFN(2)); -} void s3c6410_setup_sdhci0_cfg_card(struct platform_device *dev, void __iomem *r, @@ -84,19 +66,3 @@ void s3c6410_setup_sdhci0_cfg_card(struct platform_device *dev, writel(ctrl3, r + S3C_SDHCI_CONTROL3); } -void s3c6410_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width) -{ - unsigned int gpio; - unsigned int end; - - end = S3C64XX_GPH(2 + width); - - /* Set all the necessary GPG pins to special-function 0 */ - for (gpio = S3C64XX_GPH(0); gpio < end; gpio++) { - s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); - s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); - } - - s3c_gpio_setpull(S3C64XX_GPG(6), S3C_GPIO_PULL_UP); - s3c_gpio_cfgpin(S3C64XX_GPG(6), S3C_GPIO_SFN(3)); -} diff --git a/arch/arm/plat-s3c/include/plat/sdhci.h b/arch/arm/plat-s3c/include/plat/sdhci.h index c4ca3920ca4b..f615308ccdfb 100644 --- a/arch/arm/plat-s3c/include/plat/sdhci.h +++ b/arch/arm/plat-s3c/include/plat/sdhci.h @@ -67,12 +67,52 @@ extern struct s3c_sdhci_platdata s3c_hsmmc1_def_platdata; /* Helper function availablity */ +extern void s3c64xx_setup_sdhci0_cfg_gpio(struct platform_device *, int w); +extern void s3c64xx_setup_sdhci1_cfg_gpio(struct platform_device *, int w); + +/* S3C6400 SDHCI setup */ + +#ifdef CONFIG_S3C6400_SETUP_SDHCI +extern char *s3c6400_hsmmc_clksrcs[4]; + +#ifdef CONFIG_S3C_DEV_HSMMC +extern void s3c6400_setup_sdhci_cfg_card(struct platform_device *dev, + void __iomem *r, + struct mmc_ios *ios, + struct mmc_card *card); + +static inline void s3c6400_default_sdhci0(void) +{ + s3c_hsmmc0_def_platdata.clocks = s3c6400_hsmmc_clksrcs; + s3c_hsmmc0_def_platdata.cfg_gpio = s3c64xx_setup_sdhci0_cfg_gpio; + s3c_hsmmc0_def_platdata.cfg_card = s3c6400_setup_sdhci_cfg_card; +} + +#else +static inline void s3c6400_default_sdhci0(void) { } +#endif /* CONFIG_S3C_DEV_HSMMC */ + +#ifdef CONFIG_S3C_DEV_HSMMC1 +static inline void s3c6400_default_sdhci1(void) +{ + s3c_hsmmc1_def_platdata.clocks = s3c6400_hsmmc_clksrcs; + s3c_hsmmc1_def_platdata.cfg_gpio = s3c64xx_setup_sdhci1_cfg_gpio; + s3c_hsmmc1_def_platdata.cfg_card = s3c6400_setup_sdhci_cfg_card; +} +#else +static inline void s3c6400_default_sdhci1(void) { } +#endif /* CONFIG_S3C_DEV_HSMMC1 */ + +#else +static inline void s3c6400_default_sdhci0(void) { } +static inline void s3c6400_default_sdhci1(void) { } +#endif /* CONFIG_S3C6400_SETUP_SDHCI */ + +/* S3C6410 SDHCI setup */ + #ifdef CONFIG_S3C6410_SETUP_SDHCI extern char *s3c6410_hsmmc_clksrcs[4]; -extern void s3c6410_setup_sdhci0_cfg_gpio(struct platform_device *, int w); -extern void s3c6410_setup_sdhci1_cfg_gpio(struct platform_device *, int w); - extern void s3c6410_setup_sdhci0_cfg_card(struct platform_device *dev, void __iomem *r, struct mmc_ios *ios, @@ -82,7 +122,7 @@ extern void s3c6410_setup_sdhci0_cfg_card(struct platform_device *dev, static inline void s3c6410_default_sdhci0(void) { s3c_hsmmc0_def_platdata.clocks = s3c6410_hsmmc_clksrcs; - s3c_hsmmc0_def_platdata.cfg_gpio = s3c6410_setup_sdhci0_cfg_gpio; + s3c_hsmmc0_def_platdata.cfg_gpio = s3c64xx_setup_sdhci0_cfg_gpio; s3c_hsmmc0_def_platdata.cfg_card = s3c6410_setup_sdhci0_cfg_card; } #else @@ -93,7 +133,7 @@ static inline void s3c6410_default_sdhci0(void) { } static inline void s3c6410_default_sdhci1(void) { s3c_hsmmc1_def_platdata.clocks = s3c6410_hsmmc_clksrcs; - s3c_hsmmc1_def_platdata.cfg_gpio = s3c6410_setup_sdhci1_cfg_gpio; + s3c_hsmmc1_def_platdata.cfg_gpio = s3c64xx_setup_sdhci1_cfg_gpio; s3c_hsmmc1_def_platdata.cfg_card = s3c6410_setup_sdhci0_cfg_card; } #else diff --git a/arch/arm/plat-s3c64xx/Kconfig b/arch/arm/plat-s3c64xx/Kconfig index ad48fd73e04d..eb088db0e650 100644 --- a/arch/arm/plat-s3c64xx/Kconfig +++ b/arch/arm/plat-s3c64xx/Kconfig @@ -60,4 +60,9 @@ config S3C64XX_SETUP_FB_24BPP help Common setup code for S3C64XX with an 24bpp RGB display helper. +config S3C64XX_SETUP_SDHCI_GPIO + bool + help + Common setup code for S3C64XX SDHCI GPIO configurations + endif diff --git a/arch/arm/plat-s3c64xx/Makefile b/arch/arm/plat-s3c64xx/Makefile index 12ac7a50ab74..030050f5c76d 100644 --- a/arch/arm/plat-s3c64xx/Makefile +++ b/arch/arm/plat-s3c64xx/Makefile @@ -35,3 +35,4 @@ obj-$(CONFIG_PM) += irq-pm.o obj-$(CONFIG_S3C64XX_SETUP_I2C0) += setup-i2c0.o obj-$(CONFIG_S3C64XX_SETUP_I2C1) += setup-i2c1.o obj-$(CONFIG_S3C64XX_SETUP_FB_24BPP) += setup-fb-24bpp.o +obj-$(CONFIG_S3C64XX_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o \ No newline at end of file diff --git a/arch/arm/plat-s3c64xx/setup-sdhci-gpio.c b/arch/arm/plat-s3c64xx/setup-sdhci-gpio.c new file mode 100644 index 000000000000..5417123b0ac1 --- /dev/null +++ b/arch/arm/plat-s3c64xx/setup-sdhci-gpio.c @@ -0,0 +1,55 @@ +/* linux/arch/arm/plat-s3c64xx/setup-sdhci-gpio.c + * + * Copyright 2008 Simtec Electronics + * Ben Dooks + * http://armlinux.simtec.co.uk/ + * + * S3C64XX - Helper functions for setting up SDHCI device(s) GPIO (HSMMC) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include +#include +#include +#include +#include + +#include +#include + +void s3c64xx_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width) +{ + unsigned int gpio; + unsigned int end; + + end = S3C64XX_GPG(2 + width); + + /* Set all the necessary GPG pins to special-function 0 */ + for (gpio = S3C64XX_GPG(0); gpio < end; gpio++) { + s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); + s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); + } + + s3c_gpio_setpull(S3C64XX_GPG(6), S3C_GPIO_PULL_UP); + s3c_gpio_cfgpin(S3C64XX_GPG(6), S3C_GPIO_SFN(2)); +} + +void s3c64xx_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width) +{ + unsigned int gpio; + unsigned int end; + + end = S3C64XX_GPH(2 + width); + + /* Set all the necessary GPG pins to special-function 0 */ + for (gpio = S3C64XX_GPH(0); gpio < end; gpio++) { + s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); + s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); + } + + s3c_gpio_setpull(S3C64XX_GPG(6), S3C_GPIO_PULL_UP); + s3c_gpio_cfgpin(S3C64XX_GPG(6), S3C_GPIO_SFN(3)); +} -- cgit v1.2.3 From a03f7daf6df31b4d849031c51a3c10b8ba78ce67 Mon Sep 17 00:00:00 2001 From: Werner Almesberger Date: Thu, 5 Mar 2009 11:43:13 +0800 Subject: [ARM] S3C64XX: Add HCLKx2 Add doubled HCLK to S3C64xx. Signed-off-by: Werner Almesberger Signed-off-by: Ben Dooks --- arch/arm/plat-s3c/include/plat/clock.h | 1 + arch/arm/plat-s3c64xx/clock.c | 7 +++++++ arch/arm/plat-s3c64xx/s3c6400-clock.c | 1 + 3 files changed, 9 insertions(+) (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/plat-s3c/include/plat/clock.h b/arch/arm/plat-s3c/include/plat/clock.h index a10622eed43a..d86af84b5b8c 100644 --- a/arch/arm/plat-s3c/include/plat/clock.h +++ b/arch/arm/plat-s3c/include/plat/clock.h @@ -50,6 +50,7 @@ extern struct clk clk_xtal; extern struct clk clk_ext; /* S3C64XX specific clocks */ +extern struct clk clk_h2; extern struct clk clk_27m; extern struct clk clk_48m; diff --git a/arch/arm/plat-s3c64xx/clock.c b/arch/arm/plat-s3c64xx/clock.c index ad1b9682c9c3..679076f5071a 100644 --- a/arch/arm/plat-s3c64xx/clock.c +++ b/arch/arm/plat-s3c64xx/clock.c @@ -27,6 +27,12 @@ #include #include +struct clk clk_h2 = { + .name = "hclk2", + .id = -1, + .rate = 0, +}; + struct clk clk_27m = { .name = "clk_27m", .id = -1, @@ -246,6 +252,7 @@ static struct clk *clks[] __initdata = { &clk_epll, &clk_27m, &clk_48m, + &clk_h2, }; void __init s3c64xx_register_clocks(void) diff --git a/arch/arm/plat-s3c64xx/s3c6400-clock.c b/arch/arm/plat-s3c64xx/s3c6400-clock.c index 6dd187d04743..96fa9ea4d5bc 100644 --- a/arch/arm/plat-s3c64xx/s3c6400-clock.c +++ b/arch/arm/plat-s3c64xx/s3c6400-clock.c @@ -636,6 +636,7 @@ void __init_or_cpufreq s3c6400_setup_clocks(void) clk_fout_epll.rate = epll; clk_fout_apll.rate = apll; + clk_h2.rate = hclk2; clk_h.rate = hclk; clk_p.rate = pclk; clk_f.rate = fclk; -- cgit v1.2.3 From f0e1fa760099eef43f4450471d795807a1cc43c8 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sat, 16 May 2009 22:05:27 +0100 Subject: [ARM] S3C: Add USB high-speed/OtG device definitions Add platform device definitions for the high-speed and OtG capable device block on the newer Samsung parts. Signed-off-by: Ben Dooks Signed-off-by: Ben Dooks --- arch/arm/mach-s3c6400/include/mach/map.h | 2 ++ arch/arm/plat-s3c/Kconfig | 5 ++++ arch/arm/plat-s3c/Makefile | 1 + arch/arm/plat-s3c/dev-usb-hsotg.c | 41 ++++++++++++++++++++++++++++++++ arch/arm/plat-s3c/include/plat/devs.h | 1 + arch/arm/plat-s3c/include/plat/udc-hs.h | 29 ++++++++++++++++++++++ 6 files changed, 79 insertions(+) create mode 100644 arch/arm/plat-s3c/dev-usb-hsotg.c create mode 100644 arch/arm/plat-s3c/include/plat/udc-hs.h (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/mach-s3c6400/include/mach/map.h b/arch/arm/mach-s3c6400/include/mach/map.h index ea4223b55099..99d5e3b420ad 100644 --- a/arch/arm/mach-s3c6400/include/mach/map.h +++ b/arch/arm/mach-s3c6400/include/mach/map.h @@ -39,6 +39,7 @@ #define S3C_VA_UART3 S3C_VA_UARTx(3) #define S3C64XX_PA_FB (0x77100000) +#define S3C64XX_PA_USB_HSOTG (0x7C000000) #define S3C64XX_PA_SYSCON (0x7E00F000) #define S3C64XX_PA_TIMER (0x7F006000) #define S3C64XX_PA_IIC0 (0x7F004000) @@ -70,5 +71,6 @@ #define S3C_PA_IIC1 S3C64XX_PA_IIC1 #define S3C_PA_FB S3C64XX_PA_FB #define S3C_PA_USBHOST S3C64XX_PA_USBHOST +#define S3C_PA_USB_HSOTG S3C64XX_PA_USB_HSOTG #endif /* __ASM_ARCH_6400_MAP_H */ diff --git a/arch/arm/plat-s3c/Kconfig b/arch/arm/plat-s3c/Kconfig index a4c5027421d3..140391587c39 100644 --- a/arch/arm/plat-s3c/Kconfig +++ b/arch/arm/plat-s3c/Kconfig @@ -186,4 +186,9 @@ config S3C_DEV_USB_HOST help Compile in platform device definition for USB host. +config S3C_DEV_USB_HSOTG + bool + help + Compile in platform device definition for USB high-speed OtG + endif diff --git a/arch/arm/plat-s3c/Makefile b/arch/arm/plat-s3c/Makefile index bfc8f537db18..061e20458e89 100644 --- a/arch/arm/plat-s3c/Makefile +++ b/arch/arm/plat-s3c/Makefile @@ -32,3 +32,4 @@ obj-y += dev-i2c0.o obj-$(CONFIG_S3C_DEV_I2C1) += dev-i2c1.o obj-$(CONFIG_S3C_DEV_FB) += dev-fb.o obj-$(CONFIG_S3C_DEV_USB_HOST) += dev-usb.o +obj-$(CONFIG_S3C_DEV_USB_HSOTG) += dev-usb-hsotg.o diff --git a/arch/arm/plat-s3c/dev-usb-hsotg.c b/arch/arm/plat-s3c/dev-usb-hsotg.c new file mode 100644 index 000000000000..e2f604b51c86 --- /dev/null +++ b/arch/arm/plat-s3c/dev-usb-hsotg.c @@ -0,0 +1,41 @@ +/* linux/arch/arm/plat-s3c/dev-usb-hsotg.c + * + * Copyright 2008 Simtec Electronics + * Ben Dooks + * http://armlinux.simtec.co.uk/ + * + * S3C series device definition for USB high-speed UDC/OtG block + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include +#include +#include + +#include +#include + +#include + +static struct resource s3c_usb_hsotg_resources[] = { + [0] = { + .start = S3C_PA_USB_HSOTG, + .end = S3C_PA_USB_HSOTG + 0x10000 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_OTG, + .end = IRQ_OTG, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device s3c_device_usb_hsotg = { + .name = "s3c-hsotg", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_usb_hsotg_resources), + .resource = s3c_usb_hsotg_resources, +}; diff --git a/arch/arm/plat-s3c/include/plat/devs.h b/arch/arm/plat-s3c/include/plat/devs.h index 26f0cec3ac04..a0b6768fddcf 100644 --- a/arch/arm/plat-s3c/include/plat/devs.h +++ b/arch/arm/plat-s3c/include/plat/devs.h @@ -45,6 +45,7 @@ extern struct platform_device s3c_device_spi1; extern struct platform_device s3c_device_nand; extern struct platform_device s3c_device_usbgadget; +extern struct platform_device s3c_device_usb_hsotg; /* s3c2440 specific devices */ diff --git a/arch/arm/plat-s3c/include/plat/udc-hs.h b/arch/arm/plat-s3c/include/plat/udc-hs.h new file mode 100644 index 000000000000..dd04db043109 --- /dev/null +++ b/arch/arm/plat-s3c/include/plat/udc-hs.h @@ -0,0 +1,29 @@ +/* arch/arm/plat-s3c/include/plat/udc-hs.h + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * Ben Dooks + * http://armlinux.simtec.co.uk/ + * + * S3C USB2.0 High-speed / OtG platform information + * + * 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. +*/ + +enum s3c_hostg_dmamode { + S3C_HSOTG_DMA_NONE, /* do not use DMA at-all */ + S3C_HSOTG_DMA_ONLY, /* always use DMA */ + S3C_HSOTG_DMA_DRV, /* DMA is chosen by driver */ +}; + +/** + * struct s3c_hsotg_plat - platform data for high-speed otg/udc + * @dma: Whether to use DMA or not. + * @is_osc: The clock source is an oscillator, not a crystal + */ +struct s3c_hsotg_plat { + enum s3c_hostg_dmamode dma; + unsigned int is_osc : 1; +}; -- cgit v1.2.3 From b57f0fe10712026d15a9d5a20e31f240ee72ec15 Mon Sep 17 00:00:00 2001 From: Nelson Castillo Date: Fri, 8 May 2009 08:10:04 -0500 Subject: [ARM] S3C: ADC: Fix lines with more than 80 chars in adc.h Small cleanup. Signed-off-by: Nelson Castillo [ben-linux@fluff.org: rewrote subject] Signed-off-by: Ben Dooks --- arch/arm/plat-s3c/include/plat/adc.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/plat-s3c/include/plat/adc.h b/arch/arm/plat-s3c/include/plat/adc.h index 43df2a404b0b..ef92e50ac0a7 100644 --- a/arch/arm/plat-s3c/include/plat/adc.h +++ b/arch/arm/plat-s3c/include/plat/adc.h @@ -19,10 +19,11 @@ struct s3c_adc_client; extern int s3c_adc_start(struct s3c_adc_client *client, unsigned int channel, unsigned int nr_samples); -extern struct s3c_adc_client *s3c_adc_register(struct platform_device *pdev, - void (*select)(unsigned selected), - void (*conv)(unsigned d0, unsigned d1), - unsigned int is_ts); +extern struct s3c_adc_client * + s3c_adc_register(struct platform_device *pdev, + void (*select)(unsigned selected), + void (*conv)(unsigned d0, unsigned d1), + unsigned int is_ts); extern void s3c_adc_release(struct s3c_adc_client *client); -- cgit v1.2.3 From 3f7ea467be1bad860c0f71ba7373dd3cf76b485a Mon Sep 17 00:00:00 2001 From: Nelson Castillo Date: Fri, 8 May 2009 08:10:12 -0500 Subject: [ARM] S3C: ADC: Expose number of remaining conversions to convert callback This patch allow us to efficiently modify the number of remaining conversions from the client side. This us useful when we do not know in advance how many conversions we will need or when we need to cancel pending conversions. This change is simple enough to be compatible with existing code that can just define the new pointer in the callback and ignore it. Sample usage: http://tinyurl.com/s3c2410-ts-c (function stylus_adc_action). Signed-off-by: Nelson Castillo Signed-off-by: Ben Dooks --- arch/arm/plat-s3c/include/plat/adc.h | 3 ++- arch/arm/plat-s3c24xx/adc.c | 11 +++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/plat-s3c/include/plat/adc.h b/arch/arm/plat-s3c/include/plat/adc.h index ef92e50ac0a7..d847bd476b6c 100644 --- a/arch/arm/plat-s3c/include/plat/adc.h +++ b/arch/arm/plat-s3c/include/plat/adc.h @@ -22,7 +22,8 @@ extern int s3c_adc_start(struct s3c_adc_client *client, extern struct s3c_adc_client * s3c_adc_register(struct platform_device *pdev, void (*select)(unsigned selected), - void (*conv)(unsigned d0, unsigned d1), + void (*conv)(unsigned d0, unsigned d1, + unsigned *samples_left), unsigned int is_ts); extern void s3c_adc_release(struct s3c_adc_client *client); diff --git a/arch/arm/plat-s3c24xx/adc.c b/arch/arm/plat-s3c24xx/adc.c index 91adfa71c172..ee1baf11ad9e 100644 --- a/arch/arm/plat-s3c24xx/adc.c +++ b/arch/arm/plat-s3c24xx/adc.c @@ -45,7 +45,8 @@ struct s3c_adc_client { unsigned char channel; void (*select_cb)(unsigned selected); - void (*convert_cb)(unsigned val1, unsigned val2); + void (*convert_cb)(unsigned val1, unsigned val2, + unsigned *samples_left); }; struct adc_device { @@ -158,7 +159,8 @@ static void s3c_adc_default_select(unsigned select) struct s3c_adc_client *s3c_adc_register(struct platform_device *pdev, void (*select)(unsigned int selected), - void (*conv)(unsigned d0, unsigned d1), + void (*conv)(unsigned d0, unsigned d1, + unsigned *samples_left), unsigned int is_ts) { struct s3c_adc_client *client; @@ -227,9 +229,10 @@ static irqreturn_t s3c_adc_irq(int irq, void *pw) data1 = readl(adc->regs + S3C2410_ADCDAT1); adc_dbg(adc, "read %d: 0x%04x, 0x%04x\n", client->nr_samples, data0, data1); - (client->convert_cb)(data0 & 0x3ff, data1 & 0x3ff); + client->nr_samples--; + (client->convert_cb)(data0 & 0x3ff, data1 & 0x3ff, &client->nr_samples); - if (--client->nr_samples > 0) { + if (client->nr_samples > 0) { /* fire another conversion for this */ client->select_cb(1); -- cgit v1.2.3 From 3cba5ef862bc2c2a0cf2841d993bfb99b9a6c476 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sun, 17 May 2009 23:30:45 +0100 Subject: [ARM] S3C: Move watchdog system reset to own file. Move the watchdog reset code from to a new file as this code is needed by both s3c2410, s3c64xx and soon-to-be added s3c24a0. Signed-off-by: Ben Dooks --- arch/arm/mach-s3c2410/include/mach/system-reset.h | 36 +---------------- arch/arm/plat-s3c/include/plat/watchdog-reset.h | 48 +++++++++++++++++++++++ 2 files changed, 50 insertions(+), 34 deletions(-) create mode 100644 arch/arm/plat-s3c/include/plat/watchdog-reset.h (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/mach-s3c2410/include/mach/system-reset.h b/arch/arm/mach-s3c2410/include/mach/system-reset.h index b8687f71c304..6faadcee7729 100644 --- a/arch/arm/mach-s3c2410/include/mach/system-reset.h +++ b/arch/arm/mach-s3c2410/include/mach/system-reset.h @@ -11,21 +11,13 @@ */ #include -#include - -#include -#include - -#include -#include +#include extern void (*s3c24xx_reset_hook)(void); static void arch_reset(char mode, const char *cmd) { - struct clk *wdtclk; - if (mode == 's') { cpu_reset(0); } @@ -33,31 +25,7 @@ arch_reset(char mode, const char *cmd) if (s3c24xx_reset_hook) s3c24xx_reset_hook(); - printk("arch_reset: attempting watchdog reset\n"); - - __raw_writel(0, S3C2410_WTCON); /* disable watchdog, to be safe */ - - wdtclk = clk_get(NULL, "watchdog"); - if (!IS_ERR(wdtclk)) { - clk_enable(wdtclk); - } else - printk(KERN_WARNING "%s: warning: cannot get watchdog clock\n", __func__); - - /* put initial values into count and data */ - __raw_writel(0x80, S3C2410_WTCNT); - __raw_writel(0x80, S3C2410_WTDAT); - - /* set the watchdog to go and reset... */ - __raw_writel(S3C2410_WTCON_ENABLE|S3C2410_WTCON_DIV16|S3C2410_WTCON_RSTEN | - S3C2410_WTCON_PRESCALE(0x20), S3C2410_WTCON); - - /* wait for reset to assert... */ - mdelay(500); - - printk(KERN_ERR "Watchdog reset failed to assert reset\n"); - - /* delay to allow the serial port to show the message */ - mdelay(50); + arch_wdt_reset(); /* we'll take a jump through zero as a poor second */ cpu_reset(0); diff --git a/arch/arm/plat-s3c/include/plat/watchdog-reset.h b/arch/arm/plat-s3c/include/plat/watchdog-reset.h new file mode 100644 index 000000000000..277506aa0d51 --- /dev/null +++ b/arch/arm/plat-s3c/include/plat/watchdog-reset.h @@ -0,0 +1,48 @@ +/* arch/arm/plat-s3c/include/plat/watchdog-reset.h + * + * Copyright (c) 2008 Simtec Electronics + * Ben Dooks + * + * S3C2410 - System define for arch_reset() function + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include + +#include +#include +#include + +static inline void arch_wdt_reset(void) +{ + struct clk *wdtclk; + + printk("arch_reset: attempting watchdog reset\n"); + + __raw_writel(0, S3C2410_WTCON); /* disable watchdog, to be safe */ + + wdtclk = clk_get(NULL, "watchdog"); + if (!IS_ERR(wdtclk)) { + clk_enable(wdtclk); + } else + printk(KERN_WARNING "%s: warning: cannot get watchdog clock\n", __func__); + + /* put initial values into count and data */ + __raw_writel(0x80, S3C2410_WTCNT); + __raw_writel(0x80, S3C2410_WTDAT); + + /* set the watchdog to go and reset... */ + __raw_writel(S3C2410_WTCON_ENABLE|S3C2410_WTCON_DIV16|S3C2410_WTCON_RSTEN | + S3C2410_WTCON_PRESCALE(0x20), S3C2410_WTCON); + + /* wait for reset to assert... */ + mdelay(500); + + printk(KERN_ERR "Watchdog reset failed to assert reset\n"); + + /* delay to allow the serial port to show the message */ + mdelay(50); +} -- cgit v1.2.3 From 543899f610799426babb5313682fd9c249e34677 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sun, 17 May 2009 23:40:30 +0100 Subject: [ARM] S3C64XX: Use common watchdog reset for system reset. Use the newly moved to perform the arch_reset() call which has been unimplemented for a while. Signed-off-by: Ben Dooks --- arch/arm/mach-s3c6400/include/mach/map.h | 1 + arch/arm/mach-s3c6400/include/mach/system.h | 8 +++++++- arch/arm/plat-s3c/include/plat/watchdog-reset.h | 1 + arch/arm/plat-s3c64xx/cpu.c | 5 +++++ 4 files changed, 14 insertions(+), 1 deletion(-) (limited to 'arch/arm/plat-s3c') diff --git a/arch/arm/mach-s3c6400/include/mach/map.h b/arch/arm/mach-s3c6400/include/mach/map.h index 99d5e3b420ad..7a1e5a2455b3 100644 --- a/arch/arm/mach-s3c6400/include/mach/map.h +++ b/arch/arm/mach-s3c6400/include/mach/map.h @@ -40,6 +40,7 @@ #define S3C64XX_PA_FB (0x77100000) #define S3C64XX_PA_USB_HSOTG (0x7C000000) +#define S3C64XX_PA_WATCHDOG (0x7E004000) #define S3C64XX_PA_SYSCON (0x7E00F000) #define S3C64XX_PA_TIMER (0x7F006000) #define S3C64XX_PA_IIC0 (0x7F004000) diff --git a/arch/arm/mach-s3c6400/include/mach/system.h b/arch/arm/mach-s3c6400/include/mach/system.h index 090cfd969bc7..2e58cb7a7147 100644 --- a/arch/arm/mach-s3c6400/include/mach/system.h +++ b/arch/arm/mach-s3c6400/include/mach/system.h @@ -11,6 +11,8 @@ #ifndef __ASM_ARCH_SYSTEM_H #define __ASM_ARCH_SYSTEM_H __FILE__ +#include + static void arch_idle(void) { /* nothing here yet */ @@ -18,7 +20,11 @@ static void arch_idle(void) static void arch_reset(char mode, const char *cmd) { - /* nothing here yet */ + if (mode != 's') + arch_wdt_reset(); + + /* if all else fails, or mode was for soft, jump to 0 */ + cpu_reset(0); } #endif /* __ASM_ARCH_IRQ_H */ diff --git a/arch/arm/plat-s3c/include/plat/watchdog-reset.h b/arch/arm/plat-s3c/include/plat/watchdog-reset.h index 277506aa0d51..54b762acb5a0 100644 --- a/arch/arm/plat-s3c/include/plat/watchdog-reset.h +++ b/arch/arm/plat-s3c/include/plat/watchdog-reset.h @@ -11,6 +11,7 @@ */ #include +#include #include #include diff --git a/arch/arm/plat-s3c64xx/cpu.c b/arch/arm/plat-s3c64xx/cpu.c index 19f68b5f0d36..b1fdd83940a6 100644 --- a/arch/arm/plat-s3c64xx/cpu.c +++ b/arch/arm/plat-s3c64xx/cpu.c @@ -102,6 +102,11 @@ static struct map_desc s3c_iodesc[] __initdata = { .pfn = __phys_to_pfn(S3C64XX_PA_MODEM), .length = SZ_4K, .type = MT_DEVICE, + }, { + .virtual = (unsigned long)S3C_VA_WATCHDOG, + .pfn = __phys_to_pfn(S3C64XX_PA_WATCHDOG), + .length = SZ_4K, + .type = MT_DEVICE, }, }; -- cgit v1.2.3