diff -wur linux-2.6.10/MAINTAINERS linux-2.6.10-lab/MAINTAINERS
--- linux-2.6.10/MAINTAINERS 2004-12-24 16:35:00.000000000 -0500
+++ linux-2.6.10-lab/MAINTAINERS 2007-10-04 19:10:40.000000000 -0400
@@ -937,6 +937,13 @@
L: iss_storagedev@hp.com
S: Supported
+HOST AP DRIVER
+P: Jouni Malinen
+M: jkmaline@cc.hut.fi
+L: hostap@shmoo.com
+W: http://hostap.epitest.fi/
+S: Maintained
+
HP100: Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series
P: Jaroslav Kysela
M: perex@suse.cz
diff -wur linux-2.6.10/Makefile linux-2.6.10-lab/Makefile
--- linux-2.6.10/Makefile 2004-12-24 16:35:01.000000000 -0500
+++ linux-2.6.10-lab/Makefile 2007-10-04 19:10:40.000000000 -0400
@@ -4,6 +4,19 @@
EXTRAVERSION =
NAME=Woozy Numbat
+#
+# The following six lines makes this make default to
+# a cross-compiled arm version of Linux. This makes
+# it easier to drive make directly (without all the extra params
+# each time or the requirement of a separate script).
+#
+ifndef ARCH
+ARCH=arm
+endif
+ifndef CROSS_COMPILE
+CROSS_COMPILE=arm-linux-
+endif
+
# *DOCUMENTATION*
# To see a list of typical targets execute "make help"
# More info can be located in ./README
@@ -203,7 +216,8 @@
HOSTCC = gcc
HOSTCXX = g++
-HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
+HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -idirafter "`$(CC) -print-file-name=include`/../../../../../include/"
+
HOSTCXXFLAGS = -O2
# Decide whether to build built-in, modular, or both.
@@ -866,11 +880,11 @@
.PHONY: _modinst_
_modinst_:
- @if [ -z "`$(DEPMOD) -V | grep module-init-tools`" ]; then \
- echo "Warning: you may need to install module-init-tools"; \
- echo "See http://www.codemonkey.org.uk/docs/post-halloween-2.6.txt";\
- sleep 1; \
- fi
+## @if [ -z "`$(DEPMOD) -V | grep module-init-tools`" ]; then \
+## echo "Warning: you may need to install module-init-tools"; \
+## echo "See http://www.codemonkey.org.uk/docs/post-halloween-2.6.txt";\
+## sleep 1; \
+## fi
@rm -rf $(MODLIB)/kernel
@rm -f $(MODLIB)/source
@mkdir -p $(MODLIB)/kernel
@@ -893,7 +907,9 @@
endif
.PHONY: _modinst_post
_modinst_post: _modinst_
- if [ -r System.map ]; then $(DEPMOD) -ae -F System.map $(depmod_opts) $(KERNELRELEASE); fi
+## if [ -r System.map ]; then $(DEPMOD) -ae -F System.map $(depmod_opts) $(KERNELRELEASE); fi
+ @rm -f $(MODLIB)/build
+ @rm -f $(MODLIB)/source
else # CONFIG_MODULES
@@ -970,7 +986,8 @@
#
mrproper: rm-dirs := $(wildcard $(MRPROPER_DIRS))
mrproper: rm-files := $(wildcard $(MRPROPER_FILES))
-mrproper-dirs := $(addprefix _mrproper_,Documentation/DocBook scripts)
+# mrproper-dirs := $(addprefix _mrproper_,Documentation/DocBook scripts)
+mrproper-dirs := $(addprefix _mrproper_,scripts)
.PHONY: $(mrproper-dirs) mrproper archmrproper
$(mrproper-dirs):
@@ -1063,8 +1080,8 @@
# Documentation targets
# ---------------------------------------------------------------------------
-%docs: scripts_basic FORCE
- $(Q)$(MAKE) $(build)=Documentation/DocBook $@
+# %docs: scripts_basic FORCE
+# $(Q)$(MAKE) $(build)=Documentation/DocBook $@
else # KBUILD_EXTMOD
diff -wur linux-2.6.10/arch/arm/Kconfig linux-2.6.10-lab/arch/arm/Kconfig
--- linux-2.6.10/arch/arm/Kconfig 2004-12-24 16:34:57.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/Kconfig 2007-10-04 19:13:12.000000000 -0400
@@ -83,8 +83,8 @@
config ARCH_CO285
bool "Co-EBSA285"
- select FOOTBRIDGE
- select FOOTBRIDGE_ADDIN
+# select FOOTBRIDGE
+# select FOOTBRIDGE_ADDIN
config ARCH_EBSA110
bool "EBSA-110"
@@ -103,7 +103,7 @@
config ARCH_FOOTBRIDGE
bool "FootBridge"
- select FOOTBRIDGE
+# select FOOTBRIDGE
config ARCH_INTEGRATOR
bool "Integrator"
@@ -177,35 +177,35 @@
endchoice
-source "arch/arm/mach-clps711x/Kconfig"
+# source "arch/arm/mach-clps711x/Kconfig"
-source "arch/arm/mach-epxa10db/Kconfig"
+# source "arch/arm/mach-epxa10db/Kconfig"
-source "arch/arm/mach-footbridge/Kconfig"
+# source "arch/arm/mach-footbridge/Kconfig"
-source "arch/arm/mach-integrator/Kconfig"
+# source "arch/arm/mach-integrator/Kconfig"
-source "arch/arm/mach-iop3xx/Kconfig"
+# source "arch/arm/mach-iop3xx/Kconfig"
-source "arch/arm/mach-ixp4xx/Kconfig"
+# source "arch/arm/mach-ixp4xx/Kconfig"
-source "arch/arm/mach-ixp2000/Kconfig"
+# source "arch/arm/mach-ixp2000/Kconfig"
source "arch/arm/mach-pxa/Kconfig"
-source "arch/arm/mach-sa1100/Kconfig"
+# source "arch/arm/mach-sa1100/Kconfig"
-source "arch/arm/mach-omap/Kconfig"
+# source "arch/arm/mach-omap/Kconfig"
-source "arch/arm/mach-s3c2410/Kconfig"
+# source "arch/arm/mach-s3c2410/Kconfig"
-source "arch/arm/mach-lh7a40x/Kconfig"
+# source "arch/arm/mach-lh7a40x/Kconfig"
-source "arch/arm/mach-imx/Kconfig"
+# source "arch/arm/mach-imx/Kconfig"
-source "arch/arm/mach-h720x/Kconfig"
+# source "arch/arm/mach-h720x/Kconfig"
-source "arch/arm/mach-versatile/Kconfig"
+# source "arch/arm/mach-versatile/Kconfig"
# Definitions to make life easier
config ARCH_ACORN
@@ -396,7 +396,7 @@
In any case, make sure that MTD support is configured out for
the first attempt.
-if (ARCH_SA1100 || ARCH_INTEGRATOR)
+if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_PXA)
source "drivers/cpufreq/Kconfig"
@@ -421,9 +421,22 @@
If in doubt, say Y.
+config CPU_FREQ_PXA
+ bool
+ depends on CPU_FREQ && ARCH_PXA
+ default y
+ select CPU_FREQ_DEFAULT_GOV_USERSPACE
+
+config CPU_FREQ_TABLE
+ tristate
+ depends on CPU_FREQ
+ default y
+
endif
-source "drivers/pci/Kconfig"
+source "drivers/gpio/Kconfig"
+
+# source "drivers/pci/Kconfig"
source "drivers/pcmcia/Kconfig"
@@ -482,25 +495,7 @@
source "drivers/base/Kconfig"
-config PM
- bool "Power Management support"
- ---help---
- "Power Management" means that parts of your computer are shut
- off or put into a power conserving "sleep" mode if they are not
- being used. There are two competing standards for doing this: APM
- and ACPI. If you want to use either one, say Y here and then also
- to the requisite support below.
-
- Power Management is most important for battery powered laptop
- computers; if you have a laptop, check out the Linux Laptop home
- page on the WWW at or
- Tuxmobil - Linux on Mobile Computers at
- and the Battery Powered Linux mini-HOWTO, available from
- .
-
- Note that, even if you say N here, Linux on the x86 architecture
- will issue the hlt instruction if nothing is to be done, thereby
- sending the processor to sleep and saving power.
+source "kernel/power/Kconfig"
config PREEMPT
bool "Preemptible Kernel (EXPERIMENTAL)"
@@ -650,35 +645,35 @@
endmenu
-source "drivers/parport/Kconfig"
+# source "drivers/parport/Kconfig"
if ALIGNMENT_TRAP
source "drivers/mtd/Kconfig"
endif
-source "drivers/pnp/Kconfig"
+# source "drivers/pnp/Kconfig"
source "drivers/block/Kconfig"
-source "drivers/md/Kconfig"
+# source "drivers/md/Kconfig"
-source "drivers/acorn/block/Kconfig"
+# source "drivers/acorn/block/Kconfig"
source "net/Kconfig"
if ARCH_CLPS7500 || ARCH_IOP3XX || ARCH_IXP4XX || ARCH_L7200 || ARCH_LH7A40X || ARCH_PXA || ARCH_RPC || ARCH_S3C2410 || ARCH_SA1100 || ARCH_SHARK || FOOTBRIDGE
-source "drivers/ide/Kconfig"
+# source "drivers/ide/Kconfig"
endif
source "drivers/scsi/Kconfig"
-source "drivers/message/fusion/Kconfig"
+# source "drivers/message/fusion/Kconfig"
-source "drivers/ieee1394/Kconfig"
+# source "drivers/ieee1394/Kconfig"
-source "drivers/message/i2o/Kconfig"
+# source "drivers/message/i2o/Kconfig"
-source "drivers/isdn/Kconfig"
+# source "drivers/isdn/Kconfig"
#
# input before char - char/joystick depends on it. As does USB.
@@ -691,7 +686,7 @@
#source "drivers/l3/Kconfig"
-source "drivers/media/Kconfig"
+# source "drivers/media/Kconfig"
source "fs/Kconfig"
@@ -714,3 +709,4 @@
source "crypto/Kconfig"
source "lib/Kconfig"
+
diff -wur linux-2.6.10/arch/arm/Kconfig.debug linux-2.6.10-lab/arch/arm/Kconfig.debug
--- linux-2.6.10/arch/arm/Kconfig.debug 2004-12-24 16:35:50.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/Kconfig.debug 2007-10-04 19:10:15.000000000 -0400
@@ -115,4 +115,5 @@
The uncompressor code port configuration is now handled
by CONFIG_S3C2410_LOWLEVEL_UART_PORT.
+source "drivers/char/ppoke/Kconfig"
endmenu
diff -wur linux-2.6.10/arch/arm/Makefile linux-2.6.10-lab/arch/arm/Makefile
--- linux-2.6.10/arch/arm/Makefile 2004-12-24 16:35:50.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/Makefile 2007-10-04 19:10:15.000000000 -0400
@@ -144,8 +144,8 @@
core-$(CONFIG_VFP) += arch/arm/vfp/
drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/
-drivers-$(CONFIG_ARCH_CLPS7500) += drivers/acorn/char/
-drivers-$(CONFIG_ARCH_L7200) += drivers/acorn/char/
+# drivers-$(CONFIG_ARCH_CLPS7500) += drivers/acorn/char/
+# drivers-$(CONFIG_ARCH_L7200) += drivers/acorn/char/
libs-y += arch/arm/lib/
diff -wur linux-2.6.10/arch/arm/kernel/compat.c linux-2.6.10-lab/arch/arm/kernel/compat.c
--- linux-2.6.10/arch/arm/kernel/compat.c 2004-12-24 16:35:50.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/kernel/compat.c 2007-10-04 19:10:14.000000000 -0400
@@ -64,8 +64,12 @@
unsigned long initrd_size; /* 68 */
unsigned long rd_start; /* 72 */
unsigned long system_rev; /* 76 */
+#ifdef CONFIG_ARCH_FIONA
+ unsigned char system_serial_data[BOARD_SERIALNUM_SIZE];
+#else
unsigned long system_serial_low; /* 80 */
unsigned long system_serial_high; /* 84 */
+#endif
unsigned long mem_fclk_21285; /* 88 */
} s;
char unused[256];
@@ -143,8 +147,12 @@
tag = tag_next(tag);
tag->hdr.tag = ATAG_SERIAL;
tag->hdr.size = tag_size(tag_serialnr);
+#ifdef CONFIG_ARCH_FIONA
+ memcpy(tag->u.serialnr.data, params->u1.s.system_serial_data, BOARD_SERIALNUM_SIZE);
+#else
tag->u.serialnr.low = params->u1.s.system_serial_low;
tag->u.serialnr.high = params->u1.s.system_serial_high;
+#endif
tag = tag_next(tag);
tag->hdr.tag = ATAG_REVISION;
diff -wur linux-2.6.10/arch/arm/kernel/process.c linux-2.6.10-lab/arch/arm/kernel/process.c
--- linux-2.6.10/arch/arm/kernel/process.c 2004-12-24 16:35:28.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/kernel/process.c 2007-10-04 19:10:14.000000000 -0400
@@ -33,6 +33,10 @@
#include
#include
+#ifdef CONFIG_ARCH_FIONA
+#include
+#endif
+
extern const char *processor_modes[];
extern void setup_mm_for_reboot(char mode);
@@ -152,6 +156,14 @@
*/
setup_mm_for_reboot(reboot_mode);
+#ifdef CONFIG_ARCH_FIONA
+ // set the OneNAND back into async read mode so bootloader can fetch page zero
+ fiona_set_onenand_async();
+
+ // reset the OneNAND DBS bit to ensure the proper page zero is present
+ fiona_reset_onenand_dbs_bit();
+#endif
+
/*
* Now call the architecture specific reboot code.
*/
diff -wur linux-2.6.10/arch/arm/kernel/setup.c linux-2.6.10-lab/arch/arm/kernel/setup.c
--- linux-2.6.10/arch/arm/kernel/setup.c 2004-12-24 16:34:57.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/kernel/setup.c 2007-10-04 19:10:14.000000000 -0400
@@ -67,12 +67,19 @@
unsigned int system_rev;
EXPORT_SYMBOL(system_rev);
+unsigned int board_resistance = 0;
+EXPORT_SYMBOL(board_resistance);
+#ifdef CONFIG_ARCH_FIONA
+unsigned char system_serial_data[BOARD_SERIALNUM_SIZE];
+EXPORT_SYMBOL(system_serial_data);
+#else
unsigned int system_serial_low;
EXPORT_SYMBOL(system_serial_low);
unsigned int system_serial_high;
EXPORT_SYMBOL(system_serial_high);
+#endif
unsigned int elf_hwcap;
EXPORT_SYMBOL(elf_hwcap);
@@ -595,8 +602,12 @@
static int __init parse_tag_serialnr(const struct tag *tag)
{
+#ifdef CONFIG_ARCH_FIONA
+ memcpy(system_serial_data, tag->u.serialnr.data, BOARD_SERIALNUM_SIZE);
+#else
system_serial_low = tag->u.serialnr.low;
system_serial_high = tag->u.serialnr.high;
+#endif
return 0;
}
@@ -610,6 +621,16 @@
__tagtable(ATAG_REVISION, parse_tag_revision);
+
+static int __init parse_tag_board_resistance(const struct tag *tag)
+{
+ board_resistance = tag->u.board_resistance.mohms;
+ printk("Fiona Board Resistance : %d mOhms\n",board_resistance);
+ return 0;
+}
+
+__tagtable(ATAG_BOARD_RESISTANCE, parse_tag_board_resistance);
+
static int __init parse_tag_cmdline(const struct tag *tag)
{
strlcpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE);
@@ -780,6 +801,9 @@
static int c_show(struct seq_file *m, void *v)
{
int i;
+#ifdef CONFIG_ARCH_FIONA
+ char serial_num[BOARD_SERIALNUM_SIZE + 1];
+#endif
seq_printf(m, "Processor\t: %s rev %d (%s)\n",
cpu_name, (int)processor_id & 15, elf_platform);
@@ -841,8 +865,15 @@
seq_printf(m, "Hardware\t: %s\n", machine_name);
seq_printf(m, "Revision\t: %04x\n", system_rev);
+
+#ifdef CONFIG_ARCH_FIONA
+ memset(serial_num, '\0', sizeof(serial_num));
+ strncpy(serial_num, system_serial_data, BOARD_SERIALNUM_SIZE);
+ seq_printf(m, "Serial\t\t: \"%s\"\n", serial_num);
+#else
seq_printf(m, "Serial\t\t: %08x%08x\n",
system_serial_high, system_serial_low);
+#endif
return 0;
}
diff -wur linux-2.6.10/arch/arm/mach-pxa/Kconfig linux-2.6.10-lab/arch/arm/mach-pxa/Kconfig
--- linux-2.6.10/arch/arm/mach-pxa/Kconfig 2004-12-24 16:34:26.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/mach-pxa/Kconfig 2007-10-04 19:10:15.000000000 -0400
@@ -1,10 +1,26 @@
if ARCH_PXA
+config ARCH_LAB126
+ bool
+ default n
+
menu "Intel PXA2xx Implementations"
choice
prompt "Select target board"
+config ARCH_GUMSTIX
+ bool "Gumstix Platform"
+ depends on ARCH_PXA
+
+config ARCH_FIONA
+ bool "Fiona Platform"
+ select PXA25x
+ select PXA_SSP
+ select ARCH_LAB126
+ select ZLIB_DEFLATE
+ depends on ARCH_PXA
+
config ARCH_LUBBOCK
bool "Intel DBPXA250 Development Platform"
select PXA25x
@@ -22,6 +38,28 @@
endmenu
+
+choice
+ depends on ARCH_GUMSTIX
+ prompt "Gumstix Platform Version"
+ default ARCH_GUMSTIX_F
+
+config ARCH_GUMSTIX_ORIG
+ bool "Original Gumstix"
+ select PXA25x
+ help
+ The original gumstix platform, including the gs-200x and gs-400x and the waysmall
+ systems using these boards.
+
+config ARCH_GUMSTIX_F
+ bool "Gumstix-F"
+ select PXA25x
+ help
+ The updated Gumstix boards with 60-pin connector, including gs-200f, gs-400f and the
+ waysmall systems using these boards, including ws-200ax and ws-400ax.
+
+endchoice
+
config PXA25x
bool
help
@@ -37,4 +75,10 @@
help
Enable support for iWMMXt
+config PXA_SSP
+ tristate
+ help
+ Enable PXA ssp support
+
endif
+
diff -wur linux-2.6.10/arch/arm/mach-pxa/Makefile linux-2.6.10-lab/arch/arm/mach-pxa/Makefile
--- linux-2.6.10/arch/arm/mach-pxa/Makefile 2004-12-24 16:34:49.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/mach-pxa/Makefile 2007-10-04 19:10:15.000000000 -0400
@@ -8,6 +8,9 @@
obj-$(CONFIG_PXA27x) += pxa27x.o
# Specific board support
+obj-$(CONFIG_ARCH_FIONA) += fiona.o
+obj-$(CONFIG_ARCH_FIONA) += boot_globals.o
+obj-$(CONFIG_ARCH_GUMSTIX) += gumstix.o
obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o
obj-$(CONFIG_MACH_MAINSTONE) += mainstone.o
obj-$(CONFIG_ARCH_PXA_IDP) += idp.o
@@ -22,3 +25,5 @@
# Misc features
obj-$(CONFIG_PM) += pm.o sleep.o
+obj-$(CONFIG_CPU_FREQ) += cpu-pxa.o
+obj-$(CONFIG_PXA_SSP) += ssp.o
diff -wur linux-2.6.10/arch/arm/mach-pxa/generic.c linux-2.6.10-lab/arch/arm/mach-pxa/generic.c
--- linux-2.6.10/arch/arm/mach-pxa/generic.c 2004-12-24 16:34:29.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/mach-pxa/generic.c 2007-10-04 19:10:15.000000000 -0400
@@ -219,6 +219,10 @@
.name = "pxa2xx-uart",
.id = 2,
};
+static struct platform_device hwuart_device = {
+ .name = "pxa2xx-uart",
+ .id = 3,
+};
static struct platform_device *devices[] __initdata = {
&pxamci_device,
@@ -227,6 +231,7 @@
&ffuart_device,
&btuart_device,
&stuart_device,
+ &hwuart_device,
};
static int __init pxa_init(void)
diff -wur linux-2.6.10/arch/arm/mach-pxa/irq.c linux-2.6.10-lab/arch/arm/mach-pxa/irq.c
--- linux-2.6.10/arch/arm/mach-pxa/irq.c 2004-12-24 16:35:27.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/mach-pxa/irq.c 2007-10-04 19:10:15.000000000 -0400
@@ -97,23 +97,31 @@
type = __IRQT_RISEDGE | __IRQT_FALEDGE;
}
+#ifdef DEBUG
printk(KERN_DEBUG "IRQ%d (GPIO%d): ", irq, gpio);
+#endif
pxa_gpio_mode(gpio | GPIO_IN);
if (type & __IRQT_RISEDGE) {
+#ifdef DEBUG
printk("rising ");
+#endif
__set_bit (gpio, GPIO_IRQ_rising_edge);
} else
__clear_bit (gpio, GPIO_IRQ_rising_edge);
if (type & __IRQT_FALEDGE) {
+#ifdef DEBUG
printk("falling ");
+#endif
__set_bit (gpio, GPIO_IRQ_falling_edge);
} else
__clear_bit (gpio, GPIO_IRQ_falling_edge);
+#ifdef DEBUG
printk("edges\n");
+#endif
GRER(gpio) = GPIO_IRQ_rising_edge[idx] & GPIO_IRQ_mask[idx];
GFER(gpio) = GPIO_IRQ_falling_edge[idx] & GPIO_IRQ_mask[idx];
diff -wur linux-2.6.10/arch/arm/mach-pxa/mainstone.c linux-2.6.10-lab/arch/arm/mach-pxa/mainstone.c
--- linux-2.6.10/arch/arm/mach-pxa/mainstone.c 2004-12-24 16:35:40.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/mach-pxa/mainstone.c 2007-10-04 19:10:15.000000000 -0400
@@ -19,6 +19,7 @@
#include
#include
#include
+#include
#include
#include
@@ -33,6 +34,7 @@
#include
#include
+#include
#include
#include
@@ -120,6 +122,44 @@
.resource = smc91x_resources,
};
+static int mst_audio_startup(snd_pcm_substream_t *substream, void *priv)
+{
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ MST_MSCWR2 &= ~MST_MSCWR2_AC97_SPKROFF;
+ return 0;
+}
+
+static void mst_audio_shutdown(snd_pcm_substream_t *substream, void *priv)
+{
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ MST_MSCWR2 |= MST_MSCWR2_AC97_SPKROFF;
+}
+
+static long mst_audio_suspend_mask;
+
+static void mst_audio_suspend(void *priv)
+{
+ mst_audio_suspend_mask = MST_MSCWR2;
+ MST_MSCWR2 |= MST_MSCWR2_AC97_SPKROFF;
+}
+
+static void mst_audio_resume(void *priv)
+{
+ MST_MSCWR2 &= mst_audio_suspend_mask | ~MST_MSCWR2_AC97_SPKROFF;
+}
+
+static pxa2xx_audio_ops_t mst_audio_ops = {
+ .startup = mst_audio_startup,
+ .shutdown = mst_audio_shutdown,
+ .suspend = mst_audio_suspend,
+ .resume = mst_audio_resume,
+};
+
+static struct platform_device mst_audio_device = {
+ .name = "pxa2xx-ac97",
+ .id = -1,
+ .dev = { .platform_data = &mst_audio_ops },
+};
static void mainstone_backlight_power(int on)
{
@@ -228,7 +268,14 @@
static void __init mainstone_init(void)
{
+ /*
+ * On Mainstone, we route AC97_SYSCLK via GPIO45 to
+ * the audio daughter card
+ */
+ pxa_gpio_mode(GPIO45_SYSCLK_AC97_MD);
+
platform_device_register(&smc91x_device);
+ platform_device_register(&mst_audio_device);
/* reading Mainstone's "Virtual Configuration Register"
might be handy to select LCD type here */
diff -wur linux-2.6.10/arch/arm/mach-pxa/pm.c linux-2.6.10-lab/arch/arm/mach-pxa/pm.c
--- linux-2.6.10/arch/arm/mach-pxa/pm.c 2004-12-24 16:35:00.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/mach-pxa/pm.c 2007-10-04 19:10:15.000000000 -0400
@@ -15,6 +15,7 @@
#include
#include
#include
+#include
#include
#include
@@ -23,11 +24,15 @@
#include
#include
+#ifdef CONFIG_ARCH_FIONA
+#include
+#endif
+
/*
* Debug macros
*/
-#undef DEBUG
+#define DEBUG
extern void pxa_cpu_suspend(void);
extern void pxa_cpu_resume(void);
@@ -63,6 +68,80 @@
};
+#ifdef CONFIG_PM_DEBUG
+
+static void blink_led(int count, int cadence)
+{
+ int x;
+ for (x=0; x
@@ -34,6 +37,31 @@
#include
#include
+#define PXA_SSP_PORTS 3
+
+struct ssp_info_ {
+ int irq;
+ u32 clock;
+};
+
+/*
+ * SSP port clock and IRQ settings
+ */
+static const struct ssp_info_ ssp_info[PXA_SSP_PORTS] = {
+#if defined (CONFIG_PXA27x)
+ {IRQ_SSP, CKEN23_SSP1},
+ {IRQ_SSP2, CKEN3_SSP2},
+ {IRQ_SSP3, CKEN4_SSP3},
+#else
+ {IRQ_SSP, CKEN3_SSP},
+ {IRQ_NSSP, CKEN9_NSSP},
+ {IRQ_ASSP, CKEN10_ASSP},
+#endif
+};
+
+static DECLARE_MUTEX(sem);
+static int use_count[PXA_SSP_PORTS] = {0, 0, 0};
+
static irqreturn_t ssp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct ssp_dev *dev = (struct ssp_dev*) dev_id;
@@ -171,6 +199,30 @@
}
/**
+ * ssp_config - configure SSP port settings
+ * @mode: port operating mode
+ * @flags: port config flags
+ * @psp_flags: port PSP config flags
+ * @speed: port speed
+ *
+ * Port MUST be disabled by ssp_disable before making any config changes.
+ */
+int ssp_config(struct ssp_dev *dev, u32 mode, u32 flags, u32 psp_flags, u32 speed)
+{
+ dev->mode = mode;
+ dev->flags = flags;
+ dev->psp_flags = psp_flags;
+ dev->speed = speed;
+
+ /* set up port type, speed, port settings */
+ SSCR0_P(dev->port) = (dev->speed | dev->mode);
+ SSCR1_P(dev->port) = dev->flags;
+ SSPSP_P(dev->port) = dev->psp_flags;
+
+ return 0;
+}
+
+/**
* ssp_init - setup the SSP port
*
* initialise and claim resources for the SSP port.
@@ -180,82 +232,46 @@
* %-EBUSY if the resources are already in use
* %0 on success
*/
-int ssp_init(struct ssp_dev *dev, u32 port, u32 mode, u32 flags, u32 psp_flags,
- u32 speed)
+int ssp_init(struct ssp_dev *dev, u32 port, u32 init_flags)
{
- int ret, irq;
+ int ret;
- if (!request_mem_region(__PREG(SSCR0_P(port)), 0x2c, "SSP")) {
+ if (port > PXA_SSP_PORTS || port == 0)
+ return -ENODEV;
+
+ down(&sem);
+ if (use_count[port - 1]) {
+ up(&sem);
return -EBUSY;
}
+ use_count[port - 1]++;
- switch (port) {
- case 1:
- irq = IRQ_SSP;
- break;
-#if defined (CONFIG_PXA27x)
- case 2:
- irq = IRQ_SSP2;
- break;
- case 3:
- irq = IRQ_SSP3;
- break;
-#else
- case 2:
- irq = IRQ_NSSP;
- break;
- case 3:
- irq = IRQ_ASSP;
- break;
-#endif
- default:
- return -ENODEV;
+ if (!request_mem_region(__PREG(SSCR0_P(port)), 0x2c, "SSP")) {
+ use_count[port - 1]--;
+ up(&sem);
+ return -EBUSY;
}
-
dev->port = port;
- dev->mode = mode;
- dev->flags = flags;
- dev->psp_flags = psp_flags;
- dev->speed = speed;
- /* set up port type, speed, port settings */
- SSCR0_P(dev->port) = (dev->speed | dev->mode);
- SSCR1_P(dev->port) = dev->flags;
- SSPSP_P(dev->port) = dev->psp_flags;
-
- ret = request_irq(irq, ssp_interrupt, 0, "SSP", dev);
+ /* do we need to get irq */
+ if (!(init_flags & SSP_NO_IRQ)) {
+ ret = request_irq(ssp_info[port-1].irq, ssp_interrupt,
+ 0, "SSP", dev);
if (ret)
goto out_region;
+ dev->irq = ssp_info[port-1].irq;
+ } else
+ dev->irq = 0;
/* turn on SSP port clock */
- switch (dev->port) {
-#if defined (CONFIG_PXA27x)
- case 1:
- pxa_set_cken(CKEN23_SSP1, 1);
- break;
- case 2:
- pxa_set_cken(CKEN3_SSP2, 1);
- break;
- case 3:
- pxa_set_cken(CKEN4_SSP3, 1);
- break;
-#else
- case 1:
- pxa_set_cken(CKEN3_SSP, 1);
- break;
- case 2:
- pxa_set_cken(CKEN9_NSSP, 1);
- break;
- case 3:
- pxa_set_cken(CKEN10_ASSP, 1);
- break;
-#endif
- }
-
+ pxa_set_cken(ssp_info[port-1].clock, 1);
+ up(&sem);
return 0;
out_region:
- release_mem_region(__PREG(SSCR0_P(dev->port)), 0x2c);
+ release_mem_region(__PREG(SSCR0_P(port)), 0x2c);
+ use_count[port - 1]--;
+ up(&sem);
return ret;
}
@@ -266,46 +282,20 @@
*/
void ssp_exit(struct ssp_dev *dev)
{
- int irq;
-
+ down(&sem);
SSCR0_P(dev->port) &= ~SSCR0_SSE;
- /* find irq, save power and turn off SSP port clock */
- switch (dev->port) {
-#if defined (CONFIG_PXA27x)
- case 1:
- irq = IRQ_SSP;
- pxa_set_cken(CKEN23_SSP1, 0);
- break;
- case 2:
- irq = IRQ_SSP2;
- pxa_set_cken(CKEN3_SSP2, 0);
- break;
- case 3:
- irq = IRQ_SSP3;
- pxa_set_cken(CKEN4_SSP3, 0);
- break;
-#else
- case 1:
- irq = IRQ_SSP;
- pxa_set_cken(CKEN3_SSP, 0);
- break;
- case 2:
- irq = IRQ_NSSP;
- pxa_set_cken(CKEN9_NSSP, 0);
- break;
- case 3:
- irq = IRQ_ASSP;
- pxa_set_cken(CKEN10_ASSP, 0);
- break;
-#endif
- default:
+ if (dev->port > PXA_SSP_PORTS || dev->port == 0) {
printk(KERN_WARNING "SSP: tried to close invalid port\n");
return;
}
- free_irq(irq, dev);
+ pxa_set_cken(ssp_info[dev->port-1].clock, 0);
+ if (dev->irq)
+ free_irq(dev->irq, dev);
release_mem_region(__PREG(SSCR0_P(dev->port)), 0x2c);
+ use_count[dev->port - 1]--;
+ up(&sem);
}
EXPORT_SYMBOL(ssp_write_word);
@@ -317,3 +307,9 @@
EXPORT_SYMBOL(ssp_restore_state);
EXPORT_SYMBOL(ssp_init);
EXPORT_SYMBOL(ssp_exit);
+EXPORT_SYMBOL(ssp_config);
+
+MODULE_DESCRIPTION("PXA SSP driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
+
diff -wur linux-2.6.10/arch/arm/mach-pxa/time.c linux-2.6.10-lab/arch/arm/mach-pxa/time.c
--- linux-2.6.10/arch/arm/mach-pxa/time.c 2004-12-24 16:34:44.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/mach-pxa/time.c 2007-10-04 19:10:15.000000000 -0400
@@ -29,6 +29,9 @@
#include
#include
+#if defined(CONFIG_ARCH_FIONA)
+#include
+#endif
static inline unsigned long pxa_get_rtc_time(void)
{
@@ -75,6 +78,10 @@
{
int next_match;
+#if defined(CONFIG_ARCH_FIONA)
+ boot_globals_t *bg;
+#endif
+
write_seqlock(&xtime_lock);
/* Loop until we get ahead of the free running timer.
@@ -98,6 +105,16 @@
next_match = (OSMR0 += LATCH);
} while( (signed long)(next_match - OSCR) <= 8 );
+#if defined(CONFIG_ARCH_FIONA)
+ bg = get_boot_globals();
+ if (bg != NULL) {
+ bg_in_use_t *bd = &bg->globals;
+
+ bd->saved_rtc = RCNR;
+ bd->saved_rtc_checksum = ~bd->saved_rtc;
+ }
+#endif
+
write_sequnlock(&xtime_lock);
return IRQ_HANDLED;
diff -wur linux-2.6.10/arch/arm/mm/consistent.c linux-2.6.10-lab/arch/arm/mm/consistent.c
--- linux-2.6.10/arch/arm/mm/consistent.c 2004-12-24 16:35:24.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/mm/consistent.c 2007-10-04 19:10:15.000000000 -0400
@@ -1,7 +1,7 @@
/*
* linux/arch/arm/mm/consistent.c
*
- * Copyright (C) 2000-2002 Russell King
+ * Copyright (C) 2000-2004 Russell King
*
* 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
@@ -65,6 +65,7 @@
struct list_head vm_list;
unsigned long vm_start;
unsigned long vm_end;
+ struct page *vm_pages;
};
static struct vm_region consistent_head = {
@@ -206,6 +207,8 @@
pte_t *pte = consistent_pte + CONSISTENT_OFFSET(c->vm_start);
struct page *end = page + (1 << order);
+ c->vm_pages = page;
+
/*
* Set the "dma handle"
*/
@@ -215,6 +218,9 @@
BUG_ON(!pte_none(*pte));
set_page_count(page, 1);
+ /*
+ * x86 does not mark the pages reserved...
+ */
SetPageReserved(page);
set_pte(pte, mk_pte(page, prot));
page++;
@@ -264,6 +270,53 @@
}
EXPORT_SYMBOL(dma_alloc_writecombine);
+static int dma_mmap(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size)
+{
+ unsigned long flags, user_size, kern_size;
+ struct vm_region *c;
+ int ret = -ENXIO;
+
+ user_size = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+
+ spin_lock_irqsave(&consistent_lock, flags);
+ c = vm_region_find(&consistent_head, (unsigned long)cpu_addr);
+ spin_unlock_irqrestore(&consistent_lock, flags);
+
+ if (c) {
+ unsigned long off = vma->vm_pgoff;
+
+ kern_size = (c->vm_end - c->vm_start) >> PAGE_SHIFT;
+
+ if (off < kern_size &&
+ user_size <= (kern_size - off)) {
+ vma->vm_flags |= VM_RESERVED;
+ ret = remap_pfn_range(vma, vma->vm_start,
+ page_to_pfn(c->vm_pages) + off,
+ user_size << PAGE_SHIFT,
+ vma->vm_page_prot);
+ }
+ }
+
+ return ret;
+}
+
+int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size)
+{
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ return dma_mmap(dev, vma, cpu_addr, dma_addr, size);
+}
+EXPORT_SYMBOL(dma_mmap_coherent);
+
+int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size)
+{
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ return dma_mmap(dev, vma, cpu_addr, dma_addr, size);
+}
+EXPORT_SYMBOL(dma_mmap_writecombine);
+
/*
* free a page as defined by the above mapping.
*/
@@ -300,6 +353,10 @@
if (pfn_valid(pfn)) {
struct page *page = pfn_to_page(pfn);
+
+ /*
+ * x86 does not mark the pages reserved...
+ */
ClearPageReserved(page);
__free_page(page);
diff -wur linux-2.6.10/arch/arm/mm/proc-xscale.S linux-2.6.10-lab/arch/arm/mm/proc-xscale.S
--- linux-2.6.10/arch/arm/mm/proc-xscale.S 2004-12-24 16:35:25.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/mm/proc-xscale.S 2007-10-04 19:10:15.000000000 -0400
@@ -580,11 +580,62 @@
movne r2, #0 @ no -> fault
str r2, [r0] @ hardware version
+
+ @ We try to map 64K page entries when possible.
+ @ We do that for kernel space only since the usage pattern from
+ @ the setting of VM area is quite simple. User space is not worth
+ @ the implied complexity because of ever randomly changing PTEs
+ @ (page aging, swapout, etc) requiring constant coherency checks.
+ @ Since PTEs are usually set in increasing order, we test the
+ @ possibility for a large page only when given the last PTE of a
+ @ 64K boundary.
+ tsteq r1, #L_PTE_USER
+ andeq r1, r0, #(15 << 2)
+ teqeq r1, #(15 << 2)
+ beq 1f
+
mov ip, #0
mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line
mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
mov pc, lr
+ @ See if we have 16 identical PTEs but with consecutive base addresses
+1: bic r3, r2, #0x0000f000
+ mov r1, #0x0000f000
+2: eor r2, r2, r3
+ teq r2, r1
+ bne 4f
+ subs r1, r1, #0x00001000
+ ldr r2, [r0, #-4]!
+ bne 2b
+ eors r2, r2, r3
+ bne 4f
+
+ @ Now create our LARGE PTE from the current EXT one.
+ bic r3, r3, #PTE_TYPE_MASK
+ orr r3, r3, #PTE_TYPE_LARGE
+ and r2, r3, #0x30 @ EXT_AP --> LARGE_AP0
+ orr r2, r2, r2, lsl #2 @ add LARGE_AP1
+ orr r2, r2, r2, lsl #4 @ add LARGE_AP3 + LARGE_AP2
+ and r1, r3, #0x3c0 @ EXT_TEX
+ bic r3, r3, #0x3c0
+ orr r2, r2, r1, lsl #(12 - 6) @ --> LARGE_TEX
+ orr r2, r2, r3 @ add remaining bits
+
+ @ then put it in the pagetable
+ mov r3, r2
+3: strd r2, [r0], #8
+ tst r0, #(15 << 2)
+ bne 3b
+
+ @ Then sync the 2 corresponding cache lines
+ sub r0, r0, #(16 << 2)
+ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line
+4: orr r0, r0, #(15 << 2)
+ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line
+ mov ip, #0
+ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
+ mov pc, lr
.ltorg
diff -wur linux-2.6.10/arch/arm/tools/mach-types linux-2.6.10-lab/arch/arm/tools/mach-types
--- linux-2.6.10/arch/arm/tools/mach-types 2004-12-24 16:34:45.000000000 -0500
+++ linux-2.6.10-lab/arch/arm/tools/mach-types 2007-10-04 19:10:14.000000000 -0400
@@ -381,7 +381,7 @@
spearhead ARCH_SPEARHEAD SPEARHEAD 370
pantera ARCH_PANTERA PANTERA 371
prayoglite ARCH_PRAYOGLITE PRAYOGLITE 372
-gumstik ARCH_GUMSTIK GUMSTIK 373
+gumstix ARCH_GUMSTIX GUMSTIX 373
rcube ARCH_RCUBE RCUBE 374
rea_olv ARCH_REA_OLV REA_OLV 375
pxa_iphone ARCH_PXA_IPHONE PXA_IPHONE 376
@@ -634,3 +634,4 @@
cm4008 MACH_CM4008 CM4008 624
p2001 MACH_P2001 P2001 625
twister MACH_TWISTER TWISTER 626
+fiona ARCH_FIONA FIONA 627
diff -wur linux-2.6.10/drivers/Makefile linux-2.6.10-lab/drivers/Makefile
--- linux-2.6.10/drivers/Makefile 2004-12-24 16:36:00.000000000 -0500
+++ linux-2.6.10-lab/drivers/Makefile 2007-10-04 19:10:40.000000000 -0400
@@ -5,17 +5,17 @@
# Rewritten to use lists instead of if-statements.
#
-obj-$(CONFIG_PCI) += pci/
-obj-$(CONFIG_PARISC) += parisc/
+# obj-$(CONFIG_PCI) += pci/
+# obj-$(CONFIG_PARISC) += parisc/
obj-y += video/
-obj-$(CONFIG_ACPI_BOOT) += acpi/
+# obj-$(CONFIG_ACPI_BOOT) += acpi/
# PnP must come after ACPI since it will eventually need to check if acpi
# was used and do nothing if so
-obj-$(CONFIG_PNP) += pnp/
+# obj-$(CONFIG_PNP) += pnp/
# char/ comes before serial/ etc so that the VT console is the boot-time
# default.
-obj-y += char/
+obj-y += char/ char/ppoke/
# i810fb and intelfb depend on char/agp/
obj-$(CONFIG_FB_I810) += video/i810/
@@ -25,38 +25,41 @@
# serial drivers start registering their serio ports
obj-$(CONFIG_SERIO) += input/serio/
obj-y += serial/
-obj-$(CONFIG_PARPORT) += parport/
-obj-y += base/ block/ misc/ net/ media/
-obj-$(CONFIG_NUBUS) += nubus/
-obj-$(CONFIG_ATM) += atm/
-obj-$(CONFIG_PPC_PMAC) += macintosh/
-obj-$(CONFIG_IDE) += ide/
-obj-$(CONFIG_FC4) += fc4/
+# obj-$(CONFIG_PARPORT) += parport/
+# obj-y += base/ block/ misc/ net/ media/
+obj-y += base/ block/ misc/ net/
+# obj-$(CONFIG_NUBUS) += nubus/
+# obj-$(CONFIG_ATM) += atm/
+# obj-$(CONFIG_PPC_PMAC) += macintosh/
+# obj-$(CONFIG_IDE) += ide/
+# obj-$(CONFIG_FC4) += fc4/
obj-$(CONFIG_SCSI) += scsi/
-obj-$(CONFIG_FUSION) += message/
-obj-$(CONFIG_IEEE1394) += ieee1394/
+# obj-$(CONFIG_FUSION) += message/
+# obj-$(CONFIG_IEEE1394) += ieee1394/
obj-y += cdrom/
obj-$(CONFIG_MTD) += mtd/
+obj-$(CONFIG_RFS_XSR) += xsr/
obj-$(CONFIG_PCCARD) += pcmcia/
-obj-$(CONFIG_DIO) += dio/
-obj-$(CONFIG_SBUS) += sbus/
-obj-$(CONFIG_ZORRO) += zorro/
-obj-$(CONFIG_MAC) += macintosh/
+# obj-$(CONFIG_DIO) += dio/
+# obj-$(CONFIG_SBUS) += sbus/
+# obj-$(CONFIG_ZORRO) += zorro/
+# obj-$(CONFIG_MAC) += macintosh/
obj-$(CONFIG_PARIDE) += block/paride/
-obj-$(CONFIG_TC) += tc/
+# obj-$(CONFIG_TC) += tc/
obj-$(CONFIG_USB) += usb/
obj-$(CONFIG_USB_GADGET) += usb/gadget/
obj-$(CONFIG_INPUT) += input/
obj-$(CONFIG_GAMEPORT) += input/gameport/
-obj-$(CONFIG_I2O) += message/
+# obj-$(CONFIG_I2O) += message/
obj-$(CONFIG_I2C) += i2c/
-obj-$(CONFIG_W1) += w1/
-obj-$(CONFIG_PHONE) += telephony/
-obj-$(CONFIG_MD) += md/
-obj-$(CONFIG_BT) += bluetooth/
-obj-$(CONFIG_ISDN) += isdn/
-obj-$(CONFIG_MCA) += mca/
-obj-$(CONFIG_EISA) += eisa/
+# obj-$(CONFIG_W1) += w1/
+# obj-$(CONFIG_PHONE) += telephony/
+# obj-$(CONFIG_MD) += md/
+# obj-$(CONFIG_BT) += bluetooth/
+# obj-$(CONFIG_ISDN) += isdn/
+# obj-$(CONFIG_MCA) += mca/
+# obj-$(CONFIG_EISA) += eisa/
obj-$(CONFIG_CPU_FREQ) += cpufreq/
obj-$(CONFIG_MMC) += mmc/
+obj-$(CONFIG_PROC_GPIO) += gpio/
obj-y += firmware/
diff -wur linux-2.6.10/drivers/base/power/resume.c linux-2.6.10-lab/drivers/base/power/resume.c
--- linux-2.6.10/drivers/base/power/resume.c 2004-12-24 16:35:24.000000000 -0500
+++ linux-2.6.10-lab/drivers/base/power/resume.c 2007-10-04 19:10:37.000000000 -0400
@@ -9,8 +9,10 @@
*/
#include
+#include
#include "power.h"
+
extern int sysdev_resume(void);
@@ -27,10 +29,45 @@
return 0;
}
+#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_ARCH_FIONA)
+
+#include
+#include
+static void fdputs(char *s)
+{
+ int size = 0;
+ int x = 0, wait = 0;
+ char *cur = s;
+
+ //return;
+ if (s == NULL)
+ return;
+ size = strlen(s);
+
+ // Print the string, waiting for each character to shift out before
+ // writing the next one...
+ for (x=0; x 10) {
+ STTHR = '^';
+ return;
+ }
+ }
+ }
+}
+#endif
void dpm_resume(void)
{
+#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_ARCH_FIONA)
+ char theStr[255];
+ theStr[0] = '\0';
+#endif
+
down(&dpm_list_sem);
while(!list_empty(&dpm_off)) {
struct list_head * entry = dpm_off.next;
@@ -42,7 +79,25 @@
up(&dpm_list_sem);
if (!dev->power.prev_state)
+ {
+#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_ARCH_FIONA)
+ if ((dev->driver) && (dev->driver->name)) {
+ sprintf(theStr,"Resuming device: %s\n",dev->driver->name);
+ fdputs(theStr);
+ }
+ else {
+ sprintf(theStr,"Resuming device no-name...\n");
+ fdputs(theStr);
+ }
+#endif
resume_device(dev);
+ }
+#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_ARCH_FIONA)
+ else {
+ sprintf(theStr,"Did not resume device %s - power.prev_state (%d) not zero\n",dev->driver->name,dev->power.prev_state);
+ fdputs(theStr);
+ }
+#endif
down(&dpm_list_sem);
put_device(dev);
}
diff -wur linux-2.6.10/drivers/block/Kconfig linux-2.6.10-lab/drivers/block/Kconfig
--- linux-2.6.10/drivers/block/Kconfig 2004-12-24 16:34:26.000000000 -0500
+++ linux-2.6.10-lab/drivers/block/Kconfig 2007-10-04 19:10:29.000000000 -0400
@@ -425,7 +425,7 @@
this option is dangerous unless the CD-RW media is known good, as we
don't do deferred write error handling yet.
-source "drivers/s390/block/Kconfig"
+# source "drivers/s390/block/Kconfig"
source "drivers/block/Kconfig.iosched"
diff -wur linux-2.6.10/drivers/char/Kconfig linux-2.6.10-lab/drivers/char/Kconfig
--- linux-2.6.10/drivers/char/Kconfig 2004-12-24 16:33:49.000000000 -0500
+++ linux-2.6.10-lab/drivers/char/Kconfig 2007-10-04 19:10:40.000000000 -0400
@@ -600,6 +600,8 @@
source "drivers/char/watchdog/Kconfig"
+source "drivers/char/ioc/Kconfig"
+
config DS1620
tristate "NetWinder thermometer support"
depends on ARCH_NETWINDER
@@ -730,6 +732,8 @@
To compile this driver as a module, choose M here: the
module will be called rtc.
+
+
config SGI_DS1286
tristate "SGI DS1286 RTC support"
depends on SGI_IP22
@@ -805,6 +809,10 @@
This option enables support for the LCD display and buttons found
on Cobalt systems through a misc device.
+config SA1100_RTC
+ tristate "SA1100/PXA2xx Real Time Clock"
+ depends on ARCH_SA1100 || ARCH_PXA
+
config DTLK
tristate "Double Talk PC internal speech card support"
help
diff -wur linux-2.6.10/drivers/char/Makefile linux-2.6.10-lab/drivers/char/Makefile
--- linux-2.6.10/drivers/char/Makefile 2004-12-24 16:35:29.000000000 -0500
+++ linux-2.6.10-lab/drivers/char/Makefile 2007-10-04 19:10:40.000000000 -0400
@@ -53,6 +53,8 @@
obj-$(CONFIG_PRINTER) += lp.o
obj-$(CONFIG_TIPAR) += tipar.o
+obj-$(CONFIG_IOC) += ioc/
+
obj-$(CONFIG_DTLK) += dtlk.o
obj-$(CONFIG_R3964) += n_r3964.o
obj-$(CONFIG_APPLICOM) += applicom.o
@@ -61,6 +63,7 @@
obj-$(CONFIG_HPET) += hpet.o
obj-$(CONFIG_GEN_RTC) += genrtc.o
obj-$(CONFIG_EFI_RTC) += efirtc.o
+obj-$(CONFIG_SA1100_RTC) += sa1100-rtc.o
obj-$(CONFIG_SGI_DS1286) += ds1286.o
obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o
obj-$(CONFIG_DS1302) += ds1302.o
diff -wur linux-2.6.10/drivers/char/watchdog/sa1100_wdt.c linux-2.6.10-lab/drivers/char/watchdog/sa1100_wdt.c
--- linux-2.6.10/drivers/char/watchdog/sa1100_wdt.c 2004-12-24 16:34:45.000000000 -0500
+++ linux-2.6.10-lab/drivers/char/watchdog/sa1100_wdt.c 2007-10-04 19:10:38.000000000 -0400
@@ -16,8 +16,11 @@
* (c) Copyright 2000 Oleg Drokin
*
* 27/11/2000 Initial release
+ *
+ *
+ * Lab126 changes copyright (C) 2007 Lab126, Inc.
*/
-#include
+
#include
#include
#include
@@ -35,17 +38,73 @@
#include
#include
-#define OSCR_FREQ 3686400
-#define SA1100_CLOSE_MAGIC (0x5afc4453)
+#if defined(CONFIG_ARCH_LAB126) && defined(CONFIG_PM)
+#include
+#endif
+
+#define OSCR_FREQ CLOCK_TICK_RATE
static unsigned long sa1100wdt_users;
-static int expect_close;
static int pre_margin;
static int boot_status;
-#ifdef CONFIG_WATCHDOG_NOWAYOUT
-static int nowayout = 1;
-#else
-static int nowayout = 0;
+
+#if defined(CONFIG_ARCH_LAB126) && defined(CONFIG_PM)
+static wait_queue_head_t pm_event_wq;
+static pid_t pm_handler_thread_pid = 0;
+static DECLARE_COMPLETION(pm_handler_thread_exited);
+
+static void init_wdt(void)
+{
+ OSMR3 = OSCR + pre_margin;
+ OSSR = OSSR_M3;
+ OWER = OWER_WME;
+ OIER |= OIER_E3;
+}
+
+static int pm_handler_thread(void *unused)
+{
+ daemonize("wdtpmd");
+ allow_signal(SIGKILL);
+
+ while (1) {
+ wait_event_interruptible(pm_event_wq, 0);
+
+ if (current->flags & PF_FREEZE) {
+ refrigerator(PF_FREEZE);
+
+ init_wdt();
+ }
+
+ if (signal_pending(current)) {
+ break;
+ }
+ }
+
+ complete_and_exit(&pm_handler_thread_exited, 0);
+
+ return 0;
+}
+
+static void start_pm_thread(void)
+{
+ init_waitqueue_head(&pm_event_wq);
+
+ pm_handler_thread_pid = kernel_thread(pm_handler_thread, NULL, CLONE_KERNEL);
+}
+
+static void
+stop_pm_thread(
+ void)
+{
+ int ret;
+
+ if (pm_handler_thread_pid > 0) {
+ ret = kill_proc(pm_handler_thread_pid, SIGKILL, 1);
+ if (ret == 0) {
+ wait_for_completion(&pm_handler_thread_exited);
+ }
+ }
+}
#endif
/*
@@ -58,63 +117,46 @@
return -EBUSY;
/* Activate SA1100 Watchdog timer */
+#if defined(CONFIG_ARCH_LAB126) && defined(CONFIG_PM)
+ init_wdt();
+#else
OSMR3 = OSCR + pre_margin;
OSSR = OSSR_M3;
OWER = OWER_WME;
OIER |= OIER_E3;
+#endif
+
return 0;
}
/*
- * Shut off the timer.
- * Lock it in if it's a module and we defined ...NOWAYOUT
- * Oddly, the watchdog can only be enabled, but we can turn off
- * the interrupt, which appears to prevent the watchdog timing out.
+ * The watchdog cannot be disabled.
+ *
+ * Previous comments suggested that turning off the interrupt by
+ * clearing OIER[E3] would prevent the watchdog timing out but this
+ * does not appear to be true (at least on the PXA255).
*/
static int sa1100dog_release(struct inode *inode, struct file *file)
{
- OSMR3 = OSCR + pre_margin;
-
- if (expect_close == SA1100_CLOSE_MAGIC) {
- OIER &= ~OIER_E3;
- } else {
- printk(KERN_CRIT "WATCHDOG: WDT device closed unexpectedly. WDT will not stop!\n");
- }
+ printk(KERN_CRIT "WATCHDOG: Device closed - timer will not stop\n");
clear_bit(1, &sa1100wdt_users);
- expect_close = 0;
return 0;
}
-static ssize_t sa1100dog_write(struct file *file, const char *data, size_t len, loff_t *ppos)
+static ssize_t sa1100dog_write(struct file *file, const char __user *data, size_t len, loff_t *ppos)
{
- if (len) {
- if (!nowayout) {
- size_t i;
-
- expect_close = 0;
-
- for (i = 0; i != len; i++) {
- char c;
-
- if (get_user(c, data + i))
- return -EFAULT;
- if (c == 'V')
- expect_close = SA1100_CLOSE_MAGIC;
- }
- }
+ if (len)
/* Refresh OSMR3 timer. */
OSMR3 = OSCR + pre_margin;
- }
return len;
}
static struct watchdog_info ident = {
- .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE |
- WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
- .identity = "SA1100 Watchdog",
+ .options = WDIOF_CARDRESET | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+ .identity = "SA1100/PXA255 Watchdog",
};
static int sa1100dog_ioctl(struct inode *inode, struct file *file,
@@ -122,23 +164,25 @@
{
int ret = -ENOIOCTLCMD;
int time;
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
switch (cmd) {
case WDIOC_GETSUPPORT:
- ret = copy_to_user((struct watchdog_info *)arg, &ident,
+ ret = copy_to_user(argp, &ident,
sizeof(ident)) ? -EFAULT : 0;
break;
case WDIOC_GETSTATUS:
- ret = put_user(0, (int *)arg);
+ ret = put_user(0, p);
break;
case WDIOC_GETBOOTSTATUS:
- ret = put_user(boot_status, (int *)arg);
+ ret = put_user(boot_status, p);
break;
case WDIOC_SETTIMEOUT:
- ret = get_user(time, (int *)arg);
+ ret = get_user(time, p);
if (ret)
break;
@@ -152,7 +196,7 @@
/*fall through*/
case WDIOC_GETTIMEOUT:
- ret = put_user(pre_margin / OSCR_FREQ, (int *)arg);
+ ret = put_user(pre_margin / OSCR_FREQ, p);
break;
case WDIOC_KEEPALIVE:
@@ -163,7 +207,7 @@
return ret;
}
-static struct file_operations sa1100dog_fops =
+static const struct file_operations sa1100dog_fops =
{
.owner = THIS_MODULE,
.llseek = no_llseek,
@@ -176,8 +220,8 @@
static struct miscdevice sa1100dog_miscdev =
{
.minor = WATCHDOG_MINOR,
- .name = "SA1100/PXA2xx watchdog",
- .fops = &sa1100dog_fops,
+ .name = "watchdog",
+ .fops = (struct file_operations *)&sa1100dog_fops,
};
static int margin __initdata = 60; /* (secs) Default is 1 minute */
@@ -186,6 +230,10 @@
{
int ret;
+#if defined(CONFIG_ARCH_LAB126) && defined(CONFIG_PM)
+ start_pm_thread();
+#endif
+
/*
* Read the reset status, and save it for later. If
* we suspend, RCSR will be cleared, and the watchdog
@@ -198,12 +246,15 @@
if (ret == 0)
printk("SA1100/PXA2xx Watchdog Timer: timer margin %d sec\n",
margin);
-
return ret;
}
static void __exit sa1100dog_exit(void)
{
+#if defined(CONFIG_ARCH_LAB126) && defined(CONFIG_PM)
+ stop_pm_thread();
+#endif
+
misc_deregister(&sa1100dog_miscdev);
}
@@ -216,8 +267,5 @@
module_param(margin, int, 0);
MODULE_PARM_DESC(margin, "Watchdog margin in seconds (default 60s)");
-module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
-
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff -wur linux-2.6.10/drivers/cpufreq/Kconfig linux-2.6.10-lab/drivers/cpufreq/Kconfig
--- linux-2.6.10/drivers/cpufreq/Kconfig 2004-12-24 16:35:28.000000000 -0500
+++ linux-2.6.10-lab/drivers/cpufreq/Kconfig 2007-10-04 19:10:37.000000000 -0400
@@ -13,9 +13,13 @@
If in doubt, say N.
+if CPU_FREQ
+
+config CPU_FREQ_TABLE
+ def_tristate y
+
config CPU_FREQ_DEBUG
bool "Enable CPUfreq debugging"
- depends on CPU_FREQ
help
Say Y here to enable CPUfreq subsystem (including drivers)
debugging. You will need to activate it via the kernel
@@ -27,23 +31,29 @@
2 to activate CPUfreq drivers debugging, and
4 to activate CPUfreq governor debugging
-config CPU_FREQ_PROC_INTF
- tristate "/proc/cpufreq interface (deprecated)"
- depends on CPU_FREQ && PROC_FS
- help
- This enables the /proc/cpufreq interface for controlling
- CPUFreq. Please note that it is recommended to use the sysfs
- interface instead (which is built automatically).
-
- For details, take a look at .
-
- If in doubt, say N.
+config CPU_FREQ_STAT
+ tristate "CPU frequency translation statistics"
+ select CPU_FREQ_TABLE
+ default y
+ help
+ This driver exports CPU frequency statistics information through sysfs
+ file system
+
+config CPU_FREQ_STAT_DETAILS
+ bool "CPU frequency translation statistics details"
+ depends on CPU_FREQ_STAT
+ help
+ This will show detail CPU frequency translation table in sysfs file
+ system
+
+# Note that it is not currently possible to set the other governors (such as ondemand)
+# as the default, since if they fail to initialise, cpufreq will be
+# left in an undefined state.
choice
prompt "Default CPUFreq governor"
- depends on CPU_FREQ
- default CPU_FREQ_DEFAULT_GOV_PERFORMANCE if !CPU_FREQ_SA1100 && !CPU_FREQ_SA1110
default CPU_FREQ_DEFAULT_GOV_USERSPACE if CPU_FREQ_SA1100 || CPU_FREQ_SA1110
+ default CPU_FREQ_DEFAULT_GOV_PERFORMANCE
help
This option sets which CPUFreq governor shall be loaded at
startup. If in doubt, select 'performance'.
@@ -69,7 +79,6 @@
config CPU_FREQ_GOV_PERFORMANCE
tristate "'performance' governor"
- depends on CPU_FREQ
help
This cpufreq governor sets the frequency statically to the
highest available CPU frequency.
@@ -78,7 +87,6 @@
config CPU_FREQ_GOV_POWERSAVE
tristate "'powersave' governor"
- depends on CPU_FREQ
help
This cpufreq governor sets the frequency statically to the
lowest available CPU frequency.
@@ -87,7 +95,6 @@
config CPU_FREQ_GOV_USERSPACE
tristate "'userspace' governor for userspace frequency scaling"
- depends on CPU_FREQ
help
Enable this cpufreq governor when you either want to set the
CPU frequency manually or when an userspace program shall
@@ -98,24 +105,8 @@
If in doubt, say Y.
-config CPU_FREQ_24_API
- bool "/proc/sys/cpu/ interface (2.4. / OLD)"
- depends on CPU_FREQ_GOV_USERSPACE
- depends on SYSCTL
- help
- This enables the /proc/sys/cpu/ sysctl interface for controlling
- the CPUFreq,"userspace" governor. This is the same interface
- as known from the 2.4.-kernel patches for CPUFreq, and offers
- the same functionality as long as "userspace" is the
- selected governor for the specified CPU.
-
- For details, take a look at .
-
- If in doubt, say N.
-
config CPU_FREQ_GOV_ONDEMAND
tristate "'ondemand' cpufreq policy governor"
- depends on CPU_FREQ
help
'ondemand' - This driver adds a dynamic cpufreq policy governor.
The governor does a periodic polling and
@@ -127,3 +118,25 @@
For details, take a look at linux/Documentation/cpu-freq.
If in doubt, say N.
+
+config CPU_FREQ_GOV_CONSERVATIVE
+ tristate "'conservative' cpufreq governor"
+ depends on CPU_FREQ
+ help
+ 'conservative' - this driver is rather similar to the 'ondemand'
+ governor both in its source code and its purpose, the difference is
+ its optimisation for better suitability in a battery powered
+ environment. The frequency is gracefully increased and decreased
+ rather than jumping to 100% when speed is required.
+
+ If you have a desktop machine then you should really be considering
+ the 'ondemand' governor instead, however if you are using a laptop,
+ PDA or even an AMD64 based computer (due to the unacceptable
+ step-by-step latency issues between the minimum and maximum frequency
+ transitions in the CPU) you will probably want to use this governor.
+
+ For details, take a look at linux/Documentation/cpu-freq.
+
+ If in doubt, say N.
+
+endif # CPU_FREQ
diff -wur linux-2.6.10/drivers/cpufreq/Makefile linux-2.6.10-lab/drivers/cpufreq/Makefile
--- linux-2.6.10/drivers/cpufreq/Makefile 2004-12-24 16:35:49.000000000 -0500
+++ linux-2.6.10-lab/drivers/cpufreq/Makefile 2007-10-04 19:10:37.000000000 -0400
@@ -1,13 +1,15 @@
# CPUfreq core
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
+# CPUfreq stats
+obj-$(CONFIG_CPU_FREQ_STAT) += cpufreq_stats.o
# CPUfreq governors
obj-$(CONFIG_CPU_FREQ_GOV_PERFORMANCE) += cpufreq_performance.o
obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE) += cpufreq_powersave.o
obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o
obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o
+obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o
# CPUfreq cross-arch helpers
obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o
-obj-$(CONFIG_CPU_FREQ_PROC_INTF) += proc_intf.o
diff -wur linux-2.6.10/drivers/cpufreq/cpufreq.c linux-2.6.10-lab/drivers/cpufreq/cpufreq.c
--- linux-2.6.10/drivers/cpufreq/cpufreq.c 2004-12-24 16:34:26.000000000 -0500
+++ linux-2.6.10-lab/drivers/cpufreq/cpufreq.c 2007-10-04 19:10:37.000000000 -0400
@@ -33,7 +33,7 @@
*/
static struct cpufreq_driver *cpufreq_driver;
static struct cpufreq_policy *cpufreq_cpu_data[NR_CPUS];
-static spinlock_t cpufreq_driver_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t cpufreq_driver_lock = SPIN_LOCK_UNLOCKED;
/* we keep a copy of all ->add'ed CPU's struct sys_device here;
@@ -63,7 +63,7 @@
static LIST_HEAD(cpufreq_governor_list);
static DECLARE_MUTEX (cpufreq_governor_sem);
-static struct cpufreq_policy * cpufreq_cpu_get(unsigned int cpu)
+struct cpufreq_policy * cpufreq_cpu_get(unsigned int cpu)
{
struct cpufreq_policy *data;
unsigned long flags;
@@ -102,12 +102,14 @@
err_out:
return NULL;
}
+EXPORT_SYMBOL_GPL(cpufreq_cpu_get);
-static void cpufreq_cpu_put(struct cpufreq_policy *data)
+void cpufreq_cpu_put(struct cpufreq_policy *data)
{
kobject_put(&data->kobj);
module_put(cpufreq_driver->owner);
}
+EXPORT_SYMBOL_GPL(cpufreq_cpu_put);
/*********************************************************************
@@ -128,7 +130,7 @@
* is set, and disabled upon cpufreq driver removal
*/
static unsigned int disable_ratelimit = 1;
-static spinlock_t disable_ratelimit_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(disable_ratelimit_lock);
static inline void cpufreq_debug_enable_ratelimit(void)
{
@@ -221,7 +223,7 @@
}
if ((val == CPUFREQ_PRECHANGE && ci->old < ci->new) ||
(val == CPUFREQ_POSTCHANGE && ci->old > ci->new) ||
- (val == CPUFREQ_RESUMECHANGE)) {
+ (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, ci->new);
dprintk("scaling loops_per_jiffy to %lu for frequency %u kHz\n", loops_per_jiffy, ci->new);
}
@@ -256,7 +258,7 @@
(likely(cpufreq_cpu_data[freqs->cpu]->cur)) &&
(unlikely(freqs->old != cpufreq_cpu_data[freqs->cpu]->cur)))
{
- printk(KERN_WARNING "Warning: CPU frequency is %u, "
+ dprintk(KERN_WARNING "Warning: CPU frequency is %u, "
"cpufreq assumed %u kHz.\n", freqs->old, cpufreq_cpu_data[freqs->cpu]->cur);
freqs->old = cpufreq_cpu_data[freqs->cpu]->cur;
}
@@ -285,7 +287,7 @@
/**
* cpufreq_parse_governor - parse a governor string
*/
-int cpufreq_parse_governor (char *str_governor, unsigned int *policy,
+static int cpufreq_parse_governor (char *str_governor, unsigned int *policy,
struct cpufreq_governor **governor)
{
if (!cpufreq_driver)
@@ -519,7 +521,7 @@
policy = cpufreq_cpu_get(policy->cpu);
if (!policy)
return -EINVAL;
- ret = fattr->show ? fattr->show(policy,buf) : 0;
+ ret = fattr->show ? fattr->show(policy,buf) : -EIO;
cpufreq_cpu_put(policy);
return ret;
}
@@ -533,7 +535,7 @@
policy = cpufreq_cpu_get(policy->cpu);
if (!policy)
return -EINVAL;
- ret = fattr->store ? fattr->store(policy,buf,count) : 0;
+ ret = fattr->store ? fattr->store(policy,buf,count) : -EIO;
cpufreq_cpu_put(policy);
return ret;
}
@@ -625,7 +627,7 @@
ret = kobject_register(&policy->kobj);
if (ret)
- goto err_out;
+ goto err_out_driver_exit;
/* set up files for this cpu device */
drv_attr = cpufreq_driver->attr;
@@ -671,6 +673,10 @@
kobject_unregister(&policy->kobj);
wait_for_completion(&policy->kobj_unregister);
+err_out_driver_exit:
+ if (cpufreq_driver->exit)
+ cpufreq_driver->exit(policy);
+
err_out:
kfree(policy);
@@ -763,8 +769,11 @@
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
#endif
+ down(&data->lock);
if (cpufreq_driver->target)
__cpufreq_governor(data, CPUFREQ_GOV_STOP);
+ cpufreq_driver->target = NULL;
+ up(&data->lock);
kobject_unregister(&data->kobj);
@@ -809,7 +818,7 @@
{
struct cpufreq_freqs freqs;
- printk(KERN_WARNING "Warning: CPU frequency out of sync: cpufreq and timing "
+ dprintk(KERN_WARNING "Warning: CPU frequency out of sync: cpufreq and timing "
"core thinks of %u, is %u kHz.\n", old_freq, new_freq);
freqs.cpu = cpu;
@@ -861,11 +870,92 @@
/**
+ * cpufreq_suspend - let the low level driver prepare for suspend
+ */
+
+static int cpufreq_suspend(struct sys_device * sysdev, u32 state)
+{
+ int cpu = sysdev->id;
+ unsigned int ret = 0;
+ unsigned int cur_freq = 0;
+ struct cpufreq_policy *cpu_policy;
+
+ dprintk("resuming cpu %u\n", cpu);
+
+ if (!cpu_online(cpu))
+ return 0;
+
+ /* we may be lax here as interrupts are off. Nonetheless
+ * we need to grab the correct cpu policy, as to check
+ * whether we really run on this CPU.
+ */
+
+ cpu_policy = cpufreq_cpu_get(cpu);
+ if (!cpu_policy)
+ return -EINVAL;
+
+ /* only handle each CPU group once */
+ if (unlikely(cpu_policy->cpu != cpu)) {
+ cpufreq_cpu_put(cpu_policy);
+ return 0;
+ }
+
+ if (cpufreq_driver->suspend) {
+ ret = cpufreq_driver->suspend(cpu_policy, state);
+ if (ret) {
+ printk(KERN_ERR "cpufreq: suspend failed in ->suspend "
+ "step on CPU %u\n", cpu_policy->cpu);
+ cpufreq_cpu_put(cpu_policy);
+ return ret;
+ }
+ }
+
+
+ if (cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)
+ goto out;
+
+ if (cpufreq_driver->get)
+ cur_freq = cpufreq_driver->get(cpu_policy->cpu);
+
+ if (!cur_freq || !cpu_policy->cur) {
+#ifdef CPUFREQ_PM_ERR
+ printk(KERN_ERR "cpufreq: suspend failed to assert current "
+ "frequency is what timing core thinks it is.\n");
+#endif
+ goto out;
+ }
+
+ if (unlikely(cur_freq != cpu_policy->cur)) {
+ struct cpufreq_freqs freqs;
+
+ if (!(cpufreq_driver->flags & CPUFREQ_PM_NO_WARN))
+ dprintk(KERN_DEBUG "Warning: CPU frequency is %u, "
+ "cpufreq assumed %u kHz.\n",
+ cur_freq, cpu_policy->cur);
+
+ freqs.cpu = cpu;
+ freqs.old = cpu_policy->cur;
+ freqs.new = cur_freq;
+
+ notifier_call_chain(&cpufreq_transition_notifier_list,
+ CPUFREQ_SUSPENDCHANGE, &freqs);
+ adjust_jiffies(CPUFREQ_SUSPENDCHANGE, &freqs);
+
+ cpu_policy->cur = cur_freq;
+ }
+
+ out:
+ cpufreq_cpu_put(cpu_policy);
+ return 0;
+}
+
+/**
* cpufreq_resume - restore proper CPU frequency handling after resume
*
* 1.) resume CPUfreq hardware support (cpufreq_driver->resume())
* 2.) if ->target and !CPUFREQ_CONST_LOOPS: verify we're in sync
- * 3.) schedule call cpufreq_update_policy() ASAP as interrupts are restored.
+ * 3.) schedule call cpufreq_update_policy() ASAP as interrupts are
+ * restored.
*/
static int cpufreq_resume(struct sys_device * sysdev)
{
@@ -893,6 +983,16 @@
return 0;
}
+ if (cpufreq_driver->resume) {
+ ret = cpufreq_driver->resume(cpu_policy);
+ if (ret) {
+ printk(KERN_ERR "cpufreq: resume failed in ->resume "
+ "step on CPU %u\n", cpu_policy->cpu);
+ cpufreq_cpu_put(cpu_policy);
+ return ret;
+ }
+ }
+
if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
unsigned int cur_freq = 0;
@@ -900,21 +1000,28 @@
cur_freq = cpufreq_driver->get(cpu_policy->cpu);
if (!cur_freq || !cpu_policy->cur) {
- printk(KERN_ERR "cpufreq: resume failed to assert current frequency is what timing core thinks it is.\n");
+#ifdef CPUFREQ_PM_ERR
+ printk(KERN_ERR "cpufreq: resume failed to assert "
+ "current frequency is what timing core "
+ "thinks it is.\n");
+#endif
goto out;
}
if (unlikely(cur_freq != cpu_policy->cur)) {
struct cpufreq_freqs freqs;
- printk(KERN_WARNING "Warning: CPU frequency is %u, "
- "cpufreq assumed %u kHz.\n", cur_freq, cpu_policy->cur);
+ if (!(cpufreq_driver->flags & CPUFREQ_PM_NO_WARN))
+ dprintk(KERN_WARNING "Warning: CPU frequency"
+ "is %u, cpufreq assumed %u kHz.\n",
+ cur_freq, cpu_policy->cur);
freqs.cpu = cpu;
freqs.old = cpu_policy->cur;
freqs.new = cur_freq;
- notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_RESUMECHANGE, &freqs);
+ notifier_call_chain(&cpufreq_transition_notifier_list,
+ CPUFREQ_RESUMECHANGE, &freqs);
adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs);
cpu_policy->cur = cur_freq;
@@ -930,6 +1037,7 @@
static struct sysdev_driver cpufreq_sysdev_driver = {
.add = cpufreq_add_dev,
.remove = cpufreq_remove_dev,
+ .suspend = cpufreq_suspend,
.resume = cpufreq_resume,
};
@@ -1018,7 +1126,7 @@
lock_cpu_hotplug();
dprintk("target for CPU %u: %u kHz, relation %u\n", policy->cpu,
target_freq, relation);
- if (cpu_online(policy->cpu))
+ if (cpu_online(policy->cpu) && cpufreq_driver->target)
retval = cpufreq_driver->target(policy, target_freq, relation);
unlock_cpu_hotplug();
return retval;
@@ -1030,7 +1138,7 @@
unsigned int target_freq,
unsigned int relation)
{
- unsigned int ret;
+ int ret;
policy = cpufreq_cpu_get(policy->cpu);
if (!policy)
@@ -1051,7 +1159,7 @@
static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event)
{
- int ret = -EINVAL;
+ int ret;
if (!try_module_get(policy->governor->owner))
return -EINVAL;
diff -wur linux-2.6.10/drivers/cpufreq/cpufreq_ondemand.c linux-2.6.10-lab/drivers/cpufreq/cpufreq_ondemand.c
--- linux-2.6.10/drivers/cpufreq/cpufreq_ondemand.c 2004-12-24 16:35:29.000000000 -0500
+++ linux-2.6.10-lab/drivers/cpufreq/cpufreq_ondemand.c 2007-10-04 19:10:37.000000000 -0400
@@ -34,13 +34,9 @@
*/
#define DEF_FREQUENCY_UP_THRESHOLD (80)
-#define MIN_FREQUENCY_UP_THRESHOLD (0)
+#define MIN_FREQUENCY_UP_THRESHOLD (11)
#define MAX_FREQUENCY_UP_THRESHOLD (100)
-#define DEF_FREQUENCY_DOWN_THRESHOLD (20)
-#define MIN_FREQUENCY_DOWN_THRESHOLD (0)
-#define MAX_FREQUENCY_DOWN_THRESHOLD (100)
-
/*
* The polling frequency of this governor depends on the capability of
* the processor. Default polling frequency is 1000 times the transition
@@ -55,9 +51,9 @@
#define MIN_SAMPLING_RATE (def_sampling_rate / 2)
#define MAX_SAMPLING_RATE (500 * def_sampling_rate)
#define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000)
-#define DEF_SAMPLING_DOWN_FACTOR (10)
+#define DEF_SAMPLING_DOWN_FACTOR (1)
+#define MAX_SAMPLING_DOWN_FACTOR (10)
#define TRANSITION_LATENCY_LIMIT (10 * 1000)
-#define sampling_rate_in_HZ(x) (((x * HZ) < (1000 * 1000))?1:((x * HZ) / (1000 * 1000)))
static void do_dbs_timer(void *data);
@@ -78,15 +74,23 @@
unsigned int sampling_rate;
unsigned int sampling_down_factor;
unsigned int up_threshold;
- unsigned int down_threshold;
+ unsigned int ignore_nice;
};
static struct dbs_tuners dbs_tuners_ins = {
.up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
- .down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD,
.sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR,
};
+static inline unsigned int get_cpu_idle_time(unsigned int cpu)
+{
+ return kstat_cpu(cpu).cpustat.idle +
+ kstat_cpu(cpu).cpustat.iowait +
+ ( !dbs_tuners_ins.ignore_nice ?
+ kstat_cpu(cpu).cpustat.nice :
+ 0);
+}
+
/************************** sysfs interface ************************/
static ssize_t show_sampling_rate_max(struct cpufreq_policy *policy, char *buf)
{
@@ -115,7 +119,7 @@
show_one(sampling_rate, sampling_rate);
show_one(sampling_down_factor, sampling_down_factor);
show_one(up_threshold, up_threshold);
-show_one(down_threshold, down_threshold);
+show_one(ignore_nice, ignore_nice);
static ssize_t store_sampling_down_factor(struct cpufreq_policy *unused,
const char *buf, size_t count)
@@ -126,6 +130,9 @@
if (ret != 1 )
return -EINVAL;
+ if (input > MAX_SAMPLING_DOWN_FACTOR || input < 1)
+ return -EINVAL;
+
down(&dbs_sem);
dbs_tuners_ins.sampling_down_factor = input;
up(&dbs_sem);
@@ -161,8 +168,7 @@
down(&dbs_sem);
if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD ||
- input < MIN_FREQUENCY_UP_THRESHOLD ||
- input <= dbs_tuners_ins.down_threshold) {
+ input < MIN_FREQUENCY_UP_THRESHOLD) {
up(&dbs_sem);
return -EINVAL;
}
@@ -173,22 +179,35 @@
return count;
}
-static ssize_t store_down_threshold(struct cpufreq_policy *unused,
+static ssize_t store_ignore_nice(struct cpufreq_policy *policy,
const char *buf, size_t count)
{
unsigned int input;
int ret;
+
+ unsigned int j;
+
ret = sscanf (buf, "%u", &input);
+ if ( ret != 1 )
+ return -EINVAL;
+
+ if ( input > 1 )
+ input = 1;
down(&dbs_sem);
- if (ret != 1 || input > MAX_FREQUENCY_DOWN_THRESHOLD ||
- input < MIN_FREQUENCY_DOWN_THRESHOLD ||
- input >= dbs_tuners_ins.up_threshold) {
+ if ( input == dbs_tuners_ins.ignore_nice ) { /* nothing to do */
up(&dbs_sem);
- return -EINVAL;
+ return count;
}
+ dbs_tuners_ins.ignore_nice = input;
- dbs_tuners_ins.down_threshold = input;
+ /* we need to re-evaluate prev_cpu_idle_up and prev_cpu_idle_down */
+ for_each_online_cpu(j) {
+ struct cpu_dbs_info_s *j_dbs_info;
+ j_dbs_info = &per_cpu(cpu_dbs_info, j);
+ j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(j);
+ j_dbs_info->prev_cpu_idle_down = j_dbs_info->prev_cpu_idle_up;
+ }
up(&dbs_sem);
return count;
@@ -201,7 +220,7 @@
define_one_rw(sampling_rate);
define_one_rw(sampling_down_factor);
define_one_rw(up_threshold);
-define_one_rw(down_threshold);
+define_one_rw(ignore_nice);
static struct attribute * dbs_attributes[] = {
&sampling_rate_max.attr,
@@ -209,7 +228,7 @@
&sampling_rate.attr,
&sampling_down_factor.attr,
&up_threshold.attr,
- &down_threshold.attr,
+ &ignore_nice.attr,
NULL
};
@@ -222,48 +241,68 @@
static void dbs_check_cpu(int cpu)
{
- unsigned int idle_ticks, up_idle_ticks, down_idle_ticks;
- unsigned int total_idle_ticks;
- unsigned int freq_down_step;
+ unsigned int idle_ticks, up_idle_ticks, total_ticks;
+ unsigned int freq_next;
unsigned int freq_down_sampling_rate;
static int down_skip[NR_CPUS];
struct cpu_dbs_info_s *this_dbs_info;
+ struct cpufreq_policy *policy;
+ unsigned int j;
+
this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
if (!this_dbs_info->enable)
return;
+ policy = this_dbs_info->cur_policy;
/*
- * The default safe range is 20% to 80%
- * Every sampling_rate, we check
- * - If current idle time is less than 20%, then we try to
- * increase frequency
- * Every sampling_rate*sampling_down_factor, we check
- * - If current idle time is more than 80%, then we try to
- * decrease frequency
+ * Every sampling_rate, we check, if current idle time is less
+ * than 20% (default), then we try to increase frequency
+ * Every sampling_rate*sampling_down_factor, we look for a the lowest
+ * frequency which can sustain the load while keeping idle time over
+ * 30%. If such a frequency exist, we try to decrease to this frequency.
*
* Any frequency increase takes it to the maximum frequency.
* Frequency reduction happens at minimum steps of
- * 5% of max_frequency
+ * 5% (default) of current frequency
*/
+
/* Check for frequency increase */
- total_idle_ticks = kstat_cpu(cpu).cpustat.idle +
- kstat_cpu(cpu).cpustat.iowait;
- idle_ticks = total_idle_ticks -
- this_dbs_info->prev_cpu_idle_up;
- this_dbs_info->prev_cpu_idle_up = total_idle_ticks;
+ idle_ticks = UINT_MAX;
+ for_each_cpu_mask(j, policy->cpus) {
+ unsigned int tmp_idle_ticks, total_idle_ticks;
+ struct cpu_dbs_info_s *j_dbs_info;
+
+ j_dbs_info = &per_cpu(cpu_dbs_info, j);
+ total_idle_ticks = get_cpu_idle_time(j);
+ tmp_idle_ticks = total_idle_ticks -
+ j_dbs_info->prev_cpu_idle_up;
+ j_dbs_info->prev_cpu_idle_up = total_idle_ticks;
+
+ if (tmp_idle_ticks < idle_ticks)
+ idle_ticks = tmp_idle_ticks;
+ }
/* Scale idle ticks by 100 and compare with up and down ticks */
idle_ticks *= 100;
up_idle_ticks = (100 - dbs_tuners_ins.up_threshold) *
- sampling_rate_in_HZ(dbs_tuners_ins.sampling_rate);
+ usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
if (idle_ticks < up_idle_ticks) {
- __cpufreq_driver_target(this_dbs_info->cur_policy,
- this_dbs_info->cur_policy->max,
- CPUFREQ_RELATION_H);
down_skip[cpu] = 0;
- this_dbs_info->prev_cpu_idle_down = total_idle_ticks;
+ for_each_cpu_mask(j, policy->cpus) {
+ struct cpu_dbs_info_s *j_dbs_info;
+
+ j_dbs_info = &per_cpu(cpu_dbs_info, j);
+ j_dbs_info->prev_cpu_idle_down =
+ j_dbs_info->prev_cpu_idle_up;
+ }
+ /* if we are already at full speed then break out early */
+ if (policy->cur == policy->max)
+ return;
+
+ __cpufreq_driver_target(policy, policy->max,
+ CPUFREQ_RELATION_H);
return;
}
@@ -272,48 +311,61 @@
if (down_skip[cpu] < dbs_tuners_ins.sampling_down_factor)
return;
- idle_ticks = total_idle_ticks -
- this_dbs_info->prev_cpu_idle_down;
- /* Scale idle ticks by 100 and compare with up and down ticks */
- idle_ticks *= 100;
+ idle_ticks = UINT_MAX;
+ for_each_cpu_mask(j, policy->cpus) {
+ unsigned int tmp_idle_ticks, total_idle_ticks;
+ struct cpu_dbs_info_s *j_dbs_info;
+
+ j_dbs_info = &per_cpu(cpu_dbs_info, j);
+ /* Check for frequency decrease */
+ total_idle_ticks = j_dbs_info->prev_cpu_idle_up;
+ tmp_idle_ticks = total_idle_ticks -
+ j_dbs_info->prev_cpu_idle_down;
+ j_dbs_info->prev_cpu_idle_down = total_idle_ticks;
+
+ if (tmp_idle_ticks < idle_ticks)
+ idle_ticks = tmp_idle_ticks;
+ }
+
down_skip[cpu] = 0;
- this_dbs_info->prev_cpu_idle_down = total_idle_ticks;
+ /* if we cannot reduce the frequency anymore, break out early */
+ if (policy->cur == policy->min)
+ return;
+ /* Compute how many ticks there are between two measurements */
freq_down_sampling_rate = dbs_tuners_ins.sampling_rate *
dbs_tuners_ins.sampling_down_factor;
- down_idle_ticks = (100 - dbs_tuners_ins.down_threshold) *
- sampling_rate_in_HZ(freq_down_sampling_rate);
-
- if (idle_ticks > down_idle_ticks ) {
- freq_down_step = (5 * this_dbs_info->cur_policy->max) / 100;
+ total_ticks = usecs_to_jiffies(freq_down_sampling_rate);
- /* max freq cannot be less than 100. But who knows.... */
- if (unlikely(freq_down_step == 0))
- freq_down_step = 5;
+ /*
+ * The optimal frequency is the frequency that is the lowest that
+ * can support the current CPU usage without triggering the up
+ * policy. To be safe, we focus 10 points under the threshold.
+ */
+ freq_next = ((total_ticks - idle_ticks) * 100) / total_ticks;
+ freq_next = (freq_next * policy->cur) /
+ (dbs_tuners_ins.up_threshold - 10);
- __cpufreq_driver_target(this_dbs_info->cur_policy,
- this_dbs_info->cur_policy->cur - freq_down_step,
- CPUFREQ_RELATION_H);
- return;
- }
+ if (freq_next <= ((policy->cur * 95) / 100))
+ __cpufreq_driver_target(policy, freq_next, CPUFREQ_RELATION_L);
}
static void do_dbs_timer(void *data)
{
int i;
down(&dbs_sem);
- for (i = 0; i < NR_CPUS; i++)
- if (cpu_online(i))
+ for_each_online_cpu(i)
dbs_check_cpu(i);
schedule_delayed_work(&dbs_work,
- sampling_rate_in_HZ(dbs_tuners_ins.sampling_rate));
+ usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
up(&dbs_sem);
}
static inline void dbs_timer_init(void)
{
INIT_WORK(&dbs_work, do_dbs_timer, NULL);
- schedule_work(&dbs_work);
+ schedule_delayed_work(&dbs_work,
+ usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
return;
}
@@ -328,6 +380,7 @@
{
unsigned int cpu = policy->cpu;
struct cpu_dbs_info_s *this_dbs_info;
+ unsigned int j;
this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
@@ -344,14 +397,15 @@
break;
down(&dbs_sem);
- this_dbs_info->cur_policy = policy;
-
- this_dbs_info->prev_cpu_idle_up =
- kstat_cpu(cpu).cpustat.idle +
- kstat_cpu(cpu).cpustat.iowait;
- this_dbs_info->prev_cpu_idle_down =
- kstat_cpu(cpu).cpustat.idle +
- kstat_cpu(cpu).cpustat.iowait;
+ for_each_cpu_mask(j, policy->cpus) {
+ struct cpu_dbs_info_s *j_dbs_info;
+ j_dbs_info = &per_cpu(cpu_dbs_info, j);
+ j_dbs_info->cur_policy = policy;
+
+ j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(j);
+ j_dbs_info->prev_cpu_idle_down
+ = j_dbs_info->prev_cpu_idle_up;
+ }
this_dbs_info->enable = 1;
sysfs_create_group(&policy->kobj, &dbs_attr_group);
dbs_enable++;
@@ -370,6 +424,7 @@
def_sampling_rate = (latency / 1000) *
DEF_SAMPLING_RATE_LATENCY_MULTIPLIER;
dbs_tuners_ins.sampling_rate = def_sampling_rate;
+ dbs_tuners_ins.ignore_nice = 0;
dbs_timer_init();
}
@@ -409,12 +464,11 @@
return 0;
}
-struct cpufreq_governor cpufreq_gov_dbs = {
+static struct cpufreq_governor cpufreq_gov_dbs = {
.name = "ondemand",
.governor = cpufreq_governor_dbs,
.owner = THIS_MODULE,
};
-EXPORT_SYMBOL(cpufreq_gov_dbs);
static int __init cpufreq_gov_dbs_init(void)
{
diff -wur linux-2.6.10/drivers/cpufreq/cpufreq_userspace.c linux-2.6.10-lab/drivers/cpufreq/cpufreq_userspace.c
--- linux-2.6.10/drivers/cpufreq/cpufreq_userspace.c 2004-12-24 16:33:59.000000000 -0500
+++ linux-2.6.10-lab/drivers/cpufreq/cpufreq_userspace.c 2007-10-04 19:10:37.000000000 -0400
@@ -17,51 +17,13 @@
#include
#include
#include
-#include
#include
-#include
#include
#include
#include
#include
-#define CTL_CPU_VARS_SPEED_MAX(cpunr) { \
- .ctl_name = CPU_NR_FREQ_MAX, \
- .data = &cpu_max_freq[cpunr], \
- .procname = "speed-max", \
- .maxlen = sizeof(cpu_max_freq[cpunr]),\
- .mode = 0444, \
- .proc_handler = proc_dointvec, }
-
-#define CTL_CPU_VARS_SPEED_MIN(cpunr) { \
- .ctl_name = CPU_NR_FREQ_MIN, \
- .data = &cpu_min_freq[cpunr], \
- .procname = "speed-min", \
- .maxlen = sizeof(cpu_min_freq[cpunr]),\
- .mode = 0444, \
- .proc_handler = proc_dointvec, }
-
-#define CTL_CPU_VARS_SPEED(cpunr) { \
- .ctl_name = CPU_NR_FREQ, \
- .procname = "speed", \
- .mode = 0644, \
- .proc_handler = cpufreq_procctl, \
- .strategy = cpufreq_sysctl, \
- .extra1 = (void*) (cpunr), }
-
-#define CTL_TABLE_CPU_VARS(cpunr) static ctl_table ctl_cpu_vars_##cpunr[] = {\
- CTL_CPU_VARS_SPEED_MAX(cpunr), \
- CTL_CPU_VARS_SPEED_MIN(cpunr), \
- CTL_CPU_VARS_SPEED(cpunr), \
- { .ctl_name = 0, }, }
-
-/* the ctl_table entry for each CPU */
-#define CPU_ENUM(s) { \
- .ctl_name = (CPU_NR + s), \
- .procname = #s, \
- .mode = 0555, \
- .child = ctl_cpu_vars_##s }
/**
* A few values needed by the userspace governor
@@ -96,17 +58,17 @@
/**
- * _cpufreq_set - set the CPU frequency
+ * cpufreq_set - set the CPU frequency
* @freq: target frequency in kHz
* @cpu: CPU for which the frequency is to be set
*
* Sets the CPU frequency to freq.
*/
-static int _cpufreq_set(unsigned int freq, unsigned int cpu)
+static int cpufreq_set(unsigned int freq, unsigned int cpu)
{
int ret = -EINVAL;
- dprintk("_cpufreq_set for cpu %u, freq %u kHz\n", cpu, freq);
+ dprintk("cpufreq_set for cpu %u, freq %u kHz\n", cpu, freq);
down(&userspace_sem);
if (!cpu_is_managed[cpu])
@@ -134,359 +96,6 @@
return ret;
}
-
-#ifdef CONFIG_CPU_FREQ_24_API
-
-#warning The /proc/sys/cpu/ and sysctl interface to cpufreq will be removed from the 2.6. kernel series soon after 2005-01-01
-
-static unsigned int warning_print = 0;
-
-int __deprecated cpufreq_set(unsigned int freq, unsigned int cpu)
-{
- return _cpufreq_set(freq, cpu);
-}
-EXPORT_SYMBOL_GPL(cpufreq_set);
-
-
-/**
- * cpufreq_setmax - set the CPU to the maximum frequency
- * @cpu - affected cpu;
- *
- * Sets the CPU frequency to the maximum frequency supported by
- * this CPU.
- */
-int __deprecated cpufreq_setmax(unsigned int cpu)
-{
- if (!cpu_is_managed[cpu] || !cpu_online(cpu))
- return -EINVAL;
- return _cpufreq_set(cpu_max_freq[cpu], cpu);
-}
-EXPORT_SYMBOL_GPL(cpufreq_setmax);
-
-/*********************** cpufreq_sysctl interface ********************/
-static int
-cpufreq_procctl(ctl_table *ctl, int write, struct file *filp,
- void __user *buffer, size_t *lenp, loff_t *ppos)
-{
- char buf[16], *p;
- int cpu = (long) ctl->extra1;
- unsigned int len, left = *lenp;
-
- if (!left || (*ppos && !write) || !cpu_online(cpu)) {
- *lenp = 0;
- return 0;
- }
-
- if (!warning_print) {
- warning_print++;
- printk(KERN_INFO "Access to /proc/sys/cpu/ is deprecated and "
- "will be removed from (new) 2.6. kernels soon "
- "after 2005-01-01\n");
- }
-
- if (write) {
- unsigned int freq;
-
- len = left;
- if (left > sizeof(buf))
- left = sizeof(buf);
- if (copy_from_user(buf, buffer, left))
- return -EFAULT;
- buf[sizeof(buf) - 1] = '\0';
-
- freq = simple_strtoul(buf, &p, 0);
- _cpufreq_set(freq, cpu);
- } else {
- len = sprintf(buf, "%d\n", cpufreq_get(cpu));
- if (len > left)
- len = left;
- if (copy_to_user(buffer, buf, len))
- return -EFAULT;
- }
-
- *lenp = len;
- *ppos += len;
- return 0;
-}
-
-static int
-cpufreq_sysctl(ctl_table *table, int __user *name, int nlen,
- void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen, void **context)
-{
- int cpu = (long) table->extra1;
-
- if (!cpu_online(cpu))
- return -EINVAL;
-
- if (!warning_print) {
- warning_print++;
- printk(KERN_INFO "Access to /proc/sys/cpu/ is deprecated and "
- "will be removed from (new) 2.6. kernels soon "
- "after 2005-01-01\n");
- }
-
- if (oldval && oldlenp) {
- size_t oldlen;
-
- if (get_user(oldlen, oldlenp))
- return -EFAULT;
-
- if (oldlen != sizeof(unsigned int))
- return -EINVAL;
-
- if (put_user(cpufreq_get(cpu), (unsigned int __user *)oldval) ||
- put_user(sizeof(unsigned int), oldlenp))
- return -EFAULT;
- }
- if (newval && newlen) {
- unsigned int freq;
-
- if (newlen != sizeof(unsigned int))
- return -EINVAL;
-
- if (get_user(freq, (unsigned int __user *)newval))
- return -EFAULT;
-
- _cpufreq_set(freq, cpu);
- }
- return 1;
-}
-
-/* ctl_table ctl_cpu_vars_{0,1,...,(NR_CPUS-1)} */
-/* due to NR_CPUS tweaking, a lot of if/endifs are required, sorry */
- CTL_TABLE_CPU_VARS(0);
-#if NR_CPUS > 1
- CTL_TABLE_CPU_VARS(1);
-#endif
-#if NR_CPUS > 2
- CTL_TABLE_CPU_VARS(2);
-#endif
-#if NR_CPUS > 3
- CTL_TABLE_CPU_VARS(3);
-#endif
-#if NR_CPUS > 4
- CTL_TABLE_CPU_VARS(4);
-#endif
-#if NR_CPUS > 5
- CTL_TABLE_CPU_VARS(5);
-#endif
-#if NR_CPUS > 6
- CTL_TABLE_CPU_VARS(6);
-#endif
-#if NR_CPUS > 7
- CTL_TABLE_CPU_VARS(7);
-#endif
-#if NR_CPUS > 8
- CTL_TABLE_CPU_VARS(8);
-#endif
-#if NR_CPUS > 9
- CTL_TABLE_CPU_VARS(9);
-#endif
-#if NR_CPUS > 10
- CTL_TABLE_CPU_VARS(10);
-#endif
-#if NR_CPUS > 11
- CTL_TABLE_CPU_VARS(11);
-#endif
-#if NR_CPUS > 12
- CTL_TABLE_CPU_VARS(12);
-#endif
-#if NR_CPUS > 13
- CTL_TABLE_CPU_VARS(13);
-#endif
-#if NR_CPUS > 14
- CTL_TABLE_CPU_VARS(14);
-#endif
-#if NR_CPUS > 15
- CTL_TABLE_CPU_VARS(15);
-#endif
-#if NR_CPUS > 16
- CTL_TABLE_CPU_VARS(16);
-#endif
-#if NR_CPUS > 17
- CTL_TABLE_CPU_VARS(17);
-#endif
-#if NR_CPUS > 18
- CTL_TABLE_CPU_VARS(18);
-#endif
-#if NR_CPUS > 19
- CTL_TABLE_CPU_VARS(19);
-#endif
-#if NR_CPUS > 20
- CTL_TABLE_CPU_VARS(20);
-#endif
-#if NR_CPUS > 21
- CTL_TABLE_CPU_VARS(21);
-#endif
-#if NR_CPUS > 22
- CTL_TABLE_CPU_VARS(22);
-#endif
-#if NR_CPUS > 23
- CTL_TABLE_CPU_VARS(23);
-#endif
-#if NR_CPUS > 24
- CTL_TABLE_CPU_VARS(24);
-#endif
-#if NR_CPUS > 25
- CTL_TABLE_CPU_VARS(25);
-#endif
-#if NR_CPUS > 26
- CTL_TABLE_CPU_VARS(26);
-#endif
-#if NR_CPUS > 27
- CTL_TABLE_CPU_VARS(27);
-#endif
-#if NR_CPUS > 28
- CTL_TABLE_CPU_VARS(28);
-#endif
-#if NR_CPUS > 29
- CTL_TABLE_CPU_VARS(29);
-#endif
-#if NR_CPUS > 30
- CTL_TABLE_CPU_VARS(30);
-#endif
-#if NR_CPUS > 31
- CTL_TABLE_CPU_VARS(31);
-#endif
-#if NR_CPUS > 32
-#error please extend CPU enumeration
-#endif
-
-/* due to NR_CPUS tweaking, a lot of if/endifs are required, sorry */
-static ctl_table ctl_cpu_table[NR_CPUS + 1] = {
- CPU_ENUM(0),
-#if NR_CPUS > 1
- CPU_ENUM(1),
-#endif
-#if NR_CPUS > 2
- CPU_ENUM(2),
-#endif
-#if NR_CPUS > 3
- CPU_ENUM(3),
-#endif
-#if NR_CPUS > 4
- CPU_ENUM(4),
-#endif
-#if NR_CPUS > 5
- CPU_ENUM(5),
-#endif
-#if NR_CPUS > 6
- CPU_ENUM(6),
-#endif
-#if NR_CPUS > 7
- CPU_ENUM(7),
-#endif
-#if NR_CPUS > 8
- CPU_ENUM(8),
-#endif
-#if NR_CPUS > 9
- CPU_ENUM(9),
-#endif
-#if NR_CPUS > 10
- CPU_ENUM(10),
-#endif
-#if NR_CPUS > 11
- CPU_ENUM(11),
-#endif
-#if NR_CPUS > 12
- CPU_ENUM(12),
-#endif
-#if NR_CPUS > 13
- CPU_ENUM(13),
-#endif
-#if NR_CPUS > 14
- CPU_ENUM(14),
-#endif
-#if NR_CPUS > 15
- CPU_ENUM(15),
-#endif
-#if NR_CPUS > 16
- CPU_ENUM(16),
-#endif
-#if NR_CPUS > 17
- CPU_ENUM(17),
-#endif
-#if NR_CPUS > 18
- CPU_ENUM(18),
-#endif
-#if NR_CPUS > 19
- CPU_ENUM(19),
-#endif
-#if NR_CPUS > 20
- CPU_ENUM(20),
-#endif
-#if NR_CPUS > 21
- CPU_ENUM(21),
-#endif
-#if NR_CPUS > 22
- CPU_ENUM(22),
-#endif
-#if NR_CPUS > 23
- CPU_ENUM(23),
-#endif
-#if NR_CPUS > 24
- CPU_ENUM(24),
-#endif
-#if NR_CPUS > 25
- CPU_ENUM(25),
-#endif
-#if NR_CPUS > 26
- CPU_ENUM(26),
-#endif
-#if NR_CPUS > 27
- CPU_ENUM(27),
-#endif
-#if NR_CPUS > 28
- CPU_ENUM(28),
-#endif
-#if NR_CPUS > 29
- CPU_ENUM(29),
-#endif
-#if NR_CPUS > 30
- CPU_ENUM(30),
-#endif
-#if NR_CPUS > 31
- CPU_ENUM(31),
-#endif
-#if NR_CPUS > 32
-#error please extend CPU enumeration
-#endif
- {
- .ctl_name = 0,
- }
-};
-
-static ctl_table ctl_cpu[2] = {
- {
- .ctl_name = CTL_CPU,
- .procname = "cpu",
- .mode = 0555,
- .child = ctl_cpu_table,
- },
- {
- .ctl_name = 0,
- }
-};
-
-static struct ctl_table_header *cpufreq_sysctl_table;
-
-static inline void cpufreq_sysctl_init(void)
-{
- cpufreq_sysctl_table = register_sysctl_table(ctl_cpu, 0);
-}
-
-static inline void cpufreq_sysctl_exit(void)
-{
- unregister_sysctl_table(cpufreq_sysctl_table);
-}
-
-#else
-#define cpufreq_sysctl_init() do {} while(0)
-#define cpufreq_sysctl_exit() do {} while(0)
-#endif /* CONFIG_CPU_FREQ_24API */
-
-
/************************** sysfs interface ************************/
static ssize_t show_speed (struct cpufreq_policy *policy, char *buf)
{
@@ -503,7 +112,7 @@
if (ret != 1)
return -EINVAL;
- _cpufreq_set(freq, policy->cpu);
+ cpufreq_set(freq, policy->cpu);
return count;
}
@@ -577,7 +186,6 @@
static int __init cpufreq_gov_userspace_init(void)
{
- cpufreq_sysctl_init();
cpufreq_register_notifier(&userspace_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
return cpufreq_register_governor(&cpufreq_gov_userspace);
}
@@ -587,7 +195,6 @@
{
cpufreq_unregister_governor(&cpufreq_gov_userspace);
cpufreq_unregister_notifier(&userspace_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
- cpufreq_sysctl_exit();
}
diff -wur linux-2.6.10/drivers/cpufreq/freq_table.c linux-2.6.10-lab/drivers/cpufreq/freq_table.c
--- linux-2.6.10/drivers/cpufreq/freq_table.c 2004-12-24 16:35:28.000000000 -0500
+++ linux-2.6.10-lab/drivers/cpufreq/freq_table.c 2007-10-04 19:10:37.000000000 -0400
@@ -214,6 +214,11 @@
}
EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr);
+struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu)
+{
+ return show_table[cpu];
+}
+EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table);
MODULE_AUTHOR ("Dominik Brodowski ");
MODULE_DESCRIPTION ("CPUfreq frequency table helpers");
diff -wur linux-2.6.10/drivers/i2c/algos/Makefile linux-2.6.10-lab/drivers/i2c/algos/Makefile
--- linux-2.6.10/drivers/i2c/algos/Makefile 2004-12-24 16:35:23.000000000 -0500
+++ linux-2.6.10-lab/drivers/i2c/algos/Makefile 2007-10-04 19:10:38.000000000 -0400
@@ -6,6 +6,7 @@
obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o
obj-$(CONFIG_I2C_ALGOPCA) += i2c-algo-pca.o
obj-$(CONFIG_I2C_ALGOITE) += i2c-algo-ite.o
+obj-$(CONFIG_I2C_PXA) += i2c-algo-pxa.o
ifeq ($(CONFIG_I2C_DEBUG_ALGO),y)
EXTRA_CFLAGS += -DDEBUG
diff -wur linux-2.6.10/drivers/i2c/busses/Kconfig linux-2.6.10-lab/drivers/i2c/busses/Kconfig
--- linux-2.6.10/drivers/i2c/busses/Kconfig 2004-12-24 16:35:25.000000000 -0500
+++ linux-2.6.10-lab/drivers/i2c/busses/Kconfig 2007-10-04 19:10:38.000000000 -0400
@@ -466,4 +466,15 @@
This driver can also be built as a module. If so, the module
will be called i2c-pca-isa.
+config I2C_PXA
+ tristate "I2C interface in Intel PXA2x0"
+ depends on ARCH_PXA && I2C
+ help
+ This supports the use of the PXA I2C interface found on the Intel
+ PXA 25x and PXA 26x systems. Say Y if you have one of these.
+ You should also say Y for the PXA I2C peripheral driver support below.
+
+ To compile this driver as a module, say M here: the
+ modules will be called i2c-pxa and i2c-algo-pxa.
+
endmenu
diff -wur linux-2.6.10/drivers/i2c/busses/Makefile linux-2.6.10-lab/drivers/i2c/busses/Makefile
--- linux-2.6.10/drivers/i2c/busses/Makefile 2004-12-24 16:33:51.000000000 -0500
+++ linux-2.6.10-lab/drivers/i2c/busses/Makefile 2007-10-04 19:10:38.000000000 -0400
@@ -26,6 +26,7 @@
obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o
obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o
+obj-$(CONFIG_I2C_PXA) += i2c-pxa.o
obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o
obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o
obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o
@@ -36,6 +37,7 @@
obj-$(CONFIG_I2C_VIA) += i2c-via.o
obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o
obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o
+obj-$(CONFIG_I2C_PXA) += i2c-pxa.o
obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
diff -wur linux-2.6.10/drivers/i2c/chips/Kconfig linux-2.6.10-lab/drivers/i2c/chips/Kconfig
--- linux-2.6.10/drivers/i2c/chips/Kconfig 2004-12-24 16:34:58.000000000 -0500
+++ linux-2.6.10-lab/drivers/i2c/chips/Kconfig 2007-10-04 19:10:38.000000000 -0400
@@ -347,6 +347,11 @@
This driver can also be built as a module. If so, the module
will be called i2c-rtc8564.
+config RS5C372_RTC
+ tristate "RS5C372 Real Time Clock"
+ depends on I2C
+
+
config ISP1301_OMAP
tristate "Philips ISP1301 with OMAP OTG"
depends on I2C && ARCH_OMAP_OTG
diff -wur linux-2.6.10/drivers/i2c/chips/Makefile linux-2.6.10-lab/drivers/i2c/chips/Makefile
--- linux-2.6.10/drivers/i2c/chips/Makefile 2004-12-24 16:35:50.000000000 -0500
+++ linux-2.6.10-lab/drivers/i2c/chips/Makefile 2007-10-04 19:10:38.000000000 -0400
@@ -30,6 +30,7 @@
obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
obj-$(CONFIG_SENSORS_RTC8564) += rtc8564.o
+obj-$(CONFIG_RS5C372_RTC) += rs5c372.o
obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o
diff -wur linux-2.6.10/drivers/misc/Kconfig linux-2.6.10-lab/drivers/misc/Kconfig
--- linux-2.6.10/drivers/misc/Kconfig 2004-12-24 16:34:26.000000000 -0500
+++ linux-2.6.10-lab/drivers/misc/Kconfig 2007-10-04 19:10:29.000000000 -0400
@@ -29,5 +29,21 @@
If unsure, say N.
+config PROC_SERIALNUMBER
+ bool "Device serial number driver"
+ default n
+ ---help---
+ This option enables the creation of the /proc/serialnumber entry,
+ which returns the unique serial number of the device.
+
+config PROC_BOOTDATA
+ bool "Boot data driver"
+ default n
+ ---help---
+ This option enables the creation of the /proc/bd/ entries,
+ which provide an interface for accessing various shared boot
+ global data entries in the common memory space between the
+ kernel and bootloader
+
endmenu
diff -wur linux-2.6.10/drivers/misc/Makefile linux-2.6.10-lab/drivers/misc/Makefile
--- linux-2.6.10/drivers/misc/Makefile 2004-12-24 16:35:28.000000000 -0500
+++ linux-2.6.10-lab/drivers/misc/Makefile 2007-10-04 19:10:29.000000000 -0400
@@ -4,3 +4,5 @@
obj- := misc.o # Dummy rule to force built-in.o to be made
obj-$(CONFIG_IBM_ASM) += ibmasm/
+obj-$(CONFIG_PROC_SERIALNUMBER) += serialnumber.o
+obj-$(CONFIG_PROC_BOOTDATA) += bootdata.o
diff -wur linux-2.6.10/drivers/mmc/mmc.c linux-2.6.10-lab/drivers/mmc/mmc.c
--- linux-2.6.10/drivers/mmc/mmc.c 2004-12-24 16:35:50.000000000 -0500
+++ linux-2.6.10-lab/drivers/mmc/mmc.c 2007-10-04 19:10:37.000000000 -0400
@@ -6,6 +6,9 @@
* 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.
+ *
+ * Lab126 changes Copyright (C) 2005, 2006 Lab126, Inc.
+ *
*/
#include
#include
@@ -16,6 +19,8 @@
#include
#include
#include
+#include
+#include
#include
#include
@@ -25,8 +30,16 @@
#ifdef CONFIG_MMC_DEBUG
#define DBG(x...) printk(KERN_DEBUG x)
+#define MDEBUG(x...) printk(x)
#else
#define DBG(x...) do { } while (0)
+#define MDEBUG(x...) do { } while (0)
+#endif
+
+#if defined(CONFIG_PM_DEBUG) || defined(CONFIG_MMC_DEBUG)
+#define pinfo(x...) printk(x)
+#else
+#define pinfo(x...) do {} while (0)
#endif
#define CMD_RETRIES 3
@@ -125,8 +138,17 @@
complete(mrq->done_data);
}
+#ifdef CONFIG_ARCH_LAB126
+#define MMC_WAIT_REQUEST_TIMEOUT (1 * HZ)
+#define MMC_WAIT_REQUEST_RETRIES 3
+#endif
+
int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
{
+#ifdef CONFIG_ARCH_LAB126
+ if (host != NULL && mrq != NULL) {
+ int retries;
+#endif
DECLARE_COMPLETION(complete);
mrq->done_data = &complete;
@@ -134,7 +156,30 @@
mmc_start_request(host, mrq);
+#ifndef CONFIG_ARCH_LAB126
wait_for_completion(&complete);
+#else
+ retries = 0;
+
+ while (wait_for_completion_interruptible_timeout(&complete, MMC_WAIT_REQUEST_TIMEOUT) == 0) {
+
+ if ((retries++ >= MMC_WAIT_REQUEST_RETRIES) || !host->ops->card_inserted()) {
+ struct mmc_command *cmd = mrq->cmd;
+
+ cmd->error = MMC_ERR_ABORTED;
+ cmd->retries = 0;
+
+ mmc_request_done(host, mrq);
+
+ host->card_busy = NULL;
+
+ break;
+ }
+
+ }
+#endif
+
+ }
return 0;
}
@@ -172,7 +217,134 @@
EXPORT_SYMBOL(mmc_wait_for_cmd);
+/**
+ * mmc_wait_for_app_cmd - start an application command and wait for
+ completion
+ * @host: MMC host to start command
+ * @rca: RCA to send MMC_APP_CMD to
+ * @cmd: MMC command to start
+ * @retries: maximum number of retries
+ *
+ * Sends a MMC_APP_CMD, checks the card response, sends the command
+ * in the parameter and waits for it to complete. Return any error
+ * that occurred while the command was executing. Do not attempt to
+ * parse the response.
+ */
+int mmc_wait_for_app_cmd(struct mmc_host *host, unsigned int rca,
+ struct mmc_command *cmd, int retries)
+{
+ struct mmc_request mrq;
+ struct mmc_command appcmd;
+
+ int i, err;
+
+ BUG_ON(host->card_busy == NULL);
+ BUG_ON(retries < 0);
+
+ err = MMC_ERR_INVALID;
+
+ /*
+ * We have to resend MMC_APP_CMD for each attempt so
+ * we cannot use the retries field in mmc_command.
+ */
+ for (i = 0;i <= retries;i++) {
+ memset(&mrq, 0, sizeof(struct mmc_request));
+ appcmd.opcode = MMC_APP_CMD;
+ appcmd.arg = rca << 16;
+ appcmd.flags = MMC_RSP_R1;
+ appcmd.retries = 0;
+ memset(appcmd.resp, 0, sizeof(appcmd.resp));
+ appcmd.data = NULL;
+
+ mrq.cmd = &appcmd;
+ appcmd.data = NULL;
+
+ mmc_wait_for_req(host, &mrq);
+
+ if (appcmd.error) {
+ err = appcmd.error;
+ continue;
+ }
+
+ /* Check that card supported application commands */
+ if (!(appcmd.resp[0] & R1_APP_CMD))
+ return MMC_ERR_FAILED;
+
+ memset(&mrq, 0, sizeof(struct mmc_request));
+
+ memset(cmd->resp, 0, sizeof(cmd->resp));
+ cmd->retries = 0;
+
+ mrq.cmd = cmd;
+ cmd->data = NULL;
+
+ mmc_wait_for_req(host, &mrq);
+
+ err = cmd->error;
+ if (cmd->error == MMC_ERR_NONE)
+ break;
+ }
+
+ return err;
+}
+
+EXPORT_SYMBOL(mmc_wait_for_app_cmd);
+
+/**
+ * mmc_set_data_timeout - set the timeout for a data command
+ * @data: data phase for command
+ * @card: the MMC card associated with the data transfer
+ * @write: flag to differentiate reads from writes
+ */
+void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
+ int write)
+{
+ unsigned int mult;
+
+ /*
+ * SD cards use a 100 multiplier rather than 10
+ */
+ mult = mmc_card_sd(card) ? 100 : 10;
+
+ /*
+ * Scale up the multiplier (and therefore the timeout) by
+ * the r2w factor for writes.
+ */
+ if (write)
+ mult <<= card->csd.r2w_factor;
+
+ data->timeout_ns = card->csd.tacc_ns * mult;
+ data->timeout_clks = card->csd.tacc_clks * mult;
+
+ /*
+ * SD cards also have an upper limit on the timeout.
+ */
+ if (mmc_card_sd(card)) {
+ unsigned int timeout_us, limit_us;
+
+ timeout_us = data->timeout_ns / 1000;
+ timeout_us += data->timeout_clks * 1000 /
+ (card->host->ios.clock / 1000);
+
+ if (write)
+ limit_us = 250000;
+ else
+ limit_us = 100000;
+
+ /*
+ * SDHC cards always use these fixed values.
+ */
+ if (timeout_us > limit_us || mmc_card_blockaddr(card)) {
+ data->timeout_ns = limit_us * 1000;
+ data->timeout_clks = 0;
+ }
+ }
+}
+
+EXPORT_SYMBOL(mmc_set_data_timeout);
+
+static int mmc_select_card(struct mmc_host *host, struct mmc_card *card);
/**
* __mmc_claim_host - exclusively claim a host
@@ -191,6 +363,13 @@
unsigned long flags;
int err = 0;
+#ifdef CONFIG_ARCH_LAB126
+ if (host == NULL) {
+ /* this case can be hit on card abort */
+ return MMC_ERR_ABORTED;
+ }
+#endif
+
add_wait_queue(&host->wq, &wait);
spin_lock_irqsave(&host->lock, flags);
while (1) {
@@ -206,16 +385,17 @@
spin_unlock_irqrestore(&host->lock, flags);
remove_wait_queue(&host->wq, &wait);
- if (card != (void *)-1 && host->card_selected != card) {
- struct mmc_command cmd;
-
- host->card_selected = card;
+ if (card != (void *)-1) {
+ err = mmc_select_card(host, card);
- cmd.opcode = MMC_SELECT_CARD;
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1;
+#ifdef CONFIG_ARCH_LAB126
+ if (err == MMC_ERR_ABORTED) {
+ host->ops->clear(host);
+ }
+#endif
- err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ return err;
}
return err;
@@ -234,7 +414,14 @@
{
unsigned long flags;
+#ifdef CONFIG_ARCH_LAB126
+ if (host == NULL) {
+ /* this case can be hit on card abort */
+ return;
+ }
+#else
BUG_ON(host->card_busy == NULL);
+#endif
spin_lock_irqsave(&host->lock, flags);
host->card_busy = NULL;
@@ -245,6 +432,63 @@
EXPORT_SYMBOL(mmc_release_host);
+static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
+{
+ int err;
+ struct mmc_command cmd;
+
+ BUG_ON(host->card_busy == NULL);
+
+ if (host->card_selected == card)
+ return MMC_ERR_NONE;
+
+ host->card_selected = card;
+
+ cmd.opcode = MMC_SELECT_CARD;
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_R1;
+
+ err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ return err;
+
+ /*
+ * Default bus width is 1 bit.
+ */
+ host->ios.bus_width = MMC_BUS_WIDTH_1;
+
+ /*
+ * We can only change the bus width of the selected
+ * card so therefore we have to put the handling
+ * here.
+ */
+ if (host->caps & MMC_CAP_4_BIT_DATA) {
+ /*
+ * The card is in 1 bit mode by default so
+ * we only need to change if it supports the
+ * wider version.
+ */
+ if (mmc_card_sd(card) &&
+ (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
+ struct mmc_command cmd;
+ cmd.opcode = SD_APP_SET_BUS_WIDTH;
+ cmd.arg = SD_BUS_WIDTH_4;
+ cmd.flags = MMC_RSP_R1;
+
+ err = mmc_wait_for_app_cmd(host, card->rca, &cmd,
+ CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ return err;
+
+ host->ios.bus_width = MMC_BUS_WIDTH_4;
+ }
+ }
+
+ host->ops->set_ios(host, &host->ios);
+
+ return MMC_ERR_NONE;
+}
+
/*
* Ensure that no card is selected.
*/
@@ -321,12 +565,33 @@
memset(&card->cid, 0, sizeof(struct mmc_cid));
+ if (mmc_card_sd(card)) {
+ /*
+ * SD doesn't currently have a version field so we will
+ * have to assume we can parse this.
+ */
+ card->cid.manfid = UNSTUFF_BITS(resp, 120, 8);
+ card->cid.oemid = UNSTUFF_BITS(resp, 104, 16);
+ card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
+ card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8);
+ card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8);
+ card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
+ card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
+ card->cid.hwrev = UNSTUFF_BITS(resp, 60, 4);
+ card->cid.fwrev = UNSTUFF_BITS(resp, 56, 4);
+ card->cid.serial = UNSTUFF_BITS(resp, 24, 32);
+ card->cid.year = UNSTUFF_BITS(resp, 12, 8);
+ card->cid.month = UNSTUFF_BITS(resp, 8, 4);
+
+ card->cid.year += 2000; /* SD cards year offset */
+ }
+ else {
/*
- * The selection of the format here is guesswork based upon
- * information people have sent to date.
+ * The selection of the format here is based upon published
+ * specs from sandisk and from what people have reported.
*/
switch (card->csd.mmca_vsn) {
- case 0: /* MMC v1.? */
+ case 0: /* MMC v1.0 - v1.2 */
case 1: /* MMC v1.4 */
card->cid.manfid = UNSTUFF_BITS(resp, 104, 24);
card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
@@ -343,8 +608,9 @@
card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997;
break;
- case 2: /* MMC v2.x ? */
- case 3: /* MMC v3.x ? */
+ case 2: /* MMC v2.0 - v2.2 */
+ case 3: /* MMC v3.1 - v3.3 */
+ case 4: /* MMC v4.0 */
card->cid.manfid = UNSTUFF_BITS(resp, 120, 8);
card->cid.oemid = UNSTUFF_BITS(resp, 104, 16);
card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
@@ -365,6 +631,7 @@
break;
}
}
+}
/*
* Given a 128-bit response, decode to our card CSD structure.
@@ -375,12 +642,66 @@
unsigned int e, m, csd_struct;
u32 *resp = card->raw_csd;
+ if (mmc_card_sd(card)) {
+ csd_struct = UNSTUFF_BITS(resp, 126, 2);
+
+ switch (csd_struct) {
+ case 0:
+ m = UNSTUFF_BITS(resp, 115, 4);
+ e = UNSTUFF_BITS(resp, 112, 3);
+ csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
+ csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
+
+ m = UNSTUFF_BITS(resp, 99, 4);
+ e = UNSTUFF_BITS(resp, 96, 3);
+ csd->max_dtr = tran_exp[e] * tran_mant[m];
+ csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
+
+ e = UNSTUFF_BITS(resp, 47, 3);
+ m = UNSTUFF_BITS(resp, 62, 12);
+ csd->capacity = (1 + m) << (e + 2);
+
+ csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
+ csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
+ break;
+ case 1:
/*
- * We only understand CSD structure v1.1 and v2.
- * v2 has extra information in bits 15, 11 and 10.
+ * This is a block-addressed SDHC card. Most
+ * interesting fields are unused and have fixed
+ * values. To avoid getting tripped by buggy cards,
+ * we assume those fixed values ourselves.
+ */
+ mmc_card_set_blockaddr(card);
+
+ csd->tacc_ns = 0; /* Unused */
+ csd->tacc_clks = 0; /* Unused */
+
+ m = UNSTUFF_BITS(resp, 99, 4);
+ e = UNSTUFF_BITS(resp, 96, 3);
+ csd->max_dtr = tran_exp[e] * tran_mant[m];
+ csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
+
+ m = UNSTUFF_BITS(resp, 48, 22);
+ csd->capacity = (1 + m) << 10;
+
+ csd->read_blkbits = 9;
+ csd->r2w_factor = 4; /* Unused */
+ break;
+ default:
+ printk("%s: unrecognised CSD structure version %d\n",
+ card->host->host_name, csd_struct);
+ mmc_card_set_bad(card);
+ return;
+ }
+
+ }
+ else {
+ /*
+ * We only understand CSD structure v1.1 and v1.2.
+ * v1.2 has extra information in bits 15, 11 and 10.
*/
csd_struct = UNSTUFF_BITS(resp, 126, 2);
- if (csd_struct != 1 && csd_struct != 2) {
+ if (csd_struct != 1 && csd_struct != 2 && csd_struct != 3) {
printk("%s: unrecognised CSD structure version %d\n",
card->host->host_name, csd_struct);
mmc_card_set_bad(card);
@@ -404,6 +725,39 @@
csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
}
+}
+
+/*
+ * Given a 64-bit response, decode to our card SCR structure.
+ */
+static void mmc_decode_scr(struct mmc_card *card)
+{
+ struct sd_scr *scr = &card->scr;
+ unsigned int scr_struct;
+ u32 resp[4];
+
+ BUG_ON(!mmc_card_sd(card));
+
+ resp[3] = card->raw_scr[1];
+ resp[2] = card->raw_scr[0];
+
+ scr_struct = UNSTUFF_BITS(resp, 60, 4);
+
+// testing of SCR v1 and v3 cards indicates that the spec is
+// backwards compatible, so we shouldn't limit the operation
+// cards based on the SCR version field value
+#if 0
+ if (scr_struct != 0) {
+ printk("%s: unrecognised SCR structure version %d\n",
+ card->host->host_name, scr_struct);
+ mmc_card_set_bad(card);
+ return;
+ }
+#endif
+
+ scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
+ scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
+}
/*
* Locate a MMC card on this MMC host given a raw CID.
@@ -472,9 +826,12 @@
{
int bit = fls(host->ocr_avail) - 1;
+ MDEBUG("MMC: mmc_power_up()\n");
+
host->ios.vdd = bit;
host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
host->ios.power_mode = MMC_POWER_UP;
+ host->ios.bus_width = MMC_BUS_WIDTH_1;
host->ops->set_ios(host, &host->ios);
mmc_delay(1);
@@ -488,10 +845,12 @@
static void mmc_power_off(struct mmc_host *host)
{
+ MDEBUG("MMC: mmc_power_off()\n");
host->ios.clock = 0;
host->ios.vdd = 0;
host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
host->ios.power_mode = MMC_POWER_OFF;
+ host->ios.bus_width = MMC_BUS_WIDTH_1;
host->ops->set_ios(host, &host->ios);
}
@@ -523,6 +882,69 @@
return err;
}
+static int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
+{
+ struct mmc_command cmd;
+ int i, err = 0;
+
+ cmd.opcode = SD_APP_OP_COND;
+ cmd.arg = ocr;
+ cmd.flags = MMC_RSP_R3;
+
+ for (i = 100; i; i--) {
+ err = mmc_wait_for_app_cmd(host, 0, &cmd, CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ break;
+
+ if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+ break;
+
+ err = MMC_ERR_TIMEOUT;
+
+ mmc_delay(10);
+ }
+
+ if (rocr)
+ *rocr = cmd.resp[0];
+
+ return err;
+}
+
+static int mmc_send_if_cond(struct mmc_host *host, u32 ocr, int *rsd2)
+{
+ struct mmc_command cmd;
+ int err, sd2;
+ static const u8 test_pattern = 0xAA;
+
+ /*
+ * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND
+ * before SD_APP_OP_COND. This command will harmlessly fail for
+ * SD 1.0 cards.
+ */
+ cmd.opcode = SD_SEND_IF_COND;
+ cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
+ cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR;
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (err == MMC_ERR_NONE) {
+ if ((cmd.resp[0] & 0xFF) == test_pattern) {
+ sd2 = 1;
+ } else {
+ sd2 = 0;
+ err = MMC_ERR_FAILED;
+ }
+ } else {
+ /*
+ * Treat errors as SD 1.0 card.
+ */
+ sd2 = 0;
+ err = MMC_ERR_NONE;
+ }
+ if (rsd2)
+ *rsd2 = sd2;
+ return err;
+}
+
/*
* Discover cards by requesting their CID. If this command
* times out, it is not an error; there are no further cards
@@ -561,11 +983,36 @@
err = PTR_ERR(card);
break;
}
+ MDEBUG("MMC: mmc_discover_cards adding card to list\n");
list_add(&card->node, &host->cards);
}
card->state &= ~MMC_STATE_DEAD;
+ if (host->mode == MMC_MODE_SD) {
+ mmc_card_set_sd(card);
+
+ cmd.opcode = SD_SEND_RELATIVE_ADDR;
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_R1;
+
+ err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ mmc_card_set_dead(card);
+
+ card->rca = cmd.resp[0] >> 16;
+
+ if (!host->ops->get_ro) {
+ printk(KERN_WARNING "%s: host does not support "
+ "reading read-only switch. assuming "
+ "write-enable.\n", host->host_name);
+ }
+ else {
+ if (host->ops->get_ro(host))
+ mmc_card_set_readonly(card);
+ }
+ }
+ else {
cmd.opcode = MMC_SET_RELATIVE_ADDR;
cmd.arg = card->rca << 16;
cmd.flags = MMC_RSP_R1;
@@ -575,6 +1022,7 @@
mmc_card_set_dead(card);
}
}
+}
static void mmc_read_csds(struct mmc_host *host)
{
@@ -604,6 +1052,80 @@
}
}
+static void mmc_read_scrs(struct mmc_host *host)
+{
+ int err;
+ struct mmc_card *card;
+
+ struct mmc_request mrq;
+ struct mmc_command cmd;
+ struct mmc_data data;
+
+ struct scatterlist sg;
+
+ list_for_each_entry(card, &host->cards, node) {
+ if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
+ continue;
+ if (!mmc_card_sd(card))
+ continue;
+
+ err = mmc_select_card(host, card);
+ if (err != MMC_ERR_NONE)
+ {
+ mmc_card_set_dead(card);
+ continue;
+ }
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_APP_CMD;
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_R1;
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD)) {
+ mmc_card_set_dead(card);
+ continue;
+ }
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = SD_APP_SEND_SCR;
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_R1;
+
+ memset(&data, 0, sizeof(struct mmc_data));
+
+ mmc_set_data_timeout(&data, card, 0);
+
+ data.blksz_bits = 3;
+ data.blocks = 1;
+ data.flags = MMC_DATA_READ;
+ data.sg = &sg;
+ data.sg_len = 1;
+
+ memset(&mrq, 0, sizeof(struct mmc_request));
+
+ mrq.cmd = &cmd;
+ mrq.data = &data;
+
+ sg_init_one(&sg, (u8*)card->raw_scr, 64);
+
+ err = mmc_wait_for_req(host, &mrq);
+ if (err != MMC_ERR_NONE) {
+ mmc_card_set_dead(card);
+ continue;
+ }
+
+ card->raw_scr[0] = ntohl(card->raw_scr[0]);
+ card->raw_scr[1] = ntohl(card->raw_scr[1]);
+
+ mmc_decode_scr(card);
+ }
+
+ mmc_deselect_cards(host);
+}
+
static unsigned int mmc_calculate_clock(struct mmc_host *host)
{
struct mmc_card *card;
@@ -643,8 +1165,11 @@
cmd.flags = MMC_RSP_R1;
err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
- if (err == MMC_ERR_NONE)
+ if (err == MMC_ERR_NONE) {
+ MDEBUG("Card responded in mmc_check_cards - 0x%x\n",(int)card);
continue;
+ }
+ else MDEBUG("Couldn't find card in mmc_check_cards - dead card 0x%x\n",(int)card);
mmc_card_set_dead(card);
}
@@ -656,13 +1181,31 @@
int err;
u32 ocr;
+ host->mode = MMC_MODE_MMC;
+
mmc_power_up(host);
mmc_idle_cards(host);
+ err = mmc_send_if_cond(host, host->ocr_avail, NULL);
+ if (err != MMC_ERR_NONE) {
+ return;
+ }
+
err = mmc_send_op_cond(host, 0, &ocr);
+
+ /*
+ * If we fail to detect any cards then try
+ * searching for SD cards.
+ */
+ if (err != MMC_ERR_NONE)
+ {
+ err = mmc_send_app_op_cond(host, 0, &ocr);
if (err != MMC_ERR_NONE)
return;
+ host->mode = MMC_MODE_SD;
+ }
+
host->ocr = mmc_select_voltage(host, ocr);
/*
@@ -701,7 +1244,21 @@
* all get the idea that they should be ready for CMD2.
* (My SanDisk card seems to need this.)
*/
+ if (host->mode == MMC_MODE_SD) {
+ int err, sd2;
+ err = mmc_send_if_cond(host, host->ocr, &sd2);
+ if (err == MMC_ERR_NONE) {
+ /*
+ * If SD_SEND_IF_COND indicates an SD 2.0
+ * compliant card and we should set bit 30
+ * of the ocr to indicate that we can handle
+ * block-addressed SDHC cards.
+ */
+ mmc_send_app_op_cond(host, host->ocr | (sd2 << 30), NULL);
+ }
+ } else {
mmc_send_op_cond(host, host->ocr, NULL);
+ }
mmc_discover_cards(host);
@@ -712,6 +1269,9 @@
host->ops->set_ios(host, &host->ios);
mmc_read_csds(host);
+
+ if (host->mode == MMC_MODE_SD)
+ mmc_read_scrs(host);
}
@@ -737,8 +1297,11 @@
mmc_claim_host(host);
- if (host->ios.power_mode == MMC_POWER_ON)
+ if (host->ios.power_mode == MMC_POWER_ON) {
+ msleep(100);
mmc_check_cards(host);
+ MDEBUG("mmc_rescan found MMC_POWER_ON, checking for existence of cards\n");
+ }
mmc_setup(host);
@@ -760,19 +1323,25 @@
* If this is a new and good card, register it.
*/
if (!mmc_card_present(card) && !mmc_card_dead(card)) {
- if (mmc_register_card(card))
+ if (mmc_register_card(card)) {
+ MDEBUG("MMC: calling mmc_card_set_dead (card = 0x%x).\n",(int)card);
mmc_card_set_dead(card);
- else
+ }
+ else {
+ MDEBUG("MMC: calling mmc_card_set_present (card = 0x%x).\n",(int)card);
mmc_card_set_present(card);
}
+ }
/*
* If this card is dead, destroy it.
*/
if (mmc_card_dead(card)) {
+ MDEBUG("MMC: Removing card from list (card = 0x%x).\n",(int) card);
list_del(&card->node);
mmc_remove_card(card);
}
+ else MDEBUG("MMC: mmc card NOT dead and NOT removed (card = 0x%x).\n",(int) card);
}
/*
@@ -781,6 +1350,8 @@
*/
if (list_empty(&host->cards))
mmc_power_off(host);
+ else
+ MDEBUG("Card list NOT empty in mmc_rescan\n");
}
@@ -851,9 +1422,12 @@
{
struct list_head *l, *n;
+ MDEBUG("MMC: mmc_remove_host called\n");
+
list_for_each_safe(l, n, &host->cards) {
struct mmc_card *card = mmc_list_to_card(l);
+ MDEBUG("MMC: mmc_remove_host calling mmc_remove_card\n");
mmc_remove_card(card);
}
@@ -885,8 +1459,26 @@
*/
int mmc_suspend_host(struct mmc_host *host, u32 state)
{
+ pinfo("MMC: mmc_suspend_host()...\n");
mmc_claim_host(host);
mmc_deselect_cards(host);
+
+#ifdef CONFIG_FIONA_PM_MMC
+ {
+ struct list_head *l, *n;
+
+ list_for_each_safe(l, n, &host->cards) {
+ struct mmc_card *card = mmc_list_to_card(l);
+
+ MDEBUG("MMC: mmc_suspend_host() removing card 0x%X\n", (int)card);
+ mmc_card_set_dead(card);
+
+ list_del(&card->node);
+ mmc_remove_card(card);
+ }
+ }
+#endif
+
mmc_power_off(host);
mmc_release_host(host);
@@ -901,7 +1493,14 @@
*/
int mmc_resume_host(struct mmc_host *host)
{
+#ifdef CONFIG_FIONA_PM_MMC
+ extern struct mmc_host *g_pm_mmc_resume_host;
+
+ /* we need to defer resume processing because of "fpow" */
+ g_pm_mmc_resume_host = host;
+#else
mmc_detect_change(host);
+#endif
return 0;
}
diff -wur linux-2.6.10/drivers/mmc/mmc_block.c linux-2.6.10-lab/drivers/mmc/mmc_block.c
--- linux-2.6.10/drivers/mmc/mmc_block.c 2004-12-24 16:35:50.000000000 -0500
+++ linux-2.6.10-lab/drivers/mmc/mmc_block.c 2007-10-04 19:10:37.000000000 -0400
@@ -16,6 +16,7 @@
* Author: Andrew Christian
* 28 May 2002
*/
+#include
#include
#include
#include
@@ -42,6 +43,16 @@
*/
#define MMC_SHIFT 3
+
+#if defined(CONFIG_MMC_DEBUG) || defined(CONFIG_PM_DEBUG)
+#define pinfo(x...) printk(x)
+#else
+#define pinfo(x...) do {} while(0)
+#endif
+
+extern int mmc_suspend_host(struct mmc_host *host, u32 state);
+extern int mmc_resume_host(struct mmc_host *host);
+
static int major;
/*
@@ -95,6 +106,10 @@
if (md->usage == 2)
check_disk_change(inode->i_bdev);
ret = 0;
+
+ if ((filp->f_mode & FMODE_WRITE) &&
+ mmc_card_readonly(md->queue.card))
+ ret = -EROFS;
}
return ret;
@@ -168,7 +183,12 @@
int ret;
if (mmc_card_claim_host(card))
+#ifndef CONFIG_ARCH_LAB126
goto cmd_err;
+#else
+ /* this case can occur on card abort */
+ goto cmd_err_skip_release;
+#endif
do {
struct mmc_blk_request brq;
@@ -178,17 +198,20 @@
brq.mrq.cmd = &brq.cmd;
brq.mrq.data = &brq.data;
- brq.cmd.arg = req->sector << 9;
+ brq.cmd.arg = req->sector;
+ if (!mmc_card_blockaddr(card))
+ brq.cmd.arg <<= 9;
brq.cmd.flags = MMC_RSP_R1;
brq.data.req = req;
- brq.data.timeout_ns = card->csd.tacc_ns * 10;
- brq.data.timeout_clks = card->csd.tacc_clks * 10;
+
brq.data.blksz_bits = md->block_bits;
brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
brq.stop.opcode = MMC_STOP_TRANSMISSION;
brq.stop.arg = 0;
brq.stop.flags = MMC_RSP_R1B;
+ mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ);
+
if (rq_data_dir(req) == READ) {
brq.cmd.opcode = brq.data.blocks > 1 ? MMC_READ_MULTIPLE_BLOCK : MMC_READ_SINGLE_BLOCK;
brq.data.flags |= MMC_DATA_READ;
@@ -267,6 +290,10 @@
cmd_err:
mmc_card_release_host(card);
+#ifdef CONFIG_ARCH_LAB126
+cmd_err_skip_release:
+#endif
+
/*
* This is a little draconian, but until we get proper
* error handling sorted out here, its the best we can
@@ -332,11 +359,21 @@
md->disk->private_data = md;
md->disk->queue = md->queue.queue;
md->disk->driverfs_dev = &card->dev;
+ md->disk->flags |= GENHD_FL_REMOVABLE;
sprintf(md->disk->disk_name, "mmcblk%d", devidx);
sprintf(md->disk->devfs_name, "mmc/blk%d", devidx);
- md->block_bits = card->csd.read_blkbits;
+ /* the rest of the block operation code is written assuming */
+ /* 512-byte blocks, so let the system know that it should */
+ /* operate using 512-byte blocks as well */
+ /* md->block_bits = card->csd.read_blkbits; */
+ md->block_bits = 9; // (1 << 9) equals 512
+
+ /* in addition, adjust the known capacity by the delta */
+ if (card->csd.read_blkbits > md->block_bits) {
+ card->csd.capacity <<= (card->csd.read_blkbits - md->block_bits);
+ }
blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits);
set_capacity(md->disk, card->csd.capacity);
@@ -351,9 +388,19 @@
struct mmc_command cmd;
int err;
+ /* Block-addressed cards ignore MMC_SET_BLOCKLEN. */
+ if (mmc_card_blockaddr(card))
+ return 0;
+
mmc_card_claim_host(card);
cmd.opcode = MMC_SET_BLOCKLEN;
- cmd.arg = 1 << card->csd.read_blkbits;
+
+ /* the rest of the block operation code is written assuming */
+ /* 512-byte blocks, so base the block size on the block data- */
+ /* based size, rather than the raw CSD-based size from the card */
+ /* cmd.arg = 1 << card->csd.read_blkbits; */
+ cmd.arg = 1 << md->block_bits; // (1 << 9) equals 512
+
cmd.flags = MMC_RSP_R1;
err = mmc_wait_for_cmd(card->host, &cmd, 5);
mmc_card_release_host(card);
@@ -372,7 +419,10 @@
struct mmc_blk_data *md;
int err;
- if (card->csd.cmdclass & ~0x1ff)
+ /*
+ * Check that the card supports the command class(es) we need.
+ */
+ if (!(card->csd.cmdclass & CCC_BLOCK_READ))
return -ENODEV;
if (card->csd.read_blkbits < 9) {
@@ -389,9 +439,10 @@
if (err)
goto out;
- printk(KERN_INFO "%s: %s %s %dKiB\n",
+ printk(KERN_INFO "%s: %s %s %dKiB %s\n",
md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
- (card->csd.capacity << card->csd.read_blkbits) / 1024);
+ (int)(((long long)card->csd.capacity << md->block_bits) / 1024),
+ mmc_card_readonly(card)?"(read-only)":"");
mmc_set_drvdata(card, md);
add_disk(md->disk);
@@ -428,22 +479,15 @@
#ifdef CONFIG_PM
static int mmc_blk_suspend(struct mmc_card *card, u32 state)
{
- struct mmc_blk_data *md = mmc_get_drvdata(card);
+ pinfo("mmc_blk_suspend(%d)\n", state);
+
+ mmc_blk_remove(card);
- if (md) {
- mmc_queue_suspend(&md->queue);
- }
return 0;
}
static int mmc_blk_resume(struct mmc_card *card)
{
- struct mmc_blk_data *md = mmc_get_drvdata(card);
-
- if (md) {
- mmc_blk_set_blksize(md, card);
- mmc_queue_resume(&md->queue);
- }
return 0;
}
#else
diff -wur linux-2.6.10/drivers/mmc/mmc_queue.c linux-2.6.10-lab/drivers/mmc/mmc_queue.c
--- linux-2.6.10/drivers/mmc/mmc_queue.c 2004-12-24 16:34:58.000000000 -0500
+++ linux-2.6.10-lab/drivers/mmc/mmc_queue.c 2007-10-04 19:10:37.000000000 -0400
@@ -18,6 +18,10 @@
#define MMC_QUEUE_EXIT (1 << 0)
#define MMC_QUEUE_SUSPENDED (1 << 1)
+#ifdef CONFIG_ARCH_LAB126
+#include
+#endif
+
/*
* Prepare a MMC request. Essentially, this means passing the
* preparation off to the media driver. The media driver will
@@ -92,7 +96,16 @@
}
set_current_state(TASK_RUNNING);
+#ifdef CONFIG_ARCH_LAB126
+ cpufreq_enable_speed_changes(0);
+#endif
+
mq->issue_fn(mq, req);
+
+#ifdef CONFIG_ARCH_LAB126
+ cpufreq_enable_speed_changes(1);
+#endif
+
} while (1);
remove_wait_queue(&mq->thread_wq, &wait);
up(&mq->thread_sem);
diff -wur linux-2.6.10/drivers/mmc/mmc_sysfs.c linux-2.6.10-lab/drivers/mmc/mmc_sysfs.c
--- linux-2.6.10/drivers/mmc/mmc_sysfs.c 2004-12-24 16:35:01.000000000 -0500
+++ linux-2.6.10-lab/drivers/mmc/mmc_sysfs.c 2007-10-04 19:10:37.000000000 -0400
@@ -21,6 +21,12 @@
#define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev)
#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv)
+#if defined(CONFIG_MMC_DEBUG) || defined(CONFIG_PM_DEBUG)
+#define pinfo(x...) printk(x)
+#else
+#define pinfo(x...) do {} while(0)
+#endif
+
static void mmc_release_card(struct device *dev)
{
struct mmc_card *card = dev_to_mmc_card(dev);
@@ -80,8 +86,12 @@
struct mmc_card *card = dev_to_mmc_card(dev);
int ret = 0;
- if (dev->driver && drv->suspend)
+ pinfo("mmc_bus_suspend(%d)\n",state);
+
+ if (dev->driver && drv->suspend) {
+ pinfo("mmc_bus_suspend(%d) calling drv->suspend for %s\n",state,dev->driver->name);
ret = drv->suspend(card, state);
+ }
return ret;
}
@@ -91,8 +101,12 @@
struct mmc_card *card = dev_to_mmc_card(dev);
int ret = 0;
- if (dev->driver && drv->resume)
+ pinfo("mmc_bus_resume()\n");
+
+ if (dev->driver && drv->resume) {
+ pinfo("mmc_bus_resume() calling drv->resume for %s\n",dev->driver->name);
ret = drv->resume(card);
+ }
return ret;
}
@@ -163,6 +177,7 @@
card->raw_cid[2], card->raw_cid[3]);
MMC_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
card->raw_csd[2], card->raw_csd[3]);
+MMC_ATTR(scr, "%08x%08x\n", card->raw_scr[0], card->raw_scr[1]);
MMC_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
MMC_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
MMC_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
@@ -174,6 +189,7 @@
static struct device_attribute *mmc_dev_attributes[] = {
&dev_attr_cid,
&dev_attr_csd,
+ &dev_attr_scr,
&dev_attr_date,
&dev_attr_fwrev,
&dev_attr_hwrev,
@@ -229,7 +245,9 @@
static int __init mmc_init(void)
{
- return bus_register(&mmc_bus_type);
+ int rc = 0;
+ rc = bus_register(&mmc_bus_type);
+ return(rc);
}
static void __exit mmc_exit(void)
diff -wur linux-2.6.10/drivers/mmc/mmci.c linux-2.6.10-lab/drivers/mmc/mmci.c
--- linux-2.6.10/drivers/mmc/mmci.c 2004-12-24 16:35:23.000000000 -0500
+++ linux-2.6.10-lab/drivers/mmc/mmci.c 2007-10-04 19:10:37.000000000 -0400
@@ -37,6 +37,12 @@
#define DBG(host,fmt,args...) do { } while (0)
#endif
+#if defined(CONFIG_MMC_DEBUG) || defined(CONFIG_PM_DEBUG)
+#define pinfo(x...) printk(x)
+#else
+#define pinfo(x...) do {} while(0)
+#endif
+
static unsigned int fmax = 515633;
static void
@@ -607,9 +613,12 @@
struct mmc_host *mmc = amba_get_drvdata(dev);
int ret = 0;
+ pinfo("mmci_suspend(%d)\n",state);
+
if (mmc) {
struct mmci_host *host = mmc_priv(mmc);
+ pinfo("mmci_suspend(%d) calling mmc_suspend_host()\n",state);
ret = mmc_suspend_host(mmc, state);
if (ret == 0)
writel(0, host->base + MMCIMASK0);
@@ -623,11 +632,14 @@
struct mmc_host *mmc = amba_get_drvdata(dev);
int ret = 0;
+ pinfo("mmci_resume(%d)\n",state);
+
if (mmc) {
struct mmci_host *host = mmc_priv(mmc);
writel(MCI_IRQENABLE, host->base + MMCIMASK0);
+ pinfo("mmci_resume(%d) calling mmc_resume_host()\n",state);
ret = mmc_resume_host(mmc);
}
diff -wur linux-2.6.10/drivers/mmc/pxamci.c linux-2.6.10-lab/drivers/mmc/pxamci.c
--- linux-2.6.10/drivers/mmc/pxamci.c 2004-12-24 16:35:18.000000000 -0500
+++ linux-2.6.10-lab/drivers/mmc/pxamci.c 2007-10-04 19:10:37.000000000 -0400
@@ -15,6 +15,8 @@
*
* 1 and 3 byte data transfers not supported
* max block length up to 1023
+ *
+ * Lab126 changes Copyright (C) 2005, 2006 Lab126, Inc.
*/
#include
#include
@@ -27,6 +29,11 @@
#include
#include
#include
+#include
+#include
+#include
+#include
+#include
#include
#include
@@ -36,18 +43,45 @@
#include
#include
+#ifdef CONFIG_ARCH_LAB126
+#ifdef CONFIG_ARCH_FIONA
+#include
+#ifdef CONFIG_FIONA_PM_MMC
+#include
+#endif
+#else
+#error unsupported board configuration
+#endif
+
+#include
+#endif
+
#include "pxamci.h"
#ifdef CONFIG_MMC_DEBUG
-#define DBG(x...) printk(KERN_DEBUG x)
+//#define DBG(x...) printk(KERN_DEBUG x)
+#define _DBG(x...) do { } while (0)
+#define DBG(x...) printk(x)
+#define MDEBUG(x...) printk(x)
#else
+#define _DBG(x...) do { } while (0)
#define DBG(x...) do { } while (0)
+#define MDEBUG(x...) do { } while (0)
+#endif
+
+#if defined(CONFIG_MMC_DEBUG) || defined(CONFIG_PM_DEBUG)
+#define pinfo(x...) printk(x)
+#else
+#define pinfo(x...) do {} while(0)
#endif
#define DRIVER_NAME "pxa2xx-mci"
#define NR_SG 1
+extern int mmc_suspend_host(struct mmc_host *host, u32 state);
+extern int mmc_resume_host(struct mmc_host *host);
+
struct pxamci_host {
struct mmc_host *mmc;
spinlock_t lock;
@@ -79,6 +113,7 @@
static void pxamci_stop_clock(struct pxamci_host *host)
{
+ _DBG("PXAMCI: pxamci_stop_clock called \n");
if (readl(host->base + MMC_STAT) & STAT_CLK_EN) {
unsigned long timeout = 10000;
unsigned int v;
@@ -173,7 +208,11 @@
static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat)
{
+
+#ifndef CONFIG_ARCH_LAB126
WARN_ON(host->cmd != NULL);
+#endif
+
host->cmd = cmd;
if (cmd->flags & MMC_RSP_BUSY)
@@ -206,7 +245,7 @@
static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq)
{
- DBG("PXAMCI: request done\n");
+ _DBG("PXAMCI: request done\n");
host->mrq = NULL;
host->cmd = NULL;
host->data = NULL;
@@ -277,8 +316,7 @@
return 0;
DCSR(host->dma) = 0;
- dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,
- host->dma_dir);
+ dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len, host->dma_dir);
if (stat & STAT_READ_TIME_OUT)
data->error = MMC_ERR_TIMEOUT;
@@ -317,12 +355,12 @@
ireg = readl(host->base + MMC_I_REG);
- DBG("PXAMCI: irq %08x\n", ireg);
+ _DBG("PXAMCI: irq %08x\n", ireg);
if (ireg) {
unsigned stat = readl(host->base + MMC_STAT);
- DBG("PXAMCI: stat %08x\n", stat);
+ _DBG("PXAMCI: stat %08x\n", stat);
if (ireg & END_CMD_RES)
handled |= pxamci_cmd_done(host, stat);
@@ -338,7 +376,10 @@
struct pxamci_host *host = mmc_priv(mmc);
unsigned int cmdat;
+#ifndef CONFIG_ARCH_LAB126
+ /* mrq can be NULL on card abort case */
WARN_ON(host->mrq != NULL);
+#endif
host->mrq = mrq;
@@ -362,6 +403,17 @@
pxamci_start_cmd(host, mrq->cmd, cmdat);
}
+static int pxamci_get_ro(struct mmc_host *mmc)
+{
+ struct pxamci_host *host = mmc_priv(mmc);
+
+ if (host->pdata && host->pdata->get_ro)
+ return host->pdata->get_ro(mmc->dev);
+
+ /* Host doesn't support read only detection so assume writeable */
+ return 0;
+}
+
static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct pxamci_host *host = mmc_priv(mmc);
@@ -372,9 +424,9 @@
if (ios->clock) {
unsigned int clk = CLOCKRATE / ios->clock;
- if (CLOCKRATE / clk > ios->clock)
- clk <<= 1;
+ if(clk > (1<<6)) clk = (1<<6);
host->clkrt = fls(clk) - 1;
+ MDEBUG("PXAMCI: Starting HW clock in pxamci_set_ioc\n");
pxa_set_cken(CKEN12_MMC, 1);
/*
@@ -382,6 +434,7 @@
*/
} else {
pxamci_stop_clock(host);
+ MDEBUG("PXAMCI: Stopping HW clock in pxamci_set_ioc\n");
pxa_set_cken(CKEN12_MMC, 0);
}
@@ -399,9 +452,346 @@
host->clkrt, host->cmdat);
}
+#ifdef CONFIG_ARCH_LAB126
+
+void pxamci_clear(struct mmc_host *mmc)
+{
+ struct pxamci_host *host = mmc_priv(mmc);
+
+ pxamci_stop_clock(host);
+ writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD|
+ END_CMD_RES|PRG_DONE|DATA_TRAN_DONE,
+ host->base + MMC_I_MASK);
+
+ DRCMRRXMMC = 0;
+ DRCMRTXMMC = 0;
+}
+
+int pxamci_card_inserted(void)
+{
+ return mmc_query_insertion_state();
+}
+
+#define MMC_NOTIFY_THREAD "mmcdd"
+
+static DECLARE_COMPLETION(mmc_detect_thread_exited);
+
+static struct {
+ pid_t thread_pid;
+ wait_queue_head_t event_wq;
+ unsigned int event_count;
+} mmc_detect_data;
+
+#undef NOTIFY_SEM
+
+#ifdef NOTIFY_SEM
+static void mmc_detect_notify_sem(void)
+{
+ int sem_id;
+
+ // retrieve the notification semaphore
+ sem_id = sys_semget(MMC_NOTIFY_SEM_KEY, 1, 0666);
+ if (sem_id >= 0) {
+ struct sembuf sem_operations[1];
+
+ // signal the semaphore
+ sem_operations[0].sem_num = 0; // which semaphore to use
+ sem_operations[0].sem_op = 1; // add one from the semaphore value
+ sem_operations[0].sem_flg = 0; // set wait flag
+
+ // do the signal
+ sys_semop(sem_id, sem_operations, 1);
+
+ } else {
+ // semaphore doesn't exist; ignore as nobody may be waiting on it
+
+ }
+}
+#endif
+
+static void mmc_detect_notify(int enabled, int notify)
+{
+ int err;
+
+ char *envp[] = {
+ "HOME=/",
+ "TERM=linux",
+ "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
+ NULL
+ };
+
+ char *argv[] = {
+ MMC_NOTIFY_SCRIPT,
+ enabled ? "1" : "0",
+ notify ? "1" : "0",
+ NULL
+ };
+
+ MDEBUG("mmc_detect_notify(CARD_%s)\n", (enabled ? "INSERTED" : "REMOVED"));
+ if ((err = call_usermodehelper(argv[0], argv, envp, 0)) < 0) {
+ printk("mmc: notification exec failed: \"" MMC_NOTIFY_SCRIPT "\", err %d\n", err);
+ }
+}
+
+#ifdef CONFIG_FIONA_PM_MMC
+static void mmc_detect_notify_signal(void);
+
+struct mmc_host *g_pm_mmc_resume_host = NULL;
+
+static int pm_mmc_wake_notify = 0;
+static int pm_mmc_power_mode = FPOW_MODE_ON;
+
+static int mmc_bus_fpow_getmode(void *private);
+static FPOW_ERR mmc_bus_fpow_setmode(void *private, u32 state, u32 mode);
+
+static fpow_component *mmc_fpow_dev = NULL;
+
+static int mmc_register_with_fpow(struct device *dev, fpow_component **fpow_dev)
+{
+ struct fpow_registration_rec reg;
+ int rc = 0;
+
+ memclr(®, sizeof(reg));
+ strcpy((char*)®.name, "mmc");
+
+ reg.device_class = FPOW_CLASS_MMC;
+ reg.supported_modes = FPOW_MODE_ON_SUPPORTED | FPOW_MODE_SLEEP_SUPPORTED | FPOW_MODE_OFF_SUPPORTED;
+ reg.private = (void *)dev;
+ reg.getmode = mmc_bus_fpow_getmode;
+ reg.setmode = mmc_bus_fpow_setmode;
+ *fpow_dev = fpow_register(®);
+ if (*fpow_dev == NULL) {
+ printk("MMC: Failed to register with fpow !!\n");
+ rc = -1;
+ }
+
+ return rc;
+}
+
+static FPOW_ERR mmc_bus_fpow_setmode(void *private, u32 state, u32 mode)
+{
+ FPOW_ERR ret = FPOW_NO_ERR;
+
+ powdebug("mmc_bus_fpow_setmode(mode=%s)\n", fpow_mode_to_str(mode));
+
+ // if we're already in the correct mode, we don't need to do anything
+ if (pm_mmc_power_mode != mode) {
+
+ switch (mode) {
+
+ case FPOW_MODE_ON :
+ pm_mmc_wake_notify = 1;
+ mmc_detect_notify_signal();
+ // (fall through)
+
+ case FPOW_MODE_SLEEP :
+ case FPOW_MODE_OFF :
+ pm_mmc_power_mode = mode;
+ break;
+
+ default :
+ ret = -EINVAL;
+ break;
+ }
+
+ }
+
+ return ret;
+}
+
+static int mmc_bus_fpow_getmode(void *private)
+{
+ powdebug("mmc_bus_fpow_getmode()\n");
+
+ return pm_mmc_power_mode;
+}
+
+static void mmc_perform_suspend(void)
+{
+ // force an unmount of the card, without notification
+ mmc_detect_notify(0, 0);
+}
+
+static void mmc_perform_resume(void)
+{
+ if (g_pm_mmc_resume_host != NULL) {
+ MDEBUG("mmc_perform_resume: host=%p\n", g_pm_mmc_resume_host);
+
+ // force device rescan
+ mmc_detect_change(g_pm_mmc_resume_host);
+ flush_scheduled_work();
+
+ g_pm_mmc_resume_host = NULL;
+ }
+}
+#endif
+
+
+#define SETTLE_COUNT_MAX 10
+#define SETTLE_DELAY 10
+
+static int mmc_detect_notify_thread(void *arg)
+{
+ int last_notify = -1;
+ int settle_count;
+
+ daemonize(MMC_NOTIFY_THREAD);
+ allow_signal(SIGKILL);
+
+ while (1) {
+ wait_event_interruptible(mmc_detect_data.event_wq, mmc_detect_data.event_count != 0);
+
+#ifdef CONFIG_PM
+ if (current->