diff options
Diffstat (limited to 'arch')
222 files changed, 7946 insertions, 1698 deletions
diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c index 1898ea79d0e..9d6186d5024 100644 --- a/arch/alpha/kernel/alpha_ksyms.c +++ b/arch/alpha/kernel/alpha_ksyms.c @@ -216,8 +216,6 @@ EXPORT_SYMBOL(memcpy); EXPORT_SYMBOL(memset); EXPORT_SYMBOL(memchr); -EXPORT_SYMBOL(get_wchan); - #ifdef CONFIG_ALPHA_IRONGATE EXPORT_SYMBOL(irongate_ioremap); EXPORT_SYMBOL(irongate_iounmap); diff --git a/arch/alpha/kernel/core_marvel.c b/arch/alpha/kernel/core_marvel.c index 44866cb26a8..7f6a98455e7 100644 --- a/arch/alpha/kernel/core_marvel.c +++ b/arch/alpha/kernel/core_marvel.c @@ -435,7 +435,7 @@ marvel_specify_io7(char *str) str = pchar; } while(*str); - return 0; + return 1; } __setup("io7=", marvel_specify_io7); diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index dd876967059..a15e18a0025 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c @@ -28,6 +28,7 @@ #include <linux/init.h> #include <linux/string.h> #include <linux/ioport.h> +#include <linux/platform_device.h> #include <linux/bootmem.h> #include <linux/pci.h> #include <linux/seq_file.h> @@ -1478,3 +1479,20 @@ alpha_panic_event(struct notifier_block *this, unsigned long event, void *ptr) #endif return NOTIFY_DONE; } + +static __init int add_pcspkr(void) +{ + struct platform_device *pd; + int ret; + + pd = platform_device_alloc("pcspkr", -1); + if (!pd) + return -ENOMEM; + + ret = platform_device_add(pd); + if (ret) + platform_device_put(pd); + + return ret; +} +device_initcall(add_pcspkr); diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index ba46d779ede..dc5a9332c91 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -77,6 +77,14 @@ config FIQ config ARCH_MTD_XIP bool +config VECTORS_BASE + hex + default 0xffff0000 if MMU + default DRAM_BASE if REMAP_VECTORS_TO_RAM + default 0x00000000 + help + The base address of exception vectors. + source "init/Kconfig" menu "System Type" @@ -839,6 +847,8 @@ source "drivers/misc/Kconfig" source "drivers/mfd/Kconfig" +source "drivers/leds/Kconfig" + source "drivers/media/Kconfig" source "drivers/video/Kconfig" diff --git a/arch/arm/Kconfig-nommu b/arch/arm/Kconfig-nommu new file mode 100644 index 00000000000..e1574be2ded --- /dev/null +++ b/arch/arm/Kconfig-nommu @@ -0,0 +1,44 @@ +# +# Kconfig for uClinux(non-paged MM) depend configurations +# Hyok S. Choi <hyok.choi@samsung.com> +# + +config SET_MEM_PARAM + bool "Set flash/sdram size and base addr" + help + Say Y to manually set the base addresses and sizes. + otherwise, the default values are assigned. + +config DRAM_BASE + hex '(S)DRAM Base Address' if SET_MEM_PARAM + default 0x00800000 + +config DRAM_SIZE + hex '(S)DRAM SIZE' if SET_MEM_PARAM + default 0x00800000 + +config FLASH_MEM_BASE + hex 'FLASH Base Address' if SET_MEM_PARAM + default 0x00400000 + +config FLASH_SIZE + hex 'FLASH Size' if SET_MEM_PARAM + default 0x00400000 + +config REMAP_VECTORS_TO_RAM + bool 'Install vectors to the begining of RAM' if DRAM_BASE + depends on DRAM_BASE + help + The kernel needs to change the hardware exception vectors. + In nommu mode, the hardware exception vectors are normally + placed at address 0x00000000. However, this region may be + occupied by read-only memory depending on H/W design. + + If the region contains read-write memory, say 'n' here. + + If your CPU provides a remap facility which allows the exception + vectors to be mapped to writable memory, say 'n' here. + + Otherwise, say 'y' here. In this case, the kernel will require + external support to redirect the hardware exception vectors to + the writable versions located at DRAM_BASE. diff --git a/arch/arm/Makefile b/arch/arm/Makefile index ce3e804ea0f..95a96275f88 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -20,6 +20,11 @@ GZFLAGS :=-9 # Select a platform tht is kept up-to-date KBUILD_DEFCONFIG := versatile_defconfig +# defines filename extension depending memory manement type. +ifeq ($(CONFIG_MMU),) +MMUEXT := -nommu +endif + ifeq ($(CONFIG_FRAME_POINTER),y) CFLAGS +=-fno-omit-frame-pointer -mapcs -mno-sched-prolog endif @@ -73,7 +78,7 @@ AFLAGS +=$(CFLAGS_ABI) $(arch-y) $(tune-y) -msoft-float CHECKFLAGS += -D__arm__ #Default value -head-y := arch/arm/kernel/head.o arch/arm/kernel/init_task.o +head-y := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o textofs-y := 0x00008000 machine-$(CONFIG_ARCH_RPC) := rpc @@ -133,7 +138,7 @@ else MACHINE := endif -export TEXT_OFFSET GZFLAGS +export TEXT_OFFSET GZFLAGS MMUEXT # Do we have FASTFPE? FASTFPE :=arch/arm/fastfpe diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 491c7e4c9ac..b56f5e691d6 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -2,6 +2,7 @@ * linux/arch/arm/boot/compressed/head.S * * Copyright (C) 1996-2002 Russell King + * Copyright (C) 2004 Hyok S. Choi (MPU support) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -320,6 +321,62 @@ params: ldr r0, =params_phys cache_on: mov r3, #8 @ cache_on function b call_cache_fn +/* + * Initialize the highest priority protection region, PR7 + * to cover all 32bit address and cacheable and bufferable. + */ +__armv4_mpu_cache_on: + mov r0, #0x3f @ 4G, the whole + mcr p15, 0, r0, c6, c7, 0 @ PR7 Area Setting + mcr p15, 0, r0, c6, c7, 1 + + mov r0, #0x80 @ PR7 + mcr p15, 0, r0, c2, c0, 0 @ D-cache on + mcr p15, 0, r0, c2, c0, 1 @ I-cache on + mcr p15, 0, r0, c3, c0, 0 @ write-buffer on + + mov r0, #0xc000 + mcr p15, 0, r0, c5, c0, 1 @ I-access permission + mcr p15, 0, r0, c5, c0, 0 @ D-access permission + + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer + mcr p15, 0, r0, c7, c5, 0 @ flush(inval) I-Cache + mcr p15, 0, r0, c7, c6, 0 @ flush(inval) D-Cache + mrc p15, 0, r0, c1, c0, 0 @ read control reg + @ ...I .... ..D. WC.M + orr r0, r0, #0x002d @ .... .... ..1. 11.1 + orr r0, r0, #0x1000 @ ...1 .... .... .... + + mcr p15, 0, r0, c1, c0, 0 @ write control reg + + mov r0, #0 + mcr p15, 0, r0, c7, c5, 0 @ flush(inval) I-Cache + mcr p15, 0, r0, c7, c6, 0 @ flush(inval) D-Cache + mov pc, lr + +__armv3_mpu_cache_on: + mov r0, #0x3f @ 4G, the whole + mcr p15, 0, r0, c6, c7, 0 @ PR7 Area Setting + + mov r0, #0x80 @ PR7 + mcr p15, 0, r0, c2, c0, 0 @ cache on + mcr p15, 0, r0, c3, c0, 0 @ write-buffer on + + mov r0, #0xc000 + mcr p15, 0, r0, c5, c0, 0 @ access permission + + mov r0, #0 + mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3 + mrc p15, 0, r0, c1, c0, 0 @ read control reg + @ .... .... .... WC.M + orr r0, r0, #0x000d @ .... .... .... 11.1 + mov r0, #0 + mcr p15, 0, r0, c1, c0, 0 @ write control reg + + mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3 + mov pc, lr + __setup_mmu: sub r3, r4, #16384 @ Page directory size bic r3, r3, #0xff @ Align the pointer bic r3, r3, #0x3f00 @@ -496,6 +553,18 @@ proc_types: b __armv4_mmu_cache_off mov pc, lr + .word 0x41007400 @ ARM74x + .word 0xff00ff00 + b __armv3_mpu_cache_on + b __armv3_mpu_cache_off + b __armv3_mpu_cache_flush + + .word 0x41009400 @ ARM94x + .word 0xff00ff00 + b __armv4_mpu_cache_on + b __armv4_mpu_cache_off + b __armv4_mpu_cache_flush + .word 0x00007000 @ ARM7 IDs .word 0x0000f000 mov pc, lr @@ -562,6 +631,24 @@ proc_types: cache_off: mov r3, #12 @ cache_off function b call_cache_fn +__armv4_mpu_cache_off: + mrc p15, 0, r0, c1, c0 + bic r0, r0, #0x000d + mcr p15, 0, r0, c1, c0 @ turn MPU and cache off + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer + mcr p15, 0, r0, c7, c6, 0 @ flush D-Cache + mcr p15, 0, r0, c7, c5, 0 @ flush I-Cache + mov pc, lr + +__armv3_mpu_cache_off: + mrc p15, 0, r0, c1, c0 + bic r0, r0, #0x000d + mcr p15, 0, r0, c1, c0, 0 @ turn MPU and cache off + mov r0, #0 + mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3 + mov pc, lr + __armv4_mmu_cache_off: mrc p15, 0, r0, c1, c0 bic r0, r0, #0x000d @@ -601,6 +688,24 @@ cache_clean_flush: mov r3, #16 b call_cache_fn +__armv4_mpu_cache_flush: + mov r2, #1 + mov r3, #0 + mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache + mov r1, #7 << 5 @ 8 segments +1: orr r3, r1, #63 << 26 @ 64 entries +2: mcr p15, 0, r3, c7, c14, 2 @ clean & invalidate D index + subs r3, r3, #1 << 26 + bcs 2b @ entries 63 to 0 + subs r1, r1, #1 << 5 + bcs 1b @ segments 7 to 0 + + teq r2, #0 + mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mov pc, lr + + __armv6_mmu_cache_flush: mov r1, #0 mcr p15, 0, r1, c7, c14, 0 @ clean+invalidate D @@ -638,6 +743,7 @@ no_cache_id: mov pc, lr __armv3_mmu_cache_flush: +__armv3_mpu_cache_flush: mov r1, #0 mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3 mov pc, lr diff --git a/arch/arm/common/sharpsl_pm.c b/arch/arm/common/sharpsl_pm.c index 978d32e82d3..3cd8c9ee451 100644 --- a/arch/arm/common/sharpsl_pm.c +++ b/arch/arm/common/sharpsl_pm.c @@ -22,6 +22,7 @@ #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/platform_device.h> +#include <linux/leds.h> #include <asm/hardware.h> #include <asm/mach-types.h> @@ -75,6 +76,7 @@ static void sharpsl_battery_thread(void *private_); struct sharpsl_pm_status sharpsl_pm; DECLARE_WORK(toggle_charger, sharpsl_charge_toggle, NULL); DECLARE_WORK(sharpsl_bat, sharpsl_battery_thread, NULL); +DEFINE_LED_TRIGGER(sharpsl_charge_led_trigger); static int get_percentage(int voltage) @@ -190,10 +192,10 @@ void sharpsl_pm_led(int val) dev_err(sharpsl_pm.dev, "Charging Error!\n"); } else if (val == SHARPSL_LED_ON) { dev_dbg(sharpsl_pm.dev, "Charge LED On\n"); - + led_trigger_event(sharpsl_charge_led_trigger, LED_FULL); } else { dev_dbg(sharpsl_pm.dev, "Charge LED Off\n"); - + led_trigger_event(sharpsl_charge_led_trigger, LED_OFF); } } @@ -786,6 +788,8 @@ static int __init sharpsl_pm_probe(struct platform_device *pdev) init_timer(&sharpsl_pm.chrg_full_timer); sharpsl_pm.chrg_full_timer.function = sharpsl_chrg_full_timer; + led_trigger_register_simple("sharpsl-charge", &sharpsl_charge_led_trigger); + sharpsl_pm.machinfo->init(); device_create_file(&pdev->dev, &dev_attr_battery_percentage); @@ -807,6 +811,8 @@ static int sharpsl_pm_remove(struct platform_device *pdev) device_remove_file(&pdev->dev, &dev_attr_battery_percentage); device_remove_file(&pdev->dev, &dev_attr_battery_voltage); + led_trigger_unregister_simple(sharpsl_charge_led_trigger); + sharpsl_pm.machinfo->exit(); del_timer_sync(&sharpsl_pm.chrg_full_timer); diff --git a/arch/arm/configs/at91rm9200dk_defconfig b/arch/arm/configs/at91rm9200dk_defconfig index 1fe73d19888..9e1c1cceb73 100644 --- a/arch/arm/configs/at91rm9200dk_defconfig +++ b/arch/arm/configs/at91rm9200dk_defconfig @@ -379,7 +379,7 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2 # CONFIG_MTD_DOC2001 is not set # CONFIG_MTD_DOC2001PLUS is not set CONFIG_MTD_AT91_DATAFLASH=y -CONFIG_MTD_AT91_DATAFLASH_CARD=y +# CONFIG_MTD_AT91_DATAFLASH_CARD is not set # # NAND Flash Device Drivers diff --git a/arch/arm/configs/at91rm9200ek_defconfig b/arch/arm/configs/at91rm9200ek_defconfig index b7d934cdb1b..6e0805a971d 100644 --- a/arch/arm/configs/at91rm9200ek_defconfig +++ b/arch/arm/configs/at91rm9200ek_defconfig @@ -370,7 +370,7 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2 # CONFIG_MTD_DOC2001 is not set # CONFIG_MTD_DOC2001PLUS is not set CONFIG_MTD_AT91_DATAFLASH=y -CONFIG_MTD_AT91_DATAFLASH_CARD=y +# CONFIG_MTD_AT91_DATAFLASH_CARD is not set # # NAND Flash Device Drivers diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c index 1574941ebfe..ee083b3f052 100644 --- a/arch/arm/kernel/armksyms.c +++ b/arch/arm/kernel/armksyms.c @@ -100,23 +100,12 @@ EXPORT_SYMBOL(__raw_writesl); #endif /* string / mem functions */ -EXPORT_SYMBOL(strcpy); -EXPORT_SYMBOL(strncpy); -EXPORT_SYMBOL(strcat); -EXPORT_SYMBOL(strncat); -EXPORT_SYMBOL(strcmp); -EXPORT_SYMBOL(strncmp); EXPORT_SYMBOL(strchr); -EXPORT_SYMBOL(strlen); -EXPORT_SYMBOL(strnlen); EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strrchr); -EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(memset); EXPORT_SYMBOL(memcpy); EXPORT_SYMBOL(memmove); -EXPORT_SYMBOL(memcmp); -EXPORT_SYMBOL(memscan); EXPORT_SYMBOL(memchr); EXPORT_SYMBOL(__memzero); @@ -190,8 +179,6 @@ EXPORT_SYMBOL(_find_next_bit_be); /* syscalls */ EXPORT_SYMBOL(sys_write); -EXPORT_SYMBOL(sys_read); EXPORT_SYMBOL(sys_lseek); -EXPORT_SYMBOL(sys_open); EXPORT_SYMBOL(sys_exit); EXPORT_SYMBOL(sys_wait4); diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 355914ffb19..ab8e600c18c 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -666,7 +666,7 @@ __kuser_helper_start: * * #define __kernel_dmb() \ * asm volatile ( "mov r0, #0xffff0fff; mov lr, pc; sub pc, r0, #95" \ - * : : : "lr","cc" ) + * : : : "r0", "lr","cc" ) */ __kuser_memory_barrier: @ 0xffff0fa0 diff --git a/arch/arm/kernel/head-common.S b/arch/arm/kernel/head-common.S new file mode 100644 index 00000000000..a52da0ddb43 --- /dev/null +++ b/arch/arm/kernel/head-common.S @@ -0,0 +1,217 @@ +/* + * linux/arch/arm/kernel/head-common.S + * + * Copyright (C) 1994-2002 Russell King + * Copyright (c) 2003 ARM Limited + * All Rights Reserved + * + * 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. + * + */ + + .type __switch_data, %object +__switch_data: + .long __mmap_switched + .long __data_loc @ r4 + .long __data_start @ r5 + .long __bss_start @ r6 + .long _end @ r7 + .long processor_id @ r4 + .long __machine_arch_type @ r5 + .long cr_alignment @ r6 + .long init_thread_union + THREAD_START_SP @ sp + +/* + * The following fragment of code is executed with the MMU on in MMU mode, + * and uses absolute addresses; this is not position independent. + * + * r0 = cp#15 control register + * r1 = machine ID + * r9 = processor ID + */ + .type __mmap_switched, %function +__mmap_switched: + adr r3, __switch_data + 4 + + ldmia r3!, {r4, r5, r6, r7} + cmp r4, r5 @ Copy data segment if needed +1: cmpne r5, r6 + ldrne fp, [r4], #4 + strne fp, [r5], #4 + bne 1b + + mov fp, #0 @ Clear BSS (and zero fp) +1: cmp r6, r7 + strcc fp, [r6],#4 + bcc 1b + + ldmia r3, {r4, r5, r6, sp} + str r9, [r4] @ Save processor ID + str r1, [r5] @ Save machine type + bic r4, r0, #CR_A @ Clear 'A' bit + stmia r6, {r0, r4} @ Save control register values + b start_kernel + +/* + * Exception handling. Something went wrong and we can't proceed. We + * ought to tell the user, but since we don't have any guarantee that + * we're even running on the right architecture, we do virtually nothing. + * + * If CONFIG_DEBUG_LL is set we try to print out something about the error + * and hope for the best (useful if bootloader fails to pass a proper + * machine ID for example). + */ + + .type __error_p, %function +__error_p: +#ifdef CONFIG_DEBUG_LL + adr r0, str_p1 + bl printascii + b __error +str_p1: .asciz "\nError: unrecognized/unsupported processor variant.\n" + .align +#endif + + .type __error_a, %function +__error_a: +#ifdef CONFIG_DEBUG_LL + mov r4, r1 @ preserve machine ID + adr r0, str_a1 + bl printascii + mov r0, r4 + bl printhex8 + adr r0, str_a2 + bl printascii + adr r3, 3f + ldmia r3, {r4, r5, r6} @ get machine desc list + sub r4, r3, r4 @ get offset between virt&phys + add r5, r5, r4 @ convert virt addresses to + add r6, r6, r4 @ physical address space +1: ldr r0, [r5, #MACHINFO_TYPE] @ get machine type + bl printhex8 + mov r0, #'\t' + bl printch + ldr r0, [r5, #MACHINFO_NAME] @ get machine name + add r0, r0, r4 + bl printascii + mov r0, #'\n' + bl printch + add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc + cmp r5, r6 + blo 1b + adr r0, str_a3 + bl printascii + b __error +str_a1: .asciz "\nError: unrecognized/unsupported machine ID (r1 = 0x" +str_a2: .asciz ").\n\nAvailable machine support:\n\nID (hex)\tNAME\n" +str_a3: .asciz "\nPlease check your kernel config and/or bootloader.\n" + .align +#endif + + .type __error, %function +__error: +#ifdef CONFIG_ARCH_RPC +/* + * Turn the screen red on a error - RiscPC only. + */ + mov r0, #0x02000000 + mov r3, #0x11 + orr r3, r3, r3, lsl #8 + orr r3, r3, r3, lsl #16 + str r3, [r0], #4 + str r3, [r0], #4 + str r3, [r0], #4 + str r3, [r0], #4 +#endif +1: mov r0, r0 + b 1b + + +/* + * Read processor ID register (CP#15, CR0), and look up in the linker-built + * supported processor list. Note that we can't use the absolute addresses + * for the __proc_info lists since we aren't running with the MMU on + * (and therefore, we are not in the correct address space). We have to + * calculate the offset. + * + * r9 = cpuid + * Returns: + * r3, r4, r6 corrupted + * r5 = proc_info pointer in physical address space + * r9 = cpuid (preserved) + */ + .type __lookup_processor_type, %function +__lookup_processor_type: + adr r3, 3f + ldmda r3, {r5 - r7} + sub r3, r3, r7 @ get offset between virt&phys + add r5, r5, r3 @ convert virt addresses to + add r6, r6, r3 @ physical address space +1: ldmia r5, {r3, r4} @ value, mask + and r4, r4, r9 @ mask wanted bits + teq r3, r4 + beq 2f + add r5, r5, #PROC_INFO_SZ @ sizeof(proc_info_list) + cmp r5, r6 + blo 1b + mov r5, #0 @ unknown processor +2: mov pc, lr + +/* + * This provides a C-API version of the above function. + */ +ENTRY(lookup_processor_type) + stmfd sp!, {r4 - r7, r9, lr} + mov r9, r0 + bl __lookup_processor_type + mov r0, r5 + ldmfd sp!, {r4 - r7, r9, pc} + +/* + * Look in include/asm-arm/procinfo.h and arch/arm/kernel/arch.[ch] for + * more information about the __proc_info and __arch_info structures. + */ + .long __proc_info_begin + .long __proc_info_end +3: .long . + .long __arch_info_begin + .long __arch_info_end + +/* + * Lookup machine architecture in the linker-build list of architectures. + * Note that we can't use the absolute addresses for the __arch_info + * lists since we aren't running with the MMU on (and therefore, we are + * not in the correct address space). We have to calculate the offset. + * + * r1 = machine architecture number + * Returns: + * r3, r4, r6 corrupted + * r5 = mach_info pointer in physical address space + */ + .type __lookup_machine_type, %function +__lookup_machine_type: + adr r3, 3b + ldmia r3, {r4, r5, r6} + sub r3, r3, r4 @ get offset between virt&phys + add r5, r5, r3 @ convert virt addresses to + add r6, r6, r3 @ physical address space +1: ldr r3, [r5, #MACHINFO_TYPE] @ get machine type + teq r3, r1 @ matches loader number? + beq 2f @ found + add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc + cmp r5, r6 + blo 1b + mov r5, #0 @ unknown machine +2: mov pc, lr + +/* + * This provides a C-API version of the above function. + */ +ENTRY(lookup_machine_type) + stmfd sp!, {r4 - r6, lr} + mov r1, r0 + bl __lookup_machine_type + mov r0, r5 + ldmfd sp!, {r4 - r6, pc} diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S new file mode 100644 index 00000000000..b093ab8738b --- /dev/null +++ b/arch/arm/kernel/head-nommu.S @@ -0,0 +1,83 @@ +/* + * linux/arch/arm/kernel/head-nommu.S + * + * Copyright (C) 1994-2002 Russell King + * Copyright (C) 2003-2006 Hyok S. Choi + * + * 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. + * + * Common kernel startup code (non-paged MM) + * for 32-bit CPUs which has a process ID register(CP15). + * + */ +#include <linux/config.h> +#include <linux/linkage.h> +#include <linux/init.h> + +#include <asm/assembler.h> +#include <asm/mach-types.h> +#include <asm/procinfo.h> +#include <asm/ptrace.h> +#include <asm/constants.h> +#include <asm/system.h> + +#define PROCINFO_INITFUNC 12 + +/* + * Kernel startup entry point. + * --------------------------- + * + * This is normally called from the decompressor code. The requirements + * are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0, + * r1 = machine nr. + * + * See linux/arch/arm/tools/mach-types for the complete list of machine + * numbers for r1. + * + */ + __INIT + .type stext, %function +ENTRY(stext) + msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | MODE_SVC @ ensure svc mode + @ and irqs disabled + mrc p15, 0, r9, c0, c0 @ get processor id + bl __lookup_processor_type @ r5=procinfo r9=cpuid + movs r10, r5 @ invalid processor (r5=0)? + beq __error_p @ yes, error 'p' + bl __lookup_machine_type @ r5=machinfo + movs r8, r5 @ invalid machine (r5=0)? + beq __error_a @ yes, error 'a' + + ldr r13, __switch_data @ address to jump to after + @ the initialization is done + adr lr, __after_proc_init @ return (PIC) address + add pc, r10, #PROCINFO_INITFUNC + +/* + * Set the Control Register and Read the process ID. + */ + .type __after_proc_init, %function +__after_proc_init: + mrc p15, 0, r0, c1, c0, 0 @ read control reg +#ifdef CONFIG_ALIGNMENT_TRAP + orr r0, r0, #CR_A +#else + bic r0, r0, #CR_A +#endif +#ifdef CONFIG_CPU_DCACHE_DISABLE + bic r0, r0, #CR_C +#endif +#ifdef CONFIG_CPU_BPREDICT_DISABLE + bic r0, r0, #CR_Z +#endif +#ifdef CONFIG_CPU_ICACHE_DISABLE + bic r0, r0, #CR_I +#endif + mcr p15, 0, r0, c1, c0, 0 @ write control reg + + mov pc, r13 @ clear the BSS and jump + @ to start_kernel + +#include "head-common.S" diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 53b6901f70a..04b66a9328e 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -102,49 +102,6 @@ ENTRY(stext) adr lr, __enable_mmu @ return (PIC) address add pc, r10, #PROCINFO_INITFUNC - .type __switch_data, %object -__switch_data: - .long __mmap_switched - .long __data_loc @ r4 - .long __data_start @ r5 - .long __bss_start @ r6 - .long _end @ r7 - .long processor_id @ r4 - .long __machine_arch_type @ r5 - .long cr_alignment @ r6 - .long init_thread_union + THREAD_START_SP @ sp - -/* - * The following fragment of code is executed with the MMU on, and uses - * absolute addresses; this is not position independent. - * - * r0 = cp#15 control register - * r1 = machine ID - * r9 = processor ID - */ - .type __mmap_switched, %function -__mmap_switched: - adr r3, __switch_data + 4 - - ldmia r3!, {r4, r5, r6, r7} - cmp r4, r5 @ Copy data segment if needed -1: cmpne r5, r6 - ldrne fp, [r4], #4 - strne fp, [r5], #4 - bne 1b - - mov fp, #0 @ Clear BSS (and zero fp) -1: cmp r6, r7 - strcc fp, [r6],#4 - bcc 1b - - ldmia r3, {r4, r5, r6, sp} - str r9, [r4] @ Save processor ID - str r1, [r5] @ Save machine type - bic r4, r0, #CR_A @ Clear 'A' bit - stmia r6, {r0, r4} @ Save control register values - b start_kernel - #if defined(CONFIG_SMP) .type secondary_startup, #function ENTRY(secondary_startup) @@ -367,166 +324,4 @@ __create_page_tables: mov pc, lr .ltorg - - -/* - * Exception handling. Something went wrong and we can't proceed. We - * ought to tell the user, but since we don't have any guarantee that - * we're even running on the right architecture, we do virtually nothing. - * - * If CONFIG_DEBUG_LL is set we try to print out something about the error - * and hope for the best (useful if bootloader fails to pass a proper - * machine ID for example). - */ - - .type __error_p, %function -__error_p: -#ifdef CONFIG_DEBUG_LL - adr r0, str_p1 - bl printascii - b __error -str_p1: .asciz "\nError: unrecognized/unsupported processor variant.\n" - .align -#endif - - .type __error_a, %function -__error_a: -#ifdef CONFIG_DEBUG_LL - mov r4, r1 @ preserve machine ID - adr r0, str_a1 - bl printascii - mov r0, r4 - bl printhex8 - adr r0, str_a2 - bl printascii - adr r3, 3f - ldmia r3, {r4, r5, r6} @ get machine desc list - sub r4, r3, r4 @ get offset between virt&phys - add r5, r5, r4 @ convert virt addresses to - add r6, r6, r4 @ physical address space -1: ldr r0, [r5, #MACHINFO_TYPE] @ get machine type - bl printhex8 - mov r0, #'\t' - bl printch - ldr r0, [r5, #MACHINFO_NAME] @ get machine name - add r0, r0, r4 - bl printascii - mov r0, #'\n' - bl printch - add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc - cmp r5, r6 - blo 1b - adr r0, str_a3 - bl printascii - b __error -str_a1: .asciz "\nError: unrecognized/unsupported machine ID (r1 = 0x" -str_a2: .asciz ").\n\nAvailable machine support:\n\nID (hex)\tNAME\n" -str_a3: .asciz "\nPlease check your kernel config and/or bootloader.\n" - .align -#endif - - .type __error, %function -__error: -#ifdef CONFIG_ARCH_RPC -/* - * Turn the screen red on a error - RiscPC only. - */ - mov r0, #0x02000000 - mov r3, #0x11 - orr r3, r3, r3, lsl #8 - orr r3, r3, r3, lsl #16 - str r3, [r0], #4 - str r3, [r0], #4 - str r3, [r0], #4 - str r3, [r0], #4 -#endif -1: mov r0, r0 - b 1b - - -/* - * Read processor ID register (CP#15, CR0), and look up in the linker-built - * supported processor list. Note that we can't use the absolute addresses - * for the __proc_info lists since we aren't running with the MMU on - * (and therefore, we are not in the correct address space). We have to - * calculate the offset. - * - * r9 = cpuid - * Returns: - * r3, r4, r6 corrupted - * r5 = proc_info pointer in physical address space - * r9 = cpuid (preserved) - */ - .type __lookup_processor_type, %function -__lookup_processor_type: - adr r3, 3f - ldmda r3, {r5 - r7} - sub r3, r3, r7 @ get offset between virt&phys - add r5, r5, r3 @ convert virt addresses to - add r6, r6, r3 @ physical address space -1: ldmia r5, {r3, r4} @ value, mask - and r4, r4, r9 @ mask wanted bits - teq r3, r4 - beq 2f - add r5, r5, #PROC_INFO_SZ @ sizeof(proc_info_list) - cmp r5, r6 - blo 1b - mov r5, #0 @ unknown processor -2: mov pc, lr - -/* - * This provides a C-API version of the above function. - */ -ENTRY(lookup_processor_type) - stmfd sp!, {r4 - r7, r9, lr} - mov r9, r0 - bl __lookup_processor_type - mov r0, r5 - ldmfd sp!, {r4 - r7, r9, pc} - -/* - * Look in include/asm-arm/procinfo.h and arch/arm/kernel/arch.[ch] for - * more information about the __proc_info and __arch_info structures. - */ - .long __proc_info_begin - .long __proc_info_end -3: .long . - .long __arch_info_begin - .long __arch_info_end - -/* - * Lookup machine architecture in the linker-build list of architectures. - * Note that we can't use the absolute addresses for the __arch_info - * lists since we aren't running with the MMU on (and therefore, we are - * not in the correct address space). We have to calculate the offset. - * - * r1 = machine architecture number - * Returns: - * r3, r4, r6 corrupted - * r5 = mach_info pointer in physical address space - */ - .type __lookup_machine_type, %function -__lookup_machine_type: - adr r3, 3b - ldmia r3, {r4, r5, r6} - sub r3, r3, r4 @ get offset between virt&phys - add r5, r5, r3 @ convert virt addresses to - add r6, r6, r3 @ physical address space -1: ldr r3, [r5, #MACHINFO_TYPE] @ get machine type - teq r3, r1 @ matches loader number? - beq 2f @ found - add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc - cmp r5, r6 - blo 1b - mov r5, #0 @ unknown machine -2: mov pc, lr - -/* - * This provides a C-API version of the above function. - */ -ENTRY(lookup_machine_type) - stmfd sp!, {r4 - r6, lr} - mov r1, r0 - bl __lookup_machine_type - mov r0, r5 - ldmfd sp!, {r4 - r6, pc} +#include "head-common.S" diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 489c069e5c3..1ff75cee4b0 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -474,4 +474,3 @@ unsigned long get_wchan(struct task_struct *p) } while (count ++ < 16); return 0; } -EXPORT_SYMBOL(get_wchan); diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index b7cd280bfd6..43752840395 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -252,6 +252,9 @@ static void __init dump_cpu_info(int cpu) dump_cache("cache", cpu, CACHE_ISIZE(info)); } } + + if (arch_is_coherent()) + printk("Cache coherency enabled\n"); } int cpu_architecture(void) diff --git a/arch/arm/kernel/signal.h b/arch/arm/kernel/signal.h index 9991049c522..27beece1550 100644 --- a/arch/arm/kernel/signal.h +++ b/arch/arm/kernel/signal.h @@ -7,6 +7,6 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#define KERN_SIGRETURN_CODE 0xffff0500 +#define KERN_SIGRETURN_CODE (CONFIG_VECTORS_BASE + 0x00000500) extern const unsigned long sigreturn_codes[7]; diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index d566d5f4574..35230a06010 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -688,6 +688,7 @@ EXPORT_SYMBOL(abort); void __init trap_init(void) { + unsigned long vectors = CONFIG_VECTORS_BASE; extern char __stubs_start[], __stubs_end[]; extern char __vectors_start[], __vectors_end[]; extern char __kuser_helper_start[], __kuser_helper_end[]; @@ -698,9 +699,9 @@ void __init trap_init(void) * into the vector page, mapped at 0xffff0000, and ensure these * are visible to the instruction stream. */ - memcpy((void *)0xffff0000, __vectors_start, __vectors_end - __vectors_start); - memcpy((void *)0xffff0200, __stubs_start, __stubs_end - __stubs_start); - memcpy((void *)0xffff1000 - kuser_sz, __kuser_helper_start, kuser_sz); + memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start); + memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start); + memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz); /* * Copy signal return handlers into the vector page, and @@ -709,6 +710,6 @@ void __init trap_init(void) memcpy((void *)KERN_SIGRETURN_CODE, sigreturn_codes, sizeof(sigreturn_codes)); - flush_icache_range(0xffff0000, 0xffff0000 + PAGE_SIZE); + flush_icache_range(vectors, vectors + PAGE_SIZE); modify_domain(DOMAIN_USER, DOMAIN_CLIENT); } diff --git a/arch/arm/mach-at91rm9200/Makefile b/arch/arm/mach-at91rm9200/Makefile index 75e6ee318de..ef88c4128ed 100644 --- a/arch/arm/mach-at91rm9200/Makefile +++ b/arch/arm/mach-at91rm9200/Makefile @@ -16,11 +16,12 @@ obj-$(CONFIG_MACH_CSB637) += board-csb637.o #obj-$(CONFIG_MACH_KB9200) += board-kb9202.o # LEDs support -#led-$(CONFIG_ARCH_AT91RM9200DK) += leds.o -#led-$(CONFIG_MACH_AT91RM9200EK) += leds.o -#led-$(CONFIG_MACH_CSB337) += leds.o -#led-$(CONFIG_MACH_CSB637) += leds.o +led-$(CONFIG_ARCH_AT91RM9200DK) += leds.o +led-$(CONFIG_MACH_AT91RM9200EK) += leds.o +led-$(CONFIG_MACH_CSB337) += leds.o +led-$(CONFIG_MACH_CSB637) += leds.o #led-$(CONFIG_MACH_KB9200) += leds.o +#led-$(CONFIG_MACH_KAFA) += leds.o obj-$(CONFIG_LEDS) += $(led-y) # VGA support diff --git a/arch/arm/mach-at91rm9200/board-csb337.c b/arch/arm/mach-at91rm9200/board-csb337.c index 54022e58d50..f45104ceea8 100644 --- a/arch/arm/mach-at91rm9200/board-csb337.c +++ b/arch/arm/mach-at91rm9200/board-csb337.c @@ -67,6 +67,9 @@ static void __init csb337_map_io(void) /* Initialize clocks: 3.6864 MHz crystal */ at91_clock_init(3686400); + /* Setup the LEDs */ + at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2); + #ifdef CONFIG_SERIAL_AT91 at91_console_port = CSB337_SERIAL_CONSOLE; memcpy(at91_serial_map, serial, sizeof(serial)); diff --git a/arch/arm/mach-at91rm9200/board-csb637.c b/arch/arm/mach-at91rm9200/board-csb637.c index 8195f9d919e..f2c2d6e79bc 100644 --- a/arch/arm/mach-at91rm9200/board-csb637.c +++ b/arch/arm/mach-at91rm9200/board-csb637.c @@ -67,6 +67,9 @@ static void __init csb637_map_io(void) /* Initialize clocks: 3.6864 MHz crystal */ at91_clock_init(3686400); + /* Setup the LEDs */ + at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2); + #ifdef CONFIG_SERIAL_AT91 at91_console_port = CSB637_SERIAL_CONSOLE; memcpy(at91_serial_map, serial, sizeof(serial)); diff --git a/arch/arm/mach-at91rm9200/board-dk.c b/arch/arm/mach-at91rm9200/board-dk.c index 8a783368366..2d7200ed66e 100644 --- a/arch/arm/mach-at91rm9200/board-dk.c +++ b/arch/arm/mach-at91rm9200/board-dk.c @@ -70,6 +70,9 @@ static void __init dk_map_io(void) /* Initialize clocks: 18.432 MHz crystal */ at91_clock_init(18432000); + /* Setup the LEDs */ + at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2); + #ifdef CONFIG_SERIAL_AT91 at91_console_port = DK_SERIAL_CONSOLE; memcpy(at91_serial_map, serial, sizeof(serial)); @@ -118,9 +121,14 @@ static void __init dk_board_init(void) at91_add_device_udc(&dk_udc_data); /* Compact Flash */ at91_add_device_cf(&dk_cf_data); +#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD + /* DataFlash card */ + at91_set_gpio_output(AT91_PIN_PB7, 0); +#else /* MMC */ - at91_set_gpio_output(AT91_PIN_PB7, 1); /* this MMC card slot can optionally use SPI signaling (CS3). default: MMC */ + at91_set_gpio_output(AT91_PIN_PB7, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */ at91_add_device_mmc(&dk_mmc_data); +#endif /* VGA */ // dk_add_device_video(); } diff --git a/arch/arm/mach-at91rm9200/board-ek.c b/arch/arm/mach-at91rm9200/board-ek.c index fd0752eba89..80d90f5135a 100644 --- a/arch/arm/mach-at91rm9200/board-ek.c +++ b/arch/arm/mach-at91rm9200/board-ek.c @@ -70,6 +70,9 @@ static void __init ek_map_io(void) /* Initialize clocks: 18.432 MHz crystal */ at91_clock_init(18432000); + /* Setup the LEDs */ + at91_init_leds(AT91_PIN_PB1, AT91_PIN_PB2); + #ifdef CONFIG_SERIAL_AT91 at91_console_port = EK_SERIAL_CONSOLE; memcpy(at91_serial_map, serial, sizeof(serial)); @@ -111,9 +114,14 @@ static void __init ek_board_init(void) at91_add_device_usbh(&ek_usbh_data); /* USB Device */ at91_add_device_udc(&ek_udc_data); +#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD + /* DataFlash card */ + at91_set_gpio_output(AT91_PIN_PB22, 0); +#else /* MMC */ - at91_set_gpio_output(AT91_PIN_PB22, 1); /* this MMC card slot can optionally use SPI signaling (CS3). default: MMC */ + at91_set_gpio_output(AT91_PIN_PB22, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */ at91_add_device_mmc(&ek_mmc_data); +#endif /* VGA */ // ek_add_device_video(); } diff --git a/arch/arm/mach-at91rm9200/devices.c b/arch/arm/mach-at91rm9200/devices.c index 57eedd5beaf..1781b8f342c 100644 --- a/arch/arm/mach-at91rm9200/devices.c +++ b/arch/arm/mach-at91rm9200/devices.c @@ -28,10 +28,10 @@ static u64 ohci_dmamask = 0xffffffffUL; static struct at91_usbh_data usbh_data; -static struct resource at91rm9200_usbh_resource[] = { +static struct resource at91_usbh_resource[] = { [0] = { .start = AT91_UHP_BASE, - .end = AT91_UHP_BASE + SZ_1M -1, + .end = AT91_UHP_BASE + SZ_1M - 1, .flags = IORESOURCE_MEM, }, [1] = { @@ -49,8 +49,8 @@ static struct platform_device at91rm9200_usbh_device = { .coherent_dma_mask = 0xffffffff, .platform_data = &usbh_data, }, - .resource = at91rm9200_usbh_resource, - .num_resources = ARRAY_SIZE(at91rm9200_usbh_resource), + .resource = at91_usbh_resource, + .num_resources = ARRAY_SIZE(at91_usbh_resource), }; void __init at91_add_device_usbh(struct at91_usbh_data *data) @@ -121,6 +121,19 @@ void __init at91_add_device_udc(struct at91_udc_data *data) {} static u64 eth_dmamask = 0xffffffffUL; static struct at91_eth_data eth_data; +static struct resource at91_eth_resources[] = { + [0] = { + .start = AT91_BASE_EMAC, + .end = AT91_BASE_EMAC + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT91_ID_EMAC, + .end = AT91_ID_EMAC, + .flags = IORESOURCE_IRQ, + }, +}; + static struct platform_device at91rm9200_eth_device = { .name = "at91_ether", .id = -1, @@ -129,7 +142,8 @@ static struct platform_device at91rm9200_eth_device = { .coherent_dma_mask = 0xffffffff, .platform_data = ð_data, }, - .num_resources = 0, + .resource = at91_eth_resources, + .num_resources = ARRAY_SIZE(at91_eth_resources), }; void __init at91_add_device_eth(struct at91_eth_data *data) @@ -224,15 +238,20 @@ static u64 mmc_dmamask = 0xffffffffUL; static struct at91_mmc_data mmc_data; static struct resource at91_mmc_resources[] = { - { + [0] = { .start = AT91_BASE_MCI, .end = AT91_BASE_MCI + SZ_16K - 1, .flags = IORESOURCE_MEM, - } + }, + [1] = { + .start = AT91_ID_MCI, + .end = AT91_ID_MCI, + .flags = IORESOURCE_IRQ, + }, }; static struct platform_device at91rm9200_mmc_device = { - .name = "at91rm9200_mci", + .name = "at91_mci", .id = -1, .dev = { .dma_mask = &mmc_dmamask, @@ -290,4 +309,123 @@ void __init at91_add_device_mmc(struct at91_mmc_data *data) void __init at91_add_device_mmc(struct at91_mmc_data *data) {} #endif +/* -------------------------------------------------------------------- + * NAND / SmartMedia + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_MTD_NAND_AT91) || defined(CONFIG_MTD_NAND_AT91_MODULE) +static struct at91_nand_data nand_data; + +static struct resource at91_nand_resources[] = { + { + .start = AT91_SMARTMEDIA_BASE, + .end = AT91_SMARTMEDIA_BASE + SZ_8M - 1, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device at91_nand_device = { + .name = "at91_nand", + .id = -1, + .dev = { + .platform_data = &nand_data, + }, + .resource = at91_nand_resources, + .num_resources = ARRAY_SIZE(at91_nand_resources), +}; + +void __init at91_add_device_nand(struct at91_nand_data *data) +{ + if (!data) + return; + + /* enable pin */ + if (data->enable_pin) + at91_set_gpio_output(data->enable_pin, 1); + + /* ready/busy pin */ + if (data->rdy_pin) + at91_set_gpio_input(data->rdy_pin, 1); + + /* card detect pin */ + if (data->det_pin) + at91_set_gpio_input(data->det_pin, 1); + + at91_set_A_periph(AT91_PIN_PC1, 0); /* SMOE */ + at91_set_A_periph(AT91_PIN_PC3, 0); /* SMWE */ + + nand_data = *data; + platform_device_register(&at91_nand_device); +} +#else +void __init at91_add_device_nand(struct at91_nand_data *data) {} +#endif + + +/* -------------------------------------------------------------------- + * TWI (i2c) + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE) +static struct platform_device at91rm9200_twi_device = { + .name = "at91_i2c", + .id = -1, + .num_resources = 0, +}; + +void __init at91_add_device_i2c(void) +{ + /* pins used for TWI interface */ + at91_set_A_periph(AT91_PIN_PA25, 0); /* TWD */ + at91_set_multi_drive(AT91_PIN_PA25, 1); + + at91_set_A_periph(AT91_PIN_PA26, 0); /* TWCK */ + at91_set_multi_drive(AT91_PIN_PA26, 1); + + platform_device_register(&at91rm9200_twi_device); +} +#else +void __init at91_add_device_i2c(void) {} +#endif + + +/* -------------------------------------------------------------------- + * RTC + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_AT91_RTC) || defined(CONFIG_AT91_RTC_MODULE) +static struct platform_device at91rm9200_rtc_device = { + .name = "at91_rtc", + .id = -1, + .num_resources = 0, +}; + +void __init at91_add_device_rtc(void) +{ + platform_device_register(&at91rm9200_rtc_device); +} +#else +void __init at91_add_device_rtc(void) {} +#endif + + +/* -------------------------------------------------------------------- + * LEDs + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_LEDS) +u8 at91_leds_cpu; +u8 at91_leds_timer; + +void __init at91_init_leds(u8 cpu_led, u8 timer_led) +{ + at91_leds_cpu = cpu_led; + at91_leds_timer = timer_led; +} + +#else +void __init at91_init_leds(u8 cpu_led, u8 timer_led) {} +#endif + + /* -------------------------------------------------------------------- */ diff --git a/arch/arm/mach-at91rm9200/leds.c b/arch/arm/mach-at91rm9200/leds.c new file mode 100644 index 00000000000..28150e8905b --- /dev/null +++ b/arch/arm/mach-at91rm9200/leds.c @@ -0,0 +1,100 @@ +/* + * LED driver for Atmel AT91-based boards. + * + * Copyright (C) SAN People (Pty) Ltd + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. +*/ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> + +#include <asm/mach-types.h> +#include <asm/leds.h> +#include <asm/arch/board.h> +#include <asm/arch/gpio.h> + + +static inline void at91_led_on(unsigned int led) +{ + at91_set_gpio_value(led, 0); +} + +static inline void at91_led_off(unsigned int led) +{ + at91_set_gpio_value(led, 1); +} + +static inline void at91_led_toggle(unsigned int led) +{ + unsigned long is_off = at91_get_gpio_value(led); + if (is_off) + at91_led_on(led); + else + at91_led_off(led); +} + + +/* + * Handle LED events. + */ +static void at91_leds_event(led_event_t evt) +{ + unsigned long flags; + + local_irq_save(flags); + + switch(evt) { + case led_start: /* System startup */ + at91_led_on(at91_leds_cpu); + break; + + case led_stop: /* System stop / suspend */ + at91_led_off(at91_leds_cpu); + break; + +#ifdef CONFIG_LEDS_TIMER + case led_timer: /* Every 50 timer ticks */ + at91_led_toggle(at91_leds_timer); + break; +#endif + +#ifdef CONFIG_LEDS_CPU + case led_idle_start: /* Entering idle state */ + at91_led_off(at91_leds_cpu); + break; + + case led_idle_end: /* Exit idle state */ + at91_led_on(at91_leds_cpu); + break; +#endif + + default: + break; + } + + local_irq_restore(flags); +} + + +static int __init leds_init(void) +{ + if (!at91_leds_timer || !at91_leds_cpu) + return -ENODEV; + + /* Enable PIO to access the LEDs */ + at91_set_gpio_output(at91_leds_timer, 1); + at91_set_gpio_output(at91_leds_cpu, 1); + + leds_event = at91_leds_event; + + leds_event(led_start); + return 0; +} + +__initcall(leds_init); diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c index 2d892e4daa0..dcd41762538 100644 --- a/arch/arm/mach-ep93xx/core.c +++ b/arch/arm/mach-ep93xx/core.c @@ -424,6 +424,14 @@ static struct amba_device uart3_device = { .periphid = 0x00041010, }; + +static struct platform_device ep93xx_rtc_device = { + .name = "ep93xx-rtc", + .id = -1, + .num_resources = 0, +}; + + void __init ep93xx_init_devices(void) { unsigned int v; @@ -439,4 +447,6 @@ void __init ep93xx_init_devices(void) amba_device_register(&uart1_device, &iomem_resource); amba_device_register(&uart2_device, &iomem_resource); amba_device_register(&uart3_device, &iomem_resource); + + platform_device_register(&ep93xx_rtc_device); } diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c index 777e75daa8a..9be01b0c3f4 100644 --- a/arch/arm/mach-ep93xx/ts72xx.c +++ b/arch/arm/mach-ep93xx/ts72xx.c @@ -17,6 +17,8 @@ #include <linux/sched.h> #include <linux/interrupt.h> #include <linux/mtd/physmap.h> +#include <linux/platform_device.h> +#include <linux/m48t86.h> #include <asm/io.h> #include <asm/hardware.h> #include <asm/mach-types.h> @@ -39,6 +41,16 @@ static struct map_desc ts72xx_io_desc[] __initdata = { .pfn = __phys_to_pfn(TS72XX_OPTIONS2_PHYS_BASE), .length = TS72XX_OPTIONS2_SIZE, .type = MT_DEVICE, + }, { + .virtual = TS72XX_RTC_INDEX_VIRT_BASE, + .pfn = __phys_to_pfn(TS72XX_RTC_INDEX_PHYS_BASE), + .length = TS72XX_RTC_INDEX_SIZE, + .type = MT_DEVICE, + }, { + .virtual = TS72XX_RTC_DATA_VIRT_BASE, + .pfn = __phys_to_pfn(TS72XX_RTC_DATA_PHYS_BASE), + .length = TS72XX_RTC_DATA_SIZE, + .type = MT_DEVICE, } }; @@ -99,11 +111,38 @@ static void __init ts72xx_map_io(void) } } +static unsigned char ts72xx_rtc_readb(unsigned long addr) +{ + __raw_writeb(addr, TS72XX_RTC_INDEX_VIRT_BASE); + return __raw_readb(TS72XX_RTC_DATA_VIRT_BASE); +} + +static void ts72xx_rtc_writeb(unsigned char value, unsigned long addr) +{ + __raw_writeb(addr, TS72XX_RTC_INDEX_VIRT_BASE); + __raw_writeb(value, TS72XX_RTC_DATA_VIRT_BASE); +} + +static struct m48t86_ops ts72xx_rtc_ops = { + .readb = ts72xx_rtc_readb, + .writeb = ts72xx_rtc_writeb, +}; + +static struct platform_device ts72xx_rtc_device = { + .name = "rtc-m48t86", + .id = -1, + .dev = { + .platform_data = &ts72xx_rtc_ops, + }, + .num_resources = 0, +}; + static void __init ts72xx_init_machine(void) { ep93xx_init_devices(); if (board_is_ts7200()) physmap_configure(TS72XX_NOR_PHYS_BASE, 0x01000000, 1, NULL); + platform_device_register(&ts72xx_rtc_device); } MACHINE_START(TS72XX, "Technologic Systems TS-72xx SBC") diff --git a/arch/arm/mach-imx/dma.c b/arch/arm/mach-imx/dma.c index 71a59e19616..4ca51dcf13a 100644 --- a/arch/arm/mach-imx/dma.c +++ b/arch/arm/mach-imx/dma.c @@ -7,11 +7,18 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * 03/03/2004 Sascha Hauer <sascha@saschahauer.de> + * 2004-03-03 Sascha Hauer <sascha@saschahauer.de> * initial version heavily inspired by * linux/arch/arm/mach-pxa/dma.c + * + * 2005-04-17 Pavel Pisa <pisa@cmp.felk.cvut.cz> + * Changed to support scatter gather DMA + * by taking Russell's code from RiscPC + * */ +#undef DEBUG + #include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> @@ -22,69 +29,368 @@ #include <asm/irq.h> #include <asm/hardware.h> #include <asm/dma.h> +#include <asm/arch/imx-dma.h> + +struct imx_dma_channel imx_dma_channels[IMX_DMA_CHANNELS]; + +/* + * imx_dma_sg_next - prepare next chunk for scatter-gather DMA emulation + * @dma_ch: i.MX DMA channel number + * @lastcount: number of bytes transferred during last transfer + * + * Functions prepares DMA controller for next sg data chunk transfer. + * The @lastcount argument informs function about number of bytes transferred + * during last block. Zero value can be used for @lastcount to setup DMA + * for the first chunk. + */ +static inline int imx_dma_sg_next(imx_dmach_t dma_ch, unsigned int lastcount) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; + unsigned int nextcount; + unsigned int nextaddr; + + if (!imxdma->name) { + printk(KERN_CRIT "%s: called for not allocated channel %d\n", + __FUNCTION__, dma_ch); + return 0; + } + + imxdma->resbytes -= lastcount; + + if (!imxdma->sg) { + pr_debug("imxdma%d: no sg data\n", dma_ch); + return 0; + } + + imxdma->sgbc += lastcount; + if ((imxdma->sgbc >= imxdma->sg->length) || !imxdma->resbytes) { + if ((imxdma->sgcount <= 1) || !imxdma->resbytes) { + pr_debug("imxdma%d: sg transfer limit reached\n", + dma_ch); + imxdma->sgcount=0; + imxdma->sg = NULL; + return 0; + } else { + imxdma->sgcount--; + imxdma->sg++; + imxdma->sgbc = 0; + } + } + nextcount = imxdma->sg->length - imxdma->sgbc; + nextaddr = imxdma->sg->dma_address + imxdma->sgbc; -static struct dma_channel { - char *name; - void (*irq_handler) (int, void *, struct pt_regs *); - void (*err_handler) (int, void *, struct pt_regs *); - void *data; -} dma_channels[11]; + if(imxdma->resbytes < nextcount) + nextcount = imxdma->resbytes; -/* set err_handler to NULL to have the standard info-only error handler */ + if ((imxdma->dma_mode & DMA_MODE_MASK) == DMA_MODE_READ) + DAR(dma_ch) = nextaddr; + else + SAR(dma_ch) = nextaddr; + + CNTR(dma_ch) = nextcount; + pr_debug("imxdma%d: next sg chunk dst 0x%08x, src 0x%08x, size 0x%08x\n", + dma_ch, DAR(dma_ch), SAR(dma_ch), CNTR(dma_ch)); + + return nextcount; +} + +/* + * imx_dma_setup_sg_base - scatter-gather DMA emulation + * @dma_ch: i.MX DMA channel number + * @sg: pointer to the scatter-gather list/vector + * @sgcount: scatter-gather list hungs count + * + * Functions sets up i.MX DMA state for emulated scatter-gather transfer + * and sets up channel registers to be ready for the first chunk + */ +static int +imx_dma_setup_sg_base(imx_dmach_t dma_ch, + struct scatterlist *sg, unsigned int sgcount) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; + + imxdma->sg = sg; + imxdma->sgcount = sgcount; + imxdma->sgbc = 0; + return imx_dma_sg_next(dma_ch, 0); +} + +/** + * imx_dma_setup_single - setup i.MX DMA channel for linear memory to/from device transfer + * @dma_ch: i.MX DMA channel number + * @dma_address: the DMA/physical memory address of the linear data block + * to transfer + * @dma_length: length of the data block in bytes + * @dev_addr: physical device port address + * @dmamode: DMA transfer mode, %DMA_MODE_READ from the device to the memory + * or %DMA_MODE_WRITE from memory to the device + * + * The function setups DMA channel source and destination addresses for transfer + * specified by provided parameters. The scatter-gather emulation is disabled, + * because linear data block + * form the physical address range is transfered. + * Return value: if incorrect parameters are provided -%EINVAL. + * Zero indicates success. + */ int -imx_request_dma(char *name, imx_dma_prio prio, - void (*irq_handler) (int, void *, struct pt_regs *), - void (*err_handler) (int, void *, struct pt_regs *), void *data) +imx_dma_setup_single(imx_dmach_t dma_ch, dma_addr_t dma_address, + unsigned int dma_length, unsigned int dev_addr, + dmamode_t dmamode) { - unsigned long flags; - int i, found = 0; + struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; - /* basic sanity checks */ - if (!name || !irq_handler) + imxdma->sg = NULL; + imxdma->sgcount = 0; + imxdma->dma_mode = dmamode; + imxdma->resbytes = dma_length; + + if (!dma_address) { + printk(KERN_ERR "imxdma%d: imx_dma_setup_single null address\n", + dma_ch); return -EINVAL; + } - local_irq_save(flags); + if (!dma_length) { + printk(KERN_ERR "imxdma%d: imx_dma_setup_single zero length\n", + dma_ch); + return -EINVAL; + } - /* try grabbing a DMA channel with the requested priority */ - for (i = prio; i < prio + (prio == DMA_PRIO_LOW) ? 8 : 4; i++) { - if (!dma_channels[i].name) { - found = 1; - break; - } + if ((dmamode & DMA_MODE_MASK) == DMA_MODE_READ) { + pr_debug("imxdma%d: mx_dma_setup_single2dev dma_addressg=0x%08x dma_length=%d dev_addr=0x%08x for read\n", + dma_ch, (unsigned int)dma_address, dma_length, + dev_addr); + SAR(dma_ch) = dev_addr; + DAR(dma_ch) = (unsigned int)dma_address; + } else if ((dmamode & DMA_MODE_MASK) == DMA_MODE_WRITE) { + pr_debug("imxdma%d: mx_dma_setup_single2dev dma_addressg=0x%08x dma_length=%d dev_addr=0x%08x for write\n", + dma_ch, (unsigned int)dma_address, dma_length, + dev_addr); + SAR(dma_ch) = (unsigned int)dma_address; + DAR(dma_ch) = dev_addr; + } else { + printk(KERN_ERR "imxdma%d: imx_dma_setup_single bad dmamode\n", + dma_ch); + return -EINVAL; } - if (!found) { - /* requested prio group is full, try hier priorities */ - for (i = prio - 1; i >= 0; i--) { - if (!dma_channels[i].name) { - found = 1; - break; - } - } + CNTR(dma_ch) = dma_length; + + return 0; +} + +/** + * imx_dma_setup_sg - setup i.MX DMA channel SG list to/from device transfer + * @dma_ch: i.MX DMA channel number + * @sg: pointer to the scatter-gather list/vector + * @sgcount: scatter-gather list hungs count + * @dma_length: total length of the transfer request in bytes + * @dev_addr: physical device port address + * @dmamode: DMA transfer mode, %DMA_MODE_READ from the device to the memory + * or %DMA_MODE_WRITE from memory to the device + * + * The function setups DMA channel state and registers to be ready for transfer + * specified by provided parameters. The scatter-gather emulation is set up + * according to the parameters. + * + * The full preparation of the transfer requires setup of more register + * by the caller before imx_dma_enable() can be called. + * + * %BLR(dma_ch) holds transfer burst length in bytes, 0 means 64 bytes + * + * %RSSR(dma_ch) has to be set to the DMA request line source %DMA_REQ_xxx + * + * %CCR(dma_ch) has to specify transfer parameters, the next settings is typical + * for linear or simple scatter-gather transfers if %DMA_MODE_READ is specified + * + * %CCR_DMOD_LINEAR | %CCR_DSIZ_32 | %CCR_SMOD_FIFO | %CCR_SSIZ_x + * + * The typical setup for %DMA_MODE_WRITE is specified by next options combination + * + * %CCR_SMOD_LINEAR | %CCR_SSIZ_32 | %CCR_DMOD_FIFO | %CCR_DSIZ_x + * + * Be carefull there and do not mistakenly mix source and target device + * port sizes constants, they are really different: + * %CCR_SSIZ_8, %CCR_SSIZ_16, %CCR_SSIZ_32, + * %CCR_DSIZ_8, %CCR_DSIZ_16, %CCR_DSIZ_32 + * + * Return value: if incorrect parameters are provided -%EINVAL. + * Zero indicates success. + */ +int +imx_dma_setup_sg(imx_dmach_t dma_ch, + struct scatterlist *sg, unsigned int sgcount, unsigned int dma_length, + unsigned int dev_addr, dmamode_t dmamode) +{ + int res; + struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; + + imxdma->sg = NULL; + imxdma->sgcount = 0; + imxdma->dma_mode = dmamode; + imxdma->resbytes = dma_length; + + if (!sg || !sgcount) { + printk(KERN_ERR "imxdma%d: imx_dma_setup_sg epty sg list\n", + dma_ch); + return -EINVAL; + } + + if (!sg->length) { + printk(KERN_ERR "imxdma%d: imx_dma_setup_sg zero length\n", + dma_ch); + return -EINVAL; } - if (found) { - DIMR &= ~(1 << i); - dma_channels[i].name = name; - dma_channels[i].irq_handler = irq_handler; - dma_channels[i].err_handler = err_handler; - dma_channels[i].data = data; + if ((dmamode & DMA_MODE_MASK) == DMA_MODE_READ) { + pr_debug("imxdma%d: mx_dma_setup_sg2dev sg=%p sgcount=%d total length=%d dev_addr=0x%08x for read\n", + dma_ch, sg, sgcount, dma_length, dev_addr); + SAR(dma_ch) = dev_addr; + } else if ((dmamode & DMA_MODE_MASK) == DMA_MODE_WRITE) { + pr_debug("imxdma%d: mx_dma_setup_sg2dev sg=%p sgcount=%d total length=%d dev_addr=0x%08x for write\n", + dma_ch, sg, sgcount, dma_length, dev_addr); + DAR(dma_ch) = dev_addr; } else { - printk(KERN_WARNING "No more available DMA channels for %s\n", - name); - i = -ENODEV; + printk(KERN_ERR "imxdma%d: imx_dma_setup_sg bad dmamode\n", + dma_ch); + return -EINVAL; + } + + res = imx_dma_setup_sg_base(dma_ch, sg, sgcount); + if (res <= 0) { + printk(KERN_ERR "imxdma%d: no sg chunk ready\n", dma_ch); + return -EINVAL; + } + + return 0; +} + +/** + * imx_dma_setup_handlers - setup i.MX DMA channel end and error notification handlers + * @dma_ch: i.MX DMA channel number + * @irq_handler: the pointer to the function called if the transfer + * ends successfully + * @err_handler: the pointer to the function called if the premature + * end caused by error occurs + * @data: user specified value to be passed to the handlers + */ +int +imx_dma_setup_handlers(imx_dmach_t dma_ch, + void (*irq_handler) (int, void *, struct pt_regs *), + void (*err_handler) (int, void *, struct pt_regs *), + void *data) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; + unsigned long flags; + + if (!imxdma->name) { + printk(KERN_CRIT "%s: called for not allocated channel %d\n", + __FUNCTION__, dma_ch); + return -ENODEV; + } + + local_irq_save(flags); + DISR = (1 << dma_ch); + imxdma->irq_handler = irq_handler; + imxdma->err_handler = err_handler; + imxdma->data = data; + local_irq_restore(flags); + return 0; +} + +/** + * imx_dma_enable - function to start i.MX DMA channel operation + * @dma_ch: i.MX DMA channel number + * + * The channel has to be allocated by driver through imx_dma_request() + * or imx_dma_request_by_prio() function. + * The transfer parameters has to be set to the channel registers through + * call of the imx_dma_setup_single() or imx_dma_setup_sg() function + * and registers %BLR(dma_ch), %RSSR(dma_ch) and %CCR(dma_ch) has to + * be set prior this function call by the channel user. + */ +void imx_dma_enable(imx_dmach_t dma_ch) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; + unsigned long flags; + + pr_debug("imxdma%d: imx_dma_enable\n", dma_ch); + + if (!imxdma->name) { + printk(KERN_CRIT "%s: called for not allocated channel %d\n", + __FUNCTION__, dma_ch); + return; + } + + local_irq_save(flags); + DISR = (1 << dma_ch); + DIMR &= ~(1 << dma_ch); + CCR(dma_ch) |= CCR_CEN; + local_irq_restore(flags); +} + +/** + * imx_dma_disable - stop, finish i.MX DMA channel operatin + * @dma_ch: i.MX DMA channel number + */ +void imx_dma_disable(imx_dmach_t dma_ch) +{ + unsigned long flags; + + pr_debug("imxdma%d: imx_dma_disable\n", dma_ch); + + local_irq_save(flags); + DIMR |= (1 << dma_ch); + CCR(dma_ch) &= ~CCR_CEN; + DISR = (1 << dma_ch); + local_irq_restore(flags); +} + +/** + * imx_dma_request - request/allocate specified channel number + * @dma_ch: i.MX DMA channel number + * @name: the driver/caller own non-%NULL identification + */ +int imx_dma_request(imx_dmach_t dma_ch, const char *name) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; + unsigned long flags; + + /* basic sanity checks */ + if (!name) + return -EINVAL; + + if (dma_ch >= IMX_DMA_CHANNELS) { + printk(KERN_CRIT "%s: called for non-existed channel %d\n", + __FUNCTION__, dma_ch); + return -EINVAL; } + local_irq_save(flags); + if (imxdma->name) { + local_irq_restore(flags); + return -ENODEV; + } + + imxdma->name = name; + imxdma->irq_handler = NULL; + imxdma->err_handler = NULL; + imxdma->data = NULL; + imxdma->sg = NULL; local_irq_restore(flags); - return i; + return 0; } -void -imx_free_dma(int dma_ch) +/** + * imx_dma_free - release previously acquired channel + * @dma_ch: i.MX DMA channel number + */ +void imx_dma_free(imx_dmach_t dma_ch) { unsigned long flags; + struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; - if (!dma_channels[dma_ch].name) { + if (!imxdma->name) { printk(KERN_CRIT "%s: trying to free channel %d which is already freed\n", __FUNCTION__, dma_ch); @@ -92,27 +398,84 @@ imx_free_dma(int dma_ch) } local_irq_save(flags); - DIMR &= ~(1 << dma_ch); - dma_channels[dma_ch].name = NULL; + /* Disable interrupts */ + DIMR |= (1 << dma_ch); + CCR(dma_ch) &= ~CCR_CEN; + imxdma->name = NULL; local_irq_restore(flags); } -static irqreturn_t -dma_err_handler(int irq, void *dev_id, struct pt_regs *regs) +/** + * imx_dma_request_by_prio - find and request some of free channels best suiting requested priority + * @dma_ch: i.MX DMA channel number + * @name: the driver/caller own non-%NULL identification + * @prio: one of the hardware distinguished priority level: + * %DMA_PRIO_HIGH, %DMA_PRIO_MEDIUM, %DMA_PRIO_LOW + * + * This function tries to find free channel in the specified priority group + * if the priority cannot be achieved it tries to look for free channel + * in the higher and then even lower priority groups. + * + * Return value: If there is no free channel to allocate, -%ENODEV is returned. + * Zero value indicates successful channel allocation. + */ +int +imx_dma_request_by_prio(imx_dmach_t * pdma_ch, const char *name, + imx_dma_prio prio) +{ + int i; + int best; + + switch (prio) { + case (DMA_PRIO_HIGH): + best = 8; + break; + case (DMA_PRIO_MEDIUM): + best = 4; + break; + case (DMA_PRIO_LOW): + default: + best = 0; + break; + } + + for (i = best; i < IMX_DMA_CHANNELS; i++) { + if (!imx_dma_request(i, name)) { + *pdma_ch = i; + return 0; + } + } + + for (i = best - 1; i >= 0; i--) { + if (!imx_dma_request(i, name)) { + *pdma_ch = i; + return 0; + } + } + + printk(KERN_ERR "%s: no free DMA channel found\n", __FUNCTION__); + + return -ENODEV; +} + +static irqreturn_t dma_err_handler(int irq, void *dev_id, struct pt_regs *regs) { int i, disr = DISR; - struct dma_channel *channel; + struct imx_dma_channel *channel; unsigned int err_mask = DBTOSR | DRTOSR | DSESR | DBOSR; DISR = disr; - for (i = 0; i < 11; i++) { - channel = &dma_channels[i]; + for (i = 0; i < IMX_DMA_CHANNELS; i++) { + channel = &imx_dma_channels[i]; - if ( (err_mask & 1<<i) && channel->name && channel->err_handler) { + if ((err_mask & 1 << i) && channel->name + && channel->err_handler) { channel->err_handler(i, channel->data, regs); continue; } + imx_dma_channels[i].sg = NULL; + if (DBTOSR & (1 << i)) { printk(KERN_WARNING "Burst timeout on channel %d (%s)\n", @@ -141,17 +504,27 @@ dma_err_handler(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -static irqreturn_t -dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) { int i, disr = DISR; + pr_debug("imxdma: dma_irq_handler called, disr=0x%08x\n", + disr); + DISR = disr; - for (i = 0; i < 11; i++) { + for (i = 0; i < IMX_DMA_CHANNELS; i++) { if (disr & (1 << i)) { - struct dma_channel *channel = &dma_channels[i]; - if (channel->name && channel->irq_handler) { - channel->irq_handler(i, channel->data, regs); + struct imx_dma_channel *channel = &imx_dma_channels[i]; + if (channel->name) { + if (imx_dma_sg_next(i, CNTR(i))) { + CCR(i) &= ~CCR_CEN; + mb(); + CCR(i) |= CCR_CEN; + } else { + if (channel->irq_handler) + channel->irq_handler(i, + channel->data, regs); + } } else { /* * IRQ for an unregistered DMA channel: @@ -165,10 +538,10 @@ dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -static int __init -imx_dma_init(void) +static int __init imx_dma_init(void) { int ret; + int i; /* reset DMA module */ DCR = DCR_DRST; @@ -189,15 +562,27 @@ imx_dma_init(void) DCR = DCR_DEN; /* clear all interrupts */ - DISR = 0x3ff; + DISR = (1 << IMX_DMA_CHANNELS) - 1; /* enable interrupts */ - DIMR = 0; + DIMR = (1 << IMX_DMA_CHANNELS) - 1; + + for (i = 0; i < IMX_DMA_CHANNELS; i++) { + imx_dma_channels[i].sg = NULL; + imx_dma_channels[i].dma_num = i; + } return ret; } arch_initcall(imx_dma_init); -EXPORT_SYMBOL(imx_request_dma); -EXPORT_SYMBOL(imx_free_dma); +EXPORT_SYMBOL(imx_dma_setup_single); +EXPORT_SYMBOL(imx_dma_setup_sg); +EXPORT_SYMBOL(imx_dma_setup_handlers); +EXPORT_SYMBOL(imx_dma_enable); +EXPORT_SYMBOL(imx_dma_disable); +EXPORT_SYMBOL(imx_dma_request); +EXPORT_SYMBOL(imx_dma_free); +EXPORT_SYMBOL(imx_dma_request_by_prio); +EXPORT_SYMBOL(imx_dma_channels); diff --git a/arch/arm/mach-imx/generic.c b/arch/arm/mach-imx/generic.c index 37613ad6836..9d8331be2b5 100644 --- a/arch/arm/mach-imx/generic.c +++ b/arch/arm/mach-imx/generic.c @@ -33,6 +33,7 @@ #include <asm/arch/imx-regs.h> #include <asm/mach/map.h> +#include <asm/arch/mmc.h> void imx_gpio_mode(int gpio_mode) { @@ -175,13 +176,25 @@ static struct resource imx_mmc_resources[] = { }, }; +static u64 imxmmmc_dmamask = 0xffffffffUL; + static struct platform_device imx_mmc_device = { .name = "imx-mmc", .id = 0, + .dev = { + .dma_mask = &imxmmmc_dmamask, + .coherent_dma_mask = 0xffffffff, + }, .num_resources = ARRAY_SIZE(imx_mmc_resources), .resource = imx_mmc_resources, }; +void __init imx_set_mmc_info(struct imxmmc_platform_data *info) +{ + imx_mmc_device.dev.platform_data = info; +} +EXPORT_SYMBOL(imx_set_mmc_info); + static struct resource imx_uart1_resources[] = { [0] = { .start = 0x00206000, diff --git a/arch/arm/mach-imx/mx1ads.c b/arch/arm/mach-imx/mx1ads.c index 8ab1b040288..e34d0df90ae 100644 --- a/arch/arm/mach-imx/mx1ads.c +++ b/arch/arm/mach-imx/mx1ads.c @@ -25,6 +25,7 @@ #include <asm/mach-types.h> #include <asm/mach/arch.h> +#include <asm/arch/mmc.h> #include <linux/interrupt.h> #include "generic.h" @@ -51,12 +52,29 @@ static struct platform_device *devices[] __initdata = { &cs89x0_device, }; +#ifdef CONFIG_MMC_IMX +static int mx1ads_mmc_card_present(void) +{ + /* MMC/SD Card Detect is PB 20 on MX1ADS V1.0.7 */ + return (SSR(1) & (1 << 20) ? 0 : 1); +} + +static struct imxmmc_platform_data mx1ads_mmc_info = { + .card_present = mx1ads_mmc_card_present, +}; +#endif + static void __init mx1ads_init(void) { #ifdef CONFIG_LEDS imx_gpio_mode(GPIO_PORTA | GPIO_OUT | 2); #endif +#ifdef CONFIG_MMC_IMX + /* SD/MMC card detect */ + imx_gpio_mode(GPIO_PORTB | GPIO_GIUS | GPIO_IN | 20); + imx_set_mmc_info(&mx1ads_mmc_info); +#endif platform_add_devices(devices, ARRAY_SIZE(devices)); } diff --git a/arch/arm/mach-ixp23xx/espresso.c b/arch/arm/mach-ixp23xx/espresso.c index 2327c979041..bf688c12863 100644 --- a/arch/arm/mach-ixp23xx/espresso.c +++ b/arch/arm/mach-ixp23xx/espresso.c @@ -44,6 +44,15 @@ #include <asm/mach/irq.h> #include <asm/mach/pci.h> +static int __init espresso_pci_init(void) +{ + if (machine_is_espresso()) + ixp23xx_pci_slave_init(); + + return 0; +}; +subsys_initcall(espresso_pci_init); + static void __init espresso_init(void) { physmap_configure(0x90000000, 0x02000000, 2, NULL); diff --git a/arch/arm/mach-ixp23xx/pci.c b/arch/arm/mach-ixp23xx/pci.c index 5330ad78c1b..ac72f94c5b4 100644 --- a/arch/arm/mach-ixp23xx/pci.c +++ b/arch/arm/mach-ixp23xx/pci.c @@ -201,7 +201,7 @@ int clear_master_aborts(void) return 0; } -void __init ixp23xx_pci_preinit(void) +static void __init ixp23xx_pci_common_init(void) { #ifdef __ARMEB__ *IXP23XX_PCI_CONTROL |= 0x20000; /* set I/O swapping */ @@ -219,7 +219,18 @@ void __init ixp23xx_pci_preinit(void) *IXP23XX_PCI_CPP_ADDR_BITS &= ~(1 << 1); } else { *IXP23XX_PCI_CPP_ADDR_BITS |= (1 << 1); + + /* + * Enable coherency on A2 silicon. + */ + if (arch_is_coherent()) + *IXP23XX_CPP2XSI_CURR_XFER_REG3 &= ~IXP23XX_CPP2XSI_COH_OFF; } +} + +void __init ixp23xx_pci_preinit(void) +{ + ixp23xx_pci_common_init(); hook_fault_code(16+6, ixp23xx_pci_abort_handler, SIGBUS, "PCI config cycle to non-existent device"); @@ -273,3 +284,8 @@ int ixp23xx_pci_setup(int nr, struct pci_sys_data *sys) return 1; } + +void ixp23xx_pci_slave_init(void) +{ + ixp23xx_pci_common_init(); +} diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig index 86a0f0d1434..f8d716ccc1d 100644 --- a/arch/arm/mach-omap1/Kconfig +++ b/arch/arm/mach-omap1/Kconfig @@ -69,12 +69,6 @@ config MACH_VOICEBLUE Support for Voiceblue GSM/VoIP gateway. Say Y here if you have such a board. -config MACH_NETSTAR - bool "NetStar" - depends on ARCH_OMAP1 && ARCH_OMAP15XX - help - Support for NetStar PBX. Say Y here if you have such a board. - config MACH_OMAP_PALMTE bool "Palm Tungsten E" depends on ARCH_OMAP1 && ARCH_OMAP15XX @@ -85,6 +79,20 @@ config MACH_OMAP_PALMTE informations. Say Y here if you have such a PDA, say NO otherwise. +config MACH_NOKIA770 + bool "Nokia 770" + depends on ARCH_OMAP1 && ARCH_OMAP16XX + help + Support for the Nokia 770 Internet Tablet. Say Y here if you + have such a device. + +config MACH_AMS_DELTA + bool "Amstrad E3 (Delta)" + depends on ARCH_OMAP1 && ARCH_OMAP15XX + help + Support for the Amstrad E3 (codename Delta) videophone. Say Y here + if you have such a device. + config MACH_OMAP_GENERIC bool "Generic OMAP board" depends on ARCH_OMAP1 && (ARCH_OMAP15XX || ARCH_OMAP16XX) diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile index b0b00156faa..9ea719550ad 100644 --- a/arch/arm/mach-omap1/Makefile +++ b/arch/arm/mach-omap1/Makefile @@ -3,7 +3,13 @@ # # Common support -obj-y := io.o id.o clock.o irq.o time.o mux.o serial.o devices.o +obj-y := io.o id.o clock.o irq.o mux.o serial.o devices.o + +obj-$(CONFIG_OMAP_MPU_TIMER) += time.o + +# Power Management +obj-$(CONFIG_PM) += pm.o sleep.o + led-y := leds.o # Specific board support @@ -14,8 +20,9 @@ obj-$(CONFIG_MACH_OMAP_PERSEUS2) += board-perseus2.o obj-$(CONFIG_MACH_OMAP_OSK) += board-osk.o obj-$(CONFIG_MACH_OMAP_H3) += board-h3.o obj-$(CONFIG_MACH_VOICEBLUE) += board-voiceblue.o -obj-$(CONFIG_MACH_NETSTAR) += board-netstar.o obj-$(CONFIG_MACH_OMAP_PALMTE) += board-palmte.o +obj-$(CONFIG_MACH_NOKIA770) += board-nokia770.o +obj-$(CONFIG_MACH_AMS_DELTA) += board-ams-delta.o ifeq ($(CONFIG_ARCH_OMAP15XX),y) # Innovator-1510 FPGA diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c new file mode 100644 index 00000000000..6178f046f12 --- /dev/null +++ b/arch/arm/mach-omap1/board-ams-delta.c @@ -0,0 +1,116 @@ +/* + * linux/arch/arm/mach-omap1/board-ams-delta.c + * + * Modified from board-generic.c + * + * Board specific inits for the Amstrad E3 (codename Delta) videophone + * + * Copyright (C) 2006 Jonathan McDowell <noodles@earth.li> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> + +#include <asm/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include <asm/arch/board-ams-delta.h> +#include <asm/arch/gpio.h> +#include <asm/arch/mux.h> +#include <asm/arch/usb.h> +#include <asm/arch/board.h> +#include <asm/arch/common.h> + +static u8 ams_delta_latch1_reg; +static u16 ams_delta_latch2_reg; + +void ams_delta_latch1_write(u8 mask, u8 value) +{ + ams_delta_latch1_reg &= ~mask; + ams_delta_latch1_reg |= value; + *(volatile __u8 *) AMS_DELTA_LATCH1_VIRT = ams_delta_latch1_reg; +} + +void ams_delta_latch2_write(u16 mask, u16 value) +{ + ams_delta_latch2_reg &= ~mask; + ams_delta_latch2_reg |= value; + *(volatile __u16 *) AMS_DELTA_LATCH2_VIRT = ams_delta_latch2_reg; +} + +static void __init ams_delta_init_irq(void) +{ + omap1_init_common_hw(); + omap_init_irq(); + omap_gpio_init(); +} + +static struct map_desc ams_delta_io_desc[] __initdata = { + // AMS_DELTA_LATCH1 + { + .virtual = AMS_DELTA_LATCH1_VIRT, + .pfn = __phys_to_pfn(AMS_DELTA_LATCH1_PHYS), + .length = 0x01000000, + .type = MT_DEVICE + }, + // AMS_DELTA_LATCH2 + { + .virtual = AMS_DELTA_LATCH2_VIRT, + .pfn = __phys_to_pfn(AMS_DELTA_LATCH2_PHYS), + .length = 0x01000000, + .type = MT_DEVICE + }, + // AMS_DELTA_MODEM + { + .virtual = AMS_DELTA_MODEM_VIRT, + .pfn = __phys_to_pfn(AMS_DELTA_MODEM_PHYS), + .length = 0x01000000, + .type = MT_DEVICE + } +}; + +static struct omap_uart_config ams_delta_uart_config __initdata = { + .enabled_uarts = 1, +}; + +static struct omap_board_config_kernel ams_delta_config[] = { + { OMAP_TAG_UART, &ams_delta_uart_config }, +}; + +static void __init ams_delta_init(void) +{ + iotable_init(ams_delta_io_desc, ARRAY_SIZE(ams_delta_io_desc)); + + omap_board_config = ams_delta_config; + omap_board_config_size = ARRAY_SIZE(ams_delta_config); + omap_serial_init(); + + /* Clear latch2 (NAND, LCD, modem enable) */ + ams_delta_latch2_write(~0, 0); +} + +static void __init ams_delta_map_io(void) +{ + omap1_map_common_io(); +} + +MACHINE_START(AMS_DELTA, "Amstrad E3 (Delta)") + /* Maintainer: Jonathan McDowell <noodles@earth.li> */ + .phys_io = 0xfff00000, + .io_pg_offst = ((0xfef00000) >> 18) & 0xfffc, + .boot_params = 0x10000100, + .map_io = ams_delta_map_io, + .init_irq = ams_delta_init_irq, + .init_machine = ams_delta_init, + .timer = &omap_timer, +MACHINE_END + +EXPORT_SYMBOL(ams_delta_latch1_write); +EXPORT_SYMBOL(ams_delta_latch2_write); diff --git a/arch/arm/mach-omap1/board-generic.c b/arch/arm/mach-omap1/board-generic.c index a177e78b2b8..33d01adab1e 100644 --- a/arch/arm/mach-omap1/board-generic.c +++ b/arch/arm/mach-omap1/board-generic.c @@ -88,7 +88,7 @@ static struct omap_board_config_kernel generic_config[] = { static void __init omap_generic_init(void) { #ifdef CONFIG_ARCH_OMAP15XX - if (cpu_is_omap1510()) { + if (cpu_is_omap15xx()) { generic_config[0].data = &generic1510_usb_config; } #endif diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c index 89f0cc74a51..cd3a06dfc0a 100644 --- a/arch/arm/mach-omap1/board-h2.c +++ b/arch/arm/mach-omap1/board-h2.c @@ -24,7 +24,9 @@ #include <linux/platform_device.h> #include <linux/delay.h> #include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> #include <linux/mtd/partitions.h> +#include <linux/input.h> #include <asm/hardware.h> #include <asm/mach-types.h> @@ -35,12 +37,55 @@ #include <asm/arch/gpio.h> #include <asm/arch/mux.h> #include <asm/arch/tc.h> +#include <asm/arch/irda.h> #include <asm/arch/usb.h> +#include <asm/arch/keypad.h> #include <asm/arch/common.h> +#include <asm/arch/mcbsp.h> +#include <asm/arch/omap-alsa.h> extern int omap_gpio_init(void); -static struct mtd_partition h2_partitions[] = { +static int h2_keymap[] = { + KEY(0, 0, KEY_LEFT), + KEY(0, 1, KEY_RIGHT), + KEY(0, 2, KEY_3), + KEY(0, 3, KEY_F10), + KEY(0, 4, KEY_F5), + KEY(0, 5, KEY_9), + KEY(1, 0, KEY_DOWN), + KEY(1, 1, KEY_UP), + KEY(1, 2, KEY_2), + KEY(1, 3, KEY_F9), + KEY(1, 4, KEY_F7), + KEY(1, 5, KEY_0), + KEY(2, 0, KEY_ENTER), + KEY(2, 1, KEY_6), + KEY(2, 2, KEY_1), + KEY(2, 3, KEY_F2), + KEY(2, 4, KEY_F6), + KEY(2, 5, KEY_HOME), + KEY(3, 0, KEY_8), + KEY(3, 1, KEY_5), + KEY(3, 2, KEY_F12), + KEY(3, 3, KEY_F3), + KEY(3, 4, KEY_F8), + KEY(3, 5, KEY_END), + KEY(4, 0, KEY_7), + KEY(4, 1, KEY_4), + KEY(4, 2, KEY_F11), + KEY(4, 3, KEY_F1), + KEY(4, 4, KEY_F4), + KEY(4, 5, KEY_ESC), + KEY(5, 0, KEY_F13), + KEY(5, 1, KEY_F14), + KEY(5, 2, KEY_F15), + KEY(5, 3, KEY_F16), + KEY(5, 4, KEY_SLEEP), + 0 +}; + +static struct mtd_partition h2_nor_partitions[] = { /* bootloader (U-Boot, etc) in first sector */ { .name = "bootloader", @@ -71,26 +116,26 @@ static struct mtd_partition h2_partitions[] = { } }; -static struct flash_platform_data h2_flash_data = { +static struct flash_platform_data h2_nor_data = { .map_name = "cfi_probe", .width = 2, - .parts = h2_partitions, - .nr_parts = ARRAY_SIZE(h2_partitions), + .parts = h2_nor_partitions, + .nr_parts = ARRAY_SIZE(h2_nor_partitions), }; -static struct resource h2_flash_resource = { +static struct resource h2_nor_resource = { /* This is on CS3, wherever it's mapped */ .flags = IORESOURCE_MEM, }; -static struct platform_device h2_flash_device = { +static struct platform_device h2_nor_device = { .name = "omapflash", .id = 0, .dev = { - .platform_data = &h2_flash_data, + .platform_data = &h2_nor_data, }, .num_resources = 1, - .resource = &h2_flash_resource, + .resource = &h2_nor_resource, }; static struct resource h2_smc91x_resources[] = { @@ -113,9 +158,119 @@ static struct platform_device h2_smc91x_device = { .resource = h2_smc91x_resources, }; +static struct resource h2_kp_resources[] = { + [0] = { + .start = INT_KEYBOARD, + .end = INT_KEYBOARD, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct omap_kp_platform_data h2_kp_data = { + .rows = 8, + .cols = 8, + .keymap = h2_keymap, + .rep = 1, +}; + +static struct platform_device h2_kp_device = { + .name = "omap-keypad", + .id = -1, + .dev = { + .platform_data = &h2_kp_data, + }, + .num_resources = ARRAY_SIZE(h2_kp_resources), + .resource = h2_kp_resources, +}; + +#define H2_IRDA_FIRSEL_GPIO_PIN 17 + +#if defined(CONFIG_OMAP_IR) || defined(CONFIG_OMAP_IR_MODULE) +static int h2_transceiver_mode(struct device *dev, int state) +{ + if (state & IR_SIRMODE) + omap_set_gpio_dataout(H2_IRDA_FIRSEL_GPIO_PIN, 0); + else /* MIR/FIR */ + omap_set_gpio_dataout(H2_IRDA_FIRSEL_GPIO_PIN, 1); + + return 0; +} +#endif + +static struct omap_irda_config h2_irda_data = { + .transceiver_cap = IR_SIRMODE | IR_MIRMODE | IR_FIRMODE, + .rx_channel = OMAP_DMA_UART3_RX, + .tx_channel = OMAP_DMA_UART3_TX, + .dest_start = UART3_THR, + .src_start = UART3_RHR, + .tx_trigger = 0, + .rx_trigger = 0, +}; + +static struct resource h2_irda_resources[] = { + [0] = { + .start = INT_UART3, + .end = INT_UART3, + .flags = IORESOURCE_IRQ, + }, +}; +static struct platform_device h2_irda_device = { + .name = "omapirda", + .id = 0, + .dev = { + .platform_data = &h2_irda_data, + }, + .num_resources = ARRAY_SIZE(h2_irda_resources), + .resource = h2_irda_resources, +}; + +static struct platform_device h2_lcd_device = { + .name = "lcd_h2", + .id = -1, +}; + +static struct omap_mcbsp_reg_cfg mcbsp_regs = { + .spcr2 = FREE | FRST | GRST | XRST | XINTM(3), + .spcr1 = RINTM(3) | RRST, + .rcr2 = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) | + RWDLEN2(OMAP_MCBSP_WORD_16) | RDATDLY(1), + .rcr1 = RFRLEN1(OMAP_MCBSP_WORD_8) | RWDLEN1(OMAP_MCBSP_WORD_16), + .xcr2 = XPHASE | XFRLEN2(OMAP_MCBSP_WORD_8) | + XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(1) | XFIG, + .xcr1 = XFRLEN1(OMAP_MCBSP_WORD_8) | XWDLEN1(OMAP_MCBSP_WORD_16), + .srgr1 = FWID(15), + .srgr2 = GSYNC | CLKSP | FSGM | FPER(31), + + .pcr0 = CLKXM | CLKRM | FSXP | FSRP | CLKXP | CLKRP, + //.pcr0 = CLKXP | CLKRP, /* mcbsp: slave */ +}; + +static struct omap_alsa_codec_config alsa_config = { + .name = "H2 TSC2101", + .mcbsp_regs_alsa = &mcbsp_regs, + .codec_configure_dev = NULL, // tsc2101_configure, + .codec_set_samplerate = NULL, // tsc2101_set_samplerate, + .codec_clock_setup = NULL, // tsc2101_clock_setup, + .codec_clock_on = NULL, // tsc2101_clock_on, + .codec_clock_off = NULL, // tsc2101_clock_off, + .get_default_samplerate = NULL, // tsc2101_get_default_samplerate, +}; + +static struct platform_device h2_mcbsp1_device = { + .name = "omap_alsa_mcbsp", + .id = 1, + .dev = { + .platform_data = &alsa_config, + }, +}; + static struct platform_device *h2_devices[] __initdata = { - &h2_flash_device, + &h2_nor_device, &h2_smc91x_device, + &h2_irda_device, + &h2_kp_device, + &h2_lcd_device, + &h2_mcbsp1_device, }; static void __init h2_init_smc91x(void) @@ -164,7 +319,6 @@ static struct omap_uart_config h2_uart_config __initdata = { }; static struct omap_lcd_config h2_lcd_config __initdata = { - .panel_name = "h2", .ctrl_name = "internal", }; @@ -177,16 +331,34 @@ static struct omap_board_config_kernel h2_config[] = { static void __init h2_init(void) { - /* NOTE: revC boards support NAND-boot, which can put NOR on CS2B - * and NAND (either 16bit or 8bit) on CS3. + /* Here we assume the NOR boot config: NOR on CS3 (possibly swapped + * to address 0 by a dip switch), NAND on CS2B. The NAND driver will + * notice whether a NAND chip is enabled at probe time. + * + * FIXME revC boards (and H3) support NAND-boot, with a dip switch to + * put NOR on CS2B and NAND (which on H2 may be 16bit) on CS3. Try + * detecting that in code here, to avoid probing every possible flash + * configuration... */ - h2_flash_resource.end = h2_flash_resource.start = omap_cs3_phys(); - h2_flash_resource.end += SZ_32M - 1; + h2_nor_resource.end = h2_nor_resource.start = omap_cs3_phys(); + h2_nor_resource.end += SZ_32M - 1; + + omap_cfg_reg(L3_1610_FLASH_CS2B_OE); + omap_cfg_reg(M8_1610_FLASH_CS2B_WE); /* MMC: card detect and WP */ // omap_cfg_reg(U19_ARMIO1); /* CD */ omap_cfg_reg(BALLOUT_V8_ARMIO3); /* WP */ + /* Irda */ +#if defined(CONFIG_OMAP_IR) || defined(CONFIG_OMAP_IR_MODULE) + omap_writel(omap_readl(FUNC_MUX_CTRL_A) | 7, FUNC_MUX_CTRL_A); + if (!(omap_request_gpio(H2_IRDA_FIRSEL_GPIO_PIN))) { + omap_set_gpio_direction(H2_IRDA_FIRSEL_GPIO_PIN, 0); + h2_irda_data.transceiver_mode = h2_transceiver_mode; + } +#endif + platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices)); omap_board_config = h2_config; omap_board_config_size = ARRAY_SIZE(h2_config); diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c index d9f38626599..4b8d0ec73cb 100644 --- a/arch/arm/mach-omap1/board-h3.c +++ b/arch/arm/mach-omap1/board-h3.c @@ -21,8 +21,11 @@ #include <linux/kernel.h> #include <linux/platform_device.h> #include <linux/errno.h> +#include <linux/workqueue.h> #include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> #include <linux/mtd/partitions.h> +#include <linux/input.h> #include <asm/setup.h> #include <asm/page.h> @@ -33,15 +36,59 @@ #include <asm/mach/map.h> #include <asm/arch/gpio.h> +#include <asm/arch/gpioexpander.h> #include <asm/arch/irqs.h> #include <asm/arch/mux.h> #include <asm/arch/tc.h> +#include <asm/arch/irda.h> #include <asm/arch/usb.h> +#include <asm/arch/keypad.h> +#include <asm/arch/dma.h> #include <asm/arch/common.h> extern int omap_gpio_init(void); -static struct mtd_partition h3_partitions[] = { +static int h3_keymap[] = { + KEY(0, 0, KEY_LEFT), + KEY(0, 1, KEY_RIGHT), + KEY(0, 2, KEY_3), + KEY(0, 3, KEY_F10), + KEY(0, 4, KEY_F5), + KEY(0, 5, KEY_9), + KEY(1, 0, KEY_DOWN), + KEY(1, 1, KEY_UP), + KEY(1, 2, KEY_2), + KEY(1, 3, KEY_F9), + KEY(1, 4, KEY_F7), + KEY(1, 5, KEY_0), + KEY(2, 0, KEY_ENTER), + KEY(2, 1, KEY_6), + KEY(2, 2, KEY_1), + KEY(2, 3, KEY_F2), + KEY(2, 4, KEY_F6), + KEY(2, 5, KEY_HOME), + KEY(3, 0, KEY_8), + KEY(3, 1, KEY_5), + KEY(3, 2, KEY_F12), + KEY(3, 3, KEY_F3), + KEY(3, 4, KEY_F8), + KEY(3, 5, KEY_END), + KEY(4, 0, KEY_7), + KEY(4, 1, KEY_4), + KEY(4, 2, KEY_F11), + KEY(4, 3, KEY_F1), + KEY(4, 4, KEY_F4), + KEY(4, 5, KEY_ESC), + KEY(5, 0, KEY_F13), + KEY(5, 1, KEY_F14), + KEY(5, 2, KEY_F15), + KEY(5, 3, KEY_F16), + KEY(5, 4, KEY_SLEEP), + 0 +}; + + +static struct mtd_partition nor_partitions[] = { /* bootloader (U-Boot, etc) in first sector */ { .name = "bootloader", @@ -72,26 +119,80 @@ static struct mtd_partition h3_partitions[] = { } }; -static struct flash_platform_data h3_flash_data = { +static struct flash_platform_data nor_data = { .map_name = "cfi_probe", .width = 2, - .parts = h3_partitions, - .nr_parts = ARRAY_SIZE(h3_partitions), + .parts = nor_partitions, + .nr_parts = ARRAY_SIZE(nor_partitions), }; -static struct resource h3_flash_resource = { +static struct resource nor_resource = { /* This is on CS3, wherever it's mapped */ .flags = IORESOURCE_MEM, }; -static struct platform_device flash_device = { +static struct platform_device nor_device = { .name = "omapflash", .id = 0, .dev = { - .platform_data = &h3_flash_data, + .platform_data = &nor_data, + }, + .num_resources = 1, + .resource = &nor_resource, +}; + +static struct mtd_partition nand_partitions[] = { +#if 0 + /* REVISIT: enable these partitions if you make NAND BOOT work */ + { + .name = "xloader", + .offset = 0, + .size = 64 * 1024, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + { + .name = "bootloader", + .offset = MTDPART_OFS_APPEND, + .size = 256 * 1024, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + { + .name = "params", + .offset = MTDPART_OFS_APPEND, + .size = 192 * 1024, + }, + { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = 2 * SZ_1M, + }, +#endif + { + .name = "filesystem", + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND, + }, +}; + +/* dip switches control NAND chip access: 8 bit, 16 bit, or neither */ +static struct nand_platform_data nand_data = { + .options = NAND_SAMSUNG_LP_OPTIONS, + .parts = nand_partitions, + .nr_parts = ARRAY_SIZE(nand_partitions), +}; + +static struct resource nand_resource = { + .flags = IORESOURCE_MEM, +}; + +static struct platform_device nand_device = { + .name = "omapnand", + .id = 0, + .dev = { + .platform_data = &nand_data, }, .num_resources = 1, - .resource = &h3_flash_resource, + .resource = &nand_resource, }; static struct resource smc91x_resources[] = { @@ -138,10 +239,136 @@ static struct platform_device intlat_device = { .resource = intlat_resources, }; +static struct resource h3_kp_resources[] = { + [0] = { + .start = INT_KEYBOARD, + .end = INT_KEYBOARD, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct omap_kp_platform_data h3_kp_data = { + .rows = 8, + .cols = 8, + .keymap = h3_keymap, + .rep = 1, +}; + +static struct platform_device h3_kp_device = { + .name = "omap-keypad", + .id = -1, + .dev = { + .platform_data = &h3_kp_data, + }, + .num_resources = ARRAY_SIZE(h3_kp_resources), + .resource = h3_kp_resources, +}; + + +/* Select between the IrDA and aGPS module + */ +static int h3_select_irda(struct device *dev, int state) +{ + unsigned char expa; + int err = 0; + + if ((err = read_gpio_expa(&expa, 0x26))) { + printk(KERN_ERR "Error reading from I/O EXPANDER \n"); + return err; + } + + /* 'P6' enable/disable IRDA_TX and IRDA_RX */ + if (state & IR_SEL) { /* IrDA */ + if ((err = write_gpio_expa(expa | 0x40, 0x26))) { + printk(KERN_ERR "Error writing to I/O EXPANDER \n"); + return err; + } + } else { + if ((err = write_gpio_expa(expa & ~0x40, 0x26))) { + printk(KERN_ERR "Error writing to I/O EXPANDER \n"); + return err; + } + } + return err; +} + +static void set_trans_mode(void *data) +{ + int *mode = data; + unsigned char expa; + int err = 0; + + if ((err = read_gpio_expa(&expa, 0x27)) != 0) { + printk(KERN_ERR "Error reading from I/O expander\n"); + } + + expa &= ~0x03; + + if (*mode & IR_SIRMODE) { + expa |= 0x01; + } else { /* MIR/FIR */ + expa |= 0x03; + } + + if ((err = write_gpio_expa(expa, 0x27)) != 0) { + printk(KERN_ERR "Error writing to I/O expander\n"); + } +} + +static int h3_transceiver_mode(struct device *dev, int mode) +{ + struct omap_irda_config *irda_config = dev->platform_data; + + cancel_delayed_work(&irda_config->gpio_expa); + PREPARE_WORK(&irda_config->gpio_expa, set_trans_mode, &mode); + schedule_work(&irda_config->gpio_expa); + + return 0; +} + +static struct omap_irda_config h3_irda_data = { + .transceiver_cap = IR_SIRMODE | IR_MIRMODE | IR_FIRMODE, + .transceiver_mode = h3_transceiver_mode, + .select_irda = h3_select_irda, + .rx_channel = OMAP_DMA_UART3_RX, + .tx_channel = OMAP_DMA_UART3_TX, + .dest_start = UART3_THR, + .src_start = UART3_RHR, + .tx_trigger = 0, + .rx_trigger = 0, +}; + +static struct resource h3_irda_resources[] = { + [0] = { + .start = INT_UART3, + .end = INT_UART3, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device h3_irda_device = { + .name = "omapirda", + .id = 0, + .dev = { + .platform_data = &h3_irda_data, + }, + .num_resources = ARRAY_SIZE(h3_irda_resources), + .resource = h3_irda_resources, +}; + +static struct platform_device h3_lcd_device = { + .name = "lcd_h3", + .id = -1, +}; + static struct platform_device *devices[] __initdata = { - &flash_device, + &nor_device, + &nand_device, &smc91x_device, &intlat_device, + &h3_irda_device, + &h3_kp_device, + &h3_lcd_device, }; static struct omap_usb_config h3_usb_config __initdata = { @@ -171,7 +398,6 @@ static struct omap_uart_config h3_uart_config __initdata = { }; static struct omap_lcd_config h3_lcd_config __initdata = { - .panel_name = "h3", .ctrl_name = "internal", }; @@ -182,11 +408,36 @@ static struct omap_board_config_kernel h3_config[] = { { OMAP_TAG_LCD, &h3_lcd_config }, }; +#define H3_NAND_RB_GPIO_PIN 10 + +static int nand_dev_ready(struct nand_platform_data *data) +{ + return omap_get_gpio_datain(H3_NAND_RB_GPIO_PIN); +} + static void __init h3_init(void) { - h3_flash_resource.end = h3_flash_resource.start = omap_cs3_phys(); - h3_flash_resource.end += OMAP_CS3_SIZE - 1; - (void) platform_add_devices(devices, ARRAY_SIZE(devices)); + /* Here we assume the NOR boot config: NOR on CS3 (possibly swapped + * to address 0 by a dip switch), NAND on CS2B. The NAND driver will + * notice whether a NAND chip is enabled at probe time. + * + * H3 support NAND-boot, with a dip switch to put NOR on CS2B and NAND + * (which on H2 may be 16bit) on CS3. Try detecting that in code here, + * to avoid probing every possible flash configuration... + */ + nor_resource.end = nor_resource.start = omap_cs3_phys(); + nor_resource.end += SZ_32M - 1; + + nand_resource.end = nand_resource.start = OMAP_CS2B_PHYS; + nand_resource.end += SZ_4K - 1; + if (!(omap_request_gpio(H3_NAND_RB_GPIO_PIN))) + nand_data.dev_ready = nand_dev_ready; + + /* GPIO10 Func_MUX_CTRL reg bit 29:27, Configure V2 to mode1 as GPIO */ + /* GPIO10 pullup/down register, Enable pullup on GPIO10 */ + omap_cfg_reg(V2_1710_GPIO10); + + platform_add_devices(devices, ARRAY_SIZE(devices)); omap_board_config = h3_config; omap_board_config_size = ARRAY_SIZE(h3_config); omap_serial_init(); diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c index a04e4332915..e90c137a4cf 100644 --- a/arch/arm/mach-omap1/board-innovator.c +++ b/arch/arm/mach-omap1/board-innovator.c @@ -22,6 +22,7 @@ #include <linux/delay.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> +#include <linux/input.h> #include <asm/hardware.h> #include <asm/mach-types.h> @@ -34,8 +35,22 @@ #include <asm/arch/gpio.h> #include <asm/arch/tc.h> #include <asm/arch/usb.h> +#include <asm/arch/keypad.h> #include <asm/arch/common.h> +static int innovator_keymap[] = { + KEY(0, 0, KEY_F1), + KEY(0, 3, KEY_DOWN), + KEY(1, 1, KEY_F2), + KEY(1, 2, KEY_RIGHT), + KEY(2, 0, KEY_F3), + KEY(2, 1, KEY_F4), + KEY(2, 2, KEY_UP), + KEY(3, 2, KEY_ENTER), + KEY(3, 3, KEY_LEFT), + 0 +}; + static struct mtd_partition innovator_partitions[] = { /* bootloader (U-Boot, etc) in first sector */ { @@ -97,6 +112,31 @@ static struct platform_device innovator_flash_device = { .resource = &innovator_flash_resource, }; +static struct resource innovator_kp_resources[] = { + [0] = { + .start = INT_KEYBOARD, + .end = INT_KEYBOARD, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct omap_kp_platform_data innovator_kp_data = { + .rows = 8, + .cols = 8, + .keymap = innovator_keymap, +}; + +static struct platform_device innovator_kp_device = { + .name = "omap-keypad", + .id = -1, + .dev = { + .platform_data = &innovator_kp_data, + }, + .num_resources = ARRAY_SIZE(innovator_kp_resources), + .resource = innovator_kp_resources, +}; + + #ifdef CONFIG_ARCH_OMAP15XX /* Only FPGA needs to be mapped here. All others are done with ioremap */ @@ -129,9 +169,16 @@ static struct platform_device innovator1510_smc91x_device = { .resource = innovator1510_smc91x_resources, }; +static struct platform_device innovator1510_lcd_device = { + .name = "lcd_inn1510", + .id = -1, +}; + static struct platform_device *innovator1510_devices[] __initdata = { &innovator_flash_device, &innovator1510_smc91x_device, + &innovator_kp_device, + &innovator1510_lcd_device, }; #endif /* CONFIG_ARCH_OMAP15XX */ @@ -158,9 +205,16 @@ static struct platform_device innovator1610_smc91x_device = { .resource = innovator1610_smc91x_resources, }; +static struct platform_device innovator1610_lcd_device = { + .name = "inn1610_lcd", + .id = -1, +}; + static struct platform_device *innovator1610_devices[] __initdata = { &innovator_flash_device, &innovator1610_smc91x_device, + &innovator_kp_device, + &innovator1610_lcd_device, }; #endif /* CONFIG_ARCH_OMAP16XX */ @@ -206,7 +260,6 @@ static struct omap_usb_config innovator1510_usb_config __initdata = { }; static struct omap_lcd_config innovator1510_lcd_config __initdata = { - .panel_name = "inn1510", .ctrl_name = "internal", }; #endif @@ -228,7 +281,6 @@ static struct omap_usb_config h2_usb_config __initdata = { }; static struct omap_lcd_config innovator1610_lcd_config __initdata = { - .panel_name = "inn1610", .ctrl_name = "internal", }; #endif diff --git a/arch/arm/mach-omap1/board-netstar.c b/arch/arm/mach-omap1/board-netstar.c deleted file mode 100644 index 7520e602d7a..00000000000 --- a/arch/arm/mach-omap1/board-netstar.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Modified from board-generic.c - * - * Copyright (C) 2004 2N Telekomunikace, Ladislav Michl <michl@2n.cz> - * - * Code for Netstar OMAP board. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/delay.h> -#include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/notifier.h> -#include <linux/reboot.h> - -#include <asm/hardware.h> -#include <asm/mach-types.h> -#include <asm/mach/arch.h> -#include <asm/mach/map.h> - -#include <asm/arch/gpio.h> -#include <asm/arch/mux.h> -#include <asm/arch/usb.h> -#include <asm/arch/common.h> - -extern void __init omap_init_time(void); -extern int omap_gpio_init(void); - -static struct resource netstar_smc91x_resources[] = { - [0] = { - .start = OMAP_CS1_PHYS + 0x300, - .end = OMAP_CS1_PHYS + 0x300 + 16, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = OMAP_GPIO_IRQ(8), - .end = OMAP_GPIO_IRQ(8), - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device netstar_smc91x_device = { - .name = "smc91x", - .id = 0, - .num_resources = ARRAY_SIZE(netstar_smc91x_resources), - .resource = netstar_smc91x_resources, -}; - -static struct platform_device *netstar_devices[] __initdata = { - &netstar_smc91x_device, -}; - -static struct omap_uart_config netstar_uart_config __initdata = { - .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), -}; - -static struct omap_board_config_kernel netstar_config[] = { - { OMAP_TAG_UART, &netstar_uart_config }, -}; - -static void __init netstar_init_irq(void) -{ - omap1_init_common_hw(); - omap_init_irq(); - omap_gpio_init(); -} - -static void __init netstar_init(void) -{ - /* green LED */ - omap_request_gpio(4); - omap_set_gpio_direction(4, 0); - /* smc91x reset */ - omap_request_gpio(7); - omap_set_gpio_direction(7, 0); - omap_set_gpio_dataout(7, 1); - udelay(2); /* wait at least 100ns */ - omap_set_gpio_dataout(7, 0); - mdelay(50); /* 50ms until PHY ready */ - /* smc91x interrupt pin */ - omap_request_gpio(8); - - omap_request_gpio(12); - omap_request_gpio(13); - omap_request_gpio(14); - omap_request_gpio(15); - set_irq_type(OMAP_GPIO_IRQ(12), IRQT_FALLING); - set_irq_type(OMAP_GPIO_IRQ(13), IRQT_FALLING); - set_irq_type(OMAP_GPIO_IRQ(14), IRQT_FALLING); - set_irq_type(OMAP_GPIO_IRQ(15), IRQT_FALLING); - - platform_add_devices(netstar_devices, ARRAY_SIZE(netstar_devices)); - - /* Switch on green LED */ - omap_set_gpio_dataout(4, 0); - /* Switch off red LED */ - omap_writeb(0x00, OMAP_LPG1_PMR); /* Disable clock */ - omap_writeb(0x80, OMAP_LPG1_LCR); - - omap_board_config = netstar_config; - omap_board_config_size = ARRAY_SIZE(netstar_config); - omap_serial_init(); -} - -static void __init netstar_map_io(void) -{ - omap1_map_common_io(); -} - -#define MACHINE_PANICED 1 -#define MACHINE_REBOOTING 2 -#define MACHINE_REBOOT 4 -static unsigned long machine_state; - -static int panic_event(struct notifier_block *this, unsigned long event, - void *ptr) -{ - if (test_and_set_bit(MACHINE_PANICED, &machine_state)) - return NOTIFY_DONE; - - /* Switch off green LED */ - omap_set_gpio_dataout(4, 1); - /* Flash red LED */ - omap_writeb(0x78, OMAP_LPG1_LCR); - omap_writeb(0x01, OMAP_LPG1_PMR); /* Enable clock */ - - return NOTIFY_DONE; -} - -static struct notifier_block panic_block = { - .notifier_call = panic_event, -}; - -static int __init netstar_late_init(void) -{ - /* TODO: Setup front panel switch here */ - - /* Setup panic notifier */ - atomic_notifier_chain_register(&panic_notifier_list, &panic_block); - - return 0; -} - -postcore_initcall(netstar_late_init); - -MACHINE_START(NETSTAR, "NetStar OMAP5910") - /* Maintainer: Ladislav Michl <michl@2n.cz> */ - .phys_io = 0xfff00000, - .io_pg_offst = ((0xfef00000) >> 18) & 0xfffc, - .boot_params = 0x10000100, - .map_io = netstar_map_io, - .init_irq = netstar_init_irq, - .init_machine = netstar_init, - .timer = &omap_timer, -MACHINE_END diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c new file mode 100644 index 00000000000..02b980d77b1 --- /dev/null +++ b/arch/arm/mach-omap1/board-nokia770.c @@ -0,0 +1,268 @@ +/* + * linux/arch/arm/mach-omap1/board-nokia770.c + * + * Modified from board-generic.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <linux/clk.h> + +#include <linux/spi/spi.h> +#include <linux/spi/ads7846.h> + +#include <asm/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include <asm/arch/gpio.h> +#include <asm/arch/mux.h> +#include <asm/arch/usb.h> +#include <asm/arch/board.h> +#include <asm/arch/keypad.h> +#include <asm/arch/common.h> +#include <asm/arch/dsp_common.h> +#include <asm/arch/aic23.h> +#include <asm/arch/gpio.h> + +static void __init omap_nokia770_init_irq(void) +{ + /* On Nokia 770, the SleepX signal is masked with an + * MPUIO line by default. It has to be unmasked for it + * to become functional */ + + /* SleepX mask direction */ + omap_writew((omap_readw(0xfffb5008) & ~2), 0xfffb5008); + /* Unmask SleepX signal */ + omap_writew((omap_readw(0xfffb5004) & ~2), 0xfffb5004); + + omap1_init_common_hw(); + omap_init_irq(); +} + +static int nokia770_keymap[] = { + KEY(0, 1, GROUP_0 | KEY_UP), + KEY(0, 2, GROUP_1 | KEY_F5), + KEY(1, 0, GROUP_0 | KEY_LEFT), + KEY(1, 1, GROUP_0 | KEY_ENTER), + KEY(1, 2, GROUP_0 | KEY_RIGHT), + KEY(2, 0, GROUP_1 | KEY_ESC), + KEY(2, 1, GROUP_0 | KEY_DOWN), + KEY(2, 2, GROUP_1 | KEY_F4), + KEY(3, 0, GROUP_2 | KEY_F7), + KEY(3, 1, GROUP_2 | KEY_F8), + KEY(3, 2, GROUP_2 | KEY_F6), + 0 +}; + +static struct resource nokia770_kp_resources[] = { + [0] = { + .start = INT_KEYBOARD, + .end = INT_KEYBOARD, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct omap_kp_platform_data nokia770_kp_data = { + .rows = 8, + .cols = 8, + .keymap = nokia770_keymap +}; + +static struct platform_device nokia770_kp_device = { + .name = "omap-keypad", + .id = -1, + .dev = { + .platform_data = &nokia770_kp_data, + }, + .num_resources = ARRAY_SIZE(nokia770_kp_resources), + .resource = nokia770_kp_resources, +}; + +static struct platform_device *nokia770_devices[] __initdata = { + &nokia770_kp_device, +}; + +static struct ads7846_platform_data nokia770_ads7846_platform_data __initdata = { + .x_max = 0x0fff, + .y_max = 0x0fff, + .x_plate_ohms = 180, + .pressure_max = 255, + .debounce_max = 10, + .debounce_tol = 3, +}; + +static struct spi_board_info nokia770_spi_board_info[] __initdata = { + [0] = { + .modalias = "lcd_lph8923", + .bus_num = 2, + .chip_select = 3, + .max_speed_hz = 12000000, + }, + [1] = { + .modalias = "ads7846", + .bus_num = 2, + .chip_select = 0, + .max_speed_hz = 2500000, + .irq = OMAP_GPIO_IRQ(15), + .platform_data = &nokia770_ads7846_platform_data, + }, +}; + + +/* assume no Mini-AB port */ + +static struct omap_usb_config nokia770_usb_config __initdata = { + .otg = 1, + .register_host = 1, + .register_dev = 1, + .hmc_mode = 16, + .pins[0] = 6, +}; + +static struct omap_mmc_config nokia770_mmc_config __initdata = { + .mmc[0] = { + .enabled = 0, + .wire4 = 0, + .wp_pin = -1, + .power_pin = -1, + .switch_pin = -1, + }, + .mmc[1] = { + .enabled = 0, + .wire4 = 0, + .wp_pin = -1, + .power_pin = -1, + .switch_pin = -1, + }, +}; + +static struct omap_board_config_kernel nokia770_config[] = { + { OMAP_TAG_USB, NULL }, + { OMAP_TAG_MMC, &nokia770_mmc_config }, +}; + +/* + * audio power control + */ +#define HEADPHONE_GPIO 14 +#define AMPLIFIER_CTRL_GPIO 58 + +static struct clk *dspxor_ck; +static DECLARE_MUTEX(audio_pwr_sem); +/* + * audio_pwr_state + * +--+-------------------------+---------------------------------------+ + * |-1|down |power-up request -> 0 | + * +--+-------------------------+---------------------------------------+ + * | 0|up |power-down(1) request -> 1 | + * | | |power-down(2) request -> (ignore) | + * +--+-------------------------+---------------------------------------+ + * | 1|up, |power-up request -> 0 | + * | |received down(1) request |power-down(2) request -> -1 | + * +--+-------------------------+---------------------------------------+ + */ +static int audio_pwr_state = -1; + +/* + * audio_pwr_up / down should be called under audio_pwr_sem + */ +static void nokia770_audio_pwr_up(void) +{ + clk_enable(dspxor_ck); + + /* Turn on codec */ + tlv320aic23_power_up(); + + if (omap_get_gpio_datain(HEADPHONE_GPIO)) + /* HP not connected, turn on amplifier */ + omap_set_gpio_dataout(AMPLIFIER_CTRL_GPIO, 1); + else + /* HP connected, do not turn on amplifier */ + printk("HP connected\n"); +} + +static void codec_delayed_power_down(void *arg) +{ + down(&audio_pwr_sem); + if (audio_pwr_state == -1) + tlv320aic23_power_down(); + clk_disable(dspxor_ck); + up(&audio_pwr_sem); +} + +static DECLARE_WORK(codec_power_down_work, codec_delayed_power_down, NULL); + +static void nokia770_audio_pwr_down(void) +{ + /* Turn off amplifier */ + omap_set_gpio_dataout(AMPLIFIER_CTRL_GPIO, 0); + + /* Turn off codec: schedule delayed work */ + schedule_delayed_work(&codec_power_down_work, HZ / 20); /* 50ms */ +} + +void nokia770_audio_pwr_up_request(int stage) +{ + down(&audio_pwr_sem); + if (audio_pwr_state == -1) + nokia770_audio_pwr_up(); + /* force audio_pwr_state = 0, even if it was 1. */ + audio_pwr_state = 0; + up(&audio_pwr_sem); +} + +void nokia770_audio_pwr_down_request(int stage) +{ + down(&audio_pwr_sem); + switch (stage) { + case 1: + if (audio_pwr_state == 0) + audio_pwr_state = 1; + break; + case 2: + if (audio_pwr_state == 1) { + nokia770_audio_pwr_down(); + audio_pwr_state = -1; + } + break; + } + up(&audio_pwr_sem); +} + +static void __init omap_nokia770_init(void) +{ + nokia770_config[0].data = &nokia770_usb_config; + + platform_add_devices(nokia770_devices, ARRAY_SIZE(nokia770_devices)); + spi_register_board_info(nokia770_spi_board_info, + ARRAY_SIZE(nokia770_spi_board_info)); + omap_board_config = nokia770_config; + omap_board_config_size = ARRAY_SIZE(nokia770_config); + omap_serial_init(); + omap_dsp_audio_pwr_up_request = nokia770_audio_pwr_up_request; + omap_dsp_audio_pwr_down_request = nokia770_audio_pwr_down_request; + dspxor_ck = clk_get(0, "dspxor_ck"); +} + +static void __init omap_nokia770_map_io(void) +{ + omap1_map_common_io(); +} + +MACHINE_START(NOKIA770, "Nokia 770") + .phys_io = 0xfff00000, + .io_pg_offst = ((0xfef00000) >> 18) & 0xfffc, + .boot_params = 0x10000100, + .map_io = omap_nokia770_map_io, + .init_irq = omap_nokia770_init_irq, + .init_machine = omap_nokia770_init, + .timer = &omap_timer, +MACHINE_END diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c index 543fa136106..1160093e8ef 100644 --- a/arch/arm/mach-omap1/board-osk.c +++ b/arch/arm/mach-omap1/board-osk.c @@ -33,6 +33,7 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> +#include <linux/input.h> #include <asm/hardware.h> #include <asm/mach-types.h> @@ -44,7 +45,24 @@ #include <asm/arch/usb.h> #include <asm/arch/mux.h> #include <asm/arch/tc.h> +#include <asm/arch/keypad.h> #include <asm/arch/common.h> +#include <asm/arch/mcbsp.h> +#include <asm/arch/omap-alsa.h> + +static int osk_keymap[] = { + KEY(0, 0, KEY_F1), + KEY(0, 3, KEY_UP), + KEY(1, 1, KEY_LEFTCTRL), + KEY(1, 2, KEY_LEFT), + KEY(2, 0, KEY_SPACE), + KEY(2, 1, KEY_ESC), + KEY(2, 2, KEY_DOWN), + KEY(3, 2, KEY_ENTER), + KEY(3, 3, KEY_RIGHT), + 0 +}; + static struct mtd_partition osk_partitions[] = { /* bootloader (U-Boot, etc) in first sector */ @@ -133,9 +151,69 @@ static struct platform_device osk5912_cf_device = { .resource = osk5912_cf_resources, }; +#define DEFAULT_BITPERSAMPLE 16 + +static struct omap_mcbsp_reg_cfg mcbsp_regs = { + .spcr2 = FREE | FRST | GRST | XRST | XINTM(3), + .spcr1 = RINTM(3) | RRST, + .rcr2 = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) | + RWDLEN2(OMAP_MCBSP_WORD_16) | RDATDLY(0), + .rcr1 = RFRLEN1(OMAP_MCBSP_WORD_8) | RWDLEN1(OMAP_MCBSP_WORD_16), + .xcr2 = XPHASE | XFRLEN2(OMAP_MCBSP_WORD_8) | + XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(0) | XFIG, + .xcr1 = XFRLEN1(OMAP_MCBSP_WORD_8) | XWDLEN1(OMAP_MCBSP_WORD_16), + .srgr1 = FWID(DEFAULT_BITPERSAMPLE - 1), + .srgr2 = GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1), + /*.pcr0 = FSXM | FSRM | CLKXM | CLKRM | CLKXP | CLKRP,*/ /* mcbsp: master */ + .pcr0 = CLKXP | CLKRP, /* mcbsp: slave */ +}; + +static struct omap_alsa_codec_config alsa_config = { + .name = "OSK AIC23", + .mcbsp_regs_alsa = &mcbsp_regs, + .codec_configure_dev = NULL, // aic23_configure, + .codec_set_samplerate = NULL, // aic23_set_samplerate, + .codec_clock_setup = NULL, // aic23_clock_setup, + .codec_clock_on = NULL, // aic23_clock_on, + .codec_clock_off = NULL, // aic23_clock_off, + .get_default_samplerate = NULL, // aic23_get_default_samplerate, +}; + static struct platform_device osk5912_mcbsp1_device = { - .name = "omap_mcbsp", - .id = 1, + .name = "omap_alsa_mcbsp", + .id = 1, + .dev = { + .platform_data = &alsa_config, + }, +}; + +static struct resource osk5912_kp_resources[] = { + [0] = { + .start = INT_KEYBOARD, + .end = INT_KEYBOARD, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct omap_kp_platform_data osk_kp_data = { + .rows = 8, + .cols = 8, + .keymap = osk_keymap, +}; + +static struct platform_device osk5912_kp_device = { + .name = "omap-keypad", + .id = -1, + .dev = { + .platform_data = &osk_kp_data, + }, + .num_resources = ARRAY_SIZE(osk5912_kp_resources), + .resource = osk5912_kp_resources, +}; + +static struct platform_device osk5912_lcd_device = { + .name = "lcd_osk", + .id = -1, }; static struct platform_device *osk5912_devices[] __initdata = { @@ -143,6 +221,8 @@ static struct platform_device *osk5912_devices[] __initdata = { &osk5912_smc91x_device, &osk5912_cf_device, &osk5912_mcbsp1_device, + &osk5912_kp_device, + &osk5912_lcd_device, }; static void __init osk_init_smc91x(void) @@ -197,7 +277,6 @@ static struct omap_uart_config osk_uart_config __initdata = { }; static struct omap_lcd_config osk_lcd_config __initdata = { - .panel_name = "osk", .ctrl_name = "internal", }; @@ -255,8 +334,18 @@ static void __init osk_mistral_init(void) static void __init osk_mistral_init(void) { } #endif +#define EMIFS_CS3_VAL (0x88013141) + static void __init osk_init(void) { + /* Workaround for wrong CS3 (NOR flash) timing + * There are some U-Boot versions out there which configure + * wrong CS3 memory timings. This mainly leads to CRC + * or similiar errors if you use NOR flash (e.g. with JFFS2) + */ + if (EMIFS_CCS(3) != EMIFS_CS3_VAL) + EMIFS_CCS(3) = EMIFS_CS3_VAL; + osk_flash_resource.end = osk_flash_resource.start = omap_cs3_phys(); osk_flash_resource.end += SZ_32M - 1; platform_add_devices(osk5912_devices, ARRAY_SIZE(osk5912_devices)); diff --git a/arch/arm/mach-omap1/board-palmte.c b/arch/arm/mach-omap1/board-palmte.c index e488f723677..4bc8a62909b 100644 --- a/arch/arm/mach-omap1/board-palmte.c +++ b/arch/arm/mach-omap1/board-palmte.c @@ -38,6 +38,15 @@ static void __init omap_generic_init_irq(void) omap_init_irq(); } +static struct platform_device palmte_lcd_device = { + .name = "lcd_palmte", + .id = -1, +}; + +static struct platform_device *devices[] __initdata = { + &palmte_lcd_device, +}; + static struct omap_usb_config palmte_usb_config __initdata = { .register_dev = 1, .hmc_mode = 0, @@ -55,7 +64,6 @@ static struct omap_mmc_config palmte_mmc_config __initdata = { }; static struct omap_lcd_config palmte_lcd_config __initdata = { - .panel_name = "palmte", .ctrl_name = "internal", }; @@ -69,6 +77,8 @@ static void __init omap_generic_init(void) { omap_board_config = palmte_config; omap_board_config_size = ARRAY_SIZE(palmte_config); + + platform_add_devices(devices, ARRAY_SIZE(devices)); } static void __init omap_generic_map_io(void) diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c index 3913a3cc0ce..64b45d8ae35 100644 --- a/arch/arm/mach-omap1/board-perseus2.c +++ b/arch/arm/mach-omap1/board-perseus2.c @@ -16,7 +16,9 @@ #include <linux/platform_device.h> #include <linux/delay.h> #include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> #include <linux/mtd/partitions.h> +#include <linux/input.h> #include <asm/hardware.h> #include <asm/mach-types.h> @@ -28,9 +30,44 @@ #include <asm/arch/gpio.h> #include <asm/arch/mux.h> #include <asm/arch/fpga.h> +#include <asm/arch/keypad.h> #include <asm/arch/common.h> #include <asm/arch/board.h> +static int p2_keymap[] = { + KEY(0,0,KEY_UP), + KEY(0,1,KEY_RIGHT), + KEY(0,2,KEY_LEFT), + KEY(0,3,KEY_DOWN), + KEY(0,4,KEY_CENTER), + KEY(0,5,KEY_0_5), + KEY(1,0,KEY_SOFT2), + KEY(1,1,KEY_SEND), + KEY(1,2,KEY_END), + KEY(1,3,KEY_VOLUMEDOWN), + KEY(1,4,KEY_VOLUMEUP), + KEY(1,5,KEY_RECORD), + KEY(2,0,KEY_SOFT1), + KEY(2,1,KEY_3), + KEY(2,2,KEY_6), + KEY(2,3,KEY_9), + KEY(2,4,KEY_SHARP), + KEY(2,5,KEY_2_5), + KEY(3,0,KEY_BACK), + KEY(3,1,KEY_2), + KEY(3,2,KEY_5), + KEY(3,3,KEY_8), + KEY(3,4,KEY_0), + KEY(3,5,KEY_HEADSETHOOK), + KEY(4,0,KEY_HOME), + KEY(4,1,KEY_1), + KEY(4,2,KEY_4), + KEY(4,3,KEY_7), + KEY(4,4,KEY_STAR), + KEY(4,5,KEY_POWER), + 0 +}; + static struct resource smc91x_resources[] = { [0] = { .start = H2P2_DBG_FPGA_ETHR_START, /* Physical */ @@ -44,7 +81,7 @@ static struct resource smc91x_resources[] = { }, }; -static struct mtd_partition p2_partitions[] = { +static struct mtd_partition nor_partitions[] = { /* bootloader (U-Boot, etc) in first sector */ { .name = "bootloader", @@ -75,27 +112,47 @@ static struct mtd_partition p2_partitions[] = { }, }; -static struct flash_platform_data p2_flash_data = { +static struct flash_platform_data nor_data = { .map_name = "cfi_probe", .width = 2, - .parts = p2_partitions, - .nr_parts = ARRAY_SIZE(p2_partitions), + .parts = nor_partitions, + .nr_parts = ARRAY_SIZE(nor_partitions), }; -static struct resource p2_flash_resource = { +static struct resource nor_resource = { .start = OMAP_CS0_PHYS, .end = OMAP_CS0_PHYS + SZ_32M - 1, .flags = IORESOURCE_MEM, }; -static struct platform_device p2_flash_device = { +static struct platform_device nor_device = { .name = "omapflash", .id = 0, .dev = { - .platform_data = &p2_flash_data, + .platform_data = &nor_data, + }, + .num_resources = 1, + .resource = &nor_resource, +}; + +static struct nand_platform_data nand_data = { + .options = NAND_SAMSUNG_LP_OPTIONS, +}; + +static struct resource nand_resource = { + .start = OMAP_CS3_PHYS, + .end = OMAP_CS3_PHYS + SZ_4K - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device nand_device = { + .name = "omapnand", + .id = 0, + .dev = { + .platform_data = &nand_data, }, .num_resources = 1, - .resource = &p2_flash_resource, + .resource = &nand_resource, }; static struct platform_device smc91x_device = { @@ -105,17 +162,55 @@ static struct platform_device smc91x_device = { .resource = smc91x_resources, }; +static struct resource kp_resources[] = { + [0] = { + .start = INT_730_MPUIO_KEYPAD, + .end = INT_730_MPUIO_KEYPAD, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct omap_kp_platform_data kp_data = { + .rows = 8, + .cols = 8, + .keymap = p2_keymap, +}; + +static struct platform_device kp_device = { + .name = "omap-keypad", + .id = -1, + .dev = { + .platform_data = &kp_data, + }, + .num_resources = ARRAY_SIZE(kp_resources), + .resource = kp_resources, +}; + +static struct platform_device lcd_device = { + .name = "lcd_p2", + .id = -1, +}; + static struct platform_device *devices[] __initdata = { - &p2_flash_device, + &nor_device, + &nand_device, &smc91x_device, + &kp_device, + &lcd_device, }; +#define P2_NAND_RB_GPIO_PIN 62 + +static int nand_dev_ready(struct nand_platform_data *data) +{ + return omap_get_gpio_datain(P2_NAND_RB_GPIO_PIN); +} + static struct omap_uart_config perseus2_uart_config __initdata = { .enabled_uarts = ((1 << 0) | (1 << 1)), }; static struct omap_lcd_config perseus2_lcd_config __initdata = { - .panel_name = "p2", .ctrl_name = "internal", }; @@ -126,7 +221,13 @@ static struct omap_board_config_kernel perseus2_config[] = { static void __init omap_perseus2_init(void) { - (void) platform_add_devices(devices, ARRAY_SIZE(devices)); + if (!(omap_request_gpio(P2_NAND_RB_GPIO_PIN))) + nand_data.dev_ready = nand_dev_ready; + + omap_cfg_reg(L3_1610_FLASH_CS2B_OE); + omap_cfg_reg(M8_1610_FLASH_CS2B_WE); + + platform_add_devices(devices, ARRAY_SIZE(devices)); omap_board_config = perseus2_config; omap_board_config_size = ARRAY_SIZE(perseus2_config); diff --git a/arch/arm/mach-omap1/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c index 52e4a9d6964..447a586eb33 100644 --- a/arch/arm/mach-omap1/board-voiceblue.c +++ b/arch/arm/mach-omap1/board-voiceblue.c @@ -155,9 +155,9 @@ static struct omap_uart_config voiceblue_uart_config __initdata = { }; static struct omap_board_config_kernel voiceblue_config[] = { - { OMAP_TAG_USB, &voiceblue_usb_config }, - { OMAP_TAG_MMC, &voiceblue_mmc_config }, - { OMAP_TAG_UART, &voiceblue_uart_config }, + { OMAP_TAG_USB, &voiceblue_usb_config }, + { OMAP_TAG_MMC, &voiceblue_mmc_config }, + { OMAP_TAG_UART, &voiceblue_uart_config }, }; static void __init voiceblue_init_irq(void) @@ -235,7 +235,7 @@ static struct notifier_block panic_block = { static int __init voiceblue_setup(void) { /* Setup panic notifier */ - atomic_notifier_chain_register(&panic_notifier_list, &panic_block); + notifier_chain_register(&panic_notifier_list, &panic_block); return 0; } diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c index 75110ba1042..619db18144e 100644 --- a/arch/arm/mach-omap1/clock.c +++ b/arch/arm/mach-omap1/clock.c @@ -345,7 +345,7 @@ static unsigned calc_ext_dsor(unsigned long rate) */ for (dsor = 2; dsor < 96; ++dsor) { if ((dsor & 1) && dsor > 8) - continue; + continue; if (rate >= 96000000 / dsor) break; } @@ -687,6 +687,11 @@ int __init omap1_clk_init(void) clk_register(*clkp); continue; } + + if (((*clkp)->flags &CLOCK_IN_OMAP310) && cpu_is_omap310()) { + clk_register(*clkp); + continue; + } } info = omap_get_config(OMAP_TAG_CLOCK, struct omap_clock_config); @@ -784,7 +789,7 @@ int __init omap1_clk_init(void) clk_enable(&armxor_ck.clk); clk_enable(&armtim_ck.clk); /* This should be done by timer code */ - if (cpu_is_omap1510()) + if (cpu_is_omap15xx()) clk_enable(&arm_gpio_ck); return 0; diff --git a/arch/arm/mach-omap1/clock.h b/arch/arm/mach-omap1/clock.h index 4f18d1b9444..b7c68819c4e 100644 --- a/arch/arm/mach-omap1/clock.h +++ b/arch/arm/mach-omap1/clock.h @@ -151,7 +151,7 @@ static struct clk ck_ref = { .name = "ck_ref", .rate = 12000000, .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - ALWAYS_ENABLED, + CLOCK_IN_OMAP310 | ALWAYS_ENABLED, .enable = &omap1_clk_enable_generic, .disable = &omap1_clk_disable_generic, }; @@ -160,7 +160,7 @@ static struct clk ck_dpll1 = { .name = "ck_dpll1", .parent = &ck_ref, .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - RATE_PROPAGATES | ALWAYS_ENABLED, + CLOCK_IN_OMAP310 | RATE_PROPAGATES | ALWAYS_ENABLED, .enable = &omap1_clk_enable_generic, .disable = &omap1_clk_disable_generic, }; @@ -183,7 +183,8 @@ static struct clk arm_ck = { .name = "arm_ck", .parent = &ck_dpll1, .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - RATE_CKCTL | RATE_PROPAGATES | ALWAYS_ENABLED, + CLOCK_IN_OMAP310 | RATE_CKCTL | RATE_PROPAGATES | + ALWAYS_ENABLED, .rate_offset = CKCTL_ARMDIV_OFFSET, .recalc = &omap1_ckctl_recalc, .enable = &omap1_clk_enable_generic, @@ -195,7 +196,8 @@ static struct arm_idlect1_clk armper_ck = { .name = "armper_ck", .parent = &ck_dpll1, .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - RATE_CKCTL | CLOCK_IDLE_CONTROL, + CLOCK_IN_OMAP310 | RATE_CKCTL | + CLOCK_IDLE_CONTROL, .enable_reg = (void __iomem *)ARM_IDLECT2, .enable_bit = EN_PERCK, .rate_offset = CKCTL_PERDIV_OFFSET, @@ -209,7 +211,7 @@ static struct arm_idlect1_clk armper_ck = { static struct clk arm_gpio_ck = { .name = "arm_gpio_ck", .parent = &ck_dpll1, - .flags = CLOCK_IN_OMAP1510, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, .enable_reg = (void __iomem *)ARM_IDLECT2, .enable_bit = EN_GPIOCK, .recalc = &followparent_recalc, @@ -222,7 +224,7 @@ static struct arm_idlect1_clk armxor_ck = { .name = "armxor_ck", .parent = &ck_ref, .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - CLOCK_IDLE_CONTROL, + CLOCK_IN_OMAP310 | CLOCK_IDLE_CONTROL, .enable_reg = (void __iomem *)ARM_IDLECT2, .enable_bit = EN_XORPCK, .recalc = &followparent_recalc, @@ -237,7 +239,7 @@ static struct arm_idlect1_clk armtim_ck = { .name = "armtim_ck", .parent = &ck_ref, .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - CLOCK_IDLE_CONTROL, + CLOCK_IN_OMAP310 | CLOCK_IDLE_CONTROL, .enable_reg = (void __iomem *)ARM_IDLECT2, .enable_bit = EN_TIMCK, .recalc = &followparent_recalc, @@ -252,7 +254,7 @@ static struct arm_idlect1_clk armwdt_ck = { .name = "armwdt_ck", .parent = &ck_ref, .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - CLOCK_IDLE_CONTROL, + CLOCK_IN_OMAP310 | CLOCK_IDLE_CONTROL, .enable_reg = (void __iomem *)ARM_IDLECT2, .enable_bit = EN_WDTCK, .recalc = &omap1_watchdog_recalc, @@ -344,9 +346,9 @@ static struct arm_idlect1_clk tc_ck = { .name = "tc_ck", .parent = &ck_dpll1, .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - CLOCK_IN_OMAP730 | RATE_CKCTL | - RATE_PROPAGATES | ALWAYS_ENABLED | - CLOCK_IDLE_CONTROL, + CLOCK_IN_OMAP730 | CLOCK_IN_OMAP310 | + RATE_CKCTL | RATE_PROPAGATES | + ALWAYS_ENABLED | CLOCK_IDLE_CONTROL, .rate_offset = CKCTL_TCDIV_OFFSET, .recalc = &omap1_ckctl_recalc, .enable = &omap1_clk_enable_generic, @@ -358,7 +360,8 @@ static struct arm_idlect1_clk tc_ck = { static struct clk arminth_ck1510 = { .name = "arminth_ck", .parent = &tc_ck.clk, - .flags = CLOCK_IN_OMAP1510 | ALWAYS_ENABLED, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, .recalc = &followparent_recalc, /* Note: On 1510 the frequency follows TC_CK * @@ -372,7 +375,8 @@ static struct clk tipb_ck = { /* No-idle controlled by "tc_ck" */ .name = "tibp_ck", .parent = &tc_ck.clk, - .flags = CLOCK_IN_OMAP1510 | ALWAYS_ENABLED, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, .recalc = &followparent_recalc, .enable = &omap1_clk_enable_generic, .disable = &omap1_clk_disable_generic, @@ -417,7 +421,7 @@ static struct clk dma_ck = { .name = "dma_ck", .parent = &tc_ck.clk, .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - ALWAYS_ENABLED, + CLOCK_IN_OMAP310 | ALWAYS_ENABLED, .recalc = &followparent_recalc, .enable = &omap1_clk_enable_generic, .disable = &omap1_clk_disable_generic, @@ -437,7 +441,7 @@ static struct arm_idlect1_clk api_ck = { .name = "api_ck", .parent = &tc_ck.clk, .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - CLOCK_IDLE_CONTROL, + CLOCK_IN_OMAP310 | CLOCK_IDLE_CONTROL, .enable_reg = (void __iomem *)ARM_IDLECT2, .enable_bit = EN_APICK, .recalc = &followparent_recalc, @@ -451,7 +455,8 @@ static struct arm_idlect1_clk lb_ck = { .clk = { .name = "lb_ck", .parent = &tc_ck.clk, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IDLE_CONTROL, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | + CLOCK_IDLE_CONTROL, .enable_reg = (void __iomem *)ARM_IDLECT2, .enable_bit = EN_LBCK, .recalc = &followparent_recalc, @@ -495,8 +500,8 @@ static struct arm_idlect1_clk lcd_ck_1510 = { .clk = { .name = "lcd_ck", .parent = &ck_dpll1, - .flags = CLOCK_IN_OMAP1510 | RATE_CKCTL | - CLOCK_IDLE_CONTROL, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | + RATE_CKCTL | CLOCK_IDLE_CONTROL, .enable_reg = (void __iomem *)ARM_IDLECT2, .enable_bit = EN_LCDCK, .rate_offset = CKCTL_LCDDIV_OFFSET, @@ -512,8 +517,9 @@ static struct clk uart1_1510 = { /* Direct from ULPD, no real parent */ .parent = &armper_ck.clk, .rate = 12000000, - .flags = CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT | - ALWAYS_ENABLED | CLOCK_NO_IDLE_PARENT, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | + ENABLE_REG_32BIT | ALWAYS_ENABLED | + CLOCK_NO_IDLE_PARENT, .enable_reg = (void __iomem *)MOD_CONF_CTRL_0, .enable_bit = 29, /* Chooses between 12MHz and 48MHz */ .set_rate = &omap1_set_uart_rate, @@ -544,8 +550,8 @@ static struct clk uart2_ck = { .parent = &armper_ck.clk, .rate = 12000000, .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - ENABLE_REG_32BIT | ALWAYS_ENABLED | - CLOCK_NO_IDLE_PARENT, + CLOCK_IN_OMAP310 | ENABLE_REG_32BIT | + ALWAYS_ENABLED | CLOCK_NO_IDLE_PARENT, .enable_reg = (void __iomem *)MOD_CONF_CTRL_0, .enable_bit = 30, /* Chooses between 12MHz and 48MHz */ .set_rate = &omap1_set_uart_rate, @@ -559,8 +565,9 @@ static struct clk uart3_1510 = { /* Direct from ULPD, no real parent */ .parent = &armper_ck.clk, .rate = 12000000, - .flags = CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT | - ALWAYS_ENABLED | CLOCK_NO_IDLE_PARENT, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | + ENABLE_REG_32BIT | ALWAYS_ENABLED | + CLOCK_NO_IDLE_PARENT, .enable_reg = (void __iomem *)MOD_CONF_CTRL_0, .enable_bit = 31, /* Chooses between 12MHz and 48MHz */ .set_rate = &omap1_set_uart_rate, @@ -590,7 +597,7 @@ static struct clk usb_clko = { /* 6 MHz output on W4_USB_CLKO */ /* Direct from ULPD, no parent */ .rate = 6000000, .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - RATE_FIXED | ENABLE_REG_32BIT, + CLOCK_IN_OMAP310 | RATE_FIXED | ENABLE_REG_32BIT, .enable_reg = (void __iomem *)ULPD_CLOCK_CTRL, .enable_bit = USB_MCLK_EN_BIT, .enable = &omap1_clk_enable_generic, @@ -601,7 +608,7 @@ static struct clk usb_hhc_ck1510 = { .name = "usb_hhc_ck", /* Direct from ULPD, no parent */ .rate = 48000000, /* Actually 2 clocks, 12MHz and 48MHz */ - .flags = CLOCK_IN_OMAP1510 | + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | RATE_FIXED | ENABLE_REG_32BIT, .enable_reg = (void __iomem *)MOD_CONF_CTRL_0, .enable_bit = USB_HOST_HHC_UHOST_EN, @@ -637,7 +644,9 @@ static struct clk mclk_1510 = { .name = "mclk", /* Direct from ULPD, no parent. May be enabled by ext hardware. */ .rate = 12000000, - .flags = CLOCK_IN_OMAP1510 | RATE_FIXED, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | RATE_FIXED, + .enable_reg = (void __iomem *)SOFT_REQ_REG, + .enable_bit = 6, .enable = &omap1_clk_enable_generic, .disable = &omap1_clk_disable_generic, }; @@ -659,7 +668,7 @@ static struct clk bclk_1510 = { .name = "bclk", /* Direct from ULPD, no parent. May be enabled by ext hardware. */ .rate = 12000000, - .flags = CLOCK_IN_OMAP1510 | RATE_FIXED, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | RATE_FIXED, .enable = &omap1_clk_enable_generic, .disable = &omap1_clk_disable_generic, }; @@ -678,12 +687,14 @@ static struct clk bclk_16xx = { }; static struct clk mmc1_ck = { - .name = "mmc1_ck", + .name = "mmc_ck", + .id = 1, /* Functional clock is direct from ULPD, interface clock is ARMPER */ .parent = &armper_ck.clk, .rate = 48000000, .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - RATE_FIXED | ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT, + CLOCK_IN_OMAP310 | RATE_FIXED | ENABLE_REG_32BIT | + CLOCK_NO_IDLE_PARENT, .enable_reg = (void __iomem *)MOD_CONF_CTRL_0, .enable_bit = 23, .enable = &omap1_clk_enable_generic, @@ -691,7 +702,8 @@ static struct clk mmc1_ck = { }; static struct clk mmc2_ck = { - .name = "mmc2_ck", + .name = "mmc_ck", + .id = 2, /* Functional clock is direct from ULPD, interface clock is ARMPER */ .parent = &armper_ck.clk, .rate = 48000000, @@ -706,7 +718,7 @@ static struct clk mmc2_ck = { static struct clk virtual_ck_mpu = { .name = "mpu", .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - VIRTUAL_CLOCK | ALWAYS_ENABLED, + CLOCK_IN_OMAP310 | VIRTUAL_CLOCK | ALWAYS_ENABLED, .parent = &arm_ck, /* Is smarter alias for */ .recalc = &followparent_recalc, .set_rate = &omap1_select_table_rate, @@ -715,6 +727,20 @@ static struct clk virtual_ck_mpu = { .disable = &omap1_clk_disable_generic, }; +/* virtual functional clock domain for I2C. Just for making sure that ARMXOR_CK +remains active during MPU idle whenever this is enabled */ +static struct clk i2c_fck = { + .name = "i2c_fck", + .id = 1, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | + VIRTUAL_CLOCK | CLOCK_NO_IDLE_PARENT | + ALWAYS_ENABLED, + .parent = &armxor_ck.clk, + .recalc = &followparent_recalc, + .enable = &omap1_clk_enable_generic, + .disable = &omap1_clk_disable_generic, +}; + static struct clk * onchip_clks[] = { /* non-ULPD clocks */ &ck_ref, @@ -763,6 +789,7 @@ static struct clk * onchip_clks[] = { &mmc2_ck, /* Virtual clocks */ &virtual_ck_mpu, + &i2c_fck, }; #endif diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c index ecbc47514ad..876c38da14f 100644 --- a/arch/arm/mach-omap1/devices.c +++ b/arch/arm/mach-omap1/devices.c @@ -99,6 +99,45 @@ static void omap_init_rtc(void) static inline void omap_init_rtc(void) {} #endif +#if defined(CONFIG_OMAP_STI) + +#define OMAP1_STI_BASE IO_ADDRESS(0xfffea000) +#define OMAP1_STI_CHANNEL_BASE (OMAP1_STI_BASE + 0x400) + +static struct resource sti_resources[] = { + { + .start = OMAP1_STI_BASE, + .end = OMAP1_STI_BASE + SZ_1K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = OMAP1_STI_CHANNEL_BASE, + .end = OMAP1_STI_CHANNEL_BASE + SZ_1K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = INT_1610_STI, + .flags = IORESOURCE_IRQ, + } +}; + +static struct platform_device sti_device = { + .name = "sti", + .id = -1, + .dev = { + .release = omap_nop_release, + }, + .num_resources = ARRAY_SIZE(sti_resources), + .resource = sti_resources, +}; + +static inline void omap_init_sti(void) +{ + platform_device_register(&sti_device); +} +#else +static inline void omap_init_sti(void) {} +#endif /*-------------------------------------------------------------------------*/ @@ -129,6 +168,7 @@ static int __init omap1_init_devices(void) */ omap_init_irda(); omap_init_rtc(); + omap_init_sti(); return 0; } diff --git a/arch/arm/mach-omap1/io.c b/arch/arm/mach-omap1/io.c index 82d556be79c..be3a2a4ee2b 100644 --- a/arch/arm/mach-omap1/io.c +++ b/arch/arm/mach-omap1/io.c @@ -18,6 +18,7 @@ #include <asm/io.h> #include <asm/arch/mux.h> #include <asm/arch/tc.h> +#include <asm/arch/omapfb.h> extern int omap1_clk_init(void); extern void omap_check_revision(void); @@ -110,7 +111,7 @@ void __init omap1_map_common_io(void) } #endif #ifdef CONFIG_ARCH_OMAP15XX - if (cpu_is_omap1510()) { + if (cpu_is_omap15xx()) { iotable_init(omap1510_io_desc, ARRAY_SIZE(omap1510_io_desc)); } #endif @@ -121,6 +122,7 @@ void __init omap1_map_common_io(void) #endif omap_sram_init(); + omapfb_reserve_mem(); } /* diff --git a/arch/arm/mach-omap1/irq.c b/arch/arm/mach-omap1/irq.c index ed65a7d2e94..a0431c00fa8 100644 --- a/arch/arm/mach-omap1/irq.c +++ b/arch/arm/mach-omap1/irq.c @@ -60,7 +60,7 @@ struct omap_irq_bank { unsigned long wake_enable; }; -static unsigned int irq_bank_count = 0; +static unsigned int irq_bank_count; static struct omap_irq_bank *irq_banks; static inline unsigned int irq_bank_readl(int bank, int offset) @@ -142,28 +142,28 @@ static void omap_irq_set_cfg(int irq, int fiq, int priority, int trigger) #ifdef CONFIG_ARCH_OMAP730 static struct omap_irq_bank omap730_irq_banks[] = { - { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3f8e22f }, - { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xfdb9c1f2 }, + { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3f8e22f }, + { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xfdb9c1f2 }, { .base_reg = OMAP_IH2_BASE + 0x100, .trigger_map = 0x800040f3 }, }; #endif #ifdef CONFIG_ARCH_OMAP15XX static struct omap_irq_bank omap1510_irq_banks[] = { - { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3febfff }, - { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xffbfffed }, + { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3febfff }, + { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xffbfffed }, }; static struct omap_irq_bank omap310_irq_banks[] = { - { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3faefc3 }, - { .base_reg = OMAP_IH2_BASE, .trigger_map = 0x65b3c061 }, + { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3faefc3 }, + { .base_reg = OMAP_IH2_BASE, .trigger_map = 0x65b3c061 }, }; #endif #if defined(CONFIG_ARCH_OMAP16XX) static struct omap_irq_bank omap1610_irq_banks[] = { - { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3fefe8f }, - { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xfdb7c1fd }, + { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3fefe8f }, + { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xfdb7c1fd }, { .base_reg = OMAP_IH2_BASE + 0x100, .trigger_map = 0xffffb7ff }, { .base_reg = OMAP_IH2_BASE + 0x200, .trigger_map = 0xffffffff }, }; diff --git a/arch/arm/mach-omap1/mux.c b/arch/arm/mach-omap1/mux.c index d4b8d624e74..10fe0b3efca 100644 --- a/arch/arm/mach-omap1/mux.c +++ b/arch/arm/mach-omap1/mux.c @@ -35,16 +35,20 @@ #ifdef CONFIG_ARCH_OMAP730 struct pin_config __initdata_or_module omap730_pins[] = { -MUX_CFG_730("E2_730_KBR0", 12, 21, 0, 0, 20, 1, NA, 0, 0) -MUX_CFG_730("J7_730_KBR1", 12, 25, 0, 0, 24, 1, NA, 0, 0) -MUX_CFG_730("E1_730_KBR2", 12, 29, 0, 0, 28, 1, NA, 0, 0) -MUX_CFG_730("F3_730_KBR3", 13, 1, 0, 0, 0, 1, NA, 0, 0) -MUX_CFG_730("D2_730_KBR4", 13, 5, 0, 0, 4, 1, NA, 0, 0) -MUX_CFG_730("C2_730_KBC0", 13, 9, 0, 0, 8, 1, NA, 0, 0) -MUX_CFG_730("D3_730_KBC1", 13, 13, 0, 0, 12, 1, NA, 0, 0) -MUX_CFG_730("E4_730_KBC2", 13, 17, 0, 0, 16, 1, NA, 0, 0) -MUX_CFG_730("F4_730_KBC3", 13, 21, 0, 0, 20, 1, NA, 0, 0) -MUX_CFG_730("E3_730_KBC4", 13, 25, 0, 0, 24, 1, NA, 0, 0) +MUX_CFG_730("E2_730_KBR0", 12, 21, 0, 20, 1, 0) +MUX_CFG_730("J7_730_KBR1", 12, 25, 0, 24, 1, 0) +MUX_CFG_730("E1_730_KBR2", 12, 29, 0, 28, 1, 0) +MUX_CFG_730("F3_730_KBR3", 13, 1, 0, 0, 1, 0) +MUX_CFG_730("D2_730_KBR4", 13, 5, 0, 4, 1, 0) +MUX_CFG_730("C2_730_KBC0", 13, 9, 0, 8, 1, 0) +MUX_CFG_730("D3_730_KBC1", 13, 13, 0, 12, 1, 0) +MUX_CFG_730("E4_730_KBC2", 13, 17, 0, 16, 1, 0) +MUX_CFG_730("F4_730_KBC3", 13, 21, 0, 20, 1, 0) +MUX_CFG_730("E3_730_KBC4", 13, 25, 0, 24, 1, 0) + +MUX_CFG_730("AA17_730_USB_DM", 2, 21, 0, 20, 0, 0) +MUX_CFG_730("W16_730_USB_PU_EN", 2, 25, 0, 24, 0, 0) +MUX_CFG_730("W17_730_USB_VBUSI", 2, 29, 0, 28, 0, 0) }; #endif @@ -73,8 +77,8 @@ MUX_CFG("UART3_BCLK", A, 0, 0, 2, 6, 0, NA, 0, 0) MUX_CFG("Y15_1610_UART3_RTS", A, 0, 1, 2, 6, 0, NA, 0, 0) /* PWT & PWL, conflicts with UART3 */ -MUX_CFG("PWT", 6, 0, 2, 0, 30, 0, NA, 0, 0) -MUX_CFG("PWL", 6, 3, 1, 0, 31, 1, NA, 0, 0) +MUX_CFG("PWT", 6, 0, 2, 0, 30, 0, NA, 0, 0) +MUX_CFG("PWL", 6, 3, 1, 0, 31, 1, NA, 0, 0) /* USB internal master generic */ MUX_CFG("R18_USB_VBUS", 7, 9, 2, 1, 11, 0, NA, 0, 1) @@ -151,7 +155,7 @@ MUX_CFG("MCBSP3_CLKX", 9, 3, 1, 1, 29, 0, NA, 0, 1) /* Misc ballouts */ MUX_CFG("BALLOUT_V8_ARMIO3", B, 18, 0, 2, 25, 1, NA, 0, 1) -MUX_CFG("N20_HDQ", 6, 18, 1, 1, 4, 0, 1, 4, 0) +MUX_CFG("N20_HDQ", 6, 18, 1, 1, 4, 0, 1, 4, 0) /* OMAP-1610 MMC2 */ MUX_CFG("W8_1610_MMC2_DAT0", B, 21, 6, 2, 23, 1, 2, 1, 1) diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c new file mode 100644 index 00000000000..ddf6b07dc9c --- /dev/null +++ b/arch/arm/mach-omap1/pm.c @@ -0,0 +1,770 @@ +/* + * linux/arch/arm/mach-omap1/pm.c + * + * OMAP Power Management Routines + * + * Original code for the SA11x0: + * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com> + * + * Modified for the PXA250 by Nicolas Pitre: + * Copyright (c) 2002 Monta Vista Software, Inc. + * + * Modified for the OMAP1510 by David Singleton: + * Copyright (c) 2002 Monta Vista Software, Inc. + * + * Cleanup 2004 for OMAP1510/1610 by Dirk Behme <dirk.behme@de.bosch.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/pm.h> +#include <linux/sched.h> +#include <linux/proc_fs.h> +#include <linux/pm.h> +#include <linux/interrupt.h> +#include <linux/sysfs.h> +#include <linux/module.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/atomic.h> +#include <asm/mach/time.h> +#include <asm/mach/irq.h> +#include <asm/mach-types.h> + +#include <asm/arch/irqs.h> +#include <asm/arch/clock.h> +#include <asm/arch/sram.h> +#include <asm/arch/tc.h> +#include <asm/arch/pm.h> +#include <asm/arch/mux.h> +#include <asm/arch/tps65010.h> +#include <asm/arch/dma.h> +#include <asm/arch/dsp_common.h> +#include <asm/arch/dmtimer.h> + +static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE]; +static unsigned short dsp_sleep_save[DSP_SLEEP_SAVE_SIZE]; +static unsigned short ulpd_sleep_save[ULPD_SLEEP_SAVE_SIZE]; +static unsigned int mpui730_sleep_save[MPUI730_SLEEP_SAVE_SIZE]; +static unsigned int mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_SIZE]; +static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE]; + +static unsigned short enable_dyn_sleep = 1; + +static ssize_t omap_pm_sleep_while_idle_show(struct subsystem * subsys, char *buf) +{ + return sprintf(buf, "%hu\n", enable_dyn_sleep); +} + +static ssize_t omap_pm_sleep_while_idle_store(struct subsystem * subsys, + const char * buf, + size_t n) +{ + unsigned short value; + if (sscanf(buf, "%hu", &value) != 1 || + (value != 0 && value != 1)) { + printk(KERN_ERR "idle_sleep_store: Invalid value\n"); + return -EINVAL; + } + enable_dyn_sleep = value; + return n; +} + +static struct subsys_attribute sleep_while_idle_attr = { + .attr = { + .name = __stringify(sleep_while_idle), + .mode = 0644, + }, + .show = omap_pm_sleep_while_idle_show, + .store = omap_pm_sleep_while_idle_store, +}; + +extern struct subsystem power_subsys; +static void (*omap_sram_idle)(void) = NULL; +static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL; + +/* + * Let's power down on idle, but only if we are really + * idle, because once we start down the path of + * going idle we continue to do idle even if we get + * a clock tick interrupt . . + */ +void omap_pm_idle(void) +{ + extern __u32 arm_idlect1_mask; + __u32 use_idlect1 = arm_idlect1_mask; +#ifndef CONFIG_OMAP_MPU_TIMER + int do_sleep; +#endif + + local_irq_disable(); + local_fiq_disable(); + if (need_resched()) { + local_fiq_enable(); + local_irq_enable(); + return; + } + + /* + * Since an interrupt may set up a timer, we don't want to + * reprogram the hardware timer with interrupts enabled. + * Re-enable interrupts only after returning from idle. + */ + timer_dyn_reprogram(); + +#ifdef CONFIG_OMAP_MPU_TIMER +#warning Enable 32kHz OS timer in order to allow sleep states in idle + use_idlect1 = use_idlect1 & ~(1 << 9); +#else + + do_sleep = 0; + while (enable_dyn_sleep) { + +#ifdef CONFIG_CBUS_TAHVO_USB + extern int vbus_active; + /* Clock requirements? */ + if (vbus_active) + break; +#endif + do_sleep = 1; + break; + } + +#ifdef CONFIG_OMAP_DM_TIMER + use_idlect1 = omap_dm_timer_modify_idlect_mask(use_idlect1); +#endif + + if (omap_dma_running()) { + use_idlect1 &= ~(1 << 6); + if (omap_lcd_dma_ext_running()) + use_idlect1 &= ~(1 << 12); + } + + /* We should be able to remove the do_sleep variable and multiple + * tests above as soon as drivers, timer and DMA code have been fixed. + * Even the sleep block count should become obsolete. */ + if ((use_idlect1 != ~0) || !do_sleep) { + + __u32 saved_idlect1 = omap_readl(ARM_IDLECT1); + if (cpu_is_omap15xx()) + use_idlect1 &= OMAP1510_BIG_SLEEP_REQUEST; + else + use_idlect1 &= OMAP1610_IDLECT1_SLEEP_VAL; + omap_writel(use_idlect1, ARM_IDLECT1); + __asm__ volatile ("mcr p15, 0, r0, c7, c0, 4"); + omap_writel(saved_idlect1, ARM_IDLECT1); + + local_fiq_enable(); + local_irq_enable(); + return; + } + omap_sram_suspend(omap_readl(ARM_IDLECT1), + omap_readl(ARM_IDLECT2)); +#endif + + local_fiq_enable(); + local_irq_enable(); +} + +/* + * Configuration of the wakeup event is board specific. For the + * moment we put it into this helper function. Later it may move + * to board specific files. + */ +static void omap_pm_wakeup_setup(void) +{ + u32 level1_wake = 0; + u32 level2_wake = OMAP_IRQ_BIT(INT_UART2); + + /* + * Turn off all interrupts except GPIO bank 1, L1-2nd level cascade, + * and the L2 wakeup interrupts: keypad and UART2. Note that the + * drivers must still separately call omap_set_gpio_wakeup() to + * wake up to a GPIO interrupt. + */ + if (cpu_is_omap730()) + level1_wake = OMAP_IRQ_BIT(INT_730_GPIO_BANK1) | + OMAP_IRQ_BIT(INT_730_IH2_IRQ); + else if (cpu_is_omap15xx()) + level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) | + OMAP_IRQ_BIT(INT_1510_IH2_IRQ); + else if (cpu_is_omap16xx()) + level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) | + OMAP_IRQ_BIT(INT_1610_IH2_IRQ); + + omap_writel(~level1_wake, OMAP_IH1_MIR); + + if (cpu_is_omap730()) { + omap_writel(~level2_wake, OMAP_IH2_0_MIR); + omap_writel(~(OMAP_IRQ_BIT(INT_730_WAKE_UP_REQ) | + OMAP_IRQ_BIT(INT_730_MPUIO_KEYPAD)), + OMAP_IH2_1_MIR); + } else if (cpu_is_omap15xx()) { + level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD); + omap_writel(~level2_wake, OMAP_IH2_MIR); + } else if (cpu_is_omap16xx()) { + level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD); + omap_writel(~level2_wake, OMAP_IH2_0_MIR); + + /* INT_1610_WAKE_UP_REQ is needed for GPIO wakeup... */ + omap_writel(~OMAP_IRQ_BIT(INT_1610_WAKE_UP_REQ), + OMAP_IH2_1_MIR); + omap_writel(~0x0, OMAP_IH2_2_MIR); + omap_writel(~0x0, OMAP_IH2_3_MIR); + } + + /* New IRQ agreement, recalculate in cascade order */ + omap_writel(1, OMAP_IH2_CONTROL); + omap_writel(1, OMAP_IH1_CONTROL); +} + +#define EN_DSPCK 13 /* ARM_CKCTL */ +#define EN_APICK 6 /* ARM_IDLECT2 */ +#define DSP_EN 1 /* ARM_RSTCT1 */ + +void omap_pm_suspend(void) +{ + unsigned long arg0 = 0, arg1 = 0; + + printk("PM: OMAP%x is trying to enter deep sleep...\n", system_rev); + + omap_serial_wake_trigger(1); + + if (machine_is_omap_osk()) { + /* Stop LED1 (D9) blink */ + tps65010_set_led(LED1, OFF); + } + + omap_writew(0xffff, ULPD_SOFT_DISABLE_REQ_REG); + + /* + * Step 1: turn off interrupts (FIXME: NOTE: already disabled) + */ + + local_irq_disable(); + local_fiq_disable(); + + /* + * Step 2: save registers + * + * The omap is a strange/beautiful device. The caches, memory + * and register state are preserved across power saves. + * We have to save and restore very little register state to + * idle the omap. + * + * Save interrupt, MPUI, ARM and UPLD control registers. + */ + + if (cpu_is_omap730()) { + MPUI730_SAVE(OMAP_IH1_MIR); + MPUI730_SAVE(OMAP_IH2_0_MIR); + MPUI730_SAVE(OMAP_IH2_1_MIR); + MPUI730_SAVE(MPUI_CTRL); + MPUI730_SAVE(MPUI_DSP_BOOT_CONFIG); + MPUI730_SAVE(MPUI_DSP_API_CONFIG); + MPUI730_SAVE(EMIFS_CONFIG); + MPUI730_SAVE(EMIFF_SDRAM_CONFIG); + + } else if (cpu_is_omap15xx()) { + MPUI1510_SAVE(OMAP_IH1_MIR); + MPUI1510_SAVE(OMAP_IH2_MIR); + MPUI1510_SAVE(MPUI_CTRL); + MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG); + MPUI1510_SAVE(MPUI_DSP_API_CONFIG); + MPUI1510_SAVE(EMIFS_CONFIG); + MPUI1510_SAVE(EMIFF_SDRAM_CONFIG); + } else if (cpu_is_omap16xx()) { + MPUI1610_SAVE(OMAP_IH1_MIR); + MPUI1610_SAVE(OMAP_IH2_0_MIR); + MPUI1610_SAVE(OMAP_IH2_1_MIR); + MPUI1610_SAVE(OMAP_IH2_2_MIR); + MPUI1610_SAVE(OMAP_IH2_3_MIR); + MPUI1610_SAVE(MPUI_CTRL); + MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG); + MPUI1610_SAVE(MPUI_DSP_API_CONFIG); + MPUI1610_SAVE(EMIFS_CONFIG); + MPUI1610_SAVE(EMIFF_SDRAM_CONFIG); + } + + ARM_SAVE(ARM_CKCTL); + ARM_SAVE(ARM_IDLECT1); + ARM_SAVE(ARM_IDLECT2); + if (!(cpu_is_omap15xx())) + ARM_SAVE(ARM_IDLECT3); + ARM_SAVE(ARM_EWUPCT); + ARM_SAVE(ARM_RSTCT1); + ARM_SAVE(ARM_RSTCT2); + ARM_SAVE(ARM_SYSST); + ULPD_SAVE(ULPD_CLOCK_CTRL); + ULPD_SAVE(ULPD_STATUS_REQ); + + /* (Step 3 removed - we now allow deep sleep by default) */ + + /* + * Step 4: OMAP DSP Shutdown + */ + + /* stop DSP */ + omap_writew(omap_readw(ARM_RSTCT1) & ~(1 << DSP_EN), ARM_RSTCT1); + + /* shut down dsp_ck */ + omap_writew(omap_readw(ARM_CKCTL) & ~(1 << EN_DSPCK), ARM_CKCTL); + + /* temporarily enabling api_ck to access DSP registers */ + omap_writew(omap_readw(ARM_IDLECT2) | 1 << EN_APICK, ARM_IDLECT2); + + /* save DSP registers */ + DSP_SAVE(DSP_IDLECT2); + + /* Stop all DSP domain clocks */ + __raw_writew(0, DSP_IDLECT2); + + /* + * Step 5: Wakeup Event Setup + */ + + omap_pm_wakeup_setup(); + + /* + * Step 6: ARM and Traffic controller shutdown + */ + + /* disable ARM watchdog */ + omap_writel(0x00F5, OMAP_WDT_TIMER_MODE); + omap_writel(0x00A0, OMAP_WDT_TIMER_MODE); + + /* + * Step 6b: ARM and Traffic controller shutdown + * + * Step 6 continues here. Prepare jump to power management + * assembly code in internal SRAM. + * + * Since the omap_cpu_suspend routine has been copied to + * SRAM, we'll do an indirect procedure call to it and pass the + * contents of arm_idlect1 and arm_idlect2 so it can restore + * them when it wakes up and it will return. + */ + + arg0 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT1]; + arg1 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT2]; + + /* + * Step 6c: ARM and Traffic controller shutdown + * + * Jump to assembly code. The processor will stay there + * until wake up. + */ + omap_sram_suspend(arg0, arg1); + + /* + * If we are here, processor is woken up! + */ + + /* + * Restore DSP clocks + */ + + /* again temporarily enabling api_ck to access DSP registers */ + omap_writew(omap_readw(ARM_IDLECT2) | 1 << EN_APICK, ARM_IDLECT2); + + /* Restore DSP domain clocks */ + DSP_RESTORE(DSP_IDLECT2); + + /* + * Restore ARM state, except ARM_IDLECT1/2 which omap_cpu_suspend did + */ + + if (!(cpu_is_omap15xx())) + ARM_RESTORE(ARM_IDLECT3); + ARM_RESTORE(ARM_CKCTL); + ARM_RESTORE(ARM_EWUPCT); + ARM_RESTORE(ARM_RSTCT1); + ARM_RESTORE(ARM_RSTCT2); + ARM_RESTORE(ARM_SYSST); + ULPD_RESTORE(ULPD_CLOCK_CTRL); + ULPD_RESTORE(ULPD_STATUS_REQ); + + if (cpu_is_omap730()) { + MPUI730_RESTORE(EMIFS_CONFIG); + MPUI730_RESTORE(EMIFF_SDRAM_CONFIG); + MPUI730_RESTORE(OMAP_IH1_MIR); + MPUI730_RESTORE(OMAP_IH2_0_MIR); + MPUI730_RESTORE(OMAP_IH2_1_MIR); + } else if (cpu_is_omap15xx()) { + MPUI1510_RESTORE(MPUI_CTRL); + MPUI1510_RESTORE(MPUI_DSP_BOOT_CONFIG); + MPUI1510_RESTORE(MPUI_DSP_API_CONFIG); + MPUI1510_RESTORE(EMIFS_CONFIG); + MPUI1510_RESTORE(EMIFF_SDRAM_CONFIG); + MPUI1510_RESTORE(OMAP_IH1_MIR); + MPUI1510_RESTORE(OMAP_IH2_MIR); + } else if (cpu_is_omap16xx()) { + MPUI1610_RESTORE(MPUI_CTRL); + MPUI1610_RESTORE(MPUI_DSP_BOOT_CONFIG); + MPUI1610_RESTORE(MPUI_DSP_API_CONFIG); + MPUI1610_RESTORE(EMIFS_CONFIG); + MPUI1610_RESTORE(EMIFF_SDRAM_CONFIG); + + MPUI1610_RESTORE(OMAP_IH1_MIR); + MPUI1610_RESTORE(OMAP_IH2_0_MIR); + MPUI1610_RESTORE(OMAP_IH2_1_MIR); + MPUI1610_RESTORE(OMAP_IH2_2_MIR); + MPUI1610_RESTORE(OMAP_IH2_3_MIR); + } + + omap_writew(0, ULPD_SOFT_DISABLE_REQ_REG); + + /* + * Reenable interrupts + */ + + local_irq_enable(); + local_fiq_enable(); + + omap_serial_wake_trigger(0); + + printk("PM: OMAP%x is re-starting from deep sleep...\n", system_rev); + + if (machine_is_omap_osk()) { + /* Let LED1 (D9) blink again */ + tps65010_set_led(LED1, BLINK); + } +} + +#if defined(DEBUG) && defined(CONFIG_PROC_FS) +static int g_read_completed; + +/* + * Read system PM registers for debugging + */ +static int omap_pm_read_proc( + char *page_buffer, + char **my_first_byte, + off_t virtual_start, + int length, + int *eof, + void *data) +{ + int my_buffer_offset = 0; + char * const my_base = page_buffer; + + ARM_SAVE(ARM_CKCTL); + ARM_SAVE(ARM_IDLECT1); + ARM_SAVE(ARM_IDLECT2); + if (!(cpu_is_omap15xx())) + ARM_SAVE(ARM_IDLECT3); + ARM_SAVE(ARM_EWUPCT); + ARM_SAVE(ARM_RSTCT1); + ARM_SAVE(ARM_RSTCT2); + ARM_SAVE(ARM_SYSST); + + ULPD_SAVE(ULPD_IT_STATUS); + ULPD_SAVE(ULPD_CLOCK_CTRL); + ULPD_SAVE(ULPD_SOFT_REQ); + ULPD_SAVE(ULPD_STATUS_REQ); + ULPD_SAVE(ULPD_DPLL_CTRL); + ULPD_SAVE(ULPD_POWER_CTRL); + + if (cpu_is_omap730()) { + MPUI730_SAVE(MPUI_CTRL); + MPUI730_SAVE(MPUI_DSP_STATUS); + MPUI730_SAVE(MPUI_DSP_BOOT_CONFIG); + MPUI730_SAVE(MPUI_DSP_API_CONFIG); + MPUI730_SAVE(EMIFF_SDRAM_CONFIG); + MPUI730_SAVE(EMIFS_CONFIG); + } else if (cpu_is_omap15xx()) { + MPUI1510_SAVE(MPUI_CTRL); + MPUI1510_SAVE(MPUI_DSP_STATUS); + MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG); + MPUI1510_SAVE(MPUI_DSP_API_CONFIG); + MPUI1510_SAVE(EMIFF_SDRAM_CONFIG); + MPUI1510_SAVE(EMIFS_CONFIG); + } else if (cpu_is_omap16xx()) { + MPUI1610_SAVE(MPUI_CTRL); + MPUI1610_SAVE(MPUI_DSP_STATUS); + MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG); + MPUI1610_SAVE(MPUI_DSP_API_CONFIG); + MPUI1610_SAVE(EMIFF_SDRAM_CONFIG); + MPUI1610_SAVE(EMIFS_CONFIG); + } + + if (virtual_start == 0) { + g_read_completed = 0; + + my_buffer_offset += sprintf(my_base + my_buffer_offset, + "ARM_CKCTL_REG: 0x%-8x \n" + "ARM_IDLECT1_REG: 0x%-8x \n" + "ARM_IDLECT2_REG: 0x%-8x \n" + "ARM_IDLECT3_REG: 0x%-8x \n" + "ARM_EWUPCT_REG: 0x%-8x \n" + "ARM_RSTCT1_REG: 0x%-8x \n" + "ARM_RSTCT2_REG: 0x%-8x \n" + "ARM_SYSST_REG: 0x%-8x \n" + "ULPD_IT_STATUS_REG: 0x%-4x \n" + "ULPD_CLOCK_CTRL_REG: 0x%-4x \n" + "ULPD_SOFT_REQ_REG: 0x%-4x \n" + "ULPD_DPLL_CTRL_REG: 0x%-4x \n" + "ULPD_STATUS_REQ_REG: 0x%-4x \n" + "ULPD_POWER_CTRL_REG: 0x%-4x \n", + ARM_SHOW(ARM_CKCTL), + ARM_SHOW(ARM_IDLECT1), + ARM_SHOW(ARM_IDLECT2), + ARM_SHOW(ARM_IDLECT3), + ARM_SHOW(ARM_EWUPCT), + ARM_SHOW(ARM_RSTCT1), + ARM_SHOW(ARM_RSTCT2), + ARM_SHOW(ARM_SYSST), + ULPD_SHOW(ULPD_IT_STATUS), + ULPD_SHOW(ULPD_CLOCK_CTRL), + ULPD_SHOW(ULPD_SOFT_REQ), + ULPD_SHOW(ULPD_DPLL_CTRL), + ULPD_SHOW(ULPD_STATUS_REQ), + ULPD_SHOW(ULPD_POWER_CTRL)); + + if (cpu_is_omap730()) { + my_buffer_offset += sprintf(my_base + my_buffer_offset, + "MPUI730_CTRL_REG 0x%-8x \n" + "MPUI730_DSP_STATUS_REG: 0x%-8x \n" + "MPUI730_DSP_BOOT_CONFIG_REG: 0x%-8x \n" + "MPUI730_DSP_API_CONFIG_REG: 0x%-8x \n" + "MPUI730_SDRAM_CONFIG_REG: 0x%-8x \n" + "MPUI730_EMIFS_CONFIG_REG: 0x%-8x \n", + MPUI730_SHOW(MPUI_CTRL), + MPUI730_SHOW(MPUI_DSP_STATUS), + MPUI730_SHOW(MPUI_DSP_BOOT_CONFIG), + MPUI730_SHOW(MPUI_DSP_API_CONFIG), + MPUI730_SHOW(EMIFF_SDRAM_CONFIG), + MPUI730_SHOW(EMIFS_CONFIG)); + } else if (cpu_is_omap15xx()) { + my_buffer_offset += sprintf(my_base + my_buffer_offset, + "MPUI1510_CTRL_REG 0x%-8x \n" + "MPUI1510_DSP_STATUS_REG: 0x%-8x \n" + "MPUI1510_DSP_BOOT_CONFIG_REG: 0x%-8x \n" + "MPUI1510_DSP_API_CONFIG_REG: 0x%-8x \n" + "MPUI1510_SDRAM_CONFIG_REG: 0x%-8x \n" + "MPUI1510_EMIFS_CONFIG_REG: 0x%-8x \n", + MPUI1510_SHOW(MPUI_CTRL), + MPUI1510_SHOW(MPUI_DSP_STATUS), + MPUI1510_SHOW(MPUI_DSP_BOOT_CONFIG), + MPUI1510_SHOW(MPUI_DSP_API_CONFIG), + MPUI1510_SHOW(EMIFF_SDRAM_CONFIG), + MPUI1510_SHOW(EMIFS_CONFIG)); + } else if (cpu_is_omap16xx()) { + my_buffer_offset += sprintf(my_base + my_buffer_offset, + "MPUI1610_CTRL_REG 0x%-8x \n" + "MPUI1610_DSP_STATUS_REG: 0x%-8x \n" + "MPUI1610_DSP_BOOT_CONFIG_REG: 0x%-8x \n" + "MPUI1610_DSP_API_CONFIG_REG: 0x%-8x \n" + "MPUI1610_SDRAM_CONFIG_REG: 0x%-8x \n" + "MPUI1610_EMIFS_CONFIG_REG: 0x%-8x \n", + MPUI1610_SHOW(MPUI_CTRL), + MPUI1610_SHOW(MPUI_DSP_STATUS), + MPUI1610_SHOW(MPUI_DSP_BOOT_CONFIG), + MPUI1610_SHOW(MPUI_DSP_API_CONFIG), + MPUI1610_SHOW(EMIFF_SDRAM_CONFIG), + MPUI1610_SHOW(EMIFS_CONFIG)); + } + + g_read_completed++; + } else if (g_read_completed >= 1) { + *eof = 1; + return 0; + } + g_read_completed++; + + *my_first_byte = page_buffer; + return my_buffer_offset; +} + +static void omap_pm_init_proc(void) +{ + struct proc_dir_entry *entry; + + entry = create_proc_read_entry("driver/omap_pm", + S_IWUSR | S_IRUGO, NULL, + omap_pm_read_proc, NULL); +} + +#endif /* DEBUG && CONFIG_PROC_FS */ + +static void (*saved_idle)(void) = NULL; + +/* + * omap_pm_prepare - Do preliminary suspend work. + * @state: suspend state we're entering. + * + */ +static int omap_pm_prepare(suspend_state_t state) +{ + int error = 0; + + /* We cannot sleep in idle until we have resumed */ + saved_idle = pm_idle; + pm_idle = NULL; + + switch (state) + { + case PM_SUSPEND_STANDBY: + case PM_SUSPEND_MEM: + break; + + case PM_SUSPEND_DISK: + return -ENOTSUPP; + + default: + return -EINVAL; + } + + return error; +} + + +/* + * omap_pm_enter - Actually enter a sleep state. + * @state: State we're entering. + * + */ + +static int omap_pm_enter(suspend_state_t state) +{ + switch (state) + { + case PM_SUSPEND_STANDBY: + case PM_SUSPEND_MEM: + omap_pm_suspend(); + break; + + case PM_SUSPEND_DISK: + return -ENOTSUPP; + + default: + return -EINVAL; + } + + return 0; +} + + +/** + * omap_pm_finish - Finish up suspend sequence. + * @state: State we're coming out of. + * + * This is called after we wake back up (or if entering the sleep state + * failed). + */ + +static int omap_pm_finish(suspend_state_t state) +{ + pm_idle = saved_idle; + return 0; +} + + +static irqreturn_t omap_wakeup_interrupt(int irq, void * dev, + struct pt_regs * regs) +{ + return IRQ_HANDLED; +} + +static struct irqaction omap_wakeup_irq = { + .name = "peripheral wakeup", + .flags = SA_INTERRUPT, + .handler = omap_wakeup_interrupt +}; + + + +static struct pm_ops omap_pm_ops ={ + .pm_disk_mode = 0, + .prepare = omap_pm_prepare, + .enter = omap_pm_enter, + .finish = omap_pm_finish, +}; + +static int __init omap_pm_init(void) +{ + printk("Power Management for TI OMAP.\n"); + + /* + * We copy the assembler sleep/wakeup routines to SRAM. + * These routines need to be in SRAM as that's the only + * memory the MPU can see when it wakes up. + */ + if (cpu_is_omap730()) { + omap_sram_idle = omap_sram_push(omap730_idle_loop_suspend, + omap730_idle_loop_suspend_sz); + omap_sram_suspend = omap_sram_push(omap730_cpu_suspend, + omap730_cpu_suspend_sz); + } else if (cpu_is_omap15xx()) { + omap_sram_idle = omap_sram_push(omap1510_idle_loop_suspend, + omap1510_idle_loop_suspend_sz); + omap_sram_suspend = omap_sram_push(omap1510_cpu_suspend, + omap1510_cpu_suspend_sz); + } else if (cpu_is_omap16xx()) { + omap_sram_idle = omap_sram_push(omap1610_idle_loop_suspend, + omap1610_idle_loop_suspend_sz); + omap_sram_suspend = omap_sram_push(omap1610_cpu_suspend, + omap1610_cpu_suspend_sz); + } + + if (omap_sram_idle == NULL || omap_sram_suspend == NULL) { + printk(KERN_ERR "PM not initialized: Missing SRAM support\n"); + return -ENODEV; + } + + pm_idle = omap_pm_idle; + + if (cpu_is_omap730()) + setup_irq(INT_730_WAKE_UP_REQ, &omap_wakeup_irq); + else if (cpu_is_omap16xx()) + setup_irq(INT_1610_WAKE_UP_REQ, &omap_wakeup_irq); + + /* Program new power ramp-up time + * (0 for most boards since we don't lower voltage when in deep sleep) + */ + omap_writew(ULPD_SETUP_ANALOG_CELL_3_VAL, ULPD_SETUP_ANALOG_CELL_3); + + /* Setup ULPD POWER_CTRL_REG - enter deep sleep whenever possible */ + omap_writew(ULPD_POWER_CTRL_REG_VAL, ULPD_POWER_CTRL); + + /* Configure IDLECT3 */ + if (cpu_is_omap730()) + omap_writel(OMAP730_IDLECT3_VAL, OMAP730_IDLECT3); + else if (cpu_is_omap16xx()) + omap_writel(OMAP1610_IDLECT3_VAL, OMAP1610_IDLECT3); + + pm_set_ops(&omap_pm_ops); + +#if defined(DEBUG) && defined(CONFIG_PROC_FS) + omap_pm_init_proc(); +#endif + + subsys_create_file(&power_subsys, &sleep_while_idle_attr); + + if (cpu_is_omap16xx()) { + /* configure LOW_PWR pin */ + omap_cfg_reg(T20_1610_LOW_PWR); + } + + return 0; +} +__initcall(omap_pm_init); diff --git a/arch/arm/mach-omap1/serial.c b/arch/arm/mach-omap1/serial.c index e924e0c6a4c..9b4cd698bec 100644 --- a/arch/arm/mach-omap1/serial.c +++ b/arch/arm/mach-omap1/serial.c @@ -30,9 +30,9 @@ #include <asm/arch/pm.h> #endif -static struct clk * uart1_ck = NULL; -static struct clk * uart2_ck = NULL; -static struct clk * uart3_ck = NULL; +static struct clk * uart1_ck; +static struct clk * uart2_ck; +static struct clk * uart3_ck; static inline unsigned int omap_serial_in(struct plat_serial8250_port *up, int offset) diff --git a/arch/arm/plat-omap/sleep.S b/arch/arm/mach-omap1/sleep.S index 4cd7d292f85..e58295e2d3b 100644 --- a/arch/arm/plat-omap/sleep.S +++ b/arch/arm/mach-omap1/sleep.S @@ -1,5 +1,5 @@ /* - * linux/arch/arm/plat-omap/sleep.S + * linux/arch/arm/mach-omap1/sleep.S * * Low-level OMAP730/1510/1610 sleep/wakeUp support * @@ -383,60 +383,133 @@ ENTRY(omap1610_cpu_suspend) mcr p15, 0, r0, c7, c10, 4 nop - @ load base address of Traffic Controller + @ Load base address of Traffic Controller mov r6, #TCMIF_ASM_BASE & 0xff000000 orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000 orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00 - @ prepare to put SDRAM into self-refresh manually + @ Prepare to put SDRAM into self-refresh manually ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] orr r9, r7, #SELF_REFRESH_MODE & 0xff000000 orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] - @ prepare to put EMIFS to Sleep + @ Prepare to put EMIFS to Sleep ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] - @ load base address of ARM_IDLECT1 and ARM_IDLECT2 + @ Load base address of ARM_IDLECT1 and ARM_IDLECT2 mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 - @ turn off clock domains - @ do not disable PERCK (0x04) + @ Turn off clock domains + @ Do not disable PERCK (0x04) mov r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff orr r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00 strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] - @ request ARM idle + @ Request ARM idle mov r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff orr r3, r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff00 strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] - @ disable instruction cache - mrc p15, 0, r9, c1, c0, 0 - bic r2, r9, #0x1000 - mcr p15, 0, r2, c1, c0, 0 - nop - /* * Let's wait for the next wake up event to wake us up. r0 can't be * used here because r0 holds ARM_IDLECT1 */ mov r2, #0 mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt + + @ Errata (HEL3SU467, section 1.4.4) specifies nop-instructions + @ according to this formula: + @ 2 + (4*DPLL_MULT)/DPLL_DIV/ARMDIV + @ Max DPLL_MULT = 18 + @ DPLL_DIV = 1 + @ ARMDIV = 1 + @ => 74 nop-instructions + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop @10 + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop @20 + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop @30 + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop @40 + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop @50 + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop @60 + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop @70 + nop + nop + nop + nop @74 /* * omap1610_cpu_suspend()'s resume point. * * It will just start executing here, so we'll restore stuff from the * stack. */ - @ re-enable Icache - mcr p15, 0, r9, c1, c0, 0 - - @ reset the ARM_IDLECT1 and ARM_IDLECT2. + @ Restore the ARM_IDLECT1 and ARM_IDLECT2. strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] @@ -444,7 +517,7 @@ ENTRY(omap1610_cpu_suspend) str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] - @ restore regs and return + @ Restore regs and return ldmfd sp!, {r0 - r12, pc} ENTRY(omap1610_cpu_suspend_sz) diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c index cdbf4d7620c..a85fe6066bc 100644 --- a/arch/arm/mach-omap1/time.c +++ b/arch/arm/mach-omap1/time.c @@ -51,8 +51,6 @@ struct sys_timer omap_timer; -#ifdef CONFIG_OMAP_MPU_TIMER - /* * --------------------------------------------------------------------------- * MPU timer @@ -222,195 +220,6 @@ unsigned long long sched_clock(void) return cycles_2_ns(ticks64); } -#endif /* CONFIG_OMAP_MPU_TIMER */ - -#ifdef CONFIG_OMAP_32K_TIMER - -#ifdef CONFIG_ARCH_OMAP15XX -#error OMAP 32KHz timer does not currently work on 15XX! -#endif - -/* - * --------------------------------------------------------------------------- - * 32KHz OS timer - * - * This currently works only on 16xx, as 1510 does not have the continuous - * 32KHz synchronous timer. The 32KHz synchronous timer is used to keep track - * of time in addition to the 32KHz OS timer. Using only the 32KHz OS timer - * on 1510 would be possible, but the timer would not be as accurate as - * with the 32KHz synchronized timer. - * --------------------------------------------------------------------------- - */ -#define OMAP_32K_TIMER_BASE 0xfffb9000 -#define OMAP_32K_TIMER_CR 0x08 -#define OMAP_32K_TIMER_TVR 0x00 -#define OMAP_32K_TIMER_TCR 0x04 - -#define OMAP_32K_TICKS_PER_HZ (32768 / HZ) - -/* - * TRM says 1 / HZ = ( TVR + 1) / 32768, so TRV = (32768 / HZ) - 1 - * so with HZ = 100, TVR = 327.68. - */ -#define OMAP_32K_TIMER_TICK_PERIOD ((32768 / HZ) - 1) -#define TIMER_32K_SYNCHRONIZED 0xfffbc410 - -#define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate) \ - (((nr_jiffies) * (clock_rate)) / HZ) - -static inline void omap_32k_timer_write(int val, int reg) -{ - omap_writew(val, reg + OMAP_32K_TIMER_BASE); -} - -static inline unsigned long omap_32k_timer_read(int reg) -{ - return omap_readl(reg + OMAP_32K_TIMER_BASE) & 0xffffff; -} - -/* - * The 32KHz synchronized timer is an additional timer on 16xx. - * It is always running. - */ -static inline unsigned long omap_32k_sync_timer_read(void) -{ - return omap_readl(TIMER_32K_SYNCHRONIZED); -} - -static inline void omap_32k_timer_start(unsigned long load_val) -{ - omap_32k_timer_write(load_val, OMAP_32K_TIMER_TVR); - omap_32k_timer_write(0x0f, OMAP_32K_TIMER_CR); -} - -static inline void omap_32k_timer_stop(void) -{ - omap_32k_timer_write(0x0, OMAP_32K_TIMER_CR); -} - -/* - * Rounds down to nearest usec. Note that this will overflow for larger values. - */ -static inline unsigned long omap_32k_ticks_to_usecs(unsigned long ticks_32k) -{ - return (ticks_32k * 5*5*5*5*5*5) >> 9; -} - -/* - * Rounds down to nearest nsec. - */ -static inline unsigned long long -omap_32k_ticks_to_nsecs(unsigned long ticks_32k) -{ - return (unsigned long long) ticks_32k * 1000 * 5*5*5*5*5*5 >> 9; -} - -static unsigned long omap_32k_last_tick = 0; - -/* - * Returns elapsed usecs since last 32k timer interrupt - */ -static unsigned long omap_32k_timer_gettimeoffset(void) -{ - unsigned long now = omap_32k_sync_timer_read(); - return omap_32k_ticks_to_usecs(now - omap_32k_last_tick); -} - -/* - * Returns current time from boot in nsecs. It's OK for this to wrap - * around for now, as it's just a relative time stamp. - */ -unsigned long long sched_clock(void) -{ - return omap_32k_ticks_to_nsecs(omap_32k_sync_timer_read()); -} - -/* - * Timer interrupt for 32KHz timer. When dynamic tick is enabled, this - * function is also called from other interrupts to remove latency - * issues with dynamic tick. In the dynamic tick case, we need to lock - * with irqsave. - */ -static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id, - struct pt_regs *regs) -{ - unsigned long flags; - unsigned long now; - - write_seqlock_irqsave(&xtime_lock, flags); - now = omap_32k_sync_timer_read(); - - while (now - omap_32k_last_tick >= OMAP_32K_TICKS_PER_HZ) { - omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ; - timer_tick(regs); - } - - /* Restart timer so we don't drift off due to modulo or dynamic tick. - * By default we program the next timer to be continuous to avoid - * latencies during high system load. During dynamic tick operation the - * continuous timer can be overridden from pm_idle to be longer. - */ - omap_32k_timer_start(omap_32k_last_tick + OMAP_32K_TICKS_PER_HZ - now); - write_sequnlock_irqrestore(&xtime_lock, flags); - - return IRQ_HANDLED; -} - -#ifdef CONFIG_NO_IDLE_HZ -/* - * Programs the next timer interrupt needed. Called when dynamic tick is - * enabled, and to reprogram the ticks to skip from pm_idle. Note that - * we can keep the timer continuous, and don't need to set it to run in - * one-shot mode. This is because the timer will get reprogrammed again - * after next interrupt. - */ -void omap_32k_timer_reprogram(unsigned long next_tick) -{ - omap_32k_timer_start(JIFFIES_TO_HW_TICKS(next_tick, 32768) + 1); -} - -static struct irqaction omap_32k_timer_irq; -extern struct timer_update_handler timer_update; - -static int omap_32k_timer_enable_dyn_tick(void) -{ - /* No need to reprogram timer, just use the next interrupt */ - return 0; -} - -static int omap_32k_timer_disable_dyn_tick(void) -{ - omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD); - return 0; -} - -static struct dyn_tick_timer omap_dyn_tick_timer = { - .enable = omap_32k_timer_enable_dyn_tick, - .disable = omap_32k_timer_disable_dyn_tick, - .reprogram = omap_32k_timer_reprogram, - .handler = omap_32k_timer_interrupt, -}; -#endif /* CONFIG_NO_IDLE_HZ */ - -static struct irqaction omap_32k_timer_irq = { - .name = "32KHz timer", - .flags = SA_INTERRUPT | SA_TIMER, - .handler = omap_32k_timer_interrupt, -}; - -static __init void omap_init_32k_timer(void) -{ - -#ifdef CONFIG_NO_IDLE_HZ - omap_timer.dyn_tick = &omap_dyn_tick_timer; -#endif - - setup_irq(INT_OS_TIMER, &omap_32k_timer_irq); - omap_timer.offset = omap_32k_timer_gettimeoffset; - omap_32k_last_tick = omap_32k_sync_timer_read(); - omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD); -} -#endif /* CONFIG_OMAP_32K_TIMER */ /* * --------------------------------------------------------------------------- @@ -419,13 +228,7 @@ static __init void omap_init_32k_timer(void) */ static void __init omap_timer_init(void) { -#if defined(CONFIG_OMAP_MPU_TIMER) omap_init_mpu_timer(); -#elif defined(CONFIG_OMAP_32K_TIMER) - omap_init_32k_timer(); -#else -#error No system timer selected in Kconfig! -#endif } struct sys_timer omap_timer = { diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 578880943cf..537dd2e6d38 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -20,3 +20,6 @@ config MACH_OMAP_H4 bool "OMAP 2420 H4 board" depends on ARCH_OMAP2 && ARCH_OMAP24XX +config MACH_OMAP_APOLLON + bool "OMAP 2420 Apollon board" + depends on ARCH_OMAP2 && ARCH_OMAP24XX diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 42041166435..111eaa64258 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -3,11 +3,15 @@ # # Common support -obj-y := irq.o id.o io.o sram-fn.o clock.o mux.o devices.o serial.o +obj-y := irq.o id.o io.o sram-fn.o memory.o prcm.o clock.o mux.o devices.o serial.o obj-$(CONFIG_OMAP_MPU_TIMER) += timer-gp.o +# Power Management +obj-$(CONFIG_PM) += pm.o sleep.o + # Specific board support obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o obj-$(CONFIG_MACH_OMAP_H4) += board-h4.o +obj-$(CONFIG_MACH_OMAP_APOLLON) += board-apollon.o diff --git a/arch/arm/mach-omap2/board-apollon.c b/arch/arm/mach-omap2/board-apollon.c new file mode 100644 index 00000000000..6c6ba172cdf --- /dev/null +++ b/arch/arm/mach-omap2/board-apollon.c @@ -0,0 +1,285 @@ +/* + * linux/arch/arm/mach-omap/omap2/board-apollon.c + * + * Copyright (C) 2005,2006 Samsung Electronics + * Author: Kyungmin Park <kyungmin.park@samsung.com> + * + * Modified from mach-omap/omap2/board-h4.c + * + * Code for apollon OMAP2 board. Should work on many OMAP2 systems where + * the bootloader passes the board-specific data to the kernel. + * Do not put any board specific code to this file; create a new machine + * type if you need custom low-level initializations. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/onenand.h> +#include <linux/interrupt.h> +#include <linux/delay.h> + +#include <asm/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/flash.h> + +#include <asm/arch/gpio.h> +#include <asm/arch/mux.h> +#include <asm/arch/usb.h> +#include <asm/arch/board.h> +#include <asm/arch/common.h> +#include "prcm-regs.h" + +/* LED & Switch macros */ +#define LED0_GPIO13 13 +#define LED1_GPIO14 14 +#define LED2_GPIO15 15 +#define SW_ENTER_GPIO16 16 +#define SW_UP_GPIO17 17 +#define SW_DOWN_GPIO58 58 + +static struct mtd_partition apollon_partitions[] = { + { + .name = "X-Loader + U-Boot", + .offset = 0, + .size = SZ_128K, + .mask_flags = MTD_WRITEABLE, + }, + { + .name = "params", + .offset = MTDPART_OFS_APPEND, + .size = SZ_128K, + }, + { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = SZ_2M, + }, + { + .name = "rootfs", + .offset = MTDPART_OFS_APPEND, + .size = SZ_16M, + }, + { + .name = "filesystem00", + .offset = MTDPART_OFS_APPEND, + .size = SZ_32M, + }, + { + .name = "filesystem01", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; + +static struct flash_platform_data apollon_flash_data = { + .parts = apollon_partitions, + .nr_parts = ARRAY_SIZE(apollon_partitions), +}; + +static struct resource apollon_flash_resource = { + .start = APOLLON_CS0_BASE, + .end = APOLLON_CS0_BASE + SZ_128K, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device apollon_onenand_device = { + .name = "onenand", + .id = -1, + .dev = { + .platform_data = &apollon_flash_data, + }, + .num_resources = ARRAY_SIZE(&apollon_flash_resource), + .resource = &apollon_flash_resource, +}; + +static struct resource apollon_smc91x_resources[] = { + [0] = { + .start = APOLLON_ETHR_START, /* Physical */ + .end = APOLLON_ETHR_START + 0xf, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = OMAP_GPIO_IRQ(APOLLON_ETHR_GPIO_IRQ), + .end = OMAP_GPIO_IRQ(APOLLON_ETHR_GPIO_IRQ), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device apollon_smc91x_device = { + .name = "smc91x", + .id = -1, + .num_resources = ARRAY_SIZE(apollon_smc91x_resources), + .resource = apollon_smc91x_resources, +}; + +static struct platform_device apollon_lcd_device = { + .name = "apollon_lcd", + .id = -1, +}; + +static struct platform_device *apollon_devices[] __initdata = { + &apollon_onenand_device, + &apollon_smc91x_device, + &apollon_lcd_device, +}; + +static inline void __init apollon_init_smc91x(void) +{ + /* Make sure CS1 timings are correct */ + GPMC_CONFIG1_1 = 0x00011203; + GPMC_CONFIG2_1 = 0x001f1f01; + GPMC_CONFIG3_1 = 0x00080803; + GPMC_CONFIG4_1 = 0x1c091c09; + GPMC_CONFIG5_1 = 0x041f1f1f; + GPMC_CONFIG6_1 = 0x000004c4; + GPMC_CONFIG7_1 = 0x00000f40 | (APOLLON_CS1_BASE >> 24); + udelay(100); + + omap_cfg_reg(W4__24XX_GPIO74); + if (omap_request_gpio(APOLLON_ETHR_GPIO_IRQ) < 0) { + printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n", + APOLLON_ETHR_GPIO_IRQ); + return; + } + omap_set_gpio_direction(APOLLON_ETHR_GPIO_IRQ, 1); +} + +static void __init omap_apollon_init_irq(void) +{ + omap2_init_common_hw(); + omap_init_irq(); + omap_gpio_init(); + apollon_init_smc91x(); +} + +static struct omap_uart_config apollon_uart_config __initdata = { + .enabled_uarts = (1 << 0) | (0 << 1) | (0 << 2), +}; + +static struct omap_mmc_config apollon_mmc_config __initdata = { + .mmc [0] = { + .enabled = 0, + .wire4 = 0, + .wp_pin = -1, + .power_pin = -1, + .switch_pin = -1, + }, +}; + +static struct omap_lcd_config apollon_lcd_config __initdata = { + .ctrl_name = "internal", +}; + +static struct omap_board_config_kernel apollon_config[] = { + { OMAP_TAG_UART, &apollon_uart_config }, + { OMAP_TAG_MMC, &apollon_mmc_config }, + { OMAP_TAG_LCD, &apollon_lcd_config }, +}; + +static void __init apollon_led_init(void) +{ + /* LED0 - AA10 */ + omap_cfg_reg(AA10_242X_GPIO13); + omap_request_gpio(LED0_GPIO13); + omap_set_gpio_direction(LED0_GPIO13, 0); + omap_set_gpio_dataout(LED0_GPIO13, 0); + /* LED1 - AA6 */ + omap_cfg_reg(AA6_242X_GPIO14); + omap_request_gpio(LED1_GPIO14); + omap_set_gpio_direction(LED1_GPIO14, 0); + omap_set_gpio_dataout(LED1_GPIO14, 0); + /* LED2 - AA4 */ + omap_cfg_reg(AA4_242X_GPIO15); + omap_request_gpio(LED2_GPIO15); + omap_set_gpio_direction(LED2_GPIO15, 0); + omap_set_gpio_dataout(LED2_GPIO15, 0); +} + +static irqreturn_t apollon_sw_interrupt(int irq, void *ignored, struct pt_regs *regs) +{ + static unsigned int led0, led1, led2; + + if (irq == OMAP_GPIO_IRQ(SW_ENTER_GPIO16)) + omap_set_gpio_dataout(LED0_GPIO13, led0 ^= 1); + else if (irq == OMAP_GPIO_IRQ(SW_UP_GPIO17)) + omap_set_gpio_dataout(LED1_GPIO14, led1 ^= 1); + else if (irq == OMAP_GPIO_IRQ(SW_DOWN_GPIO58)) + omap_set_gpio_dataout(LED2_GPIO15, led2 ^= 1); + + return IRQ_HANDLED; +} + +static void __init apollon_sw_init(void) +{ + /* Enter SW - Y11 */ + omap_cfg_reg(Y11_242X_GPIO16); + omap_request_gpio(SW_ENTER_GPIO16); + omap_set_gpio_direction(SW_ENTER_GPIO16, 1); + /* Up SW - AA12 */ + omap_cfg_reg(AA12_242X_GPIO17); + omap_request_gpio(SW_UP_GPIO17); + omap_set_gpio_direction(SW_UP_GPIO17, 1); + /* Down SW - AA8 */ + omap_cfg_reg(AA8_242X_GPIO58); + omap_request_gpio(SW_DOWN_GPIO58); + omap_set_gpio_direction(SW_DOWN_GPIO58, 1); + + set_irq_type(OMAP_GPIO_IRQ(SW_ENTER_GPIO16), IRQT_RISING); + if (request_irq(OMAP_GPIO_IRQ(SW_ENTER_GPIO16), &apollon_sw_interrupt, + SA_SHIRQ, "enter sw", + &apollon_sw_interrupt)) + return; + set_irq_type(OMAP_GPIO_IRQ(SW_UP_GPIO17), IRQT_RISING); + if (request_irq(OMAP_GPIO_IRQ(SW_UP_GPIO17), &apollon_sw_interrupt, + SA_SHIRQ, "up sw", + &apollon_sw_interrupt)) + return; + set_irq_type(OMAP_GPIO_IRQ(SW_DOWN_GPIO58), IRQT_RISING); + if (request_irq(OMAP_GPIO_IRQ(SW_DOWN_GPIO58), &apollon_sw_interrupt, + SA_SHIRQ, "down sw", + &apollon_sw_interrupt)) + return; +} + +static void __init omap_apollon_init(void) +{ + apollon_led_init(); + apollon_sw_init(); + + /* REVISIT: where's the correct place */ + omap_cfg_reg(W19_24XX_SYS_NIRQ); + + /* + * Make sure the serial ports are muxed on at this point. + * You have to mux them off in device drivers later on + * if not needed. + */ + platform_add_devices(apollon_devices, ARRAY_SIZE(apollon_devices)); + omap_board_config = apollon_config; + omap_board_config_size = ARRAY_SIZE(apollon_config); + omap_serial_init(); +} + +static void __init omap_apollon_map_io(void) +{ + omap2_map_common_io(); +} + +MACHINE_START(OMAP_APOLLON, "OMAP24xx Apollon") + /* Maintainer: Kyungmin Park <kyungmin.park@samsung.com> */ + .phys_io = 0x48000000, + .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc, + .boot_params = 0x80000100, + .map_io = omap_apollon_map_io, + .init_irq = omap_apollon_init_irq, + .init_machine = omap_apollon_init, + .timer = &omap_timer, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c index a300d634d8a..4933fce766c 100644 --- a/arch/arm/mach-omap2/board-h4.c +++ b/arch/arm/mach-omap2/board-h4.c @@ -17,6 +17,8 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> #include <linux/delay.h> +#include <linux/workqueue.h> +#include <linux/input.h> #include <asm/hardware.h> #include <asm/mach-types.h> @@ -25,15 +27,57 @@ #include <asm/mach/flash.h> #include <asm/arch/gpio.h> +#include <asm/arch/gpioexpander.h> #include <asm/arch/mux.h> #include <asm/arch/usb.h> +#include <asm/arch/irda.h> #include <asm/arch/board.h> #include <asm/arch/common.h> -#include <asm/arch/prcm.h> +#include <asm/arch/keypad.h> +#include <asm/arch/menelaus.h> +#include <asm/arch/dma.h> +#include "prcm-regs.h" #include <asm/io.h> #include <asm/delay.h> +static unsigned int row_gpios[6] = { 88, 89, 124, 11, 6, 96 }; +static unsigned int col_gpios[7] = { 90, 91, 100, 36, 12, 97, 98 }; + +static int h4_keymap[] = { + KEY(0, 0, KEY_LEFT), + KEY(0, 1, KEY_RIGHT), + KEY(0, 2, KEY_A), + KEY(0, 3, KEY_B), + KEY(0, 4, KEY_C), + KEY(1, 0, KEY_DOWN), + KEY(1, 1, KEY_UP), + KEY(1, 2, KEY_E), + KEY(1, 3, KEY_F), + KEY(1, 4, KEY_G), + KEY(2, 0, KEY_ENTER), + KEY(2, 1, KEY_I), + KEY(2, 2, KEY_J), + KEY(2, 3, KEY_K), + KEY(2, 4, KEY_3), + KEY(3, 0, KEY_M), + KEY(3, 1, KEY_N), + KEY(3, 2, KEY_O), + KEY(3, 3, KEY_P), + KEY(3, 4, KEY_Q), + KEY(4, 0, KEY_R), + KEY(4, 1, KEY_4), + KEY(4, 2, KEY_T), + KEY(4, 3, KEY_U), + KEY(4, 4, KEY_ENTER), + KEY(5, 0, KEY_V), + KEY(5, 1, KEY_W), + KEY(5, 2, KEY_L), + KEY(5, 3, KEY_S), + KEY(5, 4, KEY_ENTER), + 0 +}; + static struct mtd_partition h4_partitions[] = { /* bootloader (U-Boot, etc) in first sector */ { @@ -108,9 +152,123 @@ static struct platform_device h4_smc91x_device = { .resource = h4_smc91x_resources, }; +/* Select between the IrDA and aGPS module + */ +static int h4_select_irda(struct device *dev, int state) +{ + unsigned char expa; + int err = 0; + + if ((err = read_gpio_expa(&expa, 0x21))) { + printk(KERN_ERR "Error reading from I/O expander\n"); + return err; + } + + /* 'P6' enable/disable IRDA_TX and IRDA_RX */ + if (state & IR_SEL) { /* IrDa */ + if ((err = write_gpio_expa(expa | 0x01, 0x21))) { + printk(KERN_ERR "Error writing to I/O expander\n"); + return err; + } + } else { + if ((err = write_gpio_expa(expa & ~0x01, 0x21))) { + printk(KERN_ERR "Error writing to I/O expander\n"); + return err; + } + } + return err; +} + +static void set_trans_mode(void *data) +{ + int *mode = data; + unsigned char expa; + int err = 0; + + if ((err = read_gpio_expa(&expa, 0x20)) != 0) { + printk(KERN_ERR "Error reading from I/O expander\n"); + } + + expa &= ~0x01; + + if (!(*mode & IR_SIRMODE)) { /* MIR/FIR */ + expa |= 0x01; + } + + if ((err = write_gpio_expa(expa, 0x20)) != 0) { + printk(KERN_ERR "Error writing to I/O expander\n"); + } +} + +static int h4_transceiver_mode(struct device *dev, int mode) +{ + struct omap_irda_config *irda_config = dev->platform_data; + + cancel_delayed_work(&irda_config->gpio_expa); + PREPARE_WORK(&irda_config->gpio_expa, set_trans_mode, &mode); + schedule_work(&irda_config->gpio_expa); + + return 0; +} + +static struct omap_irda_config h4_irda_data = { + .transceiver_cap = IR_SIRMODE | IR_MIRMODE | IR_FIRMODE, + .transceiver_mode = h4_transceiver_mode, + .select_irda = h4_select_irda, + .rx_channel = OMAP24XX_DMA_UART3_RX, + .tx_channel = OMAP24XX_DMA_UART3_TX, + .dest_start = OMAP_UART3_BASE, + .src_start = OMAP_UART3_BASE, + .tx_trigger = OMAP24XX_DMA_UART3_TX, + .rx_trigger = OMAP24XX_DMA_UART3_RX, +}; + +static struct resource h4_irda_resources[] = { + [0] = { + .start = INT_24XX_UART3_IRQ, + .end = INT_24XX_UART3_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device h4_irda_device = { + .name = "omapirda", + .id = -1, + .dev = { + .platform_data = &h4_irda_data, + }, + .num_resources = 1, + .resource = h4_irda_resources, +}; + +static struct omap_kp_platform_data h4_kp_data = { + .rows = 6, + .cols = 7, + .keymap = h4_keymap, + .rep = 1, + .row_gpios = row_gpios, + .col_gpios = col_gpios, +}; + +static struct platform_device h4_kp_device = { + .name = "omap-keypad", + .id = -1, + .dev = { + .platform_data = &h4_kp_data, + }, +}; + +static struct platform_device h4_lcd_device = { + .name = "lcd_h4", + .id = -1, +}; + static struct platform_device *h4_devices[] __initdata = { &h4_smc91x_device, &h4_flash_device, + &h4_irda_device, + &h4_kp_device, + &h4_lcd_device, }; static inline void __init h4_init_smc91x(void) @@ -157,7 +315,6 @@ static struct omap_mmc_config h4_mmc_config __initdata = { }; static struct omap_lcd_config h4_lcd_config __initdata = { - .panel_name = "h4", .ctrl_name = "internal", }; @@ -174,6 +331,19 @@ static void __init omap_h4_init(void) * You have to mux them off in device drivers later on * if not needed. */ +#if defined(CONFIG_OMAP_IR) || defined(CONFIG_OMAP_IR_MODULE) + omap_cfg_reg(K15_24XX_UART3_TX); + omap_cfg_reg(K14_24XX_UART3_RX); +#endif + +#if defined(CONFIG_KEYBOARD_OMAP) || defined(CONFIG_KEYBOARD_OMAP_MODULE) + if (omap_has_menelaus()) { + row_gpios[5] = 0; + col_gpios[2] = 15; + col_gpios[6] = 18; + } +#endif + platform_add_devices(h4_devices, ARRAY_SIZE(h4_devices)); omap_board_config = h4_config; omap_board_config_size = ARRAY_SIZE(h4_config); diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index 180f675c906..72eb4bf571a 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -28,14 +28,14 @@ #include <asm/arch/clock.h> #include <asm/arch/sram.h> -#include <asm/arch/prcm.h> +#include "prcm-regs.h" +#include "memory.h" #include "clock.h" //#define DOWN_VARIABLE_DPLL 1 /* Experimental */ static struct prcm_config *curr_prcm_set; -static struct memory_timings mem_timings; static u32 curr_perf_level = PRCM_FULL_SPEED; /*------------------------------------------------------------------------- @@ -54,11 +54,13 @@ static void omap2_sys_clk_recalc(struct clk * clk) static u32 omap2_get_dpll_rate(struct clk * tclk) { - int dpll_clk, dpll_mult, dpll_div, amult; + long long dpll_clk; + int dpll_mult, dpll_div, amult; dpll_mult = (CM_CLKSEL1_PLL >> 12) & 0x03ff; /* 10 bits */ dpll_div = (CM_CLKSEL1_PLL >> 8) & 0x0f; /* 4 bits */ - dpll_clk = (tclk->parent->rate * dpll_mult) / (dpll_div + 1); + dpll_clk = (long long)tclk->parent->rate * dpll_mult; + do_div(dpll_clk, dpll_div + 1); amult = CM_CLKSEL2_PLL & 0x3; dpll_clk *= amult; @@ -385,75 +387,23 @@ static u32 omap2_dll_force_needed(void) return 0; } -static void omap2_init_memory_params(u32 force_lock_to_unlock_mode) -{ - unsigned long dll_cnt; - u32 fast_dll = 0; - - mem_timings.m_type = !((SDRC_MR_0 & 0x3) == 0x1); /* DDR = 1, SDR = 0 */ - - /* 2422 es2.05 and beyond has a single SIP DDR instead of 2 like others. - * In the case of 2422, its ok to use CS1 instead of CS0. - */ - -#if 0 /* FIXME: Enable after 24xx cpu detection works */ - ctype = get_cpu_type(); - if (cpu_is_omap2422()) - mem_timings.base_cs = 1; - else -#endif - mem_timings.base_cs = 0; - - if (mem_timings.m_type != M_DDR) - return; - - /* With DDR we need to determine the low frequency DLL value */ - if (((mem_timings.fast_dll_ctrl & (1 << 2)) == M_LOCK_CTRL)) - mem_timings.dll_mode = M_UNLOCK; - else - mem_timings.dll_mode = M_LOCK; - - if (mem_timings.base_cs == 0) { - fast_dll = SDRC_DLLA_CTRL; - dll_cnt = SDRC_DLLA_STATUS & 0xff00; - } else { - fast_dll = SDRC_DLLB_CTRL; - dll_cnt = SDRC_DLLB_STATUS & 0xff00; - } - if (force_lock_to_unlock_mode) { - fast_dll &= ~0xff00; - fast_dll |= dll_cnt; /* Current lock mode */ - } - mem_timings.fast_dll_ctrl = fast_dll; - - /* No disruptions, DDR will be offline & C-ABI not followed */ - omap2_sram_ddr_init(&mem_timings.slow_dll_ctrl, - mem_timings.fast_dll_ctrl, - mem_timings.base_cs, - force_lock_to_unlock_mode); - mem_timings.slow_dll_ctrl &= 0xff00; /* Keep lock value */ - - /* Turn status into unlock ctrl */ - mem_timings.slow_dll_ctrl |= - ((mem_timings.fast_dll_ctrl & 0xF) | (1 << 2)); - - /* 90 degree phase for anything below 133Mhz */ - mem_timings.slow_dll_ctrl |= (1 << 1); -} - static u32 omap2_reprogram_sdrc(u32 level, u32 force) { + u32 slow_dll_ctrl, fast_dll_ctrl, m_type; u32 prev = curr_perf_level, flags; if ((curr_perf_level == level) && !force) return prev; + m_type = omap2_memory_get_type(); + slow_dll_ctrl = omap2_memory_get_slow_dll_ctrl(); + fast_dll_ctrl = omap2_memory_get_fast_dll_ctrl(); + if (level == PRCM_HALF_SPEED) { local_irq_save(flags); PRCM_VOLTSETUP = 0xffff; omap2_sram_reprogram_sdrc(PRCM_HALF_SPEED, - mem_timings.slow_dll_ctrl, - mem_timings.m_type); + slow_dll_ctrl, m_type); curr_perf_level = PRCM_HALF_SPEED; local_irq_restore(flags); } @@ -461,8 +411,7 @@ static u32 omap2_reprogram_sdrc(u32 level, u32 force) local_irq_save(flags); PRCM_VOLTSETUP = 0xffff; omap2_sram_reprogram_sdrc(PRCM_FULL_SPEED, - mem_timings.fast_dll_ctrl, - mem_timings.m_type); + fast_dll_ctrl, m_type); curr_perf_level = PRCM_FULL_SPEED; local_irq_restore(flags); } @@ -650,7 +599,7 @@ static u32 omap2_get_clksel(u32 *div_sel, u32 *field_mask, case 13: /* dss2 */ mask = 0x1; break; case 25: /* usb */ - mask = 0xf; break; + mask = 0x7; break; } } diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index 6cab20b1d3c..6c78d471fab 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -33,20 +33,6 @@ static u32 omap2_clksel_get_divisor(struct clk *clk); #define RATE_IN_242X (1 << 0) #define RATE_IN_243X (1 << 1) -/* Memory timings */ -#define M_DDR 1 -#define M_LOCK_CTRL (1 << 2) -#define M_UNLOCK 0 -#define M_LOCK 1 - -struct memory_timings { - u32 m_type; /* ddr = 1, sdr = 0 */ - u32 dll_mode; /* use lock mode = 1, unlock mode = 0 */ - u32 slow_dll_ctrl; /* unlock mode, dll value for slow speed */ - u32 fast_dll_ctrl; /* unlock mode, dll value for fast speed */ - u32 base_cs; /* base chip select to use for calculations */ -}; - /* Key dividers which make up a PRCM set. Ratio's for a PRCM are mandated. * xtal_speed, dpll_speed, mpu_speed, CM_CLKSEL_MPU,CM_CLKSEL_DSP * CM_CLKSEL_GFX, CM_CLKSEL1_CORE, CM_CLKSEL1_PLL CM_CLKSEL2_PLL, CM_CLKSEL_MDM @@ -731,6 +717,16 @@ static struct clk sys_clkout2 = { .recalc = &omap2_clksel_recalc, }; +static struct clk emul_ck = { + .name = "emul_ck", + .parent = &func_54m_ck, + .flags = CLOCK_IN_OMAP242X, + .enable_reg = (void __iomem *)&PRCM_CLKEMUL_CTRL, + .enable_bit = 0, + .recalc = &omap2_propagate_rate, + +}; + /* * MPU clock domain * Clocks: @@ -1702,7 +1698,8 @@ static struct clk hdq_fck = { }; static struct clk i2c2_ick = { - .name = "i2c2_ick", + .name = "i2c_ick", + .id = 2, .parent = &l4_ck, .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, @@ -1711,7 +1708,8 @@ static struct clk i2c2_ick = { }; static struct clk i2c2_fck = { - .name = "i2c2_fck", + .name = "i2c_fck", + .id = 2, .parent = &func_12m_ck, .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, @@ -1729,7 +1727,8 @@ static struct clk i2chs2_fck = { }; static struct clk i2c1_ick = { - .name = "i2c1_ick", + .name = "i2c_ick", + .id = 1, .parent = &l4_ck, .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, @@ -1738,7 +1737,8 @@ static struct clk i2c1_ick = { }; static struct clk i2c1_fck = { - .name = "i2c1_fck", + .name = "i2c_fck", + .id = 1, .parent = &func_12m_ck, .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, @@ -1971,6 +1971,7 @@ static struct clk *onchip_clks[] = { &wdt1_osc_ck, &sys_clkout, &sys_clkout2, + &emul_ck, /* mpu domain clocks */ &mpu_ck, /* dsp domain clocks */ diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index 7181edb8935..def9e5370ed 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -74,6 +74,47 @@ static void omap_init_i2c(void) {} #endif +#if defined(CONFIG_OMAP_STI) + +#define OMAP2_STI_BASE IO_ADDRESS(0x48068000) +#define OMAP2_STI_CHANNEL_BASE 0x54000000 +#define OMAP2_STI_IRQ 4 + +static struct resource sti_resources[] = { + { + .start = OMAP2_STI_BASE, + .end = OMAP2_STI_BASE + 0x7ff, + .flags = IORESOURCE_MEM, + }, + { + .start = OMAP2_STI_CHANNEL_BASE, + .end = OMAP2_STI_CHANNEL_BASE + SZ_64K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = OMAP2_STI_IRQ, + .flags = IORESOURCE_IRQ, + } +}; + +static struct platform_device sti_device = { + .name = "sti", + .id = -1, + .dev = { + .release = omap_nop_release, + }, + .num_resources = ARRAY_SIZE(sti_resources), + .resource = sti_resources, +}; + +static inline void omap_init_sti(void) +{ + platform_device_register(&sti_device); +} +#else +static inline void omap_init_sti(void) {} +#endif + /*-------------------------------------------------------------------------*/ static int __init omap2_init_devices(void) @@ -82,6 +123,7 @@ static int __init omap2_init_devices(void) * in alphabetical order so they're easier to sort through. */ omap_init_i2c(); + omap_init_sti(); return 0; } diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 8ea67bf196a..7d5711611f2 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -16,9 +16,13 @@ #include <linux/kernel.h> #include <linux/init.h> -#include <asm/mach/map.h> +#include <asm/tlb.h> #include <asm/io.h> + +#include <asm/mach/map.h> + #include <asm/arch/mux.h> +#include <asm/arch/omapfb.h> extern void omap_sram_init(void); extern int omap2_clk_init(void); @@ -43,11 +47,24 @@ static struct map_desc omap2_io_desc[] __initdata = { } }; -void __init omap_map_common_io(void) +void __init omap2_map_common_io(void) { iotable_init(omap2_io_desc, ARRAY_SIZE(omap2_io_desc)); + + /* Normally devicemaps_init() would flush caches and tlb after + * mdesc->map_io(), but we must also do it here because of the CPU + * revision check below. + */ + local_flush_tlb_all(); + flush_cache_all(); + omap2_check_revision(); omap_sram_init(); + omapfb_reserve_mem(); +} + +void __init omap2_init_common_hw(void) +{ omap2_mux_init(); omap2_clk_init(); } diff --git a/arch/arm/mach-omap2/memory.c b/arch/arm/mach-omap2/memory.c new file mode 100644 index 00000000000..1d925d69fc3 --- /dev/null +++ b/arch/arm/mach-omap2/memory.c @@ -0,0 +1,102 @@ +/* + * linux/arch/arm/mach-omap2/memory.c + * + * Memory timing related functions for OMAP24XX + * + * Copyright (C) 2005 Texas Instruments Inc. + * Richard Woodruff <r-woodruff2@ti.com> + * + * Copyright (C) 2005 Nokia Corporation + * Tony Lindgren <tony@atomide.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/list.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/clk.h> + +#include <asm/io.h> + +#include <asm/arch/clock.h> +#include <asm/arch/sram.h> + +#include "prcm-regs.h" +#include "memory.h" + +static struct memory_timings mem_timings; + +u32 omap2_memory_get_slow_dll_ctrl(void) +{ + return mem_timings.slow_dll_ctrl; +} + +u32 omap2_memory_get_fast_dll_ctrl(void) +{ + return mem_timings.fast_dll_ctrl; +} + +u32 omap2_memory_get_type(void) +{ + return mem_timings.m_type; +} + +void omap2_init_memory_params(u32 force_lock_to_unlock_mode) +{ + unsigned long dll_cnt; + u32 fast_dll = 0; + + mem_timings.m_type = !((SDRC_MR_0 & 0x3) == 0x1); /* DDR = 1, SDR = 0 */ + + /* 2422 es2.05 and beyond has a single SIP DDR instead of 2 like others. + * In the case of 2422, its ok to use CS1 instead of CS0. + */ + if (cpu_is_omap2422()) + mem_timings.base_cs = 1; + else + mem_timings.base_cs = 0; + + if (mem_timings.m_type != M_DDR) + return; + + /* With DDR we need to determine the low frequency DLL value */ + if (((mem_timings.fast_dll_ctrl & (1 << 2)) == M_LOCK_CTRL)) + mem_timings.dll_mode = M_UNLOCK; + else + mem_timings.dll_mode = M_LOCK; + + if (mem_timings.base_cs == 0) { + fast_dll = SDRC_DLLA_CTRL; + dll_cnt = SDRC_DLLA_STATUS & 0xff00; + } else { + fast_dll = SDRC_DLLB_CTRL; + dll_cnt = SDRC_DLLB_STATUS & 0xff00; + } + if (force_lock_to_unlock_mode) { + fast_dll &= ~0xff00; + fast_dll |= dll_cnt; /* Current lock mode */ + } + /* set fast timings with DLL filter disabled */ + mem_timings.fast_dll_ctrl = (fast_dll | (3 << 8)); + + /* No disruptions, DDR will be offline & C-ABI not followed */ + omap2_sram_ddr_init(&mem_timings.slow_dll_ctrl, + mem_timings.fast_dll_ctrl, + mem_timings.base_cs, + force_lock_to_unlock_mode); + mem_timings.slow_dll_ctrl &= 0xff00; /* Keep lock value */ + + /* Turn status into unlock ctrl */ + mem_timings.slow_dll_ctrl |= + ((mem_timings.fast_dll_ctrl & 0xF) | (1 << 2)); + + /* 90 degree phase for anything below 133Mhz + disable DLL filter */ + mem_timings.slow_dll_ctrl |= ((1 << 1) | (3 << 8)); +} diff --git a/arch/arm/mach-omap2/memory.h b/arch/arm/mach-omap2/memory.h new file mode 100644 index 00000000000..d212eea83a0 --- /dev/null +++ b/arch/arm/mach-omap2/memory.h @@ -0,0 +1,34 @@ +/* + * linux/arch/arm/mach-omap2/memory.h + * + * Interface for memory timing related functions for OMAP24XX + * + * Copyright (C) 2005 Texas Instruments Inc. + * Richard Woodruff <r-woodruff2@ti.com> + * + * Copyright (C) 2005 Nokia Corporation + * Tony Lindgren <tony@atomide.com> + * + * 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. + */ + +/* Memory timings */ +#define M_DDR 1 +#define M_LOCK_CTRL (1 << 2) +#define M_UNLOCK 0 +#define M_LOCK 1 + +struct memory_timings { + u32 m_type; /* ddr = 1, sdr = 0 */ + u32 dll_mode; /* use lock mode = 1, unlock mode = 0 */ + u32 slow_dll_ctrl; /* unlock mode, dll value for slow speed */ + u32 fast_dll_ctrl; /* unlock mode, dll value for fast speed */ + u32 base_cs; /* base chip select to use for calculations */ +}; + +extern void omap2_init_memory_params(u32 force_lock_to_unlock_mode); +extern u32 omap2_memory_get_slow_dll_ctrl(void); +extern u32 omap2_memory_get_fast_dll_ctrl(void); +extern u32 omap2_memory_get_type(void); diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c index ea4654815dd..1197dc38c20 100644 --- a/arch/arm/mach-omap2/mux.c +++ b/arch/arm/mach-omap2/mux.c @@ -50,9 +50,54 @@ MUX_CFG_24XX("H19_24XX_I2C2_SDA", 0x114, 0, 0, 0, 1) /* Menelaus interrupt */ MUX_CFG_24XX("W19_24XX_SYS_NIRQ", 0x12c, 0, 1, 1, 1) +/* 24xx clocks */ +MUX_CFG_24XX("W14_24XX_SYS_CLKOUT", 0x137, 0, 1, 1, 1) + +/* 24xx McBSP */ +MUX_CFG_24XX("Y15_24XX_MCBSP2_CLKX", 0x124, 1, 1, 0, 1) +MUX_CFG_24XX("R14_24XX_MCBSP2_FSX", 0x125, 1, 1, 0, 1) +MUX_CFG_24XX("W15_24XX_MCBSP2_DR", 0x126, 1, 1, 0, 1) +MUX_CFG_24XX("V15_24XX_MCBSP2_DX", 0x127, 1, 1, 0, 1) + /* 24xx GPIO */ +MUX_CFG_24XX("M21_242X_GPIO11", 0x0c9, 3, 1, 1, 1) +MUX_CFG_24XX("AA10_242X_GPIO13", 0x0e5, 3, 0, 0, 1) +MUX_CFG_24XX("AA6_242X_GPIO14", 0x0e6, 3, 0, 0, 1) +MUX_CFG_24XX("AA4_242X_GPIO15", 0x0e7, 3, 0, 0, 1) +MUX_CFG_24XX("Y11_242X_GPIO16", 0x0e8, 3, 0, 0, 1) +MUX_CFG_24XX("AA12_242X_GPIO17", 0x0e9, 3, 0, 0, 1) +MUX_CFG_24XX("AA8_242X_GPIO58", 0x0ea, 3, 0, 0, 1) MUX_CFG_24XX("Y20_24XX_GPIO60", 0x12c, 3, 0, 0, 1) +MUX_CFG_24XX("W4__24XX_GPIO74", 0x0f2, 3, 0, 0, 1) MUX_CFG_24XX("M15_24XX_GPIO92", 0x10a, 3, 0, 0, 1) +MUX_CFG_24XX("V14_24XX_GPIO117", 0x128, 3, 1, 0, 1) + +/* TSC IRQ */ +MUX_CFG_24XX("P20_24XX_TSC_IRQ", 0x108, 0, 0, 0, 1) + +/* UART3 */ +MUX_CFG_24XX("K15_24XX_UART3_TX", 0x118, 0, 0, 0, 1) +MUX_CFG_24XX("K14_24XX_UART3_RX", 0x119, 0, 0, 0, 1) + +/* Keypad GPIO*/ +MUX_CFG_24XX("T19_24XX_KBR0", 0x106, 3, 1, 1, 1) +MUX_CFG_24XX("R19_24XX_KBR1", 0x107, 3, 1, 1, 1) +MUX_CFG_24XX("V18_24XX_KBR2", 0x139, 3, 1, 1, 1) +MUX_CFG_24XX("M21_24XX_KBR3", 0xc9, 3, 1, 1, 1) +MUX_CFG_24XX("E5__24XX_KBR4", 0x138, 3, 1, 1, 1) +MUX_CFG_24XX("M18_24XX_KBR5", 0x10e, 3, 1, 1, 1) +MUX_CFG_24XX("R20_24XX_KBC0", 0x108, 3, 0, 0, 1) +MUX_CFG_24XX("M14_24XX_KBC1", 0x109, 3, 0, 0, 1) +MUX_CFG_24XX("H19_24XX_KBC2", 0x114, 3, 0, 0, 1) +MUX_CFG_24XX("V17_24XX_KBC3", 0x135, 3, 0, 0, 1) +MUX_CFG_24XX("P21_24XX_KBC4", 0xca, 3, 0, 0, 1) +MUX_CFG_24XX("L14_24XX_KBC5", 0x10f, 3, 0, 0, 1) +MUX_CFG_24XX("N19_24XX_KBC6", 0x110, 3, 0, 0, 1) + +/* 24xx Menelaus Keypad GPIO */ +MUX_CFG_24XX("B3__24XX_KBR5", 0x30, 3, 1, 1, 1) +MUX_CFG_24XX("AA4_24XX_KBC2", 0xe7, 3, 0, 0, 1) +MUX_CFG_24XX("B13_24XX_KBC6", 0x110, 3, 0, 0, 1) }; diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c new file mode 100644 index 00000000000..562168fa2b1 --- /dev/null +++ b/arch/arm/mach-omap2/pm.c @@ -0,0 +1,149 @@ +/* + * linux/arch/arm/mach-omap2/pm.c + * + * OMAP2 Power Management Routines + * + * Copyright (C) 2006 Nokia Corporation + * Tony Lindgren <tony@atomide.com> + * + * Copyright (C) 2005 Texas Instruments, Inc. + * Richard Woodruff <r-woodruff2@ti.com> + * + * Based on pm.c for omap1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/pm.h> +#include <linux/sched.h> +#include <linux/proc_fs.h> +#include <linux/pm.h> +#include <linux/interrupt.h> +#include <linux/sysfs.h> +#include <linux/module.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/atomic.h> +#include <asm/mach/time.h> +#include <asm/mach/irq.h> +#include <asm/mach-types.h> + +#include <asm/arch/irqs.h> +#include <asm/arch/clock.h> +#include <asm/arch/sram.h> +#include <asm/arch/pm.h> + +static struct clk *vclk; +static void (*omap2_sram_idle)(void); +static void (*omap2_sram_suspend)(int dllctrl, int cpu_rev); +static void (*saved_idle)(void); + +void omap2_pm_idle(void) +{ + local_irq_disable(); + local_fiq_disable(); + if (need_resched()) { + local_fiq_enable(); + local_irq_enable(); + return; + } + + /* + * Since an interrupt may set up a timer, we don't want to + * reprogram the hardware timer with interrupts enabled. + * Re-enable interrupts only after returning from idle. + */ + timer_dyn_reprogram(); + + omap2_sram_idle(); + local_fiq_enable(); + local_irq_enable(); +} + +static int omap2_pm_prepare(suspend_state_t state) +{ + int error = 0; + + /* We cannot sleep in idle until we have resumed */ + saved_idle = pm_idle; + pm_idle = NULL; + + switch (state) + { + case PM_SUSPEND_STANDBY: + case PM_SUSPEND_MEM: + break; + + case PM_SUSPEND_DISK: + return -ENOTSUPP; + + default: + return -EINVAL; + } + + return error; +} + +static int omap2_pm_enter(suspend_state_t state) +{ + switch (state) + { + case PM_SUSPEND_STANDBY: + case PM_SUSPEND_MEM: + /* FIXME: Add suspend */ + break; + + case PM_SUSPEND_DISK: + return -ENOTSUPP; + + default: + return -EINVAL; + } + + return 0; +} + +static int omap2_pm_finish(suspend_state_t state) +{ + pm_idle = saved_idle; + return 0; +} + +static struct pm_ops omap_pm_ops = { + .pm_disk_mode = 0, + .prepare = omap2_pm_prepare, + .enter = omap2_pm_enter, + .finish = omap2_pm_finish, +}; + +int __init omap2_pm_init(void) +{ + printk("Power Management for TI OMAP.\n"); + + vclk = clk_get(NULL, "virt_prcm_set"); + if (IS_ERR(vclk)) { + printk(KERN_ERR "Could not get PM vclk\n"); + return -ENODEV; + } + + /* + * We copy the assembler sleep/wakeup routines to SRAM. + * These routines need to be in SRAM as that's the only + * memory the MPU can see when it wakes up. + */ + omap2_sram_idle = omap_sram_push(omap24xx_idle_loop_suspend, + omap24xx_idle_loop_suspend_sz); + + omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend, + omap24xx_cpu_suspend_sz); + + pm_set_ops(&omap_pm_ops); + pm_idle = omap2_pm_idle; + + return 0; +} + +__initcall(omap2_pm_init); diff --git a/arch/arm/mach-omap2/prcm.h b/arch/arm/mach-omap2/prcm-regs.h index 2eb89b936c8..22ac7be4f78 100644 --- a/arch/arm/mach-omap2/prcm.h +++ b/arch/arm/mach-omap2/prcm-regs.h @@ -1,5 +1,7 @@ /* - * prcm.h - Access definations for use in OMAP24XX clock and power management + * linux/arch/arm/mach-omap2/prcm-reg.h + * + * OMAP24XX Power Reset and Clock Management (PRCM) registers * * Copyright (C) 2005 Texas Instruments, Inc. * @@ -18,8 +20,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef __ASM_ARM_ARCH_DPM_PRCM_H -#define __ASM_ARM_ARCH_DPM_PRCM_H +#ifndef __ARCH_ARM_MACH_OMAP2_PRCM_H +#define __ARCH_ARM_MACH_OMAP2_PRCM_H /* SET_PERFORMANCE_LEVEL PARAMETERS */ #define PRCM_HALF_SPEED 1 @@ -159,54 +161,63 @@ #define CM_FCLKEN_MDM PRCM_REG32(0xC00) #define CM_ICLKEN_MDM PRCM_REG32(0xC10) #define CM_IDLEST_MDM PRCM_REG32(0xC20) +#define CM_AUTOIDLE_MDM PRCM_REG32(0xC30) #define CM_CLKSEL_MDM PRCM_REG32(0xC40) - -/* FIXME: Move to header for 2430 */ -#define DISP_BASE (OMAP24XX_L4_IO_BASE+0x50000) +#define CM_CLKSTCTRL_MDM PRCM_REG32(0xC48) +#define RM_RSTCTRL_MDM PRCM_REG32(0xC50) +#define RM_RSTST_MDM PRCM_REG32(0xC58) +#define PM_WKEN_MDM PRCM_REG32(0xCA0) +#define PM_WKST_MDM PRCM_REG32(0xCB0) +#define PM_WKDEP_MDM PRCM_REG32(0xCC8) +#define PM_PWSTCTRL_MDM PRCM_REG32(0xCE0) +#define PM_PWSTST_MDM PRCM_REG32(0xCE4) + +#define OMAP24XX_L4_IO_BASE 0x48000000 + +#define DISP_BASE (OMAP24XX_L4_IO_BASE + 0x50000) #define DISP_REG32(offset) __REG32(DISP_BASE + (offset)) -#define GPMC_BASE (OMAP24XX_GPMC_BASE) -#define GPMC_REG32(offset) __REG32(GPMC_BASE + (offset)) +#define OMAP24XX_GPMC_BASE (L3_24XX_BASE + 0xa000) +#define GPMC_REG32(offset) __REG32(OMAP24XX_GPMC_BASE + (offset)) -#define GPT1_BASE (OMAP24XX_GPT1) +/* FIXME: Move these to timer code */ +#define GPT1_BASE (0x48028000) #define GPT1_REG32(offset) __REG32(GPT1_BASE + (offset)) /* Misc sysconfig */ #define DISPC_SYSCONFIG DISP_REG32(0x410) -#define SPI_BASE (OMAP24XX_L4_IO_BASE+0x98000) +#define SPI_BASE (OMAP24XX_L4_IO_BASE + 0x98000) #define MCSPI1_SYSCONFIG __REG32(SPI_BASE + 0x10) -#define MCSPI2_SYSCONFIG __REG32(SPI_BASE+0x2000 + 0x10) - -//#define DSP_MMU_SYSCONFIG 0x5A000010 -#define CAMERA_MMU_SYSCONFIG __REG32(DISP_BASE+0x2C10) -//#define IVA_MMU_SYSCONFIG 0x5D000010 -//#define DSP_DMA_SYSCONFIG 0x00FCC02C -#define CAMERA_DMA_SYSCONFIG __REG32(DISP_BASE+0x282C) -#define SYSTEM_DMA_SYSCONFIG __REG32(DISP_BASE+0x602C) +#define MCSPI2_SYSCONFIG __REG32(SPI_BASE + 0x2000 + 0x10) +#define MCSPI3_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE + 0xb8010) + +#define CAMERA_MMU_SYSCONFIG __REG32(DISP_BASE + 0x2C10) +#define CAMERA_DMA_SYSCONFIG __REG32(DISP_BASE + 0x282C) +#define SYSTEM_DMA_SYSCONFIG __REG32(DISP_BASE + 0x602C) #define GPMC_SYSCONFIG GPMC_REG32(0x010) -#define MAILBOXES_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x94010) -#define UART1_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x6A054) -#define UART2_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x6C054) -#define UART3_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x6E054) -//#define IVA_SYSCONFIG 0x5C060010 -#define SDRC_SYSCONFIG __REG32(OMAP24XX_SDRC_BASE+0x10) -#define SMS_SYSCONFIG __REG32(OMAP24XX_SMS_BASE+0x10) -#define SSI_SYSCONFIG __REG32(DISP_BASE+0x8010) -//#define VLYNQ_SYSCONFIG 0x67FFFE10 +#define MAILBOXES_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE + 0x94010) +#define UART1_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE + 0x6A054) +#define UART2_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE + 0x6C054) +#define UART3_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE + 0x6E054) +#define SDRC_SYSCONFIG __REG32(OMAP24XX_SDRC_BASE + 0x10) +#define OMAP24XX_SMS_BASE (L3_24XX_BASE + 0x8000) +#define SMS_SYSCONFIG __REG32(OMAP24XX_SMS_BASE + 0x10) +#define SSI_SYSCONFIG __REG32(DISP_BASE + 0x8010) /* rkw - good cannidates for PM_ to start what nm was trying */ -#define OMAP24XX_GPT2 (OMAP24XX_L4_IO_BASE+0x2A000) -#define OMAP24XX_GPT3 (OMAP24XX_L4_IO_BASE+0x78000) -#define OMAP24XX_GPT4 (OMAP24XX_L4_IO_BASE+0x7A000) -#define OMAP24XX_GPT5 (OMAP24XX_L4_IO_BASE+0x7C000) -#define OMAP24XX_GPT6 (OMAP24XX_L4_IO_BASE+0x7E000) -#define OMAP24XX_GPT7 (OMAP24XX_L4_IO_BASE+0x80000) -#define OMAP24XX_GPT8 (OMAP24XX_L4_IO_BASE+0x82000) -#define OMAP24XX_GPT9 (OMAP24XX_L4_IO_BASE+0x84000) -#define OMAP24XX_GPT10 (OMAP24XX_L4_IO_BASE+0x86000) -#define OMAP24XX_GPT11 (OMAP24XX_L4_IO_BASE+0x88000) -#define OMAP24XX_GPT12 (OMAP24XX_L4_IO_BASE+0x8A000) - +#define OMAP24XX_GPT2 (OMAP24XX_L4_IO_BASE + 0x2A000) +#define OMAP24XX_GPT3 (OMAP24XX_L4_IO_BASE + 0x78000) +#define OMAP24XX_GPT4 (OMAP24XX_L4_IO_BASE + 0x7A000) +#define OMAP24XX_GPT5 (OMAP24XX_L4_IO_BASE + 0x7C000) +#define OMAP24XX_GPT6 (OMAP24XX_L4_IO_BASE + 0x7E000) +#define OMAP24XX_GPT7 (OMAP24XX_L4_IO_BASE + 0x80000) +#define OMAP24XX_GPT8 (OMAP24XX_L4_IO_BASE + 0x82000) +#define OMAP24XX_GPT9 (OMAP24XX_L4_IO_BASE + 0x84000) +#define OMAP24XX_GPT10 (OMAP24XX_L4_IO_BASE + 0x86000) +#define OMAP24XX_GPT11 (OMAP24XX_L4_IO_BASE + 0x88000) +#define OMAP24XX_GPT12 (OMAP24XX_L4_IO_BASE + 0x8A000) + +/* FIXME: Move these to timer code */ #define GPTIMER1_SYSCONFIG GPT1_REG32(0x010) #define GPTIMER2_SYSCONFIG __REG32(OMAP24XX_GPT2 + 0x10) #define GPTIMER3_SYSCONFIG __REG32(OMAP24XX_GPT3 + 0x10) @@ -220,12 +231,18 @@ #define GPTIMER11_SYSCONFIG __REG32(OMAP24XX_GPT11 + 0x10) #define GPTIMER12_SYSCONFIG __REG32(OMAP24XX_GPT12 + 0x10) -#define GPIOX_BASE(X) (OMAP24XX_GPIO_BASE+(0x2000*((X)-1))) +/* FIXME: Move these to gpio code */ +#define OMAP24XX_GPIO_BASE 0x48018000 +#define GPIOX_BASE(X) (OMAP24XX_GPIO_BASE + (0x2000 * ((X) - 1))) + +#define GPIO1_SYSCONFIG __REG32((GPIOX_BASE(1) + 0x10)) +#define GPIO2_SYSCONFIG __REG32((GPIOX_BASE(2) + 0x10)) +#define GPIO3_SYSCONFIG __REG32((GPIOX_BASE(3) + 0x10)) +#define GPIO4_SYSCONFIG __REG32((GPIOX_BASE(4) + 0x10)) -#define GPIO1_SYSCONFIG __REG32((GPIOX_BASE(1)+0x10)) -#define GPIO2_SYSCONFIG __REG32((GPIOX_BASE(2)+0x10)) -#define GPIO3_SYSCONFIG __REG32((GPIOX_BASE(3)+0x10)) -#define GPIO4_SYSCONFIG __REG32((GPIOX_BASE(4)+0x10)) +#if defined(CONFIG_ARCH_OMAP243X) +#define GPIO5_SYSCONFIG __REG32((OMAP24XX_GPIO5_BASE + 0x10)) +#endif /* GP TIMER 1 */ #define GPTIMER1_TISTAT GPT1_REG32(0x014) @@ -243,15 +260,15 @@ #define GPTIMER1_TCAR2 GPT1_REG32(0x044) /* rkw -- base fix up please... */ -#define GPTIMER3_TISR __REG32(OMAP24XX_L4_IO_BASE+0x78018) +#define GPTIMER3_TISR __REG32(OMAP24XX_L4_IO_BASE + 0x78018) /* SDRC */ -#define SDRC_DLLA_CTRL __REG32(OMAP24XX_SDRC_BASE+0x060) -#define SDRC_DLLA_STATUS __REG32(OMAP24XX_SDRC_BASE+0x064) -#define SDRC_DLLB_CTRL __REG32(OMAP24XX_SDRC_BASE+0x068) -#define SDRC_DLLB_STATUS __REG32(OMAP24XX_SDRC_BASE+0x06C) -#define SDRC_POWER __REG32(OMAP24XX_SDRC_BASE+0x070) -#define SDRC_MR_0 __REG32(OMAP24XX_SDRC_BASE+0x084) +#define SDRC_DLLA_CTRL __REG32(OMAP24XX_SDRC_BASE + 0x060) +#define SDRC_DLLA_STATUS __REG32(OMAP24XX_SDRC_BASE + 0x064) +#define SDRC_DLLB_CTRL __REG32(OMAP24XX_SDRC_BASE + 0x068) +#define SDRC_DLLB_STATUS __REG32(OMAP24XX_SDRC_BASE + 0x06C) +#define SDRC_POWER __REG32(OMAP24XX_SDRC_BASE + 0x070) +#define SDRC_MR_0 __REG32(OMAP24XX_SDRC_BASE + 0x084) /* GPIO 1 */ #define GPIO1_BASE GPIOX_BASE(1) @@ -278,6 +295,8 @@ #define GPIO2_DATAIN GPIO2_REG32(0x038) #define GPIO2_OE GPIO2_REG32(0x034) #define GPIO2_DATAOUT GPIO2_REG32(0x03C) +#define GPIO2_DEBOUNCENABLE GPIO2_REG32(0x050) +#define GPIO2_DEBOUNCINGTIME GPIO2_REG32(0x054) /* GPIO 3 */ #define GPIO3_BASE GPIOX_BASE(3) @@ -294,6 +313,8 @@ #define GPIO3_DATAOUT GPIO3_REG32(0x03C) #define GPIO3_DEBOUNCENABLE GPIO3_REG32(0x050) #define GPIO3_DEBOUNCINGTIME GPIO3_REG32(0x054) +#define GPIO3_DEBOUNCENABLE GPIO3_REG32(0x050) +#define GPIO3_DEBOUNCINGTIME GPIO3_REG32(0x054) /* GPIO 4 */ #define GPIO4_BASE GPIOX_BASE(4) @@ -311,10 +332,26 @@ #define GPIO4_DEBOUNCENABLE GPIO4_REG32(0x050) #define GPIO4_DEBOUNCINGTIME GPIO4_REG32(0x054) +#if defined(CONFIG_ARCH_OMAP243X) +/* GPIO 5 */ +#define GPIO5_REG32(offset) __REG32((OMAP24XX_GPIO5_BASE + (offset))) +#define GPIO5_IRQENABLE1 GPIO5_REG32(0x01C) +#define GPIO5_IRQSTATUS1 GPIO5_REG32(0x018) +#define GPIO5_IRQENABLE2 GPIO5_REG32(0x02C) +#define GPIO5_IRQSTATUS2 GPIO5_REG32(0x028) +#define GPIO5_WAKEUPENABLE GPIO5_REG32(0x020) +#define GPIO5_RISINGDETECT GPIO5_REG32(0x048) +#define GPIO5_FALLINGDETECT GPIO5_REG32(0x04C) +#define GPIO5_DATAIN GPIO5_REG32(0x038) +#define GPIO5_OE GPIO5_REG32(0x034) +#define GPIO5_DATAOUT GPIO5_REG32(0x03C) +#define GPIO5_DEBOUNCENABLE GPIO5_REG32(0x050) +#define GPIO5_DEBOUNCINGTIME GPIO5_REG32(0x054) +#endif /* IO CONFIG */ -#define CONTROL_BASE (OMAP24XX_CTRL_BASE) -#define CONTROL_REG32(offset) __REG32(CONTROL_BASE + (offset)) +#define OMAP24XX_CTRL_BASE (L4_24XX_BASE) +#define CONTROL_REG32(offset) __REG32(OMAP24XX_CTRL_BASE + (offset)) #define CONTROL_PADCONF_SPI1_NCS2 CONTROL_REG32(0x104) #define CONTROL_PADCONF_SYS_XTALOUT CONTROL_REG32(0x134) @@ -322,15 +359,18 @@ #define CONTROL_PADCONF_MCBSP1_DX CONTROL_REG32(0x10C) #define CONTROL_PADCONF_GPMC_NCS4 CONTROL_REG32(0x090) #define CONTROL_PADCONF_DSS_D5 CONTROL_REG32(0x0B8) -#define CONTROL_PADCONF_DSS_D9 CONTROL_REG32(0x0BC) +#define CONTROL_PADCONF_DSS_D9 CONTROL_REG32(0x0BC) /* 2420 */ #define CONTROL_PADCONF_DSS_D13 CONTROL_REG32(0x0C0) #define CONTROL_PADCONF_DSS_VSYNC CONTROL_REG32(0x0CC) +#define CONTROL_PADCONF_SYS_NIRQW0 CONTROL_REG32(0x0BC) /* 2430 */ +#define CONTROL_PADCONF_SSI1_FLAG_TX CONTROL_REG32(0x108) /* 2430 */ /* CONTROL */ #define CONTROL_DEVCONF CONTROL_REG32(0x274) +#define CONTROL_DEVCONF1 CONTROL_REG32(0x2E8) /* INTERRUPT CONTROLLER */ -#define INTC_BASE (OMAP24XX_L4_IO_BASE+0xfe000) +#define INTC_BASE ((L4_24XX_BASE) + 0xfe000) #define INTC_REG32(offset) __REG32(INTC_BASE + (offset)) #define INTC1_U_BASE INTC_REG32(0x000) @@ -348,10 +388,12 @@ #define INTC_ISR_CLEAR2 INTC_REG32(0x0D4) #define INTC_SIR_IRQ INTC_REG32(0x040) #define INTC_CONTROL INTC_REG32(0x048) -#define INTC_ILR11 INTC_REG32(0x12C) +#define INTC_ILR11 INTC_REG32(0x12C) /* PRCM on MPU PIC */ +#define INTC_ILR30 INTC_REG32(0x178) +#define INTC_ILR31 INTC_REG32(0x17C) #define INTC_ILR32 INTC_REG32(0x180) -#define INTC_ILR37 INTC_REG32(0x194) -#define INTC_SYSCONFIG INTC_REG32(0x010) +#define INTC_ILR37 INTC_REG32(0x194) /* GPIO4 on MPU PIC */ +#define INTC_SYSCONFIG INTC_REG32(0x010) /* GPT1 on MPU PIC */ /* RAM FIREWALL */ #define RAMFW_BASE (0x68005000) @@ -373,6 +415,24 @@ #define GPMC_CONFIG6_0 GPMC_REG32(0x074) #define GPMC_CONFIG7_0 GPMC_REG32(0x078) +/* GPMC CS1 */ +#define GPMC_CONFIG1_1 GPMC_REG32(0x090) +#define GPMC_CONFIG2_1 GPMC_REG32(0x094) +#define GPMC_CONFIG3_1 GPMC_REG32(0x098) +#define GPMC_CONFIG4_1 GPMC_REG32(0x09C) +#define GPMC_CONFIG5_1 GPMC_REG32(0x0a0) +#define GPMC_CONFIG6_1 GPMC_REG32(0x0a4) +#define GPMC_CONFIG7_1 GPMC_REG32(0x0a8) + +/* GPMC CS3 */ +#define GPMC_CONFIG1_3 GPMC_REG32(0x0F0) +#define GPMC_CONFIG2_3 GPMC_REG32(0x0F4) +#define GPMC_CONFIG3_3 GPMC_REG32(0x0F8) +#define GPMC_CONFIG4_3 GPMC_REG32(0x0FC) +#define GPMC_CONFIG5_3 GPMC_REG32(0x100) +#define GPMC_CONFIG6_3 GPMC_REG32(0x104) +#define GPMC_CONFIG7_3 GPMC_REG32(0x108) + /* DSS */ #define DSS_CONTROL DISP_REG32(0x040) #define DISPC_CONTROL DISP_REG32(0x440) @@ -405,11 +465,15 @@ #define DISPC_DATA_CYCLE2 DISP_REG32(0x5D8) #define DISPC_DATA_CYCLE3 DISP_REG32(0x5DC) -/* Wake up define for board */ -#define GPIO97 (1 << 1) -#define GPIO88 (1 << 24) +/* HSUSB Suspend */ +#define HSUSB_CTRL __REG8(0x480AC001) +#define USBOTG_POWER __REG32(0x480AC000) + +/* HS MMC */ +#define MMCHS1_SYSCONFIG __REG32(0x4809C010) +#define MMCHS2_SYSCONFIG __REG32(0x480b4010) -#endif /* __ASSEMBLER__ */ +#endif /* __ASSEMBLER__ */ #endif diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c new file mode 100644 index 00000000000..8893479dc7e --- /dev/null +++ b/arch/arm/mach-omap2/prcm.c @@ -0,0 +1,40 @@ +/* + * linux/arch/arm/mach-omap2/prcm.c + * + * OMAP 24xx Power Reset and Clock Management (PRCM) functions + * + * Copyright (C) 2005 Nokia Corporation + * + * Written by Tony Lindgren <tony.lindgren@nokia.com> + * + * Some pieces of code Copyright (C) 2005 Texas Instruments, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/clk.h> + +#include "prcm-regs.h" + +u32 omap_prcm_get_reset_sources(void) +{ + return RM_RSTST_WKUP & 0x7f; +} +EXPORT_SYMBOL(omap_prcm_get_reset_sources); + +/* Resets clock rates and reboots the system. Only called from system.h */ +void omap_prcm_arch_reset(char mode) +{ + u32 rate; + struct clk *vclk, *sclk; + + vclk = clk_get(NULL, "virt_prcm_set"); + sclk = clk_get(NULL, "sys_ck"); + rate = clk_get_rate(sclk); + clk_set_rate(vclk, rate); /* go to bypass for OMAP limitation */ + RM_RSTCTRL_WKUP |= 2; +} diff --git a/arch/arm/mach-omap2/sleep.S b/arch/arm/mach-omap2/sleep.S new file mode 100644 index 00000000000..00299cbeb91 --- /dev/null +++ b/arch/arm/mach-omap2/sleep.S @@ -0,0 +1,144 @@ +/* + * linux/arch/arm/mach-omap2/sleep.S + * + * (C) Copyright 2004 + * Texas Instruments, <www.ti.com> + * Richard Woodruff <r-woodruff2@ti.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <linux/config.h> +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/arch/io.h> +#include <asm/arch/pm.h> + +#define A_32KSYNC_CR_V IO_ADDRESS(OMAP_TIMER32K_BASE+0x10) +#define A_PRCM_VOLTCTRL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x50) +#define A_PRCM_CLKCFG_CTRL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x80) +#define A_CM_CLKEN_PLL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x500) +#define A_CM_IDLEST_CKGEN_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x520) +#define A_CM_CLKSEL1_PLL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x540) +#define A_CM_CLKSEL2_PLL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x544) + +#define A_SDRC_DLLA_CTRL_V IO_ADDRESS(OMAP24XX_SDRC_BASE+0x60) +#define A_SDRC_POWER_V IO_ADDRESS(OMAP24XX_SDRC_BASE+0x70) +#define A_SDRC_RFR_CTRL_V IO_ADDRESS(OMAP24XX_SDRC_BASE+0xA4) +#define A_SDRC0_V (0xC0000000) +#define A_SDRC_MANUAL_V IO_ADDRESS(OMAP24XX_SDRC_BASE+0xA8) + + .text + +/* + * Forces OMAP into idle state + * + * omap24xx_idle_loop_suspend() - This bit of code just executes the WFI + * for normal idles. + * + * Note: This code get's copied to internal SRAM at boot. When the OMAP + * wakes up it continues execution at the point it went to sleep. + */ +ENTRY(omap24xx_idle_loop_suspend) + stmfd sp!, {r0, lr} @ save registers on stack + mov r0, #0 @ clear for mcr setup + mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt + ldmfd sp!, {r0, pc} @ restore regs and return + +ENTRY(omap24xx_idle_loop_suspend_sz) + .word . - omap24xx_idle_loop_suspend + +/* + * omap242x_cpu_suspend() - Forces OMAP into deep sleep state by completing + * SDRC shutdown then ARM shutdown. Upon wake MPU is back on so just restore + * SDRC. + * + * Input: + * R0 : DLL ctrl value pre-Sleep + * R1 : Processor+Revision + * 2420: 0x21 = 242xES1, 0x26 = 242xES2.2 + * 2430: 0x31 = 2430ES1, 0x32 = 2430ES2 + * + * The if the DPLL is going to AutoIdle. It seems like the DPLL may be back on + * when we get called, but the DLL probably isn't. We will wait a bit more in + * case the DPLL isn't quite there yet. The code will wait on DLL for DDR even + * if in unlocked mode. + * + * For less than 242x-ES2.2 upon wake from a sleep mode where the external + * oscillator was stopped, a timing bug exists where a non-stabilized 12MHz + * clock can pass into the PRCM can cause problems at DSP and IVA. + * To work around this the code will switch to the 32kHz source prior to sleep. + * Post sleep we will shift back to using the DPLL. Apparently, + * CM_IDLEST_CLKGEN does not reflect the full clock change so you need to wait + * 3x12MHz + 3x32kHz clocks for a full switch. + * + * The DLL load value is not kept in RETENTION or OFF. It needs to be restored + * at wake + */ +ENTRY(omap24xx_cpu_suspend) + stmfd sp!, {r0 - r12, lr} @ save registers on stack + mov r3, #0x0 @ clear for mrc call + mcr p15, 0, r3, c7, c10, 4 @ memory barrier, hope SDR/DDR finished + nop + nop + ldr r3, A_SDRC_POWER @ addr of sdrc power + ldr r4, [r3] @ value of sdrc power + orr r4, r4, #0x40 @ enable self refresh on idle req + mov r5, #0x2000 @ set delay (DPLL relock + DLL relock) + str r4, [r3] @ make it so + mov r2, #0 + nop + mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt + nop +loop: + subs r5, r5, #0x1 @ awake, wait just a bit + bne loop + + /* The DPLL has on before we take the DDR out of self refresh */ + bic r4, r4, #0x40 @ now clear self refresh bit. + str r4, [r3] @ put vlaue back. + ldr r4, A_SDRC0 @ make a clock happen + ldr r4, [r4] + nop @ start auto refresh only after clk ok + movs r0, r0 @ see if DDR or SDR + ldrne r1, A_SDRC_DLLA_CTRL_S @ get addr of DLL ctrl + strne r0, [r1] @ rewrite DLLA to force DLL reload + addne r1, r1, #0x8 @ move to DLLB + strne r0, [r1] @ rewrite DLLB to force DLL reload + + mov r5, #0x1000 +loop2: + subs r5, r5, #0x1 + bne loop2 + /* resume*/ + ldmfd sp!, {r0 - r12, pc} @ restore regs and return + +A_SDRC_POWER: + .word A_SDRC_POWER_V +A_SDRC0: + .word A_SDRC0_V +A_CM_CLKSEL2_PLL_S: + .word A_CM_CLKSEL2_PLL_V +A_CM_CLKEN_PLL: + .word A_CM_CLKEN_PLL_V +A_SDRC_DLLA_CTRL_S: + .word A_SDRC_DLLA_CTRL_V +A_SDRC_MANUAL_S: + .word A_SDRC_MANUAL_V + +ENTRY(omap24xx_cpu_suspend_sz) + .word . - omap24xx_cpu_suspend + diff --git a/arch/arm/mach-omap2/sram-fn.S b/arch/arm/mach-omap2/sram-fn.S index 2a869e20334..d261e4ff4d9 100644 --- a/arch/arm/mach-omap2/sram-fn.S +++ b/arch/arm/mach-omap2/sram-fn.S @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap1/sram.S + * linux/arch/arm/mach-omap2/sram.S * * Omap2 specific functions that need to be run in internal SRAM * @@ -28,7 +28,7 @@ #include <asm/arch/io.h> #include <asm/hardware.h> -#include <asm/arch/prcm.h> +#include "prcm-regs.h" #define TIMER_32KSYNCT_CR_V IO_ADDRESS(OMAP24XX_32KSYNCT_BASE + 0x010) diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c index 68923b1d2b6..d6d72603636 100644 --- a/arch/arm/mach-pxa/corgi.c +++ b/arch/arm/mach-pxa/corgi.c @@ -141,6 +141,8 @@ struct corgissp_machinfo corgi_ssp_machinfo = { */ static struct corgibl_machinfo corgi_bl_machinfo = { .max_intensity = 0x2f, + .default_intensity = 0x1f, + .limit_mask = 0x0b, .set_bl_intensity = corgi_bl_set_intensity, }; @@ -164,6 +166,14 @@ static struct platform_device corgikbd_device = { /* + * Corgi LEDs + */ +static struct platform_device corgiled_device = { + .name = "corgi-led", + .id = -1, +}; + +/* * Corgi Touch Screen Device */ static struct resource corgits_resources[] = { @@ -297,6 +307,7 @@ static struct platform_device *devices[] __initdata = { &corgikbd_device, &corgibl_device, &corgits_device, + &corgiled_device, }; static void __init corgi_init(void) diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c index b45560a8f6c..a042473deed 100644 --- a/arch/arm/mach-pxa/poodle.c +++ b/arch/arm/mach-pxa/poodle.c @@ -307,6 +307,10 @@ static void __init fixup_poodle(struct machine_desc *desc, struct tag *tags, char **cmdline, struct meminfo *mi) { sharpsl_save_param(); + mi->nr_banks=1; + mi->bank[0].start = 0xa0000000; + mi->bank[0].node = 0; + mi->bank[0].size = (32*1024*1024); } MACHINE_START(POODLE, "SHARP Poodle") diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index 0dbb079ecd2..19b372df544 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -220,6 +220,8 @@ struct corgissp_machinfo spitz_ssp_machinfo = { * Spitz Backlight Device */ static struct corgibl_machinfo spitz_bl_machinfo = { + .default_intensity = 0x1f, + .limit_mask = 0x0b, .max_intensity = 0x2f, }; @@ -242,6 +244,14 @@ static struct platform_device spitzkbd_device = { /* + * Spitz LEDs + */ +static struct platform_device spitzled_device = { + .name = "spitz-led", + .id = -1, +}; + +/* * Spitz Touch Screen Device */ static struct resource spitzts_resources[] = { @@ -418,6 +428,7 @@ static struct platform_device *devices[] __initdata = { &spitzkbd_device, &spitzts_device, &spitzbl_device, + &spitzled_device, }; static void __init common_init(void) diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c index 66ec71756d0..76c0e7f0a21 100644 --- a/arch/arm/mach-pxa/tosa.c +++ b/arch/arm/mach-pxa/tosa.c @@ -251,10 +251,19 @@ static struct platform_device tosakbd_device = { .id = -1, }; +/* + * Tosa LEDs + */ +static struct platform_device tosaled_device = { + .name = "tosa-led", + .id = -1, +}; + static struct platform_device *devices[] __initdata = { &tosascoop_device, &tosascoop_jc_device, &tosakbd_device, + &tosaled_device, }; static void __init tosa_init(void) diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig index ed07c4149d8..ce7d8100069 100644 --- a/arch/arm/mach-s3c2410/Kconfig +++ b/arch/arm/mach-s3c2410/Kconfig @@ -50,9 +50,15 @@ config MACH_N30 <http://zoo.weinigel.se/n30>. +config MACH_SMDK + bool + help + Common machine code for SMDK2410 and SMDK2440 + config ARCH_SMDK2410 bool "SMDK2410/A9M2410" select CPU_S3C2410 + select MACH_SMDK help Say Y here if you are using the SMDK2410 or the derived module A9M2410 <http://www.fsforth.de> @@ -60,6 +66,7 @@ config ARCH_SMDK2410 config ARCH_S3C2440 bool "SMDK2440" select CPU_S3C2440 + select MACH_SMDK help Say Y here if you are using the SMDK2440. diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile index 1b3b476e563..3e5712db6b5 100644 --- a/arch/arm/mach-s3c2410/Makefile +++ b/arch/arm/mach-s3c2410/Makefile @@ -48,3 +48,5 @@ obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o usb-simtec.o obj-$(CONFIG_MACH_RX3715) += mach-rx3715.o obj-$(CONFIG_MACH_OTOM) += mach-otom.o obj-$(CONFIG_MACH_NEXCODER_2440) += mach-nexcoder.o + +obj-$(CONFIG_MACH_SMDK) += common-smdk.o
\ No newline at end of file diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c index fec02c92f95..b7f85e6d6b7 100644 --- a/arch/arm/mach-s3c2410/clock.c +++ b/arch/arm/mach-s3c2410/clock.c @@ -249,7 +249,7 @@ static int s3c24xx_upll_enable(struct clk *clk, int enable) /* if we started the UPLL, then allow to settle */ - if (enable && !(orig & S3C2410_CLKSLOW_UCLK_OFF)) + if (enable && (orig & S3C2410_CLKSLOW_UCLK_OFF)) udelay(200); return 0; diff --git a/arch/arm/mach-s3c2410/common-smdk.c b/arch/arm/mach-s3c2410/common-smdk.c new file mode 100644 index 00000000000..36b8291b5e0 --- /dev/null +++ b/arch/arm/mach-s3c2410/common-smdk.c @@ -0,0 +1,134 @@ +/* linux/arch/arm/mach-s3c2410/common-smdk.c + * + * Copyright (c) 2006 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * Common code for SMDK2410 and SMDK2440 boards + * + * http://www.fluff.org/ben/smdk2440/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/platform_device.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/nand_ecc.h> +#include <linux/mtd/partitions.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/irq.h> + +#include <asm/arch/regs-gpio.h> + +#include <asm/arch/nand.h> + +#include "devs.h" +#include "pm.h" + +/* NAND parititon from 2.4.18-swl5 */ + +static struct mtd_partition smdk_default_nand_part[] = { + [0] = { + .name = "Boot Agent", + .size = SZ_16K, + .offset = 0, + }, + [1] = { + .name = "S3C2410 flash parition 1", + .offset = 0, + .size = SZ_2M, + }, + [2] = { + .name = "S3C2410 flash partition 2", + .offset = SZ_4M, + .size = SZ_4M, + }, + [3] = { + .name = "S3C2410 flash partition 3", + .offset = SZ_8M, + .size = SZ_2M, + }, + [4] = { + .name = "S3C2410 flash partition 4", + .offset = SZ_1M * 10, + .size = SZ_4M, + }, + [5] = { + .name = "S3C2410 flash partition 5", + .offset = SZ_1M * 14, + .size = SZ_1M * 10, + }, + [6] = { + .name = "S3C2410 flash partition 6", + .offset = SZ_1M * 24, + .size = SZ_1M * 24, + }, + [7] = { + .name = "S3C2410 flash partition 7", + .offset = SZ_1M * 48, + .size = SZ_16M, + } +}; + +static struct s3c2410_nand_set smdk_nand_sets[] = { + [0] = { + .name = "NAND", + .nr_chips = 1, + .nr_partitions = ARRAY_SIZE(smdk_default_nand_part), + .partitions = smdk_default_nand_part, + }, +}; + +/* choose a set of timings which should suit most 512Mbit + * chips and beyond. +*/ + +static struct s3c2410_platform_nand smdk_nand_info = { + .tacls = 20, + .twrph0 = 60, + .twrph1 = 20, + .nr_sets = ARRAY_SIZE(smdk_nand_sets), + .sets = smdk_nand_sets, +}; + +/* devices we initialise */ + +static struct platform_device __initdata *smdk_devs[] = { + &s3c_device_nand, +}; + +void __init smdk_machine_init(void) +{ + /* Configure the LEDs (even if we have no LED support)*/ + + s3c2410_gpio_cfgpin(S3C2410_GPF4, S3C2410_GPF4_OUTP); + s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP); + s3c2410_gpio_cfgpin(S3C2410_GPF6, S3C2410_GPF6_OUTP); + s3c2410_gpio_cfgpin(S3C2410_GPF7, S3C2410_GPF7_OUTP); + + s3c2410_gpio_setpin(S3C2410_GPF4, 1); + s3c2410_gpio_setpin(S3C2410_GPF5, 1); + s3c2410_gpio_setpin(S3C2410_GPF6, 1); + s3c2410_gpio_setpin(S3C2410_GPF7, 1); + + s3c_device_nand.dev.platform_data = &smdk_nand_info; + + platform_add_devices(smdk_devs, ARRAY_SIZE(smdk_devs)); + + s3c2410_pm_init(); +} diff --git a/arch/arm/mach-s3c2410/common-smdk.h b/arch/arm/mach-s3c2410/common-smdk.h new file mode 100644 index 00000000000..0e3a3be330a --- /dev/null +++ b/arch/arm/mach-s3c2410/common-smdk.h @@ -0,0 +1,15 @@ +/* linux/arch/arm/mach-s3c2410/common-smdk.h + * + * Copyright (c) 2006 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * Common code for SMDK2410 and SMDK2440 boards + * + * http://www.fluff.org/ben/smdk2440/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +extern void smdk_machine_init(void); diff --git a/arch/arm/mach-s3c2410/mach-anubis.c b/arch/arm/mach-s3c2410/mach-anubis.c index 3e327b8e46b..cc97fbf6629 100644 --- a/arch/arm/mach-s3c2410/mach-anubis.c +++ b/arch/arm/mach-s3c2410/mach-anubis.c @@ -232,8 +232,8 @@ static void anubis_nand_select(struct s3c2410_nand_set *set, int slot) static struct s3c2410_platform_nand anubis_nand_info = { .tacls = 25, - .twrph0 = 80, - .twrph1 = 80, + .twrph0 = 55, + .twrph1 = 40, .nr_sets = ARRAY_SIZE(anubis_nand_sets), .sets = anubis_nand_sets, .select_chip = anubis_nand_select, diff --git a/arch/arm/mach-s3c2410/mach-rx3715.c b/arch/arm/mach-s3c2410/mach-rx3715.c index 0260ed5ab94..306afc1d7cd 100644 --- a/arch/arm/mach-s3c2410/mach-rx3715.c +++ b/arch/arm/mach-s3c2410/mach-rx3715.c @@ -32,6 +32,11 @@ #include <linux/serial_core.h> #include <linux/serial.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/nand_ecc.h> +#include <linux/mtd/partitions.h> + #include <asm/mach/arch.h> #include <asm/mach/map.h> #include <asm/mach/irq.h> @@ -46,6 +51,7 @@ #include <asm/arch/regs-gpio.h> #include <asm/arch/regs-lcd.h> +#include <asm/arch/nand.h> #include <asm/arch/fb.h> #include "clock.h" @@ -170,12 +176,39 @@ static struct s3c2410fb_mach_info rx3715_lcdcfg __initdata = { }, }; +static struct mtd_partition rx3715_nand_part[] = { + [0] = { + .name = "Whole Flash", + .offset = 0, + .size = MTDPART_SIZ_FULL, + .mask_flags = MTD_WRITEABLE, + } +}; + +static struct s3c2410_nand_set rx3715_nand_sets[] = { + [0] = { + .name = "Internal", + .nr_chips = 1, + .nr_partitions = ARRAY_SIZE(rx3715_nand_part), + .partitions = rx3715_nand_part, + }, +}; + +static struct s3c2410_platform_nand rx3715_nand_info = { + .tacls = 25, + .twrph0 = 50, + .twrph1 = 15, + .nr_sets = ARRAY_SIZE(rx3715_nand_sets), + .sets = rx3715_nand_sets, +}; + static struct platform_device *rx3715_devices[] __initdata = { &s3c_device_usb, &s3c_device_lcd, &s3c_device_wdt, &s3c_device_i2c, &s3c_device_iis, + &s3c_device_nand, }; static struct s3c24xx_board rx3715_board __initdata = { @@ -185,6 +218,8 @@ static struct s3c24xx_board rx3715_board __initdata = { static void __init rx3715_map_io(void) { + s3c_device_nand.dev.platform_data = &rx3715_nand_info; + s3c24xx_init_io(rx3715_iodesc, ARRAY_SIZE(rx3715_iodesc)); s3c24xx_init_clocks(16934000); s3c24xx_init_uarts(rx3715_uartcfgs, ARRAY_SIZE(rx3715_uartcfgs)); diff --git a/arch/arm/mach-s3c2410/mach-smdk2410.c b/arch/arm/mach-s3c2410/mach-smdk2410.c index 1e76e1fdfce..2db932d72c5 100644 --- a/arch/arm/mach-s3c2410/mach-smdk2410.c +++ b/arch/arm/mach-s3c2410/mach-smdk2410.c @@ -28,7 +28,8 @@ * Ben Dooks <ben@simtec.co.uk> * * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA - * 20-Sep-2005 BJD Added static to non-exported items + * 20-Sep-2005 BJD Added static to non-exported items + * 01-Apr-2006 BJD Moved init code to common smdk * ***********************************************************************/ @@ -54,6 +55,8 @@ #include "devs.h" #include "cpu.h" +#include "common-smdk.h" + static struct map_desc smdk2410_iodesc[] __initdata = { /* nothing here yet */ }; @@ -107,11 +110,6 @@ static void __init smdk2410_map_io(void) s3c24xx_set_board(&smdk2410_board); } -static void __init smdk2410_init_irq(void) -{ - s3c24xx_init_irq(); -} - MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch * to SMDK2410 */ /* Maintainer: Jonas Dietsche */ @@ -119,7 +117,8 @@ MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switc .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc, .boot_params = S3C2410_SDRAM_PA + 0x100, .map_io = smdk2410_map_io, - .init_irq = smdk2410_init_irq, + .init_irq = s3c24xx_init_irq, + .init_machine = smdk_machine_init, .timer = &s3c24xx_timer, MACHINE_END diff --git a/arch/arm/mach-s3c2410/mach-smdk2440.c b/arch/arm/mach-s3c2410/mach-smdk2440.c index f4315721c3b..5fffd1d5104 100644 --- a/arch/arm/mach-s3c2410/mach-smdk2440.c +++ b/arch/arm/mach-s3c2410/mach-smdk2440.c @@ -53,7 +53,8 @@ #include "clock.h" #include "devs.h" #include "cpu.h" -#include "pm.h" + +#include "common-smdk.h" static struct map_desc smdk2440_iodesc[] __initdata = { /* ISA IO Space map (memory space selected by A24) */ @@ -197,21 +198,9 @@ static void __init smdk2440_map_io(void) static void __init smdk2440_machine_init(void) { - /* Configure the LEDs (even if we have no LED support)*/ - - s3c2410_gpio_cfgpin(S3C2410_GPF4, S3C2410_GPF4_OUTP); - s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP); - s3c2410_gpio_cfgpin(S3C2410_GPF6, S3C2410_GPF6_OUTP); - s3c2410_gpio_cfgpin(S3C2410_GPF7, S3C2410_GPF7_OUTP); - - s3c2410_gpio_setpin(S3C2410_GPF4, 0); - s3c2410_gpio_setpin(S3C2410_GPF5, 0); - s3c2410_gpio_setpin(S3C2410_GPF6, 0); - s3c2410_gpio_setpin(S3C2410_GPF7, 0); - s3c24xx_fb_set_platdata(&smdk2440_lcd_cfg); - s3c2410_pm_init(); + smdk_machine_init(); } MACHINE_START(S3C2440, "SMDK2440") diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c index 10245408247..676b5c5b75b 100644 --- a/arch/arm/mach-sa1100/collie.c +++ b/arch/arm/mach-sa1100/collie.c @@ -11,7 +11,8 @@ * published by the Free Software Foundation. * * ChangeLog: - * 03-06-2004 John Lenz <jelenz@wisc.edu> + * 2006 Pavel Machek <pavel@suse.cz> + * 03-06-2004 John Lenz <lenz@cs.wisc.edu> * 06-04-2002 Chris Larson <kergoth@digitalnemesis.net> * 04-16-2001 Lineo Japan,Inc. ... */ @@ -87,12 +88,75 @@ static struct mcp_plat_data collie_mcp_data = { .sclk_rate = 11981000, }; +#ifdef CONFIG_SHARP_LOCOMO +/* + * low-level UART features. + */ +static struct locomo_dev *uart_dev = NULL; + +static void collie_uart_set_mctrl(struct uart_port *port, u_int mctrl) +{ + if (!uart_dev) return; + + if (mctrl & TIOCM_RTS) + locomo_gpio_write(uart_dev, LOCOMO_GPIO_RTS, 0); + else + locomo_gpio_write(uart_dev, LOCOMO_GPIO_RTS, 1); + + if (mctrl & TIOCM_DTR) + locomo_gpio_write(uart_dev, LOCOMO_GPIO_DTR, 0); + else + locomo_gpio_write(uart_dev, LOCOMO_GPIO_DTR, 1); +} + +static u_int collie_uart_get_mctrl(struct uart_port *port) +{ + int ret = TIOCM_CD; + unsigned int r; + if (!uart_dev) return ret; + + r = locomo_gpio_read_output(uart_dev, LOCOMO_GPIO_CTS & LOCOMO_GPIO_DSR); + if (r & LOCOMO_GPIO_CTS) + ret |= TIOCM_CTS; + if (r & LOCOMO_GPIO_DSR) + ret |= TIOCM_DSR; + + return ret; +} static struct sa1100_port_fns collie_port_fns __initdata = { .set_mctrl = collie_uart_set_mctrl, .get_mctrl = collie_uart_get_mctrl, }; +static int collie_uart_probe(struct locomo_dev *dev) +{ + uart_dev = dev; + return 0; +} + +static int collie_uart_remove(struct locomo_dev *dev) +{ + uart_dev = NULL; + return 0; +} + +static struct locomo_driver collie_uart_driver = { + .drv = { + .name = "collie_uart", + }, + .devid = LOCOMO_DEVID_UART, + .probe = collie_uart_probe, + .remove = collie_uart_remove, +}; + +static int __init collie_uart_init(void) { + return locomo_driver_register(&collie_uart_driver); +} +device_initcall(collie_uart_init); + +#endif + static struct resource locomo_resources[] = { [0] = { @@ -218,6 +282,12 @@ static void __init collie_map_io(void) { sa1100_map_io(); iotable_init(collie_io_desc, ARRAY_SIZE(collie_io_desc)); + +#ifdef CONFIG_SHARP_LOCOMO + sa1100_register_uart_fns(&collie_port_fns); +#endif + sa1100_register_uart(0, 3); + sa1100_register_uart(1, 1); } MACHINE_START(COLLIE, "Sharp-Collie") diff --git a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c index 8a1bfcd5008..50e6b6bfb2e 100644 --- a/arch/arm/mm/consistent.c +++ b/arch/arm/mm/consistent.c @@ -18,6 +18,7 @@ #include <linux/device.h> #include <linux/dma-mapping.h> +#include <asm/memory.h> #include <asm/cacheflush.h> #include <asm/tlbflush.h> #include <asm/sizes.h> @@ -272,6 +273,17 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp, void * dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp) { + if (arch_is_coherent()) { + void *virt; + + virt = kmalloc(size, gfp); + if (!virt) + return NULL; + *handle = virt_to_dma(dev, virt); + + return virt; + } + return __dma_alloc(dev, size, handle, gfp, pgprot_noncached(pgprot_kernel)); } @@ -350,6 +362,11 @@ void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr WARN_ON(irqs_disabled()); + if (arch_is_coherent()) { + kfree(cpu_addr); + return; + } + size = PAGE_ALIGN(size); spin_lock_irqsave(&consistent_lock, flags); diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c index 5e5d05bcad5..f14b2d0f369 100644 --- a/arch/arm/mm/mm-armv.c +++ b/arch/arm/mm/mm-armv.c @@ -389,6 +389,17 @@ void __init build_mem_type_table(void) kern_pgprot = user_pgprot = cp->pte; /* + * Enable CPU-specific coherency if supported. + * (Only available on XSC3 at the moment.) + */ + if (arch_is_coherent()) { + if (cpu_is_xsc3()) { + mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S; + mem_types[MT_MEMORY].prot_pte |= L_PTE_COHERENT; + } + } + + /* * ARMv6 and above have extended page tables. */ if (cpu_arch >= CPU_ARCH_ARMv6 && (cr & CR_XP)) { diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S index f90513e9af0..80873b36c3f 100644 --- a/arch/arm/mm/proc-xsc3.S +++ b/arch/arm/mm/proc-xsc3.S @@ -30,6 +30,7 @@ #include <asm/procinfo.h> #include <asm/hardware.h> #include <asm/pgtable.h> +#include <asm/pgtable-hwdef.h> #include <asm/page.h> #include <asm/ptrace.h> #include "proc-macros.S" @@ -370,7 +371,7 @@ ENTRY(cpu_xsc3_switch_mm) ENTRY(cpu_xsc3_set_pte) str r1, [r0], #-2048 @ linux version - bic r2, r1, #0xff0 + bic r2, r1, #0xdf0 @ Keep C, B, coherency bits orr r2, r2, #PTE_TYPE_EXT @ extended page eor r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index 0887bb2a255..ec49495e651 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -70,13 +70,13 @@ config OMAP_MPU_TIMER config OMAP_32K_TIMER bool "Use 32KHz timer" - depends on ARCH_OMAP16XX + depends on ARCH_OMAP16XX || ARCH_OMAP24XX help Select this option if you want to enable the OMAP 32KHz timer. This timer saves power compared to the OMAP_MPU_TIMER, and has support for no tick during idle. The 32KHz timer provides less intra-tick resolution than OMAP_MPU_TIMER. The 32KHz timer is - currently only available for OMAP-16xx. + currently only available for OMAP16XX and 24XX. endchoice diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile index 9ccf1943fc9..2896b454641 100644 --- a/arch/arm/plat-omap/Makefile +++ b/arch/arm/plat-omap/Makefile @@ -3,16 +3,16 @@ # # Common support -obj-y := common.o sram.o sram-fn.o clock.o devices.o dma.o mux.o gpio.o mcbsp.o usb.o +obj-y := common.o sram.o sram-fn.o clock.o devices.o dma.o mux.o gpio.o mcbsp.o usb.o fb.o obj-m := obj-n := obj- := +obj-$(CONFIG_OMAP_32K_TIMER) += timer32k.o + # OCPI interconnect support for 1710, 1610 and 5912 obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o -# Power Management -obj-$(CONFIG_PM) += pm.o sleep.o obj-$(CONFIG_CPU_FREQ) += cpu-omap.o obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c index 3c2bfc0efda..06485c193ee 100644 --- a/arch/arm/plat-omap/clock.c +++ b/arch/arm/plat-omap/clock.c @@ -21,6 +21,7 @@ #include <linux/string.h> #include <linux/clk.h> #include <linux/mutex.h> +#include <linux/platform_device.h> #include <asm/io.h> #include <asm/semaphore.h> @@ -37,17 +38,37 @@ static struct clk_functions *arch_clock; * Standard clock functions defined in include/linux/clk.h *-------------------------------------------------------------------------*/ +/* + * Returns a clock. Note that we first try to use device id on the bus + * and clock name. If this fails, we try to use clock name only. + */ struct clk * clk_get(struct device *dev, const char *id) { struct clk *p, *clk = ERR_PTR(-ENOENT); + int idno; + + if (dev == NULL || dev->bus != &platform_bus_type) + idno = -1; + else + idno = to_platform_device(dev)->id; mutex_lock(&clocks_mutex); + + list_for_each_entry(p, &clocks, node) { + if (p->id == idno && + strcmp(id, p->name) == 0 && try_module_get(p->owner)) { + clk = p; + break; + } + } + list_for_each_entry(p, &clocks, node) { if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { clk = p; break; } } + mutex_unlock(&clocks_mutex); return clk; @@ -59,6 +80,9 @@ int clk_enable(struct clk *clk) unsigned long flags; int ret = 0; + if (clk == NULL || IS_ERR(clk)) + return -EINVAL; + spin_lock_irqsave(&clockfw_lock, flags); if (arch_clock->clk_enable) ret = arch_clock->clk_enable(clk); @@ -72,6 +96,9 @@ void clk_disable(struct clk *clk) { unsigned long flags; + if (clk == NULL || IS_ERR(clk)) + return; + spin_lock_irqsave(&clockfw_lock, flags); if (arch_clock->clk_disable) arch_clock->clk_disable(clk); @@ -84,6 +111,9 @@ int clk_get_usecount(struct clk *clk) unsigned long flags; int ret = 0; + if (clk == NULL || IS_ERR(clk)) + return 0; + spin_lock_irqsave(&clockfw_lock, flags); ret = clk->usecount; spin_unlock_irqrestore(&clockfw_lock, flags); @@ -97,6 +127,9 @@ unsigned long clk_get_rate(struct clk *clk) unsigned long flags; unsigned long ret = 0; + if (clk == NULL || IS_ERR(clk)) + return 0; + spin_lock_irqsave(&clockfw_lock, flags); ret = clk->rate; spin_unlock_irqrestore(&clockfw_lock, flags); @@ -121,6 +154,9 @@ long clk_round_rate(struct clk *clk, unsigned long rate) unsigned long flags; long ret = 0; + if (clk == NULL || IS_ERR(clk)) + return ret; + spin_lock_irqsave(&clockfw_lock, flags); if (arch_clock->clk_round_rate) ret = arch_clock->clk_round_rate(clk, rate); @@ -133,7 +169,10 @@ EXPORT_SYMBOL(clk_round_rate); int clk_set_rate(struct clk *clk, unsigned long rate) { unsigned long flags; - int ret = 0; + int ret = -EINVAL; + + if (clk == NULL || IS_ERR(clk)) + return ret; spin_lock_irqsave(&clockfw_lock, flags); if (arch_clock->clk_set_rate) @@ -147,7 +186,10 @@ EXPORT_SYMBOL(clk_set_rate); int clk_set_parent(struct clk *clk, struct clk *parent) { unsigned long flags; - int ret = 0; + int ret = -EINVAL; + + if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent)) + return ret; spin_lock_irqsave(&clockfw_lock, flags); if (arch_clock->clk_set_parent) @@ -163,6 +205,9 @@ struct clk *clk_get_parent(struct clk *clk) unsigned long flags; struct clk * ret = NULL; + if (clk == NULL || IS_ERR(clk)) + return ret; + spin_lock_irqsave(&clockfw_lock, flags); if (arch_clock->clk_get_parent) ret = arch_clock->clk_get_parent(clk); @@ -199,6 +244,9 @@ __setup("mpurate=", omap_clk_setup); /* Used for clocks that always have same value as the parent clock */ void followparent_recalc(struct clk *clk) { + if (clk == NULL || IS_ERR(clk)) + return; + clk->rate = clk->parent->rate; } @@ -207,6 +255,9 @@ void propagate_rate(struct clk * tclk) { struct clk *clkp; + if (tclk == NULL || IS_ERR(tclk)) + return; + list_for_each_entry(clkp, &clocks, node) { if (likely(clkp->parent != tclk)) continue; @@ -217,6 +268,9 @@ void propagate_rate(struct clk * tclk) int clk_register(struct clk *clk) { + if (clk == NULL || IS_ERR(clk)) + return -EINVAL; + mutex_lock(&clocks_mutex); list_add(&clk->node, &clocks); if (clk->init) @@ -229,6 +283,9 @@ EXPORT_SYMBOL(clk_register); void clk_unregister(struct clk *clk) { + if (clk == NULL || IS_ERR(clk)) + return; + mutex_lock(&clocks_mutex); list_del(&clk->node); mutex_unlock(&clocks_mutex); @@ -239,6 +296,9 @@ void clk_deny_idle(struct clk *clk) { unsigned long flags; + if (clk == NULL || IS_ERR(clk)) + return; + spin_lock_irqsave(&clockfw_lock, flags); if (arch_clock->clk_deny_idle) arch_clock->clk_deny_idle(clk); @@ -250,6 +310,9 @@ void clk_allow_idle(struct clk *clk) { unsigned long flags; + if (clk == NULL || IS_ERR(clk)) + return; + spin_lock_irqsave(&clockfw_lock, flags); if (arch_clock->clk_allow_idle) arch_clock->clk_allow_idle(clk); diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c index 9dcce904b60..079b67deac0 100644 --- a/arch/arm/plat-omap/devices.c +++ b/arch/arm/plat-omap/devices.c @@ -24,6 +24,7 @@ #include <asm/arch/board.h> #include <asm/arch/mux.h> #include <asm/arch/gpio.h> +#include <asm/arch/menelaus.h> void omap_nop_release(struct device *dev) @@ -98,6 +99,62 @@ static inline void omap_init_i2c(void) {} #endif /*-------------------------------------------------------------------------*/ +#if defined(CONFIG_KEYBOARD_OMAP) || defined(CONFIG_KEYBOARD_OMAP_MODULE) + +static void omap_init_kp(void) +{ + if (machine_is_omap_h2() || machine_is_omap_h3()) { + omap_cfg_reg(F18_1610_KBC0); + omap_cfg_reg(D20_1610_KBC1); + omap_cfg_reg(D19_1610_KBC2); + omap_cfg_reg(E18_1610_KBC3); + omap_cfg_reg(C21_1610_KBC4); + + omap_cfg_reg(G18_1610_KBR0); + omap_cfg_reg(F19_1610_KBR1); + omap_cfg_reg(H14_1610_KBR2); + omap_cfg_reg(E20_1610_KBR3); + omap_cfg_reg(E19_1610_KBR4); + omap_cfg_reg(N19_1610_KBR5); + } else if (machine_is_omap_perseus2()) { + omap_cfg_reg(E2_730_KBR0); + omap_cfg_reg(J7_730_KBR1); + omap_cfg_reg(E1_730_KBR2); + omap_cfg_reg(F3_730_KBR3); + omap_cfg_reg(D2_730_KBR4); + + omap_cfg_reg(C2_730_KBC0); + omap_cfg_reg(D3_730_KBC1); + omap_cfg_reg(E4_730_KBC2); + omap_cfg_reg(F4_730_KBC3); + omap_cfg_reg(E3_730_KBC4); + } else if (machine_is_omap_h4()) { + omap_cfg_reg(T19_24XX_KBR0); + omap_cfg_reg(R19_24XX_KBR1); + omap_cfg_reg(V18_24XX_KBR2); + omap_cfg_reg(M21_24XX_KBR3); + omap_cfg_reg(E5__24XX_KBR4); + if (omap_has_menelaus()) { + omap_cfg_reg(B3__24XX_KBR5); + omap_cfg_reg(AA4_24XX_KBC2); + omap_cfg_reg(B13_24XX_KBC6); + } else { + omap_cfg_reg(M18_24XX_KBR5); + omap_cfg_reg(H19_24XX_KBC2); + omap_cfg_reg(N19_24XX_KBC6); + } + omap_cfg_reg(R20_24XX_KBC0); + omap_cfg_reg(M14_24XX_KBC1); + omap_cfg_reg(V17_24XX_KBC3); + omap_cfg_reg(P21_24XX_KBC4); + omap_cfg_reg(L14_24XX_KBC5); + } +} +#else +static inline void omap_init_kp(void) {} +#endif + +/*-------------------------------------------------------------------------*/ #if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) @@ -240,6 +297,55 @@ static void __init omap_init_mmc(void) static inline void omap_init_mmc(void) {} #endif +/*-------------------------------------------------------------------------*/ + +/* Numbering for the SPI-capable controllers when used for SPI: + * spi = 1 + * uwire = 2 + * mmc1..2 = 3..4 + * mcbsp1..3 = 5..7 + */ + +#if defined(CONFIG_SPI_OMAP_UWIRE) || defined(CONFIG_SPI_OMAP_UWIRE_MODULE) + +#define OMAP_UWIRE_BASE 0xfffb3000 + +static struct resource uwire_resources[] = { + { + .start = OMAP_UWIRE_BASE, + .end = OMAP_UWIRE_BASE + 0x20, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device omap_uwire_device = { + .name = "omap_uwire", + .id = -1, + .dev = { + .release = omap_nop_release, + }, + .num_resources = ARRAY_SIZE(uwire_resources), + .resource = uwire_resources, +}; + +static void omap_init_uwire(void) +{ + /* FIXME define and use a boot tag; not all boards will be hooking + * up devices to the microwire controller, and multi-board configs + * mean that CONFIG_SPI_OMAP_UWIRE may be configured anyway... + */ + + /* board-specific code must configure chipselects (only a few + * are normally used) and SCLK/SDI/SDO (each has two choices). + */ + (void) platform_device_register(&omap_uwire_device); +} +#else +static inline void omap_init_uwire(void) {} +#endif + +/*-------------------------------------------------------------------------*/ + #if defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE) #ifdef CONFIG_ARCH_OMAP24XX @@ -310,40 +416,6 @@ static void omap_init_rng(void) static inline void omap_init_rng(void) {} #endif -#if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE) - -static struct omap_lcd_config omap_fb_conf; - -static u64 omap_fb_dma_mask = ~(u32)0; - -static struct platform_device omap_fb_device = { - .name = "omapfb", - .id = -1, - .dev = { - .release = omap_nop_release, - .dma_mask = &omap_fb_dma_mask, - .coherent_dma_mask = ~(u32)0, - .platform_data = &omap_fb_conf, - }, - .num_resources = 0, -}; - -static inline void omap_init_fb(void) -{ - const struct omap_lcd_config *conf; - - conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config); - if (conf != NULL) - omap_fb_conf = *conf; - platform_device_register(&omap_fb_device); -} - -#else - -static inline void omap_init_fb(void) {} - -#endif - /* * This gets called after board-specific INIT_MACHINE, and initializes most * on-chip peripherals accessible on this board (except for few like USB): @@ -369,9 +441,10 @@ static int __init omap_init_devices(void) /* please keep these calls, and their implementations above, * in alphabetical order so they're easier to sort through. */ - omap_init_fb(); omap_init_i2c(); + omap_init_kp(); omap_init_mmc(); + omap_init_uwire(); omap_init_wdt(); omap_init_rng(); diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c index a4e5ac77f6d..5dac4230360 100644 --- a/arch/arm/plat-omap/dma.c +++ b/arch/arm/plat-omap/dma.c @@ -1258,6 +1258,11 @@ void omap_stop_lcd_dma(void) omap_writew(w, OMAP1610_DMA_LCD_CTRL); } +int omap_lcd_dma_ext_running(void) +{ + return lcd_dma.ext_ctrl && lcd_dma.active; +} + /*----------------------------------------------------------------------------*/ static int __init omap_init_dma(void) @@ -1389,6 +1394,7 @@ EXPORT_SYMBOL(omap_free_lcd_dma); EXPORT_SYMBOL(omap_enable_lcd_dma); EXPORT_SYMBOL(omap_setup_lcd_dma); EXPORT_SYMBOL(omap_stop_lcd_dma); +EXPORT_SYMBOL(omap_lcd_dma_ext_running); EXPORT_SYMBOL(omap_set_lcd_dma_b1); EXPORT_SYMBOL(omap_set_lcd_dma_single_transfer); EXPORT_SYMBOL(omap_set_lcd_dma_ext_controller); diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index 38d7ebf8792..eba3cb52ad8 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -97,6 +97,32 @@ int omap_dm_timers_active(void) } +/** + * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR + * @inputmask: current value of idlect mask + */ +__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask) +{ + int n; + + /* If ARMXOR cannot be idled this function call is unnecessary */ + if (!(inputmask & (1 << 1))) + return inputmask; + + /* If any active timer is using ARMXOR return modified mask */ + for (n = 0; dm_timers[n].base; ++n) + if (omap_dm_timer_read_reg(&dm_timers[n], OMAP_TIMER_CTRL_REG)& + OMAP_TIMER_CTRL_ST) { + if (((omap_readl(MOD_CONF_CTRL_1)>>(n*2)) & 0x03) == 0) + inputmask &= ~(1 << 1); + else + inputmask &= ~(1 << 2); + } + + return inputmask; +} + + void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) { int n = (timer - dm_timers) << 1; diff --git a/arch/arm/plat-omap/fb.c b/arch/arm/plat-omap/fb.c new file mode 100644 index 00000000000..305e9b990b7 --- /dev/null +++ b/arch/arm/plat-omap/fb.c @@ -0,0 +1,80 @@ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/bootmem.h> + +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/mach-types.h> +#include <asm/mach/map.h> + +#include <asm/arch/board.h> +#include <asm/arch/sram.h> +#include <asm/arch/omapfb.h> + +#if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE) + +static struct omapfb_platform_data omapfb_config; + +static u64 omap_fb_dma_mask = ~(u32)0; + +static struct platform_device omap_fb_device = { + .name = "omapfb", + .id = -1, + .dev = { + .dma_mask = &omap_fb_dma_mask, + .coherent_dma_mask = ~(u32)0, + .platform_data = &omapfb_config, + }, + .num_resources = 0, +}; + +/* called from map_io */ +void omapfb_reserve_mem(void) +{ + const struct omap_fbmem_config *fbmem_conf; + + omapfb_config.fbmem.fb_sram_start = omap_fb_sram_start; + omapfb_config.fbmem.fb_sram_size = omap_fb_sram_size; + + fbmem_conf = omap_get_config(OMAP_TAG_FBMEM, struct omap_fbmem_config); + + if (fbmem_conf != NULL) { + /* indicate that the bootloader already initialized the + * fb device, so we'll skip that part in the fb driver + */ + omapfb_config.fbmem.fb_sdram_start = fbmem_conf->fb_sdram_start; + omapfb_config.fbmem.fb_sdram_size = fbmem_conf->fb_sdram_size; + if (fbmem_conf->fb_sdram_size) { + pr_info("Reserving %u bytes SDRAM for frame buffer\n", + fbmem_conf->fb_sdram_size); + reserve_bootmem(fbmem_conf->fb_sdram_start, + fbmem_conf->fb_sdram_size); + } + } +} + +static inline int omap_init_fb(void) +{ + const struct omap_lcd_config *conf; + + conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config); + if (conf == NULL) + return 0; + + omapfb_config.lcd = *conf; + + return platform_device_register(&omap_fb_device); +} + +arch_initcall(omap_init_fb); + +#else + +void omapfb_reserve_mem(void) {} + +#endif + + diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index b4d5b9e4bfc..d3c8ea7eecf 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -174,7 +174,7 @@ static int gpio_bank_count; static inline struct gpio_bank *get_gpio_bank(int gpio) { #ifdef CONFIG_ARCH_OMAP15XX - if (cpu_is_omap1510()) { + if (cpu_is_omap15xx()) { if (OMAP_GPIO_IS_MPUIO(gpio)) return &gpio_bank[0]; return &gpio_bank[1]; @@ -223,7 +223,7 @@ static inline int gpio_valid(int gpio) return 0; } #ifdef CONFIG_ARCH_OMAP15XX - if (cpu_is_omap1510() && gpio < 16) + if (cpu_is_omap15xx() && gpio < 16) return 0; #endif #if defined(CONFIG_ARCH_OMAP16XX) @@ -402,13 +402,13 @@ static inline void set_24xx_gpio_triggering(void __iomem *base, int gpio, int tr u32 gpio_bit = 1 << gpio; MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT0, gpio_bit, - trigger & IRQT_LOW); + trigger & __IRQT_LOWLVL); MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT1, gpio_bit, - trigger & IRQT_HIGH); + trigger & __IRQT_HIGHLVL); MOD_REG_BIT(OMAP24XX_GPIO_RISINGDETECT, gpio_bit, - trigger & IRQT_RISING); + trigger & __IRQT_RISEDGE); MOD_REG_BIT(OMAP24XX_GPIO_FALLINGDETECT, gpio_bit, - trigger & IRQT_FALLING); + trigger & __IRQT_FALEDGE); /* FIXME: Possibly do 'set_irq_handler(j, do_level_IRQ)' if only level * triggering requested. */ } @@ -422,9 +422,9 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) case METHOD_MPUIO: reg += OMAP_MPUIO_GPIO_INT_EDGE; l = __raw_readl(reg); - if (trigger == IRQT_RISING) + if (trigger & __IRQT_RISEDGE) l |= 1 << gpio; - else if (trigger == IRQT_FALLING) + else if (trigger & __IRQT_FALEDGE) l &= ~(1 << gpio); else goto bad; @@ -432,9 +432,9 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) case METHOD_GPIO_1510: reg += OMAP1510_GPIO_INT_CONTROL; l = __raw_readl(reg); - if (trigger == IRQT_RISING) + if (trigger & __IRQT_RISEDGE) l |= 1 << gpio; - else if (trigger == IRQT_FALLING) + else if (trigger & __IRQT_FALEDGE) l &= ~(1 << gpio); else goto bad; @@ -446,20 +446,21 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) reg += OMAP1610_GPIO_EDGE_CTRL1; gpio &= 0x07; /* We allow only edge triggering, i.e. two lowest bits */ - if (trigger & ~IRQT_BOTHEDGE) + if (trigger & (__IRQT_LOWLVL | __IRQT_HIGHLVL)) BUG(); - /* NOTE: knows __IRQT_{FAL,RIS}EDGE match OMAP hardware */ - trigger &= 0x03; l = __raw_readl(reg); l &= ~(3 << (gpio << 1)); - l |= trigger << (gpio << 1); + if (trigger & __IRQT_RISEDGE) + l |= 2 << (gpio << 1); + if (trigger & __IRQT_FALEDGE) + l |= 1 << (gpio << 1); break; case METHOD_GPIO_730: reg += OMAP730_GPIO_INT_CONTROL; l = __raw_readl(reg); - if (trigger == IRQT_RISING) + if (trigger & __IRQT_RISEDGE) l |= 1 << gpio; - else if (trigger == IRQT_FALLING) + else if (trigger & __IRQT_FALEDGE) l &= ~(1 << gpio); else goto bad; @@ -491,7 +492,9 @@ static int gpio_irq_type(unsigned irq, unsigned type) if (check_gpio(gpio) < 0) return -EINVAL; - if (type & (__IRQT_LOWLVL|__IRQT_HIGHLVL|IRQT_PROBE)) + if (type & IRQT_PROBE) + return -EINVAL; + if (!cpu_is_omap24xx() && (type & (__IRQT_LOWLVL|__IRQT_HIGHLVL))) return -EINVAL; bank = get_gpio_bank(gpio); @@ -755,13 +758,32 @@ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc, if (bank->method == METHOD_GPIO_24XX) isr_reg = bank->base + OMAP24XX_GPIO_IRQSTATUS1; #endif - while(1) { - isr = __raw_readl(isr_reg); - _enable_gpio_irqbank(bank, isr, 0); - _clear_gpio_irqbank(bank, isr); - _enable_gpio_irqbank(bank, isr, 1); - desc->chip->unmask(irq); + u32 isr_saved, level_mask = 0; + + isr_saved = isr = __raw_readl(isr_reg); + + if (cpu_is_omap15xx() && (bank->method == METHOD_MPUIO)) + isr &= 0x0000ffff; + + if (cpu_is_omap24xx()) + level_mask = + __raw_readl(bank->base + + OMAP24XX_GPIO_LEVELDETECT0) | + __raw_readl(bank->base + + OMAP24XX_GPIO_LEVELDETECT1); + + /* clear edge sensitive interrupts before handler(s) are + called so that we don't miss any interrupt occurred while + executing them */ + _enable_gpio_irqbank(bank, isr_saved & ~level_mask, 0); + _clear_gpio_irqbank(bank, isr_saved & ~level_mask); + _enable_gpio_irqbank(bank, isr_saved & ~level_mask, 1); + + /* if there is only edge sensitive GPIO pin interrupts + configured, we could unmask GPIO bank interrupt immediately */ + if (!level_mask) + desc->chip->unmask(irq); if (!isr) break; @@ -774,6 +796,20 @@ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc, d = irq_desc + gpio_irq; desc_handle_irq(gpio_irq, d, regs); } + + if (cpu_is_omap24xx()) { + /* clear level sensitive interrupts after handler(s) */ + _enable_gpio_irqbank(bank, isr_saved & level_mask, 0); + _clear_gpio_irqbank(bank, isr_saved & level_mask); + _enable_gpio_irqbank(bank, isr_saved & level_mask, 1); + } + + /* if bank has any level sensitive GPIO pin interrupt + configured, we must unmask the bank interrupt only after + handler(s) are executed in order to avoid spurious bank + interrupt */ + if (level_mask) + desc->chip->unmask(irq); } } @@ -848,7 +884,7 @@ static int __init _omap_gpio_init(void) initialized = 1; - if (cpu_is_omap1510()) { + if (cpu_is_omap15xx()) { gpio_ick = clk_get(NULL, "arm_gpio_ck"); if (IS_ERR(gpio_ick)) printk("Could not get arm_gpio_ck\n"); @@ -869,7 +905,7 @@ static int __init _omap_gpio_init(void) } #ifdef CONFIG_ARCH_OMAP15XX - if (cpu_is_omap1510()) { + if (cpu_is_omap15xx()) { printk(KERN_INFO "OMAP1510 GPIO hardware\n"); gpio_bank_count = 2; gpio_bank = gpio_bank_1510; diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index 1cd2cace7e1..196aac3ac32 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -34,7 +34,7 @@ #ifdef CONFIG_MCBSP_DEBUG #define DBG(x...) printk(x) #else -#define DBG(x...) do { } while (0) +#define DBG(x...) do { } while (0) #endif struct omap_mcbsp { @@ -44,6 +44,7 @@ struct omap_mcbsp { omap_mcbsp_word_length rx_word_length; omap_mcbsp_word_length tx_word_length; + omap_mcbsp_io_type_t io_type; /* IRQ or poll */ /* IRQ based TX/RX */ int rx_irq; int tx_irq; @@ -64,10 +65,19 @@ struct omap_mcbsp { }; static struct omap_mcbsp mcbsp[OMAP_MAX_MCBSP_COUNT]; +#ifdef CONFIG_ARCH_OMAP1 static struct clk *mcbsp_dsp_ck = 0; static struct clk *mcbsp_api_ck = 0; static struct clk *mcbsp_dspxor_ck = 0; - +#endif +#ifdef CONFIG_ARCH_OMAP2 +static struct clk *mcbsp1_ick = 0; +static struct clk *mcbsp1_fck = 0; +static struct clk *mcbsp2_ick = 0; +static struct clk *mcbsp2_fck = 0; +static struct clk *sys_ck = 0; +static struct clk *sys_clkout = 0; +#endif static void omap_mcbsp_dump_reg(u8 id) { @@ -88,7 +98,6 @@ static void omap_mcbsp_dump_reg(u8 id) DBG("***********************\n"); } - static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id, struct pt_regs *regs) { struct omap_mcbsp * mcbsp_tx = (struct omap_mcbsp *)(dev_id); @@ -109,7 +118,6 @@ static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id, struct pt_re return IRQ_HANDLED; } - static void omap_mcbsp_tx_dma_callback(int lch, u16 ch_status, void *data) { struct omap_mcbsp * mcbsp_dma_tx = (struct omap_mcbsp *)(data); @@ -176,7 +184,7 @@ static int omap_mcbsp_check(unsigned int id) return 0; } - if (cpu_is_omap1510() || cpu_is_omap16xx()) { + if (cpu_is_omap15xx() || cpu_is_omap16xx() || cpu_is_omap24xx()) { if (id > OMAP_MAX_MCBSP_COUNT) { printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1); return -1; @@ -187,9 +195,10 @@ static int omap_mcbsp_check(unsigned int id) return -1; } +#ifdef CONFIG_ARCH_OMAP1 static void omap_mcbsp_dsp_request(void) { - if (cpu_is_omap1510() || cpu_is_omap16xx()) { + if (cpu_is_omap15xx() || cpu_is_omap16xx()) { clk_enable(mcbsp_dsp_ck); clk_enable(mcbsp_api_ck); @@ -207,12 +216,49 @@ static void omap_mcbsp_dsp_request(void) static void omap_mcbsp_dsp_free(void) { - if (cpu_is_omap1510() || cpu_is_omap16xx()) { + if (cpu_is_omap15xx() || cpu_is_omap16xx()) { clk_disable(mcbsp_dspxor_ck); clk_disable(mcbsp_dsp_ck); clk_disable(mcbsp_api_ck); } } +#endif + +#ifdef CONFIG_ARCH_OMAP2 +static void omap2_mcbsp2_mux_setup(void) +{ + omap_cfg_reg(Y15_24XX_MCBSP2_CLKX); + omap_cfg_reg(R14_24XX_MCBSP2_FSX); + omap_cfg_reg(W15_24XX_MCBSP2_DR); + omap_cfg_reg(V15_24XX_MCBSP2_DX); + omap_cfg_reg(V14_24XX_GPIO117); + omap_cfg_reg(W14_24XX_SYS_CLKOUT); +} +#endif + +/* + * We can choose between IRQ based or polled IO. + * This needs to be called before omap_mcbsp_request(). + */ +int omap_mcbsp_set_io_type(unsigned int id, omap_mcbsp_io_type_t io_type) +{ + if (omap_mcbsp_check(id) < 0) + return -EINVAL; + + spin_lock(&mcbsp[id].lock); + + if (!mcbsp[id].free) { + printk (KERN_ERR "OMAP-McBSP: McBSP%d is currently in use\n", id + 1); + spin_unlock(&mcbsp[id].lock); + return -EINVAL; + } + + mcbsp[id].io_type = io_type; + + spin_unlock(&mcbsp[id].lock); + + return 0; +} int omap_mcbsp_request(unsigned int id) { @@ -221,12 +267,26 @@ int omap_mcbsp_request(unsigned int id) if (omap_mcbsp_check(id) < 0) return -EINVAL; +#ifdef CONFIG_ARCH_OMAP1 /* * On 1510, 1610 and 1710, McBSP1 and McBSP3 * are DSP public peripherals. */ if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3) omap_mcbsp_dsp_request(); +#endif + +#ifdef CONFIG_ARCH_OMAP2 + if (cpu_is_omap24xx()) { + if (id == OMAP_MCBSP1) { + clk_enable(mcbsp1_ick); + clk_enable(mcbsp1_fck); + } else { + clk_enable(mcbsp2_ick); + clk_enable(mcbsp2_fck); + } + } +#endif spin_lock(&mcbsp[id].lock); if (!mcbsp[id].free) { @@ -238,30 +298,33 @@ int omap_mcbsp_request(unsigned int id) mcbsp[id].free = 0; spin_unlock(&mcbsp[id].lock); - /* We need to get IRQs here */ - err = request_irq(mcbsp[id].tx_irq, omap_mcbsp_tx_irq_handler, 0, - "McBSP", - (void *) (&mcbsp[id])); - if (err != 0) { - printk(KERN_ERR "OMAP-McBSP: Unable to request TX IRQ %d for McBSP%d\n", - mcbsp[id].tx_irq, mcbsp[id].id); - return err; - } + if (mcbsp[id].io_type == OMAP_MCBSP_IRQ_IO) { + /* We need to get IRQs here */ + err = request_irq(mcbsp[id].tx_irq, omap_mcbsp_tx_irq_handler, 0, + "McBSP", + (void *) (&mcbsp[id])); + if (err != 0) { + printk(KERN_ERR "OMAP-McBSP: Unable to request TX IRQ %d for McBSP%d\n", + mcbsp[id].tx_irq, mcbsp[id].id); + return err; + } - init_completion(&(mcbsp[id].tx_irq_completion)); + init_completion(&(mcbsp[id].tx_irq_completion)); - err = request_irq(mcbsp[id].rx_irq, omap_mcbsp_rx_irq_handler, 0, - "McBSP", - (void *) (&mcbsp[id])); - if (err != 0) { - printk(KERN_ERR "OMAP-McBSP: Unable to request RX IRQ %d for McBSP%d\n", - mcbsp[id].rx_irq, mcbsp[id].id); - free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id])); - return err; + err = request_irq(mcbsp[id].rx_irq, omap_mcbsp_rx_irq_handler, 0, + "McBSP", + (void *) (&mcbsp[id])); + if (err != 0) { + printk(KERN_ERR "OMAP-McBSP: Unable to request RX IRQ %d for McBSP%d\n", + mcbsp[id].rx_irq, mcbsp[id].id); + free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id])); + return err; + } + + init_completion(&(mcbsp[id].rx_irq_completion)); } - init_completion(&(mcbsp[id].rx_irq_completion)); return 0; } @@ -271,8 +334,24 @@ void omap_mcbsp_free(unsigned int id) if (omap_mcbsp_check(id) < 0) return; - if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3) - omap_mcbsp_dsp_free(); +#ifdef CONFIG_ARCH_OMAP1 + if (cpu_class_is_omap1()) { + if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3) + omap_mcbsp_dsp_free(); + } +#endif + +#ifdef CONFIG_ARCH_OMAP2 + if (cpu_is_omap24xx()) { + if (id == OMAP_MCBSP1) { + clk_disable(mcbsp1_ick); + clk_disable(mcbsp1_fck); + } else { + clk_disable(mcbsp2_ick); + clk_disable(mcbsp2_fck); + } + } +#endif spin_lock(&mcbsp[id].lock); if (mcbsp[id].free) { @@ -284,9 +363,11 @@ void omap_mcbsp_free(unsigned int id) mcbsp[id].free = 1; spin_unlock(&mcbsp[id].lock); - /* Free IRQs */ - free_irq(mcbsp[id].rx_irq, (void *) (&mcbsp[id])); - free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id])); + if (mcbsp[id].io_type == OMAP_MCBSP_IRQ_IO) { + /* Free IRQs */ + free_irq(mcbsp[id].rx_irq, (void *) (&mcbsp[id])); + free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id])); + } } /* @@ -461,6 +542,115 @@ u32 omap_mcbsp_recv_word(unsigned int id) } +int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word) +{ + u32 io_base = mcbsp[id].io_base; + omap_mcbsp_word_length tx_word_length = mcbsp[id].tx_word_length; + omap_mcbsp_word_length rx_word_length = mcbsp[id].rx_word_length; + u16 spcr2, spcr1, attempts = 0, word_lsb, word_msb = 0; + + if (tx_word_length != rx_word_length) + return -EINVAL; + + /* First we wait for the transmitter to be ready */ + spcr2 = OMAP_MCBSP_READ(io_base, SPCR2); + while (!(spcr2 & XRDY)) { + spcr2 = OMAP_MCBSP_READ(io_base, SPCR2); + if (attempts++ > 1000) { + /* We must reset the transmitter */ + OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 & (~XRST)); + udelay(10); + OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 | XRST); + udelay(10); + printk("McBSP transmitter not ready\n"); + return -EAGAIN; + } + } + + /* Now we can push the data */ + if (tx_word_length > OMAP_MCBSP_WORD_16) + OMAP_MCBSP_WRITE(io_base, DXR2, word >> 16); + OMAP_MCBSP_WRITE(io_base, DXR1, word & 0xffff); + + /* We wait for the receiver to be ready */ + spcr1 = OMAP_MCBSP_READ(io_base, SPCR1); + while (!(spcr1 & RRDY)) { + spcr1 = OMAP_MCBSP_READ(io_base, SPCR1); + if (attempts++ > 1000) { + /* We must reset the receiver */ + OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 & (~RRST)); + udelay(10); + OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 | RRST); + udelay(10); + printk("McBSP receiver not ready\n"); + return -EAGAIN; + } + } + + /* Receiver is ready, let's read the dummy data */ + if (rx_word_length > OMAP_MCBSP_WORD_16) + word_msb = OMAP_MCBSP_READ(io_base, DRR2); + word_lsb = OMAP_MCBSP_READ(io_base, DRR1); + + return 0; +} + +int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 * word) +{ + u32 io_base = mcbsp[id].io_base, clock_word = 0; + omap_mcbsp_word_length tx_word_length = mcbsp[id].tx_word_length; + omap_mcbsp_word_length rx_word_length = mcbsp[id].rx_word_length; + u16 spcr2, spcr1, attempts = 0, word_lsb, word_msb = 0; + + if (tx_word_length != rx_word_length) + return -EINVAL; + + /* First we wait for the transmitter to be ready */ + spcr2 = OMAP_MCBSP_READ(io_base, SPCR2); + while (!(spcr2 & XRDY)) { + spcr2 = OMAP_MCBSP_READ(io_base, SPCR2); + if (attempts++ > 1000) { + /* We must reset the transmitter */ + OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 & (~XRST)); + udelay(10); + OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 | XRST); + udelay(10); + printk("McBSP transmitter not ready\n"); + return -EAGAIN; + } + } + + /* We first need to enable the bus clock */ + if (tx_word_length > OMAP_MCBSP_WORD_16) + OMAP_MCBSP_WRITE(io_base, DXR2, clock_word >> 16); + OMAP_MCBSP_WRITE(io_base, DXR1, clock_word & 0xffff); + + /* We wait for the receiver to be ready */ + spcr1 = OMAP_MCBSP_READ(io_base, SPCR1); + while (!(spcr1 & RRDY)) { + spcr1 = OMAP_MCBSP_READ(io_base, SPCR1); + if (attempts++ > 1000) { + /* We must reset the receiver */ + OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 & (~RRST)); + udelay(10); + OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 | RRST); + udelay(10); + printk("McBSP receiver not ready\n"); + return -EAGAIN; + } + } + + /* Receiver is ready, there is something for us */ + if (rx_word_length > OMAP_MCBSP_WORD_16) + word_msb = OMAP_MCBSP_READ(io_base, DRR2); + word_lsb = OMAP_MCBSP_READ(io_base, DRR1); + + word[0] = (word_lsb | (word_msb << 16)); + + return 0; +} + + /* * Simple DMA based buffer rx/tx routines. * Nothing fancy, just a single buffer tx/rx through DMA. @@ -471,6 +661,9 @@ u32 omap_mcbsp_recv_word(unsigned int id) int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, unsigned int length) { int dma_tx_ch; + int src_port = 0; + int dest_port = 0; + int sync_dev = 0; if (omap_mcbsp_check(id) < 0) return -EINVAL; @@ -487,20 +680,27 @@ int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, unsigned int leng init_completion(&(mcbsp[id].tx_dma_completion)); + if (cpu_class_is_omap1()) { + src_port = OMAP_DMA_PORT_TIPB; + dest_port = OMAP_DMA_PORT_EMIFF; + } + if (cpu_is_omap24xx()) + sync_dev = mcbsp[id].dma_tx_sync; + omap_set_dma_transfer_params(mcbsp[id].dma_tx_lch, OMAP_DMA_DATA_TYPE_S16, length >> 1, 1, OMAP_DMA_SYNC_ELEMENT, - 0, 0); + sync_dev, 0); omap_set_dma_dest_params(mcbsp[id].dma_tx_lch, - OMAP_DMA_PORT_TIPB, + src_port, OMAP_DMA_AMODE_CONSTANT, mcbsp[id].io_base + OMAP_MCBSP_REG_DXR1, 0, 0); omap_set_dma_src_params(mcbsp[id].dma_tx_lch, - OMAP_DMA_PORT_EMIFF, + dest_port, OMAP_DMA_AMODE_POST_INC, buffer, 0, 0); @@ -514,6 +714,9 @@ int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, unsigned int leng int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer, unsigned int length) { int dma_rx_ch; + int src_port = 0; + int dest_port = 0; + int sync_dev = 0; if (omap_mcbsp_check(id) < 0) return -EINVAL; @@ -530,20 +733,27 @@ int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer, unsigned int leng init_completion(&(mcbsp[id].rx_dma_completion)); + if (cpu_class_is_omap1()) { + src_port = OMAP_DMA_PORT_TIPB; + dest_port = OMAP_DMA_PORT_EMIFF; + } + if (cpu_is_omap24xx()) + sync_dev = mcbsp[id].dma_rx_sync; + omap_set_dma_transfer_params(mcbsp[id].dma_rx_lch, OMAP_DMA_DATA_TYPE_S16, length >> 1, 1, OMAP_DMA_SYNC_ELEMENT, - 0, 0); + sync_dev, 0); omap_set_dma_src_params(mcbsp[id].dma_rx_lch, - OMAP_DMA_PORT_TIPB, + src_port, OMAP_DMA_AMODE_CONSTANT, mcbsp[id].io_base + OMAP_MCBSP_REG_DRR1, 0, 0); omap_set_dma_dest_params(mcbsp[id].dma_rx_lch, - OMAP_DMA_PORT_EMIFF, + dest_port, OMAP_DMA_AMODE_POST_INC, buffer, 0, 0); @@ -688,6 +898,23 @@ static const struct omap_mcbsp_info mcbsp_1610[] = { }; #endif +#if defined(CONFIG_ARCH_OMAP24XX) +static const struct omap_mcbsp_info mcbsp_24xx[] = { + [0] = { .virt_base = IO_ADDRESS(OMAP24XX_MCBSP1_BASE), + .dma_rx_sync = OMAP24XX_DMA_MCBSP1_RX, + .dma_tx_sync = OMAP24XX_DMA_MCBSP1_TX, + .rx_irq = INT_24XX_MCBSP1_IRQ_RX, + .tx_irq = INT_24XX_MCBSP1_IRQ_TX, + }, + [1] = { .virt_base = IO_ADDRESS(OMAP24XX_MCBSP2_BASE), + .dma_rx_sync = OMAP24XX_DMA_MCBSP2_RX, + .dma_tx_sync = OMAP24XX_DMA_MCBSP2_TX, + .rx_irq = INT_24XX_MCBSP2_IRQ_RX, + .tx_irq = INT_24XX_MCBSP2_IRQ_TX, + }, +}; +#endif + static int __init omap_mcbsp_init(void) { int mcbsp_count = 0, i; @@ -695,6 +922,7 @@ static int __init omap_mcbsp_init(void) printk("Initializing OMAP McBSP system\n"); +#ifdef CONFIG_ARCH_OMAP1 mcbsp_dsp_ck = clk_get(0, "dsp_ck"); if (IS_ERR(mcbsp_dsp_ck)) { printk(KERN_ERR "mcbsp: could not acquire dsp_ck handle.\n"); @@ -710,6 +938,29 @@ static int __init omap_mcbsp_init(void) printk(KERN_ERR "mcbsp: could not acquire dspxor_ck handle.\n"); return PTR_ERR(mcbsp_dspxor_ck); } +#endif +#ifdef CONFIG_ARCH_OMAP2 + mcbsp1_ick = clk_get(0, "mcbsp1_ick"); + if (IS_ERR(mcbsp1_ick)) { + printk(KERN_ERR "mcbsp: could not acquire mcbsp1_ick handle.\n"); + return PTR_ERR(mcbsp1_ick); + } + mcbsp1_fck = clk_get(0, "mcbsp1_fck"); + if (IS_ERR(mcbsp1_fck)) { + printk(KERN_ERR "mcbsp: could not acquire mcbsp1_fck handle.\n"); + return PTR_ERR(mcbsp1_fck); + } + mcbsp2_ick = clk_get(0, "mcbsp2_ick"); + if (IS_ERR(mcbsp2_ick)) { + printk(KERN_ERR "mcbsp: could not acquire mcbsp2_ick handle.\n"); + return PTR_ERR(mcbsp2_ick); + } + mcbsp2_fck = clk_get(0, "mcbsp2_fck"); + if (IS_ERR(mcbsp2_fck)) { + printk(KERN_ERR "mcbsp: could not acquire mcbsp2_fck handle.\n"); + return PTR_ERR(mcbsp2_fck); + } +#endif #ifdef CONFIG_ARCH_OMAP730 if (cpu_is_omap730()) { @@ -718,7 +969,7 @@ static int __init omap_mcbsp_init(void) } #endif #ifdef CONFIG_ARCH_OMAP15XX - if (cpu_is_omap1510()) { + if (cpu_is_omap15xx()) { mcbsp_info = mcbsp_1510; mcbsp_count = ARRAY_SIZE(mcbsp_1510); } @@ -729,6 +980,19 @@ static int __init omap_mcbsp_init(void) mcbsp_count = ARRAY_SIZE(mcbsp_1610); } #endif +#if defined(CONFIG_ARCH_OMAP24XX) + if (cpu_is_omap24xx()) { + mcbsp_info = mcbsp_24xx; + mcbsp_count = ARRAY_SIZE(mcbsp_24xx); + + /* REVISIT: where's the right place? */ + omap2_mcbsp2_mux_setup(); + sys_ck = clk_get(0, "sys_ck"); + sys_clkout = clk_get(0, "sys_clkout"); + clk_set_parent(sys_clkout, sys_ck); + clk_enable(sys_clkout); + } +#endif for (i = 0; i < OMAP_MAX_MCBSP_COUNT ; i++) { if (i >= mcbsp_count) { mcbsp[i].io_base = 0; @@ -741,6 +1005,7 @@ static int __init omap_mcbsp_init(void) mcbsp[i].dma_rx_lch = -1; mcbsp[i].io_base = mcbsp_info[i].virt_base; + mcbsp[i].io_type = OMAP_MCBSP_IRQ_IO; /* Default I/O is IRQ based */ mcbsp[i].tx_irq = mcbsp_info[i].tx_irq; mcbsp[i].rx_irq = mcbsp_info[i].rx_irq; mcbsp[i].dma_rx_sync = mcbsp_info[i].dma_rx_sync; @@ -751,11 +1016,11 @@ static int __init omap_mcbsp_init(void) return 0; } - arch_initcall(omap_mcbsp_init); EXPORT_SYMBOL(omap_mcbsp_config); EXPORT_SYMBOL(omap_mcbsp_request); +EXPORT_SYMBOL(omap_mcbsp_set_io_type); EXPORT_SYMBOL(omap_mcbsp_free); EXPORT_SYMBOL(omap_mcbsp_start); EXPORT_SYMBOL(omap_mcbsp_stop); @@ -763,4 +1028,6 @@ EXPORT_SYMBOL(omap_mcbsp_xmit_word); EXPORT_SYMBOL(omap_mcbsp_recv_word); EXPORT_SYMBOL(omap_mcbsp_xmit_buffer); EXPORT_SYMBOL(omap_mcbsp_recv_buffer); +EXPORT_SYMBOL(omap_mcbsp_spi_master_xmit_word_poll); +EXPORT_SYMBOL(omap_mcbsp_spi_master_recv_word_poll); EXPORT_SYMBOL(omap_mcbsp_set_spi_mode); diff --git a/arch/arm/plat-omap/ocpi.c b/arch/arm/plat-omap/ocpi.c index 5cc6775c789..37792d43738 100644 --- a/arch/arm/plat-omap/ocpi.c +++ b/arch/arm/plat-omap/ocpi.c @@ -62,9 +62,6 @@ int ocpi_enable(void) if (!cpu_is_omap16xx()) return -ENODEV; - /* Make sure there's clock for OCPI */ - clk_enable(ocpi_ck); - /* Enable access for OHCI in OCPI */ val = omap_readl(OCPI_PROT); val &= ~0xff; diff --git a/arch/arm/plat-omap/pm.c b/arch/arm/plat-omap/pm.c index 093efd786f2..1a24e2c1071 100644 --- a/arch/arm/plat-omap/pm.c +++ b/arch/arm/plat-omap/pm.c @@ -38,6 +38,7 @@ #include <linux/pm.h> #include <linux/sched.h> #include <linux/proc_fs.h> +#include <linux/pm.h> #include <linux/interrupt.h> #include <asm/io.h> diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c index ee82763b02b..b7bf09b1b41 100644 --- a/arch/arm/plat-omap/sram.c +++ b/arch/arm/plat-omap/sram.c @@ -16,24 +16,94 @@ #include <linux/kernel.h> #include <linux/init.h> -#include <asm/mach/map.h> #include <asm/tlb.h> #include <asm/io.h> #include <asm/cacheflush.h> +#include <asm/mach/map.h> + #include <asm/arch/sram.h> +#include <asm/arch/board.h> #define OMAP1_SRAM_PA 0x20000000 #define OMAP1_SRAM_VA 0xd0000000 #define OMAP2_SRAM_PA 0x40200000 +#define OMAP2_SRAM_PUB_PA 0x4020f800 #define OMAP2_SRAM_VA 0xd0000000 +#define OMAP2_SRAM_PUB_VA 0xd0000800 +#if defined(CONFIG_ARCH_OMAP24XX) +#define SRAM_BOOTLOADER_SZ 0x00 +#else #define SRAM_BOOTLOADER_SZ 0x80 +#endif + +#define VA_REQINFOPERM0 IO_ADDRESS(0x68005048) +#define VA_READPERM0 IO_ADDRESS(0x68005050) +#define VA_WRITEPERM0 IO_ADDRESS(0x68005058) +#define VA_CONTROL_STAT IO_ADDRESS(0x480002F8) +#define GP_DEVICE 0x300 +#define TYPE_MASK 0x700 + +#define ROUND_DOWN(value,boundary) ((value) & (~((boundary)-1))) static unsigned long omap_sram_base; static unsigned long omap_sram_size; static unsigned long omap_sram_ceil; +unsigned long omap_fb_sram_start; +unsigned long omap_fb_sram_size; + +/* Depending on the target RAMFS firewall setup, the public usable amount of + * SRAM varies. The default accessable size for all device types is 2k. A GP + * device allows ARM11 but not other initators for full size. This + * functionality seems ok until some nice security API happens. + */ +static int is_sram_locked(void) +{ + int type = 0; + + if (cpu_is_omap242x()) + type = __raw_readl(VA_CONTROL_STAT) & TYPE_MASK; + + if (type == GP_DEVICE) { + /* RAMFW: R/W access to all initators for all qualifier sets */ + if (cpu_is_omap242x()) { + __raw_writel(0xFF, VA_REQINFOPERM0); /* all q-vects */ + __raw_writel(0xCFDE, VA_READPERM0); /* all i-read */ + __raw_writel(0xCFDE, VA_WRITEPERM0); /* all i-write */ + } + return 0; + } else + return 1; /* assume locked with no PPA or security driver */ +} + +void get_fb_sram_conf(unsigned long start_avail, unsigned size_avail, + unsigned long *start, unsigned long *size) +{ + const struct omap_fbmem_config *fbmem_conf; + + fbmem_conf = omap_get_config(OMAP_TAG_FBMEM, struct omap_fbmem_config); + if (fbmem_conf != NULL) { + *start = fbmem_conf->fb_sram_start; + *size = fbmem_conf->fb_sram_size; + } else { + *size = 0; + *start = 0; + } + + if (*size && ( + *start < start_avail || + *start + *size > start_avail + size_avail)) { + printk(KERN_ERR "invalid FB SRAM configuration\n"); + *start = start_avail; + *size = size_avail; + } + + if (*size) + pr_info("Reserving %lu bytes SRAM for frame buffer\n", *size); +} + /* * The amount of SRAM depends on the core type. * Note that we cannot try to test for SRAM here because writes @@ -42,26 +112,45 @@ static unsigned long omap_sram_ceil; */ void __init omap_detect_sram(void) { - if (!cpu_is_omap24xx()) + unsigned long sram_start; + + if (cpu_is_omap24xx()) { + if (is_sram_locked()) { + omap_sram_base = OMAP2_SRAM_PUB_VA; + sram_start = OMAP2_SRAM_PUB_PA; + omap_sram_size = 0x800; /* 2K */ + } else { + omap_sram_base = OMAP2_SRAM_VA; + sram_start = OMAP2_SRAM_PA; + if (cpu_is_omap242x()) + omap_sram_size = 0xa0000; /* 640K */ + else if (cpu_is_omap243x()) + omap_sram_size = 0x10000; /* 64K */ + } + } else { omap_sram_base = OMAP1_SRAM_VA; - else - omap_sram_base = OMAP2_SRAM_VA; - - if (cpu_is_omap730()) - omap_sram_size = 0x32000; /* 200K */ - else if (cpu_is_omap15xx()) - omap_sram_size = 0x30000; /* 192K */ - else if (cpu_is_omap1610() || cpu_is_omap1621() || cpu_is_omap1710()) - omap_sram_size = 0x4000; /* 16K */ - else if (cpu_is_omap1611()) - omap_sram_size = 0x3e800; /* 250K */ - else if (cpu_is_omap2420()) - omap_sram_size = 0xa0014; /* 640K */ - else { - printk(KERN_ERR "Could not detect SRAM size\n"); - omap_sram_size = 0x4000; + sram_start = OMAP1_SRAM_PA; + + if (cpu_is_omap730()) + omap_sram_size = 0x32000; /* 200K */ + else if (cpu_is_omap15xx()) + omap_sram_size = 0x30000; /* 192K */ + else if (cpu_is_omap1610() || cpu_is_omap1621() || + cpu_is_omap1710()) + omap_sram_size = 0x4000; /* 16K */ + else if (cpu_is_omap1611()) + omap_sram_size = 0x3e800; /* 250K */ + else { + printk(KERN_ERR "Could not detect SRAM size\n"); + omap_sram_size = 0x4000; + } } - + get_fb_sram_conf(sram_start + SRAM_BOOTLOADER_SZ, + omap_sram_size - SRAM_BOOTLOADER_SZ, + &omap_fb_sram_start, &omap_fb_sram_size); + if (omap_fb_sram_size) + omap_sram_size -= sram_start + omap_sram_size - + omap_fb_sram_start; omap_sram_ceil = omap_sram_base + omap_sram_size; } @@ -80,12 +169,20 @@ static struct map_desc omap_sram_io_desc[] __initdata = { */ void __init omap_map_sram(void) { + unsigned long base; + if (omap_sram_size == 0) return; if (cpu_is_omap24xx()) { omap_sram_io_desc[0].virtual = OMAP2_SRAM_VA; - omap_sram_io_desc[0].pfn = __phys_to_pfn(OMAP2_SRAM_PA); + + if (is_sram_locked()) + base = OMAP2_SRAM_PUB_PA; + else + base = OMAP2_SRAM_PA; + base = ROUND_DOWN(base, PAGE_SIZE); + omap_sram_io_desc[0].pfn = __phys_to_pfn(base); } omap_sram_io_desc[0].length = (omap_sram_size + PAGE_SIZE-1)/PAGE_SIZE; @@ -93,7 +190,8 @@ void __init omap_map_sram(void) iotable_init(omap_sram_io_desc, ARRAY_SIZE(omap_sram_io_desc)); printk(KERN_INFO "SRAM: Mapped pa 0x%08lx to va 0x%08lx size: 0x%lx\n", - omap_sram_io_desc[0].pfn, omap_sram_io_desc[0].virtual, + __pfn_to_phys(omap_sram_io_desc[0].pfn), + omap_sram_io_desc[0].virtual, omap_sram_io_desc[0].length); /* @@ -118,8 +216,9 @@ void * omap_sram_push(void * start, unsigned long size) printk(KERN_ERR "Not enough space in SRAM\n"); return NULL; } + omap_sram_ceil -= size; - omap_sram_ceil &= ~0x3; + omap_sram_ceil = ROUND_DOWN(omap_sram_ceil, sizeof(void *)); memcpy((void *)omap_sram_ceil, start, size); return (void *)omap_sram_ceil; diff --git a/arch/arm/plat-omap/timer32k.c b/arch/arm/plat-omap/timer32k.c new file mode 100644 index 00000000000..b2a943bf11e --- /dev/null +++ b/arch/arm/plat-omap/timer32k.c @@ -0,0 +1,325 @@ +/* + * linux/arch/arm/plat-omap/timer32k.c + * + * OMAP 32K Timer + * + * Copyright (C) 2004 - 2005 Nokia Corporation + * Partial timer rewrite and additional dynamic tick timer support by + * Tony Lindgen <tony@atomide.com> and + * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> + * + * MPU timer code based on the older MPU timer code for OMAP + * Copyright (C) 2000 RidgeRun, Inc. + * Author: Greg Lonnon <glonnon@ridgerun.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/sched.h> +#include <linux/spinlock.h> +#include <linux/err.h> +#include <linux/clk.h> + +#include <asm/system.h> +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/leds.h> +#include <asm/irq.h> +#include <asm/mach/irq.h> +#include <asm/mach/time.h> + +struct sys_timer omap_timer; + +/* + * --------------------------------------------------------------------------- + * 32KHz OS timer + * + * This currently works only on 16xx, as 1510 does not have the continuous + * 32KHz synchronous timer. The 32KHz synchronous timer is used to keep track + * of time in addition to the 32KHz OS timer. Using only the 32KHz OS timer + * on 1510 would be possible, but the timer would not be as accurate as + * with the 32KHz synchronized timer. + * --------------------------------------------------------------------------- + */ + +#if defined(CONFIG_ARCH_OMAP16XX) +#define TIMER_32K_SYNCHRONIZED 0xfffbc410 +#elif defined(CONFIG_ARCH_OMAP24XX) +#define TIMER_32K_SYNCHRONIZED 0x48004010 +#else +#error OMAP 32KHz timer does not currently work on 15XX! +#endif + +/* 16xx specific defines */ +#define OMAP1_32K_TIMER_BASE 0xfffb9000 +#define OMAP1_32K_TIMER_CR 0x08 +#define OMAP1_32K_TIMER_TVR 0x00 +#define OMAP1_32K_TIMER_TCR 0x04 + +/* 24xx specific defines */ +#define OMAP2_GP_TIMER_BASE 0x48028000 +#define CM_CLKSEL_WKUP 0x48008440 +#define GP_TIMER_TIDR 0x00 +#define GP_TIMER_TISR 0x18 +#define GP_TIMER_TIER 0x1c +#define GP_TIMER_TCLR 0x24 +#define GP_TIMER_TCRR 0x28 +#define GP_TIMER_TLDR 0x2c +#define GP_TIMER_TTGR 0x30 +#define GP_TIMER_TSICR 0x40 + +#define OMAP_32K_TICKS_PER_HZ (32768 / HZ) + +/* + * TRM says 1 / HZ = ( TVR + 1) / 32768, so TRV = (32768 / HZ) - 1 + * so with HZ = 128, TVR = 255. + */ +#define OMAP_32K_TIMER_TICK_PERIOD ((32768 / HZ) - 1) + +#define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate) \ + (((nr_jiffies) * (clock_rate)) / HZ) + +static inline void omap_32k_timer_write(int val, int reg) +{ + if (cpu_class_is_omap1()) + omap_writew(val, OMAP1_32K_TIMER_BASE + reg); + + if (cpu_is_omap24xx()) + omap_writel(val, OMAP2_GP_TIMER_BASE + reg); +} + +static inline unsigned long omap_32k_timer_read(int reg) +{ + if (cpu_class_is_omap1()) + return omap_readl(OMAP1_32K_TIMER_BASE + reg) & 0xffffff; + + if (cpu_is_omap24xx()) + return omap_readl(OMAP2_GP_TIMER_BASE + reg); +} + +/* + * The 32KHz synchronized timer is an additional timer on 16xx. + * It is always running. + */ +static inline unsigned long omap_32k_sync_timer_read(void) +{ + return omap_readl(TIMER_32K_SYNCHRONIZED); +} + +static inline void omap_32k_timer_start(unsigned long load_val) +{ + if (cpu_class_is_omap1()) { + omap_32k_timer_write(load_val, OMAP1_32K_TIMER_TVR); + omap_32k_timer_write(0x0f, OMAP1_32K_TIMER_CR); + } + + if (cpu_is_omap24xx()) { + omap_32k_timer_write(0xffffffff - load_val, GP_TIMER_TCRR); + omap_32k_timer_write((1 << 1), GP_TIMER_TIER); + omap_32k_timer_write((1 << 1) | 1, GP_TIMER_TCLR); + } +} + +static inline void omap_32k_timer_stop(void) +{ + if (cpu_class_is_omap1()) + omap_32k_timer_write(0x0, OMAP1_32K_TIMER_CR); + + if (cpu_is_omap24xx()) + omap_32k_timer_write(0x0, GP_TIMER_TCLR); +} + +/* + * Rounds down to nearest usec. Note that this will overflow for larger values. + */ +static inline unsigned long omap_32k_ticks_to_usecs(unsigned long ticks_32k) +{ + return (ticks_32k * 5*5*5*5*5*5) >> 9; +} + +/* + * Rounds down to nearest nsec. + */ +static inline unsigned long long +omap_32k_ticks_to_nsecs(unsigned long ticks_32k) +{ + return (unsigned long long) ticks_32k * 1000 * 5*5*5*5*5*5 >> 9; +} + +static unsigned long omap_32k_last_tick = 0; + +/* + * Returns elapsed usecs since last 32k timer interrupt + */ +static unsigned long omap_32k_timer_gettimeoffset(void) +{ + unsigned long now = omap_32k_sync_timer_read(); + return omap_32k_ticks_to_usecs(now - omap_32k_last_tick); +} + +/* + * Returns current time from boot in nsecs. It's OK for this to wrap + * around for now, as it's just a relative time stamp. + */ +unsigned long long sched_clock(void) +{ + return omap_32k_ticks_to_nsecs(omap_32k_sync_timer_read()); +} + +/* + * Timer interrupt for 32KHz timer. When dynamic tick is enabled, this + * function is also called from other interrupts to remove latency + * issues with dynamic tick. In the dynamic tick case, we need to lock + * with irqsave. + */ +static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +{ + unsigned long flags; + unsigned long now; + + write_seqlock_irqsave(&xtime_lock, flags); + + if (cpu_is_omap24xx()) { + u32 status = omap_32k_timer_read(GP_TIMER_TISR); + omap_32k_timer_write(status, GP_TIMER_TISR); + } + + now = omap_32k_sync_timer_read(); + + while (now - omap_32k_last_tick >= OMAP_32K_TICKS_PER_HZ) { + omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ; + timer_tick(regs); + } + + /* Restart timer so we don't drift off due to modulo or dynamic tick. + * By default we program the next timer to be continuous to avoid + * latencies during high system load. During dynamic tick operation the + * continuous timer can be overridden from pm_idle to be longer. + */ + omap_32k_timer_start(omap_32k_last_tick + OMAP_32K_TICKS_PER_HZ - now); + write_sequnlock_irqrestore(&xtime_lock, flags); + + return IRQ_HANDLED; +} + +#ifdef CONFIG_NO_IDLE_HZ +/* + * Programs the next timer interrupt needed. Called when dynamic tick is + * enabled, and to reprogram the ticks to skip from pm_idle. Note that + * we can keep the timer continuous, and don't need to set it to run in + * one-shot mode. This is because the timer will get reprogrammed again + * after next interrupt. + */ +void omap_32k_timer_reprogram(unsigned long next_tick) +{ + omap_32k_timer_start(JIFFIES_TO_HW_TICKS(next_tick, 32768) + 1); +} + +static struct irqaction omap_32k_timer_irq; +extern struct timer_update_handler timer_update; + +static int omap_32k_timer_enable_dyn_tick(void) +{ + /* No need to reprogram timer, just use the next interrupt */ + return 0; +} + +static int omap_32k_timer_disable_dyn_tick(void) +{ + omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD); + return 0; +} + +static struct dyn_tick_timer omap_dyn_tick_timer = { + .enable = omap_32k_timer_enable_dyn_tick, + .disable = omap_32k_timer_disable_dyn_tick, + .reprogram = omap_32k_timer_reprogram, + .handler = omap_32k_timer_interrupt, +}; +#endif /* CONFIG_NO_IDLE_HZ */ + +static struct irqaction omap_32k_timer_irq = { + .name = "32KHz timer", + .flags = SA_INTERRUPT | SA_TIMER, + .handler = omap_32k_timer_interrupt, +}; + +static struct clk * gpt1_ick; +static struct clk * gpt1_fck; + +static __init void omap_init_32k_timer(void) +{ +#ifdef CONFIG_NO_IDLE_HZ + omap_timer.dyn_tick = &omap_dyn_tick_timer; +#endif + + if (cpu_class_is_omap1()) + setup_irq(INT_OS_TIMER, &omap_32k_timer_irq); + if (cpu_is_omap24xx()) + setup_irq(37, &omap_32k_timer_irq); + omap_timer.offset = omap_32k_timer_gettimeoffset; + omap_32k_last_tick = omap_32k_sync_timer_read(); + + /* REVISIT: Check 24xx TIOCP_CFG settings after idle works */ + if (cpu_is_omap24xx()) { + omap_32k_timer_write(0, GP_TIMER_TCLR); + omap_writel(0, CM_CLKSEL_WKUP); /* 32KHz clock source */ + + gpt1_ick = clk_get(NULL, "gpt1_ick"); + if (IS_ERR(gpt1_ick)) + printk(KERN_ERR "Could not get gpt1_ick\n"); + else + clk_enable(gpt1_ick); + + gpt1_fck = clk_get(NULL, "gpt1_fck"); + if (IS_ERR(gpt1_fck)) + printk(KERN_ERR "Could not get gpt1_fck\n"); + else + clk_enable(gpt1_fck); + + mdelay(100); /* Wait for clocks to stabilize */ + + omap_32k_timer_write(0x7, GP_TIMER_TISR); + } + + omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD); +} + +/* + * --------------------------------------------------------------------------- + * Timer initialization + * --------------------------------------------------------------------------- + */ +static void __init omap_timer_init(void) +{ + omap_init_32k_timer(); +} + +struct sys_timer omap_timer = { + .init = omap_timer_init, + .offset = NULL, /* Initialized later */ +}; diff --git a/arch/arm26/kernel/armksyms.c b/arch/arm26/kernel/armksyms.c index 811a6376c62..a6a1b337344 100644 --- a/arch/arm26/kernel/armksyms.c +++ b/arch/arm26/kernel/armksyms.c @@ -212,8 +212,6 @@ EXPORT_SYMBOL(sys_open); EXPORT_SYMBOL(sys_exit); EXPORT_SYMBOL(sys_wait4); -EXPORT_SYMBOL(get_wchan); - #ifdef CONFIG_PREEMPT EXPORT_SYMBOL(kernel_flag); #endif diff --git a/arch/frv/kernel/frv_ksyms.c b/arch/frv/kernel/frv_ksyms.c index aa6b7d0a210..07c8ffa0dd3 100644 --- a/arch/frv/kernel/frv_ksyms.c +++ b/arch/frv/kernel/frv_ksyms.c @@ -79,8 +79,6 @@ EXPORT_SYMBOL(memmove); EXPORT_SYMBOL(__outsl_ns); EXPORT_SYMBOL(__insl_ns); -EXPORT_SYMBOL(get_wchan); - #ifdef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS EXPORT_SYMBOL(atomic_test_and_ANDNOT_mask); EXPORT_SYMBOL(atomic_test_and_OR_mask); diff --git a/arch/h8300/kernel/h8300_ksyms.c b/arch/h8300/kernel/h8300_ksyms.c index 69d6ad32d56..b6cd78c972b 100644 --- a/arch/h8300/kernel/h8300_ksyms.c +++ b/arch/h8300/kernel/h8300_ksyms.c @@ -55,8 +55,6 @@ EXPORT_SYMBOL(memcmp); EXPORT_SYMBOL(memscan); EXPORT_SYMBOL(memmove); -EXPORT_SYMBOL(get_wchan); - /* * libgcc functions - functions that are used internally by the * compiler... (prototypes are not correct though, but that diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index eb5279d23b7..6273bf74c20 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c @@ -415,6 +415,7 @@ void __init init_bsp_APIC(void) void __devinit setup_local_APIC(void) { unsigned long oldvalue, value, ver, maxlvt; + int i, j; /* Pound the ESR really hard over the head with a big hammer - mbligh */ if (esr_disable) { @@ -452,6 +453,25 @@ void __devinit setup_local_APIC(void) apic_write_around(APIC_TASKPRI, value); /* + * After a crash, we no longer service the interrupts and a pending + * interrupt from previous kernel might still have ISR bit set. + * + * Most probably by now CPU has serviced that pending interrupt and + * it might not have done the ack_APIC_irq() because it thought, + * interrupt came from i8259 as ExtInt. LAPIC did not get EOI so it + * does not clear the ISR bit and cpu thinks it has already serivced + * the interrupt. Hence a vector might get locked. It was noticed + * for timer irq (vector 0x31). Issue an extra EOI to clear ISR. + */ + for (i = APIC_ISR_NR - 1; i >= 0; i--) { + value = apic_read(APIC_ISR + i*0x10); + for (j = 31; j >= 0; j--) { + if (value & (1<<j)) + ack_APIC_irq(); + } + } + + /* * Now that we are all set up, enable the APIC */ value = apic_read(APIC_SPIV); @@ -732,7 +752,7 @@ static int __init apic_set_verbosity(char *str) printk(KERN_WARNING "APIC Verbosity level %s not recognised" " use apic=verbose or apic=debug\n", str); - return 0; + return 1; } __setup("apic=", apic_set_verbosity); diff --git a/arch/i386/kernel/cpu/mcheck/mce.c b/arch/i386/kernel/cpu/mcheck/mce.c index 6170af3c271..afa0888f9a1 100644 --- a/arch/i386/kernel/cpu/mcheck/mce.c +++ b/arch/i386/kernel/cpu/mcheck/mce.c @@ -64,13 +64,13 @@ void mcheck_init(struct cpuinfo_x86 *c) static int __init mcheck_disable(char *str) { mce_disabled = 1; - return 0; + return 1; } static int __init mcheck_enable(char *str) { mce_disabled = -1; - return 0; + return 1; } __setup("nomce", mcheck_disable); diff --git a/arch/i386/kernel/crash.c b/arch/i386/kernel/crash.c index e3c5fca0aa8..2b0cfce24a6 100644 --- a/arch/i386/kernel/crash.c +++ b/arch/i386/kernel/crash.c @@ -69,7 +69,7 @@ static void crash_save_this_cpu(struct pt_regs *regs, int cpu) * for the data I pass, and I need tags * on the data to indicate what information I have * squirrelled away. ELF notes happen to provide - * all of that that no need to invent something new. + * all of that, so there is no need to invent something new. */ buf = (u32*)per_cpu_ptr(crash_notes, cpu); if (!buf) diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 3b329af4afc..f8f132aa547 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -644,7 +644,7 @@ failed: int __init irqbalance_disable(char *str) { irqbalance_disabled = 1; - return 0; + return 1; } __setup("noirqbalance", irqbalance_disable); diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index 24b3e745478..6259afea46d 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -781,7 +781,6 @@ unsigned long get_wchan(struct task_struct *p) } while (count++ < 16); return 0; } -EXPORT_SYMBOL(get_wchan); /* * sys_alloc_thread_area: get a yet unused TLS descriptor index. diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index 8c08660b4e5..eacc3f0a2ea 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -34,6 +34,7 @@ #include <linux/initrd.h> #include <linux/bootmem.h> #include <linux/seq_file.h> +#include <linux/platform_device.h> #include <linux/console.h> #include <linux/mca.h> #include <linux/root_dev.h> @@ -1547,6 +1548,23 @@ void __init setup_arch(char **cmdline_p) #endif } +static __init int add_pcspkr(void) +{ + struct platform_device *pd; + int ret; + + pd = platform_device_alloc("pcspkr", -1); + if (!pd) + return -ENOMEM; + + ret = platform_device_add(pd); + if (ret) + platform_device_put(pd); + + return ret; +} +device_initcall(add_pcspkr); + #include "setup_arch_post.h" /* * Local Variables: diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S index ce3ef4fa055..4f58b9c0efe 100644 --- a/arch/i386/kernel/syscall_table.S +++ b/arch/i386/kernel/syscall_table.S @@ -313,3 +313,4 @@ ENTRY(sys_call_table) .long sys_set_robust_list .long sys_get_robust_list .long sys_splice + .long sys_sync_file_range diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 6b63a5aa1e4..e3852799459 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -1193,6 +1193,6 @@ void __init trap_init(void) static int __init kstack_setup(char *s) { kstack_depth_to_print = simple_strtoul(s, NULL, 0); - return 0; + return 1; } __setup("kstack=", kstack_setup); diff --git a/arch/i386/kernel/vsyscall-sigreturn.S b/arch/i386/kernel/vsyscall-sigreturn.S index fadb5bc3c37..a92262f4165 100644 --- a/arch/i386/kernel/vsyscall-sigreturn.S +++ b/arch/i386/kernel/vsyscall-sigreturn.S @@ -44,7 +44,7 @@ __kernel_rt_sigreturn: .LSTARTCIEDLSI1: .long 0 /* CIE ID */ .byte 1 /* Version number */ - .string "zR" /* NUL-terminated augmentation string */ + .string "zRS" /* NUL-terminated augmentation string */ .uleb128 1 /* Code alignment factor */ .sleb128 -4 /* Data alignment factor */ .byte 8 /* Return address register column */ diff --git a/arch/ia64/kernel/palinfo.c b/arch/ia64/kernel/palinfo.c index 89faa603c6b..6386f63c413 100644 --- a/arch/ia64/kernel/palinfo.c +++ b/arch/ia64/kernel/palinfo.c @@ -240,7 +240,7 @@ cache_info(char *page) } p += sprintf(p, "%s Cache level %lu:\n" - "\tSize : %lu bytes\n" + "\tSize : %u bytes\n" "\tAttributes : ", cache_types[j+cci.pcci_unified], i+1, cci.pcci_cache_size); @@ -648,9 +648,9 @@ frequency_info(char *page) if (ia64_pal_freq_ratios(&proc, &bus, &itc) != 0) return 0; p += sprintf(p, - "Processor/Clock ratio : %ld/%ld\n" - "Bus/Clock ratio : %ld/%ld\n" - "ITC/Clock ratio : %ld/%ld\n", + "Processor/Clock ratio : %d/%d\n" + "Bus/Clock ratio : %d/%d\n" + "ITC/Clock ratio : %d/%d\n", proc.num, proc.den, bus.num, bus.den, itc.num, itc.den); return p - page; diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c index ac167436e93..49958904045 100644 --- a/arch/ia64/kernel/time.c +++ b/arch/ia64/kernel/time.c @@ -188,7 +188,7 @@ ia64_init_itm (void) itc_freq = (platform_base_freq*itc_ratio.num)/itc_ratio.den; local_cpu_data->itm_delta = (itc_freq + HZ/2) / HZ; - printk(KERN_DEBUG "CPU %d: base freq=%lu.%03luMHz, ITC ratio=%lu/%lu, " + printk(KERN_DEBUG "CPU %d: base freq=%lu.%03luMHz, ITC ratio=%u/%u, " "ITC freq=%lu.%03luMHz", smp_processor_id(), platform_base_freq / 1000000, (platform_base_freq / 1000) % 1000, itc_ratio.num, itc_ratio.den, itc_freq / 1000000, (itc_freq / 1000) % 1000); diff --git a/arch/ia64/kernel/topology.c b/arch/ia64/kernel/topology.c index 3b6fd798c4d..b47476d655f 100644 --- a/arch/ia64/kernel/topology.c +++ b/arch/ia64/kernel/topology.c @@ -9,6 +9,8 @@ * 2002/08/07 Erich Focht <efocht@ess.nec.de> * Populate cpu entries in sysfs for non-numa systems as well * Intel Corporation - Ashok Raj + * 02/27/2006 Zhang, Yanmin + * Populate cpu cache entries in sysfs for cpu cache info */ #include <linux/config.h> @@ -19,6 +21,7 @@ #include <linux/init.h> #include <linux/bootmem.h> #include <linux/nodemask.h> +#include <linux/notifier.h> #include <asm/mmzone.h> #include <asm/numa.h> #include <asm/cpu.h> @@ -101,3 +104,367 @@ out: } subsys_initcall(topology_init); + + +/* + * Export cpu cache information through sysfs + */ + +/* + * A bunch of string array to get pretty printing + */ +static const char *cache_types[] = { + "", /* not used */ + "Instruction", + "Data", + "Unified" /* unified */ +}; + +static const char *cache_mattrib[]={ + "WriteThrough", + "WriteBack", + "", /* reserved */ + "" /* reserved */ +}; + +struct cache_info { + pal_cache_config_info_t cci; + cpumask_t shared_cpu_map; + int level; + int type; + struct kobject kobj; +}; + +struct cpu_cache_info { + struct cache_info *cache_leaves; + int num_cache_leaves; + struct kobject kobj; +}; + +static struct cpu_cache_info all_cpu_cache_info[NR_CPUS]; +#define LEAF_KOBJECT_PTR(x,y) (&all_cpu_cache_info[x].cache_leaves[y]) + +#ifdef CONFIG_SMP +static void cache_shared_cpu_map_setup( unsigned int cpu, + struct cache_info * this_leaf) +{ + pal_cache_shared_info_t csi; + int num_shared, i = 0; + unsigned int j; + + if (cpu_data(cpu)->threads_per_core <= 1 && + cpu_data(cpu)->cores_per_socket <= 1) { + cpu_set(cpu, this_leaf->shared_cpu_map); + return; + } + + if (ia64_pal_cache_shared_info(this_leaf->level, + this_leaf->type, + 0, + &csi) != PAL_STATUS_SUCCESS) + return; + + num_shared = (int) csi.num_shared; + do { + for_each_cpu(j) + if (cpu_data(cpu)->socket_id == cpu_data(j)->socket_id + && cpu_data(j)->core_id == csi.log1_cid + && cpu_data(j)->thread_id == csi.log1_tid) + cpu_set(j, this_leaf->shared_cpu_map); + + i++; + } while (i < num_shared && + ia64_pal_cache_shared_info(this_leaf->level, + this_leaf->type, + i, + &csi) == PAL_STATUS_SUCCESS); +} +#else +static void cache_shared_cpu_map_setup(unsigned int cpu, + struct cache_info * this_leaf) +{ + cpu_set(cpu, this_leaf->shared_cpu_map); + return; +} +#endif + +static ssize_t show_coherency_line_size(struct cache_info *this_leaf, + char *buf) +{ + return sprintf(buf, "%u\n", 1 << this_leaf->cci.pcci_line_size); +} + +static ssize_t show_ways_of_associativity(struct cache_info *this_leaf, + char *buf) +{ + return sprintf(buf, "%u\n", this_leaf->cci.pcci_assoc); +} + +static ssize_t show_attributes(struct cache_info *this_leaf, char *buf) +{ + return sprintf(buf, + "%s\n", + cache_mattrib[this_leaf->cci.pcci_cache_attr]); +} + +static ssize_t show_size(struct cache_info *this_leaf, char *buf) +{ + return sprintf(buf, "%uK\n", this_leaf->cci.pcci_cache_size / 1024); +} + +static ssize_t show_number_of_sets(struct cache_info *this_leaf, char *buf) +{ + unsigned number_of_sets = this_leaf->cci.pcci_cache_size; + number_of_sets /= this_leaf->cci.pcci_assoc; + number_of_sets /= 1 << this_leaf->cci.pcci_line_size; + + return sprintf(buf, "%u\n", number_of_sets); +} + +static ssize_t show_shared_cpu_map(struct cache_info *this_leaf, char *buf) +{ + ssize_t len; + cpumask_t shared_cpu_map; + + cpus_and(shared_cpu_map, this_leaf->shared_cpu_map, cpu_online_map); + len = cpumask_scnprintf(buf, NR_CPUS+1, shared_cpu_map); + len += sprintf(buf+len, "\n"); + return len; +} + +static ssize_t show_type(struct cache_info *this_leaf, char *buf) +{ + int type = this_leaf->type + this_leaf->cci.pcci_unified; + return sprintf(buf, "%s\n", cache_types[type]); +} + +static ssize_t show_level(struct cache_info *this_leaf, char *buf) +{ + return sprintf(buf, "%u\n", this_leaf->level); +} + +struct cache_attr { + struct attribute attr; + ssize_t (*show)(struct cache_info *, char *); + ssize_t (*store)(struct cache_info *, const char *, size_t count); +}; + +#ifdef define_one_ro + #undef define_one_ro +#endif +#define define_one_ro(_name) \ + static struct cache_attr _name = \ +__ATTR(_name, 0444, show_##_name, NULL) + +define_one_ro(level); +define_one_ro(type); +define_one_ro(coherency_line_size); +define_one_ro(ways_of_associativity); +define_one_ro(size); +define_one_ro(number_of_sets); +define_one_ro(shared_cpu_map); +define_one_ro(attributes); + +static struct attribute * cache_default_attrs[] = { + &type.attr, + &level.attr, + &coherency_line_size.attr, + &ways_of_associativity.attr, + &attributes.attr, + &size.attr, + &number_of_sets.attr, + &shared_cpu_map.attr, + NULL +}; + +#define to_object(k) container_of(k, struct cache_info, kobj) +#define to_attr(a) container_of(a, struct cache_attr, attr) + +static ssize_t cache_show(struct kobject * kobj, struct attribute * attr, char * buf) +{ + struct cache_attr *fattr = to_attr(attr); + struct cache_info *this_leaf = to_object(kobj); + ssize_t ret; + + ret = fattr->show ? fattr->show(this_leaf, buf) : 0; + return ret; +} + +static struct sysfs_ops cache_sysfs_ops = { + .show = cache_show +}; + +static struct kobj_type cache_ktype = { + .sysfs_ops = &cache_sysfs_ops, + .default_attrs = cache_default_attrs, +}; + +static struct kobj_type cache_ktype_percpu_entry = { + .sysfs_ops = &cache_sysfs_ops, +}; + +static void __cpuinit cpu_cache_sysfs_exit(unsigned int cpu) +{ + if (all_cpu_cache_info[cpu].cache_leaves) { + kfree(all_cpu_cache_info[cpu].cache_leaves); + all_cpu_cache_info[cpu].cache_leaves = NULL; + } + all_cpu_cache_info[cpu].num_cache_leaves = 0; + memset(&all_cpu_cache_info[cpu].kobj, 0, sizeof(struct kobject)); + + return; +} + +static int __cpuinit cpu_cache_sysfs_init(unsigned int cpu) +{ + u64 i, levels, unique_caches; + pal_cache_config_info_t cci; + int j; + s64 status; + struct cache_info *this_cache; + int num_cache_leaves = 0; + + if ((status = ia64_pal_cache_summary(&levels, &unique_caches)) != 0) { + printk(KERN_ERR "ia64_pal_cache_summary=%ld\n", status); + return -1; + } + + this_cache=kzalloc(sizeof(struct cache_info)*unique_caches, + GFP_KERNEL); + if (this_cache == NULL) + return -ENOMEM; + + for (i=0; i < levels; i++) { + for (j=2; j >0 ; j--) { + if ((status=ia64_pal_cache_config_info(i,j, &cci)) != + PAL_STATUS_SUCCESS) + continue; + + this_cache[num_cache_leaves].cci = cci; + this_cache[num_cache_leaves].level = i + 1; + this_cache[num_cache_leaves].type = j; + + cache_shared_cpu_map_setup(cpu, + &this_cache[num_cache_leaves]); + num_cache_leaves ++; + } + } + + all_cpu_cache_info[cpu].cache_leaves = this_cache; + all_cpu_cache_info[cpu].num_cache_leaves = num_cache_leaves; + + memset(&all_cpu_cache_info[cpu].kobj, 0, sizeof(struct kobject)); + + return 0; +} + +/* Add cache interface for CPU device */ +static int __cpuinit cache_add_dev(struct sys_device * sys_dev) +{ + unsigned int cpu = sys_dev->id; + unsigned long i, j; + struct cache_info *this_object; + int retval = 0; + cpumask_t oldmask; + + if (all_cpu_cache_info[cpu].kobj.parent) + return 0; + + oldmask = current->cpus_allowed; + retval = set_cpus_allowed(current, cpumask_of_cpu(cpu)); + if (unlikely(retval)) + return retval; + + retval = cpu_cache_sysfs_init(cpu); + set_cpus_allowed(current, oldmask); + if (unlikely(retval < 0)) + return retval; + + all_cpu_cache_info[cpu].kobj.parent = &sys_dev->kobj; + kobject_set_name(&all_cpu_cache_info[cpu].kobj, "%s", "cache"); + all_cpu_cache_info[cpu].kobj.ktype = &cache_ktype_percpu_entry; + retval = kobject_register(&all_cpu_cache_info[cpu].kobj); + + for (i = 0; i < all_cpu_cache_info[cpu].num_cache_leaves; i++) { + this_object = LEAF_KOBJECT_PTR(cpu,i); + this_object->kobj.parent = &all_cpu_cache_info[cpu].kobj; + kobject_set_name(&(this_object->kobj), "index%1lu", i); + this_object->kobj.ktype = &cache_ktype; + retval = kobject_register(&(this_object->kobj)); + if (unlikely(retval)) { + for (j = 0; j < i; j++) { + kobject_unregister( + &(LEAF_KOBJECT_PTR(cpu,j)->kobj)); + } + kobject_unregister(&all_cpu_cache_info[cpu].kobj); + cpu_cache_sysfs_exit(cpu); + break; + } + } + return retval; +} + +/* Remove cache interface for CPU device */ +static int __cpuinit cache_remove_dev(struct sys_device * sys_dev) +{ + unsigned int cpu = sys_dev->id; + unsigned long i; + + for (i = 0; i < all_cpu_cache_info[cpu].num_cache_leaves; i++) + kobject_unregister(&(LEAF_KOBJECT_PTR(cpu,i)->kobj)); + + if (all_cpu_cache_info[cpu].kobj.parent) { + kobject_unregister(&all_cpu_cache_info[cpu].kobj); + memset(&all_cpu_cache_info[cpu].kobj, + 0, + sizeof(struct kobject)); + } + + cpu_cache_sysfs_exit(cpu); + + return 0; +} + +/* + * When a cpu is hot-plugged, do a check and initiate + * cache kobject if necessary + */ +static int __cpuinit cache_cpu_callback(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + unsigned int cpu = (unsigned long)hcpu; + struct sys_device *sys_dev; + + sys_dev = get_cpu_sysdev(cpu); + switch (action) { + case CPU_ONLINE: + cache_add_dev(sys_dev); + break; + case CPU_DEAD: + cache_remove_dev(sys_dev); + break; + } + return NOTIFY_OK; +} + +static struct notifier_block cache_cpu_notifier = +{ + .notifier_call = cache_cpu_callback +}; + +static int __cpuinit cache_sysfs_init(void) +{ + int i; + + for_each_online_cpu(i) { + cache_cpu_callback(&cache_cpu_notifier, CPU_ONLINE, + (void *)(long)i); + } + + register_cpu_notifier(&cache_cpu_notifier); + + return 0; +} + +device_initcall(cache_sysfs_init); + diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c index 3d7f2000b71..c3319514a85 100644 --- a/arch/m68k/kernel/m68k_ksyms.c +++ b/arch/m68k/kernel/m68k_ksyms.c @@ -79,4 +79,3 @@ EXPORT_SYMBOL(__down_failed_interruptible); EXPORT_SYMBOL(__down_failed_trylock); EXPORT_SYMBOL(__up_wakeup); -EXPORT_SYMBOL(get_wchan); diff --git a/arch/m68knommu/kernel/m68k_ksyms.c b/arch/m68knommu/kernel/m68k_ksyms.c index d844c755945..f9b4ea16c09 100644 --- a/arch/m68knommu/kernel/m68k_ksyms.c +++ b/arch/m68knommu/kernel/m68k_ksyms.c @@ -57,8 +57,6 @@ EXPORT_SYMBOL(__down_failed_interruptible); EXPORT_SYMBOL(__down_failed_trylock); EXPORT_SYMBOL(__up_wakeup); -EXPORT_SYMBOL(get_wchan); - /* * libgcc functions - functions that are used internally by the * compiler... (prototypes are not correct though, but that diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 5080ea1799a..e15709ce886 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -233,6 +233,7 @@ config MACH_JAZZ select ARC32 select ARCH_MAY_HAVE_PC_FDC select GENERIC_ISA_DMA + select I8253 select I8259 select ISA select SYS_HAS_CPU_R4X00 @@ -530,6 +531,7 @@ config QEMU select DMA_COHERENT select GENERIC_ISA_DMA select HAVE_STD_PC_SERIAL_PORT + select I8253 select I8259 select ISA select SWAP_IO_SPACE @@ -714,6 +716,7 @@ config SNI_RM200_PCI select HAVE_STD_PC_SERIAL_PORT select HW_HAS_EISA select HW_HAS_PCI + select I8253 select I8259 select ISA select SYS_HAS_CPU_R4X00 @@ -1721,6 +1724,9 @@ config MMU bool default y +config I8253 + bool + source "drivers/pcmcia/Kconfig" source "drivers/pci/hotplug/Kconfig" diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index f36c4f20ee8..309d54cceda 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -59,6 +59,8 @@ obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_64BIT) += cpu-bugs64.o +obj-$(CONFIG_I8253) += i8253.o + CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(CFLAGS) -Wa,-mdaddi -c -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi) EXTRA_AFLAGS := $(CFLAGS) diff --git a/arch/mips/kernel/i8253.c b/arch/mips/kernel/i8253.c new file mode 100644 index 00000000000..475df690421 --- /dev/null +++ b/arch/mips/kernel/i8253.c @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2006 IBM Corporation + * + * Implements device information for i8253 timer chip + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation + */ + +#include <linux/platform_device.h> + +static __init int add_pcspkr(void) +{ + struct platform_device *pd; + int ret; + + pd = platform_device_alloc("pcspkr", -1); + if (!pd) + return -ENOMEM; + + ret = platform_device_add(pd); + if (ret) + platform_device_put(pd); + + return ret; +} +device_initcall(add_pcspkr); diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index a8f435d8294..c66db5e5ab6 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -419,4 +419,3 @@ unsigned long get_wchan(struct task_struct *p) return pc; } -EXPORT_SYMBOL(get_wchan); diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c index 211d72653ea..764d0732971 100644 --- a/arch/powerpc/kernel/crash_dump.c +++ b/arch/powerpc/kernel/crash_dump.c @@ -61,7 +61,7 @@ static int __init parse_elfcorehdr(char *p) if (p) elfcorehdr_addr = memparse(p, &p); - return 0; + return 1; } __setup("elfcorehdr=", parse_elfcorehdr); #endif @@ -71,7 +71,7 @@ static int __init parse_savemaxmem(char *p) if (p) saved_max_pfn = (memparse(p, &p) >> PAGE_SHIFT) - 1; - return 0; + return 1; } __setup("savemaxmem=", parse_savemaxmem); diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c index 1b73508ecb2..2cbde865d4f 100644 --- a/arch/powerpc/kernel/lparcfg.c +++ b/arch/powerpc/kernel/lparcfg.c @@ -37,7 +37,7 @@ #include <asm/prom.h> #include <asm/vdso_datapage.h> -#define MODULE_VERS "1.6" +#define MODULE_VERS "1.7" #define MODULE_NAME "lparcfg" /* #define LPARCFG_DEBUG */ @@ -149,17 +149,17 @@ static void log_plpar_hcall_return(unsigned long rc, char *tag) if (rc == 0) /* success, return */ return; /* check for null tag ? */ - if (rc == H_Hardware) + if (rc == H_HARDWARE) printk(KERN_INFO "plpar-hcall (%s) failed with hardware fault\n", tag); - else if (rc == H_Function) + else if (rc == H_FUNCTION) printk(KERN_INFO "plpar-hcall (%s) failed; function not allowed\n", tag); - else if (rc == H_Authority) + else if (rc == H_AUTHORITY) printk(KERN_INFO - "plpar-hcall (%s) failed; not authorized to this function\n", - tag); - else if (rc == H_Parameter) + "plpar-hcall (%s) failed; not authorized to this" + " function\n", tag); + else if (rc == H_PARAMETER) printk(KERN_INFO "plpar-hcall (%s) failed; Bad parameter(s)\n", tag); else @@ -209,7 +209,7 @@ static void h_pic(unsigned long *pool_idle_time, unsigned long *num_procs) unsigned long dummy; rc = plpar_hcall(H_PIC, 0, 0, 0, 0, pool_idle_time, num_procs, &dummy); - if (rc != H_Authority) + if (rc != H_AUTHORITY) log_plpar_hcall_return(rc, "H_PIC"); } @@ -242,7 +242,7 @@ static void parse_system_parameter_string(struct seq_file *m) { int call_status; - char *local_buffer = kmalloc(SPLPAR_MAXLENGTH, GFP_KERNEL); + unsigned char *local_buffer = kmalloc(SPLPAR_MAXLENGTH, GFP_KERNEL); if (!local_buffer) { printk(KERN_ERR "%s %s kmalloc failure at line %d \n", __FILE__, __FUNCTION__, __LINE__); @@ -254,7 +254,8 @@ static void parse_system_parameter_string(struct seq_file *m) call_status = rtas_call(rtas_token("ibm,get-system-parameter"), 3, 1, NULL, SPLPAR_CHARACTERISTICS_TOKEN, - __pa(rtas_data_buf)); + __pa(rtas_data_buf), + RTAS_DATA_BUF_SIZE); memcpy(local_buffer, rtas_data_buf, SPLPAR_MAXLENGTH); spin_unlock(&rtas_data_buf_lock); @@ -275,7 +276,7 @@ static void parse_system_parameter_string(struct seq_file *m) #ifdef LPARCFG_DEBUG printk(KERN_INFO "success calling get-system-parameter \n"); #endif - splpar_strlen = local_buffer[0] * 16 + local_buffer[1]; + splpar_strlen = local_buffer[0] * 256 + local_buffer[1]; local_buffer += 2; /* step over strlen value */ memset(workbuffer, 0, SPLPAR_MAXLENGTH); @@ -529,13 +530,13 @@ static ssize_t lparcfg_write(struct file *file, const char __user * buf, retval = plpar_hcall_norets(H_SET_PPP, *new_entitled_ptr, *new_weight_ptr); - if (retval == H_Success || retval == H_Constrained) { + if (retval == H_SUCCESS || retval == H_CONSTRAINED) { retval = count; - } else if (retval == H_Busy) { + } else if (retval == H_BUSY) { retval = -EBUSY; - } else if (retval == H_Hardware) { + } else if (retval == H_HARDWARE) { retval = -EIO; - } else if (retval == H_Parameter) { + } else if (retval == H_PARAMETER) { retval = -EINVAL; } else { printk(KERN_WARNING "%s: received unknown hv return code %ld", diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 706090c99f4..2dd47d2dd99 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -834,7 +834,6 @@ unsigned long get_wchan(struct task_struct *p) } while (count++ < 16); return 0; } -EXPORT_SYMBOL(get_wchan); static int kstack_depth_to_print = 64; diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 06636c927a7..0112318213a 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -578,18 +578,18 @@ static void rtas_percpu_suspend_me(void *info) * We use "waiting" to indicate our state. As long * as it is >0, we are still trying to all join up. * If it goes to 0, we have successfully joined up and - * one thread got H_Continue. If any error happens, + * one thread got H_CONTINUE. If any error happens, * we set it to <0. */ local_irq_save(flags); do { rc = plpar_hcall_norets(H_JOIN); smp_rmb(); - } while (rc == H_Success && data->waiting > 0); - if (rc == H_Success) + } while (rc == H_SUCCESS && data->waiting > 0); + if (rc == H_SUCCESS) goto out; - if (rc == H_Continue) { + if (rc == H_CONTINUE) { data->waiting = 0; data->args->args[data->args->nargs] = rtas_call(ibm_suspend_me_token, 0, 1, NULL); @@ -597,7 +597,7 @@ static void rtas_percpu_suspend_me(void *info) plpar_hcall_norets(H_PROD,i); } else { data->waiting = -EBUSY; - printk(KERN_ERR "Error on H_Join hypervisor call\n"); + printk(KERN_ERR "Error on H_JOIN hypervisor call\n"); } out: @@ -624,7 +624,7 @@ static int rtas_ibm_suspend_me(struct rtas_args *args) printk(KERN_ERR "Error doing global join\n"); /* Prod each CPU. This won't hurt, and will wake - * anyone we successfully put to sleep with H_Join + * anyone we successfully put to sleep with H_JOIN. */ for_each_possible_cpu(i) plpar_hcall_norets(H_PROD, i); diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index c607f3b9ca1..1d93e73a700 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -21,6 +21,7 @@ #include <linux/reboot.h> #include <linux/delay.h> #include <linux/initrd.h> +#include <linux/platform_device.h> #include <linux/ide.h> #include <linux/seq_file.h> #include <linux/ioport.h> @@ -462,6 +463,29 @@ static int __init early_xmon(char *p) early_param("xmon", early_xmon); #endif +static __init int add_pcspkr(void) +{ + struct device_node *np; + struct platform_device *pd; + int ret; + + np = of_find_compatible_node(NULL, NULL, "pnpPNP,100"); + of_node_put(np); + if (!np) + return -ENODEV; + + pd = platform_device_alloc("pcspkr", -1); + if (!pd) + return -ENOMEM; + + ret = platform_device_add(pd); + if (ret) + platform_device_put(pd); + + return ret; +} +device_initcall(add_pcspkr); + void probe_machine(void) { extern struct machdep_calls __machine_desc_start; diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index a72bf5dceee..69ac2570134 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -50,7 +50,6 @@ #include <asm/kgdb.h> #endif -extern void platform_init(void); extern void bootx_init(unsigned long r4, unsigned long phys); boot_infos_t *boot_infos; @@ -138,12 +137,7 @@ void __init machine_init(unsigned long dt_ptr, unsigned long phys) strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line)); #endif /* CONFIG_CMDLINE */ -#ifdef CONFIG_PPC_MULTIPLATFORM probe_machine(); -#else - /* Base init based on machine type. Obsoloete, please kill ! */ - platform_init(); -#endif #ifdef CONFIG_6xx if (cpu_has_feature(CPU_FTR_CAN_DOZE) || diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 59aa92cd6fa..13e91c4d70a 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -215,12 +215,10 @@ void __init early_setup(unsigned long dt_ptr) /* * Initialize stab / SLB management except on iSeries */ - if (!firmware_has_feature(FW_FEATURE_ISERIES)) { - if (cpu_has_feature(CPU_FTR_SLB)) - slb_initialize(); - else - stab_initialize(get_paca()->stab_real); - } + if (cpu_has_feature(CPU_FTR_SLB)) + slb_initialize(); + else if (!firmware_has_feature(FW_FEATURE_ISERIES)) + stab_initialize(get_paca()->stab_real); DBG(" <- early_setup()\n"); } diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S index 1ad55f0466f..1424eab450e 100644 --- a/arch/powerpc/kernel/systbl.S +++ b/arch/powerpc/kernel/systbl.S @@ -322,3 +322,4 @@ SYSCALL(spu_create) COMPAT_SYS(pselect6) COMPAT_SYS(ppoll) SYSCALL(unshare) +SYSCALL(splice) diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 4cbde211eb6..064a5256469 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -228,7 +228,7 @@ void system_reset_exception(struct pt_regs *regs) */ static inline int check_io_access(struct pt_regs *regs) { -#ifdef CONFIG_PPC_PMAC +#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32) unsigned long msr = regs->msr; const struct exception_table_entry *entry; unsigned int *nip = (unsigned int *)regs->nip; @@ -261,7 +261,7 @@ static inline int check_io_access(struct pt_regs *regs) return 1; } } -#endif /* CONFIG_PPC_PMAC */ +#endif /* CONFIG_PPC_PMAC && CONFIG_PPC32 */ return 0; } @@ -308,8 +308,8 @@ platform_machine_check(struct pt_regs *regs) void machine_check_exception(struct pt_regs *regs) { -#ifdef CONFIG_PPC64 int recover = 0; + unsigned long reason = get_mc_reason(regs); /* See if any machine dependent calls */ if (ppc_md.machine_check_exception) @@ -317,8 +317,6 @@ void machine_check_exception(struct pt_regs *regs) if (recover) return; -#else - unsigned long reason = get_mc_reason(regs); if (user_mode(regs)) { regs->msr |= MSR_RI; @@ -462,7 +460,6 @@ void machine_check_exception(struct pt_regs *regs) * additional info, e.g. bus error registers. */ platform_machine_check(regs); -#endif /* CONFIG_PPC64 */ if (debugger_fault_handler(regs)) return; diff --git a/arch/powerpc/kernel/vdso32/sigtramp.S b/arch/powerpc/kernel/vdso32/sigtramp.S index e0464278191..0c6a37b29dd 100644 --- a/arch/powerpc/kernel/vdso32/sigtramp.S +++ b/arch/powerpc/kernel/vdso32/sigtramp.S @@ -261,7 +261,7 @@ V_FUNCTION_END(__kernel_sigtramp_rt32) .Lcie_start: .long 0 /* CIE ID */ .byte 1 /* Version number */ - .string "zR" /* NUL-terminated augmentation string */ + .string "zRS" /* NUL-terminated augmentation string */ .uleb128 4 /* Code alignment factor */ .sleb128 -4 /* Data alignment factor */ .byte 67 /* Return address register column, ap */ diff --git a/arch/powerpc/kernel/vdso64/sigtramp.S b/arch/powerpc/kernel/vdso64/sigtramp.S index 31b604ab56d..7479edb101b 100644 --- a/arch/powerpc/kernel/vdso64/sigtramp.S +++ b/arch/powerpc/kernel/vdso64/sigtramp.S @@ -263,7 +263,7 @@ V_FUNCTION_END(__kernel_sigtramp_rt64) .Lcie_start: .long 0 /* CIE ID */ .byte 1 /* Version number */ - .string "zR" /* NUL-terminated augmentation string */ + .string "zRS" /* NUL-terminated augmentation string */ .uleb128 4 /* Code alignment factor */ .sleb128 -8 /* Data alignment factor */ .byte 67 /* Return address register column, ap */ diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index 5aea0909a5e..fdbba4206d5 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -177,15 +177,15 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, /* When running in the kernel we expect faults to occur only to * addresses in user space. All other faults represent errors in the - * kernel and should generate an OOPS. Unfortunatly, in the case of an - * erroneous fault occuring in a code path which already holds mmap_sem + * kernel and should generate an OOPS. Unfortunately, in the case of an + * erroneous fault occurring in a code path which already holds mmap_sem * we will deadlock attempting to validate the fault against the * address space. Luckily the kernel only validly references user * space from well defined areas of code, which are listed in the * exceptions table. * * As the vast majority of faults will be valid we will only perform - * the source reference check when there is a possibilty of a deadlock. + * the source reference check when there is a possibility of a deadlock. * Attempt to lock the address space, if we cannot we then validate the * source. If this is invalid we can skip the address space check, * thus avoiding the deadlock. diff --git a/arch/powerpc/platforms/83xx/mpc834x_sys.c b/arch/powerpc/platforms/83xx/mpc834x_sys.c index 7c18b4cd5db..7e789d2420b 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_sys.c +++ b/arch/powerpc/platforms/83xx/mpc834x_sys.c @@ -158,25 +158,25 @@ static int __init mpc834x_rtc_hookup(void) late_initcall(mpc834x_rtc_hookup); #endif -void __init platform_init(void) +/* + * Called very early, MMU is off, device-tree isn't unflattened + */ +static int __init mpc834x_sys_probe(void) { - /* setup the PowerPC module struct */ - ppc_md.setup_arch = mpc834x_sys_setup_arch; - - ppc_md.init_IRQ = mpc834x_sys_init_IRQ; - ppc_md.get_irq = ipic_get_irq; - - ppc_md.restart = mpc83xx_restart; - - ppc_md.time_init = mpc83xx_time_init; - ppc_md.set_rtc_time = NULL; - ppc_md.get_rtc_time = NULL; - ppc_md.calibrate_decr = generic_calibrate_decr; - - ppc_md.progress = udbg_progress; - - if (ppc_md.progress) - ppc_md.progress("mpc834x_sys_init(): exit", 0); - - return; + /* We always match for now, eventually we should look at the flat + dev tree to ensure this is the board we are suppose to run on + */ + return 1; } + +define_machine(mpc834x_sys) { + .name = "MPC834x SYS", + .probe = mpc834x_sys_probe, + .setup_arch = mpc834x_sys_setup_arch, + .init_IRQ = mpc834x_sys_init_IRQ, + .get_irq = ipic_get_irq, + .restart = mpc83xx_restart, + .time_init = mpc83xx_time_init, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index b7821dbae00..5eeff370f5f 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -220,25 +220,25 @@ void mpc85xx_ads_show_cpuinfo(struct seq_file *m) seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024)); } -void __init platform_init(void) +/* + * Called very early, device-tree isn't unflattened + */ +static int __init mpc85xx_ads_probe(void) { - ppc_md.setup_arch = mpc85xx_ads_setup_arch; - ppc_md.show_cpuinfo = mpc85xx_ads_show_cpuinfo; - - ppc_md.init_IRQ = mpc85xx_ads_pic_init; - ppc_md.get_irq = mpic_get_irq; - - ppc_md.restart = mpc85xx_restart; - ppc_md.power_off = NULL; - ppc_md.halt = NULL; - - ppc_md.time_init = NULL; - ppc_md.set_rtc_time = NULL; - ppc_md.get_rtc_time = NULL; - ppc_md.calibrate_decr = generic_calibrate_decr; - - ppc_md.progress = udbg_progress; - - if (ppc_md.progress) - ppc_md.progress("mpc85xx_ads platform_init(): exit", 0); + /* We always match for now, eventually we should look at the flat + dev tree to ensure this is the board we are suppose to run on + */ + return 1; } + +define_machine(mpc85xx_ads) { + .name = "MPC85xx ADS", + .probe = mpc85xx_ads_probe, + .setup_arch = mpc85xx_ads_setup_arch, + .init_IRQ = mpc85xx_ads_pic_init, + .show_cpuinfo = mpc85xx_ads_show_cpuinfo, + .get_irq = mpic_get_irq, + .restart = mpc85xx_restart, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; diff --git a/arch/powerpc/platforms/cell/spu_callbacks.c b/arch/powerpc/platforms/cell/spu_callbacks.c index 3a4245c926a..6594bec7388 100644 --- a/arch/powerpc/platforms/cell/spu_callbacks.c +++ b/arch/powerpc/platforms/cell/spu_callbacks.c @@ -316,6 +316,7 @@ void *spu_syscall_table[] = { [__NR_pselect6] sys_ni_syscall, /* sys_pselect */ [__NR_ppoll] sys_ni_syscall, /* sys_ppoll */ [__NR_unshare] sys_unshare, + [__NR_splice] sys_splice, }; long spu_sys_callback(struct spu_syscall_block *s) diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c index c04e078c0fe..483c8b76232 100644 --- a/arch/powerpc/platforms/cell/spufs/run.c +++ b/arch/powerpc/platforms/cell/spufs/run.c @@ -2,6 +2,7 @@ #include <linux/ptrace.h> #include <asm/spu.h> +#include <asm/unistd.h> #include "spufs.h" diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index 9b2b1cb117b..780fb27a009 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -865,7 +865,7 @@ void __init eeh_init(void) * on the CEC architecture, type of the device, on earlier boot * command-line arguments & etc. */ -void eeh_add_device_early(struct device_node *dn) +static void eeh_add_device_early(struct device_node *dn) { struct pci_controller *phb; struct eeh_early_enable_info info; @@ -882,7 +882,6 @@ void eeh_add_device_early(struct device_node *dn) info.buid_lo = BUID_LO(phb->buid); early_enable_eeh(dn, &info); } -EXPORT_SYMBOL_GPL(eeh_add_device_early); void eeh_add_device_tree_early(struct device_node *dn) { @@ -893,20 +892,6 @@ void eeh_add_device_tree_early(struct device_node *dn) } EXPORT_SYMBOL_GPL(eeh_add_device_tree_early); -void eeh_add_device_tree_late(struct pci_bus *bus) -{ - struct pci_dev *dev; - - list_for_each_entry(dev, &bus->devices, bus_list) { - eeh_add_device_late(dev); - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - struct pci_bus *subbus = dev->subordinate; - if (subbus) - eeh_add_device_tree_late(subbus); - } - } -} - /** * eeh_add_device_late - perform EEH initialization for the indicated pci device * @dev: pci device for which to set up EEH @@ -914,7 +899,7 @@ void eeh_add_device_tree_late(struct pci_bus *bus) * This routine must be used to complete EEH initialization for PCI * devices that were added after system boot (e.g. hotplug, dlpar). */ -void eeh_add_device_late(struct pci_dev *dev) +static void eeh_add_device_late(struct pci_dev *dev) { struct device_node *dn; struct pci_dn *pdn; @@ -933,16 +918,33 @@ void eeh_add_device_late(struct pci_dev *dev) pci_addr_cache_insert_device (dev); } -EXPORT_SYMBOL_GPL(eeh_add_device_late); + +void eeh_add_device_tree_late(struct pci_bus *bus) +{ + struct pci_dev *dev; + + list_for_each_entry(dev, &bus->devices, bus_list) { + eeh_add_device_late(dev); + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + struct pci_bus *subbus = dev->subordinate; + if (subbus) + eeh_add_device_tree_late(subbus); + } + } +} +EXPORT_SYMBOL_GPL(eeh_add_device_tree_late); /** * eeh_remove_device - undo EEH setup for the indicated pci device * @dev: pci device to be removed * - * This routine should be when a device is removed from a running - * system (e.g. by hotplug or dlpar). + * This routine should be called when a device is removed from + * a running system (e.g. by hotplug or dlpar). It unregisters + * the PCI device from the EEH subsystem. I/O errors affecting + * this device will no longer be detected after this call; thus, + * i/o errors affecting this slot may leave this device unusable. */ -void eeh_remove_device(struct pci_dev *dev) +static void eeh_remove_device(struct pci_dev *dev) { struct device_node *dn; if (!dev || !eeh_subsystem_enabled) @@ -958,21 +960,17 @@ void eeh_remove_device(struct pci_dev *dev) PCI_DN(dn)->pcidev = NULL; pci_dev_put (dev); } -EXPORT_SYMBOL_GPL(eeh_remove_device); void eeh_remove_bus_device(struct pci_dev *dev) { + struct pci_bus *bus = dev->subordinate; + struct pci_dev *child, *tmp; + eeh_remove_device(dev); - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - struct pci_bus *bus = dev->subordinate; - struct list_head *ln; - if (!bus) - return; - for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) { - struct pci_dev *pdev = pci_dev_b(ln); - if (pdev) - eeh_remove_bus_device(pdev); - } + + if (bus && dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + list_for_each_entry_safe(child, tmp, &bus->devices, bus_list) + eeh_remove_bus_device(child); } } EXPORT_SYMBOL_GPL(eeh_remove_bus_device); diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c index cc2495a0cdd..1fba695e32e 100644 --- a/arch/powerpc/platforms/pseries/eeh_driver.c +++ b/arch/powerpc/platforms/pseries/eeh_driver.c @@ -293,15 +293,16 @@ void handle_eeh_events (struct eeh_event *event) frozen_pdn = PCI_DN(frozen_dn); frozen_pdn->eeh_freeze_count++; - pci_str = pci_name (frozen_pdn->pcidev); - drv_str = pcid_name (frozen_pdn->pcidev); - if (!pci_str) { + if (frozen_pdn->pcidev) { + pci_str = pci_name (frozen_pdn->pcidev); + drv_str = pcid_name (frozen_pdn->pcidev); + } else { pci_str = pci_name (event->dev); drv_str = pcid_name (event->dev); } if (frozen_pdn->eeh_freeze_count > EEH_MAX_ALLOWED_FREEZES) - goto hard_fail; + goto excess_failures; /* If the reset state is a '5' and the time to reset is 0 (infinity) * or is more then 15 seconds, then mark this as a permanent failure. @@ -356,7 +357,7 @@ void handle_eeh_events (struct eeh_event *event) return; -hard_fail: +excess_failures: /* * About 90% of all real-life EEH failures in the field * are due to poorly seated PCI cards. Only 10% or so are @@ -367,7 +368,15 @@ hard_fail: "and has been permanently disabled. Please try reseating\n" "this device or replacing it.\n", drv_str, pci_str, frozen_pdn->eeh_freeze_count); + goto perm_error; + +hard_fail: + printk(KERN_ERR + "EEH: Unable to recover from failure of PCI device %s - %s\n" + "Please try reseating this device or replacing it.\n", + drv_str, pci_str); +perm_error: eeh_slot_error_detail(frozen_pdn, 2 /* Permanent Error */); /* Notify all devices that they're about to go down. */ diff --git a/arch/powerpc/platforms/pseries/eeh_event.c b/arch/powerpc/platforms/pseries/eeh_event.c index 9a9961f2748..a1bda6f96fd 100644 --- a/arch/powerpc/platforms/pseries/eeh_event.c +++ b/arch/powerpc/platforms/pseries/eeh_event.c @@ -19,7 +19,9 @@ */ #include <linux/list.h> +#include <linux/mutex.h> #include <linux/pci.h> +#include <linux/workqueue.h> #include <asm/eeh_event.h> #include <asm/ppc-pci.h> @@ -37,14 +39,18 @@ LIST_HEAD(eeh_eventlist); static void eeh_thread_launcher(void *); DECLARE_WORK(eeh_event_wq, eeh_thread_launcher, NULL); +/* Serialize reset sequences for a given pci device */ +DEFINE_MUTEX(eeh_event_mutex); + /** - * eeh_event_handler - dispatch EEH events. The detection of a frozen - * slot can occur inside an interrupt, where it can be hard to do - * anything about it. The goal of this routine is to pull these - * detection events out of the context of the interrupt handler, and - * re-dispatch them for processing at a later time in a normal context. - * + * eeh_event_handler - dispatch EEH events. * @dummy - unused + * + * The detection of a frozen slot can occur inside an interrupt, + * where it can be hard to do anything about it. The goal of this + * routine is to pull these detection events out of the context + * of the interrupt handler, and re-dispatch them for processing + * at a later time in a normal context. */ static int eeh_event_handler(void * dummy) { @@ -64,23 +70,24 @@ static int eeh_event_handler(void * dummy) event = list_entry(eeh_eventlist.next, struct eeh_event, list); list_del(&event->list); } - - if (event) - eeh_mark_slot(event->dn, EEH_MODE_RECOVERING); - spin_unlock_irqrestore(&eeh_eventlist_lock, flags); + if (event == NULL) break; + /* Serialize processing of EEH events */ + mutex_lock(&eeh_event_mutex); + eeh_mark_slot(event->dn, EEH_MODE_RECOVERING); + printk(KERN_INFO "EEH: Detected PCI bus error on device %s\n", pci_name(event->dev)); handle_eeh_events(event); eeh_clear_slot(event->dn, EEH_MODE_RECOVERING); - pci_dev_put(event->dev); kfree(event); + mutex_unlock(&eeh_event_mutex); } return 0; @@ -88,7 +95,6 @@ static int eeh_event_handler(void * dummy) /** * eeh_thread_launcher - * * @dummy - unused */ static void eeh_thread_launcher(void *dummy) diff --git a/arch/powerpc/platforms/pseries/hvCall.S b/arch/powerpc/platforms/pseries/hvCall.S index db7c19fe929..c9ff547f9d2 100644 --- a/arch/powerpc/platforms/pseries/hvCall.S +++ b/arch/powerpc/platforms/pseries/hvCall.S @@ -127,3 +127,103 @@ _GLOBAL(plpar_hcall_4out) mtcrf 0xff,r0 blr /* return r3 = status */ + +/* plpar_hcall_7arg_7ret(unsigned long opcode, R3 + unsigned long arg1, R4 + unsigned long arg2, R5 + unsigned long arg3, R6 + unsigned long arg4, R7 + unsigned long arg5, R8 + unsigned long arg6, R9 + unsigned long arg7, R10 + unsigned long *out1, 112(R1) + unsigned long *out2, 110(R1) + unsigned long *out3, 108(R1) + unsigned long *out4, 106(R1) + unsigned long *out5, 104(R1) + unsigned long *out6, 102(R1) + unsigned long *out7); 100(R1) +*/ +_GLOBAL(plpar_hcall_7arg_7ret) + HMT_MEDIUM + + mfcr r0 + stw r0,8(r1) + + HVSC /* invoke the hypervisor */ + + lwz r0,8(r1) + + ld r11,STK_PARM(r11)(r1) /* Fetch r4 ret arg */ + std r4,0(r11) + ld r11,STK_PARM(r12)(r1) /* Fetch r5 ret arg */ + std r5,0(r11) + ld r11,STK_PARM(r13)(r1) /* Fetch r6 ret arg */ + std r6,0(r11) + ld r11,STK_PARM(r14)(r1) /* Fetch r7 ret arg */ + std r7,0(r11) + ld r11,STK_PARM(r15)(r1) /* Fetch r8 ret arg */ + std r8,0(r11) + ld r11,STK_PARM(r16)(r1) /* Fetch r9 ret arg */ + std r9,0(r11) + ld r11,STK_PARM(r17)(r1) /* Fetch r10 ret arg */ + std r10,0(r11) + + mtcrf 0xff,r0 + + blr /* return r3 = status */ + +/* plpar_hcall_9arg_9ret(unsigned long opcode, R3 + unsigned long arg1, R4 + unsigned long arg2, R5 + unsigned long arg3, R6 + unsigned long arg4, R7 + unsigned long arg5, R8 + unsigned long arg6, R9 + unsigned long arg7, R10 + unsigned long arg8, 112(R1) + unsigned long arg9, 110(R1) + unsigned long *out1, 108(R1) + unsigned long *out2, 106(R1) + unsigned long *out3, 104(R1) + unsigned long *out4, 102(R1) + unsigned long *out5, 100(R1) + unsigned long *out6, 98(R1) + unsigned long *out7); 96(R1) + unsigned long *out8, 94(R1) + unsigned long *out9, 92(R1) +*/ +_GLOBAL(plpar_hcall_9arg_9ret) + HMT_MEDIUM + + mfcr r0 + stw r0,8(r1) + + ld r11,STK_PARM(r11)(r1) /* put arg8 in R11 */ + ld r12,STK_PARM(r12)(r1) /* put arg9 in R12 */ + + HVSC /* invoke the hypervisor */ + + ld r0,STK_PARM(r13)(r1) /* Fetch r4 ret arg */ + stdx r4,r0,r0 + ld r0,STK_PARM(r14)(r1) /* Fetch r5 ret arg */ + stdx r5,r0,r0 + ld r0,STK_PARM(r15)(r1) /* Fetch r6 ret arg */ + stdx r6,r0,r0 + ld r0,STK_PARM(r16)(r1) /* Fetch r7 ret arg */ + stdx r7,r0,r0 + ld r0,STK_PARM(r17)(r1) /* Fetch r8 ret arg */ + stdx r8,r0,r0 + ld r0,STK_PARM(r18)(r1) /* Fetch r9 ret arg */ + stdx r9,r0,r0 + ld r0,STK_PARM(r19)(r1) /* Fetch r10 ret arg */ + stdx r10,r0,r0 + ld r0,STK_PARM(r20)(r1) /* Fetch r11 ret arg */ + stdx r11,r0,r0 + ld r0,STK_PARM(r21)(r1) /* Fetch r12 ret arg */ + stdx r12,r0,r0 + + lwz r0,8(r1) + mtcrf 0xff,r0 + + blr /* return r3 = status */ diff --git a/arch/powerpc/platforms/pseries/hvconsole.c b/arch/powerpc/platforms/pseries/hvconsole.c index ba6befd9663..a72a987f1d4 100644 --- a/arch/powerpc/platforms/pseries/hvconsole.c +++ b/arch/powerpc/platforms/pseries/hvconsole.c @@ -41,7 +41,7 @@ int hvc_get_chars(uint32_t vtermno, char *buf, int count) unsigned long got; if (plpar_hcall(H_GET_TERM_CHAR, vtermno, 0, 0, 0, &got, - (unsigned long *)buf, (unsigned long *)buf+1) == H_Success) + (unsigned long *)buf, (unsigned long *)buf+1) == H_SUCCESS) return got; return 0; } @@ -69,9 +69,9 @@ int hvc_put_chars(uint32_t vtermno, const char *buf, int count) ret = plpar_hcall_norets(H_PUT_TERM_CHAR, vtermno, count, lbuf[0], lbuf[1]); - if (ret == H_Success) + if (ret == H_SUCCESS) return count; - if (ret == H_Busy) + if (ret == H_BUSY) return 0; return -EIO; } diff --git a/arch/powerpc/platforms/pseries/hvcserver.c b/arch/powerpc/platforms/pseries/hvcserver.c index 22bfb5c89db..fcf4b4cbeaf 100644 --- a/arch/powerpc/platforms/pseries/hvcserver.c +++ b/arch/powerpc/platforms/pseries/hvcserver.c @@ -43,21 +43,21 @@ MODULE_VERSION(HVCS_ARCH_VERSION); static int hvcs_convert(long to_convert) { switch (to_convert) { - case H_Success: + case H_SUCCESS: return 0; - case H_Parameter: + case H_PARAMETER: return -EINVAL; - case H_Hardware: + case H_HARDWARE: return -EIO; - case H_Busy: - case H_LongBusyOrder1msec: - case H_LongBusyOrder10msec: - case H_LongBusyOrder100msec: - case H_LongBusyOrder1sec: - case H_LongBusyOrder10sec: - case H_LongBusyOrder100sec: + case H_BUSY: + case H_LONG_BUSY_ORDER_1_MSEC: + case H_LONG_BUSY_ORDER_10_MSEC: + case H_LONG_BUSY_ORDER_100_MSEC: + case H_LONG_BUSY_ORDER_1_SEC: + case H_LONG_BUSY_ORDER_10_SEC: + case H_LONG_BUSY_ORDER_100_SEC: return -EBUSY; - case H_Function: /* fall through */ + case H_FUNCTION: /* fall through */ default: return -EPERM; } diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 8952528d31a..634b7d06d3c 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -54,7 +54,8 @@ EXPORT_SYMBOL(plpar_hcall); EXPORT_SYMBOL(plpar_hcall_4out); EXPORT_SYMBOL(plpar_hcall_norets); EXPORT_SYMBOL(plpar_hcall_8arg_2ret); - +EXPORT_SYMBOL(plpar_hcall_7arg_7ret); +EXPORT_SYMBOL(plpar_hcall_9arg_9ret); extern void pSeries_find_serial_port(void); @@ -72,7 +73,7 @@ static void udbg_hvsi_putc(char c) do { rc = plpar_put_term_char(vtermno, sizeof(packet), packet); - } while (rc == H_Busy); + } while (rc == H_BUSY); } static long hvsi_udbg_buf_len; @@ -85,7 +86,7 @@ static int udbg_hvsi_getc_poll(void) if (hvsi_udbg_buf_len == 0) { rc = plpar_get_term_char(vtermno, &hvsi_udbg_buf_len, hvsi_udbg_buf); - if (rc != H_Success || hvsi_udbg_buf[0] != 0xff) { + if (rc != H_SUCCESS || hvsi_udbg_buf[0] != 0xff) { /* bad read or non-data packet */ hvsi_udbg_buf_len = 0; } else { @@ -139,7 +140,7 @@ static void udbg_putcLP(char c) buf[0] = c; do { rc = plpar_put_term_char(vtermno, 1, buf); - } while(rc == H_Busy); + } while(rc == H_BUSY); } /* Buffered chars getc */ @@ -158,7 +159,7 @@ static int udbg_getc_pollLP(void) /* get some more chars. */ inbuflen = 0; rc = plpar_get_term_char(vtermno, &inbuflen, buf); - if (rc != H_Success) + if (rc != H_SUCCESS) inbuflen = 0; /* otherwise inbuflen is garbage */ } if (inbuflen <= 0 || inbuflen > 16) { @@ -304,7 +305,7 @@ long pSeries_lpar_hpte_insert(unsigned long hpte_group, lpar_rc = plpar_hcall(H_ENTER, flags, hpte_group, hpte_v, hpte_r, &slot, &dummy0, &dummy1); - if (unlikely(lpar_rc == H_PTEG_Full)) { + if (unlikely(lpar_rc == H_PTEG_FULL)) { if (!(vflags & HPTE_V_BOLTED)) DBG_LOW(" full\n"); return -1; @@ -315,7 +316,7 @@ long pSeries_lpar_hpte_insert(unsigned long hpte_group, * will fail. However we must catch the failure in hash_page * or we will loop forever, so return -2 in this case. */ - if (unlikely(lpar_rc != H_Success)) { + if (unlikely(lpar_rc != H_SUCCESS)) { if (!(vflags & HPTE_V_BOLTED)) DBG_LOW(" lpar err %d\n", lpar_rc); return -2; @@ -346,9 +347,9 @@ static long pSeries_lpar_hpte_remove(unsigned long hpte_group) /* don't remove a bolted entry */ lpar_rc = plpar_pte_remove(H_ANDCOND, hpte_group + slot_offset, (0x1UL << 4), &dummy1, &dummy2); - if (lpar_rc == H_Success) + if (lpar_rc == H_SUCCESS) return i; - BUG_ON(lpar_rc != H_Not_Found); + BUG_ON(lpar_rc != H_NOT_FOUND); slot_offset++; slot_offset &= 0x7; @@ -391,14 +392,14 @@ static long pSeries_lpar_hpte_updatepp(unsigned long slot, lpar_rc = plpar_pte_protect(flags, slot, want_v & HPTE_V_AVPN); - if (lpar_rc == H_Not_Found) { + if (lpar_rc == H_NOT_FOUND) { DBG_LOW("not found !\n"); return -1; } DBG_LOW("ok\n"); - BUG_ON(lpar_rc != H_Success); + BUG_ON(lpar_rc != H_SUCCESS); return 0; } @@ -417,7 +418,7 @@ static unsigned long pSeries_lpar_hpte_getword0(unsigned long slot) lpar_rc = plpar_pte_read(flags, slot, &dword0, &dummy_word1); - BUG_ON(lpar_rc != H_Success); + BUG_ON(lpar_rc != H_SUCCESS); return dword0; } @@ -468,7 +469,7 @@ static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp, flags = newpp & 7; lpar_rc = plpar_pte_protect(flags, slot, 0); - BUG_ON(lpar_rc != H_Success); + BUG_ON(lpar_rc != H_SUCCESS); } static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, @@ -484,10 +485,10 @@ static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, want_v = hpte_encode_v(va, psize); lpar_rc = plpar_pte_remove(H_AVPN, slot, want_v & HPTE_V_AVPN, &dummy1, &dummy2); - if (lpar_rc == H_Not_Found) + if (lpar_rc == H_NOT_FOUND) return; - BUG_ON(lpar_rc != H_Success); + BUG_ON(lpar_rc != H_SUCCESS); } /* diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index b2fbf8ba8fb..5eb55ef1c91 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -463,7 +463,7 @@ static void pseries_dedicated_idle_sleep(void) * very low priority. The cede enables interrupts, which * doesn't matter here. */ - if (!lppaca[cpu ^ 1].idle || poll_pending() == H_Pending) + if (!lppaca[cpu ^ 1].idle || poll_pending() == H_PENDING) cede_processor(); out: diff --git a/arch/powerpc/platforms/pseries/vio.c b/arch/powerpc/platforms/pseries/vio.c index 866379b80c0..8e53e04ada8 100644 --- a/arch/powerpc/platforms/pseries/vio.c +++ b/arch/powerpc/platforms/pseries/vio.c @@ -258,7 +258,7 @@ EXPORT_SYMBOL(vio_find_node); int vio_enable_interrupts(struct vio_dev *dev) { int rc = h_vio_signal(dev->unit_address, VIO_IRQ_ENABLE); - if (rc != H_Success) + if (rc != H_SUCCESS) printk(KERN_ERR "vio: Error 0x%x enabling interrupts\n", rc); return rc; } @@ -267,7 +267,7 @@ EXPORT_SYMBOL(vio_enable_interrupts); int vio_disable_interrupts(struct vio_dev *dev) { int rc = h_vio_signal(dev->unit_address, VIO_IRQ_DISABLE); - if (rc != H_Success) + if (rc != H_SUCCESS) printk(KERN_ERR "vio: Error 0x%x disabling interrupts\n", rc); return rc; } diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index 4864cb32be2..2d60ea30fed 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c @@ -168,7 +168,7 @@ static int pSeriesLP_xirr_info_get(int n_cpu) unsigned long return_value; lpar_rc = plpar_xirr(&return_value); - if (lpar_rc != H_Success) + if (lpar_rc != H_SUCCESS) panic(" bad return code xirr - rc = %lx \n", lpar_rc); return (int)return_value; } @@ -179,7 +179,7 @@ static void pSeriesLP_xirr_info_set(int n_cpu, int value) unsigned long val64 = value & 0xffffffff; lpar_rc = plpar_eoi(val64); - if (lpar_rc != H_Success) + if (lpar_rc != H_SUCCESS) panic("bad return code EOI - rc = %ld, value=%lx\n", lpar_rc, val64); } @@ -189,7 +189,7 @@ void pSeriesLP_cppr_info(int n_cpu, u8 value) unsigned long lpar_rc; lpar_rc = plpar_cppr(value); - if (lpar_rc != H_Success) + if (lpar_rc != H_SUCCESS) panic("bad return code cppr - rc = %lx\n", lpar_rc); } @@ -198,7 +198,7 @@ static void pSeriesLP_qirr_info(int n_cpu , u8 value) unsigned long lpar_rc; lpar_rc = plpar_ipi(get_hard_smp_processor_id(n_cpu), value); - if (lpar_rc != H_Success) + if (lpar_rc != H_SUCCESS) panic("bad return code qirr - rc = %lx\n", lpar_rc); } diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 2b8841f8553..343120c9223 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -801,7 +801,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus) */ print_cpu_info(&S390_lowcore.cpu_data); - for_each_cpu(i) { + for_each_possible_cpu(i) { lowcore_ptr[i] = (struct _lowcore *) __get_free_pages(GFP_KERNEL|GFP_DMA, sizeof(void*) == 8 ? 1 : 0); @@ -831,7 +831,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus) #endif set_prefix((u32)(unsigned long) lowcore_ptr[smp_processor_id()]); - for_each_cpu(cpu) + for_each_possible_cpu(cpu) if (cpu != smp_processor_id()) smp_create_idle(cpu); } @@ -868,7 +868,7 @@ static int __init topology_init(void) int cpu; int ret; - for_each_cpu(cpu) { + for_each_possible_cpu(cpu) { ret = register_cpu(&per_cpu(cpu_devices, cpu), cpu, NULL); if (ret) printk(KERN_WARNING "topology_init: register_cpu %d " diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c index cf94e8ef17c..868e68b2888 100644 --- a/arch/sh/kernel/cpu/init.c +++ b/arch/sh/kernel/cpu/init.c @@ -30,7 +30,7 @@ static int x##_disabled __initdata = 0; \ static int __init x##_setup(char *opts) \ { \ x##_disabled = 1; \ - return 0; \ + return 1; \ } \ __setup("no" __stringify(x), x##_setup); diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 7ee4ca20361..bb229ef030f 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -401,7 +401,7 @@ static int __init topology_init(void) { int cpu_id; - for_each_cpu(cpu_id) + for_each_possible_cpu(cpu_id) register_cpu(&cpu[cpu_id], cpu_id, NULL); return 0; diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S index 768de64b371..fbbec5e761c 100644 --- a/arch/sparc/kernel/systbls.S +++ b/arch/sparc/kernel/systbls.S @@ -64,13 +64,13 @@ sys_call_table: /*215*/ .long sys_ipc, sys_sigreturn, sys_clone, sys_ioprio_get, sys_adjtimex /*220*/ .long sys_sigprocmask, sys_ni_syscall, sys_delete_module, sys_ni_syscall, sys_getpgid /*225*/ .long sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid16, sys_setfsgid16 -/*230*/ .long sys_select, sys_time, sys_nis_syscall, sys_stime, sys_statfs64 +/*230*/ .long sys_select, sys_time, sys_splice, sys_stime, sys_statfs64 /* "We are the Knights of the Forest of Ni!!" */ /*235*/ .long sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys_mlockall /*240*/ .long sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler /*245*/ .long sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep /*250*/ .long sparc_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl -/*255*/ .long sys_nis_syscall, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep +/*255*/ .long sys_sync_file_range, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep /*260*/ .long sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun /*265*/ .long sys_timer_delete, sys_timer_create, sys_nis_syscall, sys_io_setup, sys_io_destroy /*270*/ .long sys_io_submit, sys_io_cancel, sys_io_getevents, sys_mq_open, sys_mq_unlink diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index 900fb0b940d..30389085a35 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.16 -# Sun Mar 26 14:58:11 2006 +# Fri Mar 31 01:40:57 2006 # CONFIG_SPARC=y CONFIG_SPARC64=y @@ -180,6 +180,7 @@ CONFIG_SYN_COOKIES=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y +CONFIG_INET_XFRM_TUNNEL=y CONFIG_INET_TUNNEL=y CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y @@ -203,6 +204,7 @@ CONFIG_IPV6_ROUTE_INFO=y CONFIG_INET6_AH=m CONFIG_INET6_ESP=m CONFIG_INET6_IPCOMP=m +CONFIG_INET6_XFRM_TUNNEL=m CONFIG_INET6_TUNNEL=m CONFIG_IPV6_TUNNEL=m # CONFIG_NETFILTER is not set @@ -308,7 +310,6 @@ CONFIG_BLK_DEV_NBD=m # CONFIG_BLK_DEV_SX8 is not set CONFIG_BLK_DEV_UB=m # CONFIG_BLK_DEV_RAM is not set -CONFIG_BLK_DEV_RAM_COUNT=16 # CONFIG_BLK_DEV_INITRD is not set CONFIG_CDROM_PKTCDVD=m CONFIG_CDROM_PKTCDVD_BUFFERS=8 @@ -449,6 +450,7 @@ CONFIG_MD_RAID0=m CONFIG_MD_RAID1=m CONFIG_MD_RAID10=m CONFIG_MD_RAID5=m +# CONFIG_MD_RAID5_RESHAPE is not set CONFIG_MD_RAID6=m CONFIG_MD_MULTIPATH=m # CONFIG_MD_FAULTY is not set @@ -741,9 +743,7 @@ CONFIG_I2C_ALGOBIT=y # CONFIG_SENSORS_PCF8574 is not set # CONFIG_SENSORS_PCA9539 is not set # CONFIG_SENSORS_PCF8591 is not set -# CONFIG_SENSORS_RTC8564 is not set # CONFIG_SENSORS_MAX6875 is not set -# CONFIG_RTC_X1205_I2C is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set @@ -826,6 +826,7 @@ CONFIG_FB_CFB_FILLRECT=y CONFIG_FB_CFB_COPYAREA=y CONFIG_FB_CFB_IMAGEBLIT=y # CONFIG_FB_MACMODES is not set +# CONFIG_FB_FIRMWARE_EDID is not set CONFIG_FB_MODE_HELPERS=y CONFIG_FB_TILEBLITTING=y # CONFIG_FB_CIRRUS is not set @@ -1117,6 +1118,11 @@ CONFIG_USB_HIDDEV=y # # +# Real Time Clock +# +# CONFIG_RTC_CLASS is not set + +# # Misc Linux/SPARC drivers # CONFIG_SUN_OPENPROMIO=m diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 7dc28a48426..8175a6968c6 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -830,9 +830,16 @@ void smp_call_function_client(int irq, struct pt_regs *regs) static void tsb_sync(void *info) { + struct trap_per_cpu *tp = &trap_block[raw_smp_processor_id()]; struct mm_struct *mm = info; - if (current->active_mm == mm) + /* It is not valid to test "currrent->active_mm == mm" here. + * + * The value of "current" is not changed atomically with + * switch_mm(). But that's OK, we just need to check the + * current cpu's trap block PGD physical address. + */ + if (tp->pgd_paddr == __pa(mm->pgd)) tsb_context_switch(mm); } diff --git a/arch/sparc64/kernel/sys32.S b/arch/sparc64/kernel/sys32.S index c4a1cef4b1e..86dd5cb81e0 100644 --- a/arch/sparc64/kernel/sys32.S +++ b/arch/sparc64/kernel/sys32.S @@ -136,6 +136,8 @@ SIGN1(sys32_getpeername, sys_getpeername, %o0) SIGN1(sys32_getsockname, sys_getsockname, %o0) SIGN2(sys32_ioprio_get, sys_ioprio_get, %o0, %o1) SIGN3(sys32_ioprio_set, sys_ioprio_set, %o0, %o1, %o2) +SIGN2(sys32_splice, sys_splice, %o0, %o1) +SIGN2(sys32_sync_file_range, compat_sync_file_range, %o0, %o5) .globl sys32_mmap2 sys32_mmap2: diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index 2e906bad56f..31030bf00f1 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -1069,3 +1069,11 @@ long sys32_lookup_dcookie(unsigned long cookie_high, return sys_lookup_dcookie((cookie_high << 32) | cookie_low, buf, len); } + +long compat_sync_file_range(int fd, unsigned long off_high, unsigned long off_low, unsigned long nb_high, unsigned long nb_low, int flags) +{ + return sys_sync_file_range(fd, + (off_high << 32) | off_low, + (nb_high << 32) | nb_low, + flags); +} diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S index 3b250f2318f..857b82c8287 100644 --- a/arch/sparc64/kernel/systbls.S +++ b/arch/sparc64/kernel/systbls.S @@ -66,12 +66,12 @@ sys_call_table32: .word sys32_ipc, sys32_sigreturn, sys_clone, sys32_ioprio_get, compat_sys_adjtimex /*220*/ .word sys32_sigprocmask, sys_ni_syscall, sys32_delete_module, sys_ni_syscall, sys32_getpgid .word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys32_setfsuid16, sys32_setfsgid16 -/*230*/ .word sys32_select, compat_sys_time, sys_nis_syscall, compat_sys_stime, compat_sys_statfs64 +/*230*/ .word sys32_select, compat_sys_time, sys32_splice, compat_sys_stime, compat_sys_statfs64 .word compat_sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys32_mlockall /*240*/ .word sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys32_sched_setscheduler, sys32_sched_getscheduler .word sys_sched_yield, sys32_sched_get_priority_max, sys32_sched_get_priority_min, sys32_sched_rr_get_interval, compat_sys_nanosleep /*250*/ .word sys32_mremap, sys32_sysctl, sys32_getsid, sys_fdatasync, sys32_nfsservctl - .word sys_ni_syscall, compat_sys_clock_settime, compat_sys_clock_gettime, compat_sys_clock_getres, sys32_clock_nanosleep + .word sys32_sync_file_range, compat_sys_clock_settime, compat_sys_clock_gettime, compat_sys_clock_getres, sys32_clock_nanosleep /*260*/ .word compat_sys_sched_getaffinity, compat_sys_sched_setaffinity, sys32_timer_settime, compat_sys_timer_gettime, sys_timer_getoverrun .word sys_timer_delete, compat_sys_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy /*270*/ .word sys32_io_submit, sys_io_cancel, compat_sys_io_getevents, sys32_mq_open, sys_mq_unlink @@ -135,12 +135,12 @@ sys_call_table: .word sys_ipc, sys_nis_syscall, sys_clone, sys_ioprio_get, sys_adjtimex /*220*/ .word sys_nis_syscall, sys_ni_syscall, sys_delete_module, sys_ni_syscall, sys_getpgid .word sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid -/*230*/ .word sys_select, sys_nis_syscall, sys_nis_syscall, sys_stime, sys_statfs64 +/*230*/ .word sys_select, sys_nis_syscall, sys_splice, sys_stime, sys_statfs64 .word sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys_mlockall /*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler .word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep /*250*/ .word sys64_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl - .word sys_ni_syscall, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep + .word sys_sync_file_range, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep /*260*/ .word sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun .word sys_timer_delete, sys_timer_create, sys_ni_syscall, sys_io_setup, sys_io_destroy /*270*/ .word sys_io_submit, sys_io_cancel, sys_io_getevents, sys_mq_open, sys_mq_unlink diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c index 0db2f7d9fab..6e002aacb96 100644 --- a/arch/sparc64/mm/fault.c +++ b/arch/sparc64/mm/fault.c @@ -327,8 +327,12 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) insn = get_fault_insn(regs, 0); if (!insn) goto continue_fault; + /* All loads, stores and atomics have bits 30 and 31 both set + * in the instruction. Bit 21 is set in all stores, but we + * have to avoid prefetches which also have bit 21 set. + */ if ((insn & 0xc0200000) == 0xc0200000 && - (insn & 0x1780000) != 0x1680000) { + (insn & 0x01780000) != 0x01680000) { /* Don't bother updating thread struct value, * because update_mmu_cache only cares which tlb * the access came from. diff --git a/arch/sparc64/mm/hugetlbpage.c b/arch/sparc64/mm/hugetlbpage.c index 074620d413d..fbbbebbad8a 100644 --- a/arch/sparc64/mm/hugetlbpage.c +++ b/arch/sparc64/mm/hugetlbpage.c @@ -198,6 +198,13 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) pmd_t *pmd; pte_t *pte = NULL; + /* We must align the address, because our caller will run + * set_huge_pte_at() on whatever we return, which writes out + * all of the sub-ptes for the hugepage range. So we have + * to give it the first such sub-pte. + */ + addr &= HPAGE_MASK; + pgd = pgd_offset(mm, addr); pud = pud_alloc(mm, pgd, addr); if (pud) { diff --git a/arch/um/Kconfig b/arch/um/Kconfig index 5982fe2753e..05fbb20636c 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -22,6 +22,9 @@ config SBUS config PCI bool +config PCMCIA + bool + config GENERIC_CALIBRATE_DELAY bool default y diff --git a/arch/um/Makefile b/arch/um/Makefile index 8d14c7a831b..24790bed205 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -20,7 +20,7 @@ core-y += $(ARCH_DIR)/kernel/ \ # Have to precede the include because the included Makefiles reference them. SYMLINK_HEADERS := archparam.h system.h sigcontext.h processor.h ptrace.h \ - module.h vm-flags.h elf.h ldt.h + module.h vm-flags.h elf.h host_ldt.h SYMLINK_HEADERS := $(foreach header,$(SYMLINK_HEADERS),include/asm-um/$(header)) # XXX: The "os" symlink is only used by arch/um/include/os.h, which includes @@ -129,7 +129,7 @@ CPPFLAGS_vmlinux.lds = -U$(SUBARCH) \ -DSTART=$(START) -DELF_ARCH=$(ELF_ARCH) \ -DELF_FORMAT="$(ELF_FORMAT)" $(CPP_MODE-y) \ -DKERNEL_STACK_SIZE=$(STACK_SIZE) \ - -DUNMAP_PATH=arch/um/sys-$(SUBARCH)/unmap_fin.o + -DUNMAP_PATH=arch/um/sys-$(SUBARCH)/unmap.o #The wrappers will select whether using "malloc" or the kernel allocator. LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc @@ -150,8 +150,7 @@ CLEAN_FILES += linux x.i gmon.out $(ARCH_DIR)/include/uml-config.h \ $(ARCH_DIR)/include/user_constants.h \ $(ARCH_DIR)/include/kern_constants.h $(ARCH_DIR)/Kconfig.arch -MRPROPER_FILES += $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) \ - $(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS)) $(ARCH_DIR)/os +MRPROPER_FILES += $(ARCH_SYMLINKS) archclean: @find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \ diff --git a/arch/um/Makefile-x86_64 b/arch/um/Makefile-x86_64 index 38df311e75d..dfd88b652fb 100644 --- a/arch/um/Makefile-x86_64 +++ b/arch/um/Makefile-x86_64 @@ -1,7 +1,7 @@ # Copyright 2003 - 2004 Pathscale, Inc # Released under the GPL -libs-y += arch/um/sys-x86_64/ +core-y += arch/um/sys-x86_64/ START := 0x60000000 #We #undef __x86_64__ for kernelspace, not for userspace where diff --git a/arch/um/drivers/daemon_kern.c b/arch/um/drivers/daemon_kern.c index a61b7b46bc0..53d09ed78b4 100644 --- a/arch/um/drivers/daemon_kern.c +++ b/arch/um/drivers/daemon_kern.c @@ -95,18 +95,7 @@ static struct transport daemon_transport = { static int register_daemon(void) { register_transport(&daemon_transport); - return(1); + return 0; } __initcall(register_daemon); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/harddog_kern.c b/arch/um/drivers/harddog_kern.c index 49acb2badf3..d18a974735e 100644 --- a/arch/um/drivers/harddog_kern.c +++ b/arch/um/drivers/harddog_kern.c @@ -104,7 +104,7 @@ static int harddog_release(struct inode *inode, struct file *file) extern int ping_watchdog(int fd); -static ssize_t harddog_write(struct file *file, const char *data, size_t len, +static ssize_t harddog_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) { /* @@ -118,6 +118,7 @@ static ssize_t harddog_write(struct file *file, const char *data, size_t len, static int harddog_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { + void __user *argp= (void __user *)arg; static struct watchdog_info ident = { WDIOC_SETTIMEOUT, 0, @@ -127,13 +128,12 @@ static int harddog_ioctl(struct inode *inode, struct file *file, default: return -ENOTTY; case WDIOC_GETSUPPORT: - if(copy_to_user((struct harddog_info *)arg, &ident, - sizeof(ident))) + if(copy_to_user(argp, &ident, sizeof(ident))) return -EFAULT; return 0; case WDIOC_GETSTATUS: case WDIOC_GETBOOTSTATUS: - return put_user(0,(int *)arg); + return put_user(0,(int __user *)argp); case WDIOC_KEEPALIVE: return(ping_watchdog(harddog_out_fd)); } diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c index 59602b81b24..37232f908cd 100644 --- a/arch/um/drivers/hostaudio_kern.c +++ b/arch/um/drivers/hostaudio_kern.c @@ -67,8 +67,8 @@ MODULE_PARM_DESC(mixer, MIXER_HELP); /* /dev/dsp file operations */ -static ssize_t hostaudio_read(struct file *file, char *buffer, size_t count, - loff_t *ppos) +static ssize_t hostaudio_read(struct file *file, char __user *buffer, + size_t count, loff_t *ppos) { struct hostaudio_state *state = file->private_data; void *kbuf; @@ -94,7 +94,7 @@ static ssize_t hostaudio_read(struct file *file, char *buffer, size_t count, return(err); } -static ssize_t hostaudio_write(struct file *file, const char *buffer, +static ssize_t hostaudio_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { struct hostaudio_state *state = file->private_data; @@ -152,7 +152,7 @@ static int hostaudio_ioctl(struct inode *inode, struct file *file, case SNDCTL_DSP_CHANNELS: case SNDCTL_DSP_SUBDIVIDE: case SNDCTL_DSP_SETFRAGMENT: - if(get_user(data, (int *) arg)) + if(get_user(data, (int __user *) arg)) return(-EFAULT); break; default: @@ -168,7 +168,7 @@ static int hostaudio_ioctl(struct inode *inode, struct file *file, case SNDCTL_DSP_CHANNELS: case SNDCTL_DSP_SUBDIVIDE: case SNDCTL_DSP_SETFRAGMENT: - if(put_user(data, (int *) arg)) + if(put_user(data, (int __user *) arg)) return(-EFAULT); break; default: diff --git a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c index c9b078fba03..3a7af18cf94 100644 --- a/arch/um/drivers/mcast_kern.c +++ b/arch/um/drivers/mcast_kern.c @@ -124,18 +124,7 @@ static struct transport mcast_transport = { static int register_mcast(void) { register_transport(&mcast_transport); - return(1); + return 0; } __initcall(register_mcast); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index 1488816588e..28e3760e8b9 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -20,6 +20,8 @@ #include "linux/namei.h" #include "linux/proc_fs.h" #include "linux/syscalls.h" +#include "linux/list.h" +#include "linux/mm.h" #include "linux/console.h" #include "asm/irq.h" #include "asm/uaccess.h" @@ -347,6 +349,142 @@ static struct mc_device *mconsole_find_dev(char *name) return(NULL); } +#define UNPLUGGED_PER_PAGE \ + ((PAGE_SIZE - sizeof(struct list_head)) / sizeof(unsigned long)) + +struct unplugged_pages { + struct list_head list; + void *pages[UNPLUGGED_PER_PAGE]; +}; + +static unsigned long long unplugged_pages_count = 0; +static struct list_head unplugged_pages = LIST_HEAD_INIT(unplugged_pages); +static int unplug_index = UNPLUGGED_PER_PAGE; + +static int mem_config(char *str) +{ + unsigned long long diff; + int err = -EINVAL, i, add; + char *ret; + + if(str[0] != '=') + goto out; + + str++; + if(str[0] == '-') + add = 0; + else if(str[0] == '+'){ + add = 1; + } + else goto out; + + str++; + diff = memparse(str, &ret); + if(*ret != '\0') + goto out; + + diff /= PAGE_SIZE; + + for(i = 0; i < diff; i++){ + struct unplugged_pages *unplugged; + void *addr; + + if(add){ + if(list_empty(&unplugged_pages)) + break; + + unplugged = list_entry(unplugged_pages.next, + struct unplugged_pages, list); + if(unplug_index > 0) + addr = unplugged->pages[--unplug_index]; + else { + list_del(&unplugged->list); + addr = unplugged; + unplug_index = UNPLUGGED_PER_PAGE; + } + + free_page((unsigned long) addr); + unplugged_pages_count--; + } + else { + struct page *page; + + page = alloc_page(GFP_ATOMIC); + if(page == NULL) + break; + + unplugged = page_address(page); + if(unplug_index == UNPLUGGED_PER_PAGE){ + INIT_LIST_HEAD(&unplugged->list); + list_add(&unplugged->list, &unplugged_pages); + unplug_index = 0; + } + else { + struct list_head *entry = unplugged_pages.next; + addr = unplugged; + + unplugged = list_entry(entry, + struct unplugged_pages, + list); + unplugged->pages[unplug_index++] = addr; + err = os_drop_memory(addr, PAGE_SIZE); + if(err) + printk("Failed to release memory - " + "errno = %d\n", err); + } + + unplugged_pages_count++; + } + } + + err = 0; +out: + return err; +} + +static int mem_get_config(char *name, char *str, int size, char **error_out) +{ + char buf[sizeof("18446744073709551615")]; + int len = 0; + + sprintf(buf, "%ld", uml_physmem); + CONFIG_CHUNK(str, size, len, buf, 1); + + return len; +} + +static int mem_id(char **str, int *start_out, int *end_out) +{ + *start_out = 0; + *end_out = 0; + + return 0; +} + +static int mem_remove(int n) +{ + return -EBUSY; +} + +static struct mc_device mem_mc = { + .name = "mem", + .config = mem_config, + .get_config = mem_get_config, + .id = mem_id, + .remove = mem_remove, +}; + +static int mem_mc_init(void) +{ + if(can_drop_memory()) + mconsole_register_dev(&mem_mc); + else printk("Can't release memory to the host - memory hotplug won't " + "be supported\n"); + return 0; +} + +__initcall(mem_mc_init); + #define CONFIG_BUF_SIZE 64 static void mconsole_get_config(int (*get_config)(char *, char *, int, @@ -478,7 +616,7 @@ static void console_write(struct console *console, const char *string, return; while(1){ - n = min(len, ARRAY_SIZE(console_buf) - console_index); + n = min((size_t)len, ARRAY_SIZE(console_buf) - console_index); strncpy(&console_buf[console_index], string, n); console_index += n; string += n; diff --git a/arch/um/drivers/pcap_kern.c b/arch/um/drivers/pcap_kern.c index 07c80f2156e..466ff2c2f91 100644 --- a/arch/um/drivers/pcap_kern.c +++ b/arch/um/drivers/pcap_kern.c @@ -106,18 +106,7 @@ static struct transport pcap_transport = { static int register_pcap(void) { register_transport(&pcap_transport); - return(1); + return 0; } __initcall(register_pcap); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/slip_kern.c b/arch/um/drivers/slip_kern.c index a62f5ef445c..163ee0d5f75 100644 --- a/arch/um/drivers/slip_kern.c +++ b/arch/um/drivers/slip_kern.c @@ -93,18 +93,7 @@ static struct transport slip_transport = { static int register_slip(void) { register_transport(&slip_transport); - return(1); + return 0; } __initcall(register_slip); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/slirp_kern.c b/arch/um/drivers/slirp_kern.c index 33d7982be5d..95e50c943e1 100644 --- a/arch/um/drivers/slirp_kern.c +++ b/arch/um/drivers/slirp_kern.c @@ -77,7 +77,7 @@ static int slirp_setup(char *str, char **mac_out, void *data) int i=0; *init = ((struct slirp_init) - { argw : { { "slirp", NULL } } }); + { .argw = { { "slirp", NULL } } }); str = split_if_spec(str, mac_out, NULL); @@ -116,18 +116,7 @@ static struct transport slirp_transport = { static int register_slirp(void) { register_transport(&slirp_transport); - return(1); + return 0; } __initcall(register_slirp); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 0336575d244..0897852b09a 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -891,7 +891,7 @@ int ubd_driver_init(void){ SA_INTERRUPT, "ubd", ubd_dev); if(err != 0) printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err); - return(err); + return 0; } device_initcall(ubd_driver_init); diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h index 07176d92e1c..42557130a40 100644 --- a/arch/um/include/kern_util.h +++ b/arch/um/include/kern_util.h @@ -116,7 +116,11 @@ extern void *get_current(void); extern struct task_struct *get_task(int pid, int require); extern void machine_halt(void); extern int is_syscall(unsigned long addr); -extern void arch_switch(void); + +extern void arch_switch_to_tt(struct task_struct *from, struct task_struct *to); + +extern void arch_switch_to_skas(struct task_struct *from, struct task_struct *to); + extern void free_irq(unsigned int, void *); extern int cpu(void); diff --git a/arch/um/include/line.h b/arch/um/include/line.h index 6f4d680dc1d..6ac0f8252e2 100644 --- a/arch/um/include/line.h +++ b/arch/um/include/line.h @@ -58,23 +58,17 @@ struct line { }; #define LINE_INIT(str, d) \ - { init_str : str, \ - init_pri : INIT_STATIC, \ - valid : 1, \ - throttled : 0, \ - lock : SPIN_LOCK_UNLOCKED, \ - buffer : NULL, \ - head : NULL, \ - tail : NULL, \ - sigio : 0, \ - driver : d, \ - have_irq : 0 } + { .init_str = str, \ + .init_pri = INIT_STATIC, \ + .valid = 1, \ + .lock = SPIN_LOCK_UNLOCKED, \ + .driver = d } struct lines { int num; }; -#define LINES_INIT(n) { num : n } +#define LINES_INIT(n) { .num = n } extern void line_close(struct tty_struct *tty, struct file * filp); extern int line_open(struct line *lines, struct tty_struct *tty); diff --git a/arch/um/include/mem_user.h b/arch/um/include/mem_user.h index a1064c5823b..a54514d2cc3 100644 --- a/arch/um/include/mem_user.h +++ b/arch/um/include/mem_user.h @@ -49,7 +49,6 @@ extern int iomem_size; extern unsigned long host_task_size; extern unsigned long task_size; -extern void check_devanon(void); extern int init_mem_user(void); extern void setup_memory(void *entry); extern unsigned long find_iomem(char *driver, unsigned long *len_out); diff --git a/arch/um/include/os.h b/arch/um/include/os.h index d3d1bc6074e..f88856c28a6 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h @@ -13,6 +13,7 @@ #include "kern_util.h" #include "skas/mm_id.h" #include "irq_user.h" +#include "sysdep/tls.h" #define OS_TYPE_FILE 1 #define OS_TYPE_DIR 2 @@ -172,6 +173,7 @@ extern int os_fchange_dir(int fd); extern void os_early_checks(void); extern int can_do_skas(void); extern void os_check_bugs(void); +extern void check_host_supports_tls(int *supports_tls, int *tls_min); /* Make sure they are clear when running in TT mode. Required by * SEGV_MAYBE_FIXABLE */ @@ -205,6 +207,8 @@ extern int os_map_memory(void *virt, int fd, unsigned long long off, extern int os_protect_memory(void *addr, unsigned long len, int r, int w, int x); extern int os_unmap_memory(void *addr, int len); +extern int os_drop_memory(void *addr, int length); +extern int can_drop_memory(void); extern void os_flush_stdout(void); /* tt.c @@ -234,8 +238,12 @@ extern int run_helper_thread(int (*proc)(void *), void *arg, int stack_order); extern int helper_wait(int pid); -/* umid.c */ +/* tls.c */ +extern int os_set_thread_area(user_desc_t *info, int pid); +extern int os_get_thread_area(user_desc_t *info, int pid); + +/* umid.c */ extern int umid_file_name(char *name, char *buf, int len); extern int set_umid(char *name); extern char *get_umid(void); diff --git a/arch/um/include/sysdep-i386/checksum.h b/arch/um/include/sysdep-i386/checksum.h index 7d3d202d7ff..052bb061a97 100644 --- a/arch/um/include/sysdep-i386/checksum.h +++ b/arch/um/include/sysdep-i386/checksum.h @@ -48,7 +48,8 @@ unsigned int csum_partial_copy_nocheck(const unsigned char *src, unsigned char * */ static __inline__ -unsigned int csum_partial_copy_from_user(const unsigned char *src, unsigned char *dst, +unsigned int csum_partial_copy_from_user(const unsigned char __user *src, + unsigned char *dst, int len, int sum, int *err_ptr) { if(copy_from_user(dst, src, len)){ @@ -192,7 +193,7 @@ static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr, */ #define HAVE_CSUM_COPY_USER static __inline__ unsigned int csum_and_copy_to_user(const unsigned char *src, - unsigned char *dst, + unsigned char __user *dst, int len, int sum, int *err_ptr) { if (access_ok(VERIFY_WRITE, dst, len)){ diff --git a/arch/um/include/sysdep-i386/ptrace.h b/arch/um/include/sysdep-i386/ptrace.h index c8ee9559f3a..6670cc992ec 100644 --- a/arch/um/include/sysdep-i386/ptrace.h +++ b/arch/um/include/sysdep-i386/ptrace.h @@ -14,7 +14,12 @@ #define MAX_REG_NR (UM_FRAME_SIZE / sizeof(unsigned long)) #define MAX_REG_OFFSET (UM_FRAME_SIZE) +#ifdef UML_CONFIG_PT_PROXY extern void update_debugregs(int seq); +#else +static inline void update_debugregs(int seq) {} +#endif + /* syscall emulation path in ptrace */ diff --git a/arch/um/include/sysdep-i386/tls.h b/arch/um/include/sysdep-i386/tls.h new file mode 100644 index 00000000000..918fd3c5ff9 --- /dev/null +++ b/arch/um/include/sysdep-i386/tls.h @@ -0,0 +1,32 @@ +#ifndef _SYSDEP_TLS_H +#define _SYSDEP_TLS_H + +# ifndef __KERNEL__ + +/* Change name to avoid conflicts with the original one from <asm/ldt.h>, which + * may be named user_desc (but in 2.4 and in header matching its API was named + * modify_ldt_ldt_s). */ + +typedef struct um_dup_user_desc { + unsigned int entry_number; + unsigned int base_addr; + unsigned int limit; + unsigned int seg_32bit:1; + unsigned int contents:2; + unsigned int read_exec_only:1; + unsigned int limit_in_pages:1; + unsigned int seg_not_present:1; + unsigned int useable:1; +} user_desc_t; + +# else /* __KERNEL__ */ + +# include <asm/ldt.h> +typedef struct user_desc user_desc_t; + +# endif /* __KERNEL__ */ + +#define GDT_ENTRY_TLS_MIN_I386 6 +#define GDT_ENTRY_TLS_MIN_X86_64 12 + +#endif /* _SYSDEP_TLS_H */ diff --git a/arch/um/include/sysdep-x86_64/tls.h b/arch/um/include/sysdep-x86_64/tls.h new file mode 100644 index 00000000000..35f19f25bd3 --- /dev/null +++ b/arch/um/include/sysdep-x86_64/tls.h @@ -0,0 +1,29 @@ +#ifndef _SYSDEP_TLS_H +#define _SYSDEP_TLS_H + +# ifndef __KERNEL__ + +/* Change name to avoid conflicts with the original one from <asm/ldt.h>, which + * may be named user_desc (but in 2.4 and in header matching its API was named + * modify_ldt_ldt_s). */ + +typedef struct um_dup_user_desc { + unsigned int entry_number; + unsigned int base_addr; + unsigned int limit; + unsigned int seg_32bit:1; + unsigned int contents:2; + unsigned int read_exec_only:1; + unsigned int limit_in_pages:1; + unsigned int seg_not_present:1; + unsigned int useable:1; + unsigned int lm:1; +} user_desc_t; + +# else /* __KERNEL__ */ + +# include <asm/ldt.h> +typedef struct user_desc user_desc_t; + +# endif /* __KERNEL__ */ +#endif /* _SYSDEP_TLS_H */ diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h index 992a7e1e0fc..fe0c29b5144 100644 --- a/arch/um/include/user_util.h +++ b/arch/um/include/user_util.h @@ -8,6 +8,9 @@ #include "sysdep/ptrace.h" +/* Copied from kernel.h */ +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + #define CATCH_EINTR(expr) while ((errno = 0, ((expr) < 0)) && (errno == EINTR)) extern int mode_tt; @@ -31,7 +34,7 @@ extern unsigned long uml_physmem; extern unsigned long uml_reserved; extern unsigned long end_vm; extern unsigned long start_vm; -extern unsigned long highmem; +extern unsigned long long highmem; extern char host_info[]; diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c index 1ca84319317..c0cb627bf59 100644 --- a/arch/um/kernel/exec_kern.c +++ b/arch/um/kernel/exec_kern.c @@ -22,6 +22,7 @@ void flush_thread(void) { + arch_flush_thread(¤t->thread.arch); CHOOSE_MODE(flush_thread_tt(), flush_thread_skas()); } @@ -58,14 +59,14 @@ long um_execve(char *file, char __user *__user *argv, char __user *__user *env) return(err); } -long sys_execve(char *file, char __user *__user *argv, +long sys_execve(char __user *file, char __user *__user *argv, char __user *__user *env) { long error; char *filename; lock_kernel(); - filename = getname((char __user *) file); + filename = getname(file); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; error = execve1(filename, argv, env); @@ -74,14 +75,3 @@ long sys_execve(char *file, char __user *__user *argv, unlock_kernel(); return(error); } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c index 92cce96b5e2..44e41a35f00 100644 --- a/arch/um/kernel/mem.c +++ b/arch/um/kernel/mem.c @@ -30,7 +30,7 @@ extern char __binary_start; unsigned long *empty_zero_page = NULL; unsigned long *empty_bad_page = NULL; pgd_t swapper_pg_dir[PTRS_PER_PGD]; -unsigned long highmem; +unsigned long long highmem; int kmalloc_ok = 0; static unsigned long brk_end; diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c index 3113cab8675..f6a5a502120 100644 --- a/arch/um/kernel/process_kern.c +++ b/arch/um/kernel/process_kern.c @@ -156,9 +156,25 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, unsigned long stack_top, struct task_struct * p, struct pt_regs *regs) { + int ret; + p->thread = (struct thread_struct) INIT_THREAD; - return(CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr, - clone_flags, sp, stack_top, p, regs)); + ret = CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr, + clone_flags, sp, stack_top, p, regs); + + if (ret || !current->thread.forking) + goto out; + + clear_flushed_tls(p); + + /* + * Set a new TLS for the child thread? + */ + if (clone_flags & CLONE_SETTLS) + ret = arch_copy_tls(p); + +out: + return ret; } void initial_thread_cb(void (*proc)(void *), void *arg) @@ -185,10 +201,6 @@ void default_idle(void) { CHOOSE_MODE(uml_idle_timer(), (void) 0); - atomic_inc(&init_mm.mm_count); - current->mm = &init_mm; - current->active_mm = &init_mm; - while(1){ /* endless idle loop with no priority at all */ @@ -407,7 +419,7 @@ static int proc_read_sysemu(char *buf, char **start, off_t offset, int size,int return strlen(buf); } -static int proc_write_sysemu(struct file *file,const char *buf, unsigned long count,void *data) +static int proc_write_sysemu(struct file *file,const char __user *buf, unsigned long count,void *data) { char tmp[2]; diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index 98e09395c09..60d2eda995c 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -46,6 +46,7 @@ extern int poke_user(struct task_struct * child, long addr, long data); long arch_ptrace(struct task_struct *child, long request, long addr, long data) { int i, ret; + unsigned long __user *p = (void __user *)(unsigned long)data; switch (request) { /* when I and D space are separate, these will need to be fixed. */ @@ -58,7 +59,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); if (copied != sizeof(tmp)) break; - ret = put_user(tmp, (unsigned long __user *) data); + ret = put_user(tmp, p); break; } @@ -136,15 +137,13 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) #ifdef PTRACE_GETREGS case PTRACE_GETREGS: { /* Get all gp regs from the child. */ - if (!access_ok(VERIFY_WRITE, (unsigned long *)data, - MAX_REG_OFFSET)) { + if (!access_ok(VERIFY_WRITE, p, MAX_REG_OFFSET)) { ret = -EIO; break; } for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) { - __put_user(getreg(child, i), - (unsigned long __user *) data); - data += sizeof(long); + __put_user(getreg(child, i), p); + p++; } ret = 0; break; @@ -153,15 +152,14 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) #ifdef PTRACE_SETREGS case PTRACE_SETREGS: { /* Set all gp regs in the child. */ unsigned long tmp = 0; - if (!access_ok(VERIFY_READ, (unsigned *)data, - MAX_REG_OFFSET)) { + if (!access_ok(VERIFY_READ, p, MAX_REG_OFFSET)) { ret = -EIO; break; } for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) { - __get_user(tmp, (unsigned long __user *) data); + __get_user(tmp, p); putreg(child, i, tmp); - data += sizeof(long); + p++; } ret = 0; break; @@ -187,14 +185,23 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) ret = set_fpxregs(data, child); break; #endif + case PTRACE_GET_THREAD_AREA: + ret = ptrace_get_thread_area(child, addr, + (struct user_desc __user *) data); + break; + + case PTRACE_SET_THREAD_AREA: + ret = ptrace_set_thread_area(child, addr, + (struct user_desc __user *) data); + break; + case PTRACE_FAULTINFO: { - /* Take the info from thread->arch->faultinfo, - * but transfer max. sizeof(struct ptrace_faultinfo). - * On i386, ptrace_faultinfo is smaller! - */ - ret = copy_to_user((unsigned long __user *) data, - &child->thread.arch.faultinfo, - sizeof(struct ptrace_faultinfo)); + /* Take the info from thread->arch->faultinfo, + * but transfer max. sizeof(struct ptrace_faultinfo). + * On i386, ptrace_faultinfo is smaller! + */ + ret = copy_to_user(p, &child->thread.arch.faultinfo, + sizeof(struct ptrace_faultinfo)); if(ret) break; break; @@ -204,8 +211,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) case PTRACE_LDT: { struct ptrace_ldt ldt; - if(copy_from_user(&ldt, (unsigned long __user *) data, - sizeof(ldt))){ + if(copy_from_user(&ldt, p, sizeof(ldt))){ ret = -EIO; break; } diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c index 3f70a2e12f0..2135eaf98a9 100644 --- a/arch/um/kernel/skas/process_kern.c +++ b/arch/um/kernel/skas/process_kern.c @@ -35,6 +35,8 @@ void switch_to_skas(void *prev, void *next) switch_threads(&from->thread.mode.skas.switch_buf, to->thread.mode.skas.switch_buf); + arch_switch_to_skas(current->thread.prev_sched, current); + if(current->pid == 0) switch_timers(1); } @@ -89,10 +91,17 @@ void fork_handler(int sig) panic("blech"); schedule_tail(current->thread.prev_sched); + + /* XXX: if interrupt_end() calls schedule, this call to + * arch_switch_to_skas isn't needed. We could want to apply this to + * improve performance. -bb */ + arch_switch_to_skas(current->thread.prev_sched, current); + current->thread.prev_sched = NULL; /* Handle any immediate reschedules or signals */ interrupt_end(); + userspace(¤t->thread.regs.regs); } @@ -109,6 +118,8 @@ int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp, if(sp != 0) REGS_SP(p->thread.regs.regs.skas.regs) = sp; handler = fork_handler; + + arch_copy_thread(¤t->thread.arch, &p->thread.arch); } else { init_thread_registers(&p->thread.regs.regs); diff --git a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c index 8e1a3501ff4..37d3978337d 100644 --- a/arch/um/kernel/syscall_kern.c +++ b/arch/um/kernel/syscall_kern.c @@ -104,7 +104,7 @@ long sys_pipe(unsigned long __user * fildes) } -long sys_uname(struct old_utsname * name) +long sys_uname(struct old_utsname __user * name) { long err; if (!name) @@ -115,7 +115,7 @@ long sys_uname(struct old_utsname * name) return err?-EFAULT:0; } -long sys_olduname(struct oldold_utsname * name) +long sys_olduname(struct oldold_utsname __user * name) { long error; diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c index d56046c2aba..02f6d4d8dc3 100644 --- a/arch/um/kernel/trap_kern.c +++ b/arch/um/kernel/trap_kern.c @@ -198,7 +198,7 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc) si.si_signo = SIGBUS; si.si_errno = 0; si.si_code = BUS_ADRERR; - si.si_addr = (void *)address; + si.si_addr = (void __user *)address; current->thread.arch.faultinfo = fi; force_sig_info(SIGBUS, &si, current); } else if (err == -ENOMEM) { @@ -207,7 +207,7 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc) } else { BUG_ON(err != -EFAULT); si.si_signo = SIGSEGV; - si.si_addr = (void *) address; + si.si_addr = (void __user *) address; current->thread.arch.faultinfo = fi; force_sig_info(SIGSEGV, &si, current); } @@ -220,8 +220,8 @@ void bad_segv(struct faultinfo fi, unsigned long ip) si.si_signo = SIGSEGV; si.si_code = SEGV_ACCERR; - si.si_addr = (void *) FAULT_ADDRESS(fi); - current->thread.arch.faultinfo = fi; + si.si_addr = (void __user *) FAULT_ADDRESS(fi); + current->thread.arch.faultinfo = fi; force_sig_info(SIGSEGV, &si, current); } diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c index 295c1ac817b..a9c1443fc54 100644 --- a/arch/um/kernel/tt/process_kern.c +++ b/arch/um/kernel/tt/process_kern.c @@ -51,6 +51,13 @@ void switch_to_tt(void *prev, void *next) c = 0; + /* Notice that here we "up" the semaphore on which "to" is waiting, and + * below (the read) we wait on this semaphore (which is implemented by + * switch_pipe) and go sleeping. Thus, after that, we have resumed in + * "to", and can't use any more the value of "from" (which is outdated), + * nor the value in "to" (since it was the task which stole us the CPU, + * which we don't care about). */ + err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c)); if(err != sizeof(c)) panic("write of switch_pipe failed, err = %d", -err); @@ -77,7 +84,7 @@ void switch_to_tt(void *prev, void *next) change_sig(SIGALRM, alrm); change_sig(SIGPROF, prof); - arch_switch(); + arch_switch_to_tt(prev_sched, current); flush_tlb_all(); local_irq_restore(flags); @@ -141,7 +148,6 @@ static void new_thread_handler(int sig) set_cmdline("(kernel thread)"); change_sig(SIGUSR1, 1); - change_sig(SIGVTALRM, 1); change_sig(SIGPROF, 1); local_irq_enable(); if(!run_kernel_thread(fn, arg, ¤t->thread.exec_buf)) diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile index 1659386b42b..f4bfc4c7cca 100644 --- a/arch/um/os-Linux/Makefile +++ b/arch/um/os-Linux/Makefile @@ -4,7 +4,7 @@ # obj-y = aio.o elf_aux.o file.o helper.o irq.o main.o mem.o process.o sigio.o \ - signal.o start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o \ + signal.o start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o tls.o \ user_syms.o util.o drivers/ sys-$(SUBARCH)/ obj-$(CONFIG_MODE_SKAS) += skas/ @@ -12,12 +12,9 @@ obj-$(CONFIG_TTY_LOG) += tty_log.o user-objs-$(CONFIG_TTY_LOG) += tty_log.o USER_OBJS := $(user-objs-y) aio.o elf_aux.o file.o helper.o irq.o main.o mem.o \ - process.o sigio.o signal.o start_up.o time.o trap.o tt.o tty.o \ + process.o sigio.o signal.o start_up.o time.o trap.o tt.o tty.o tls.o \ uaccess.o umid.o util.o -elf_aux.o: $(ARCH_DIR)/kernel-offsets.h -CFLAGS_elf_aux.o += -I$(objtree)/arch/um - CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH) HAVE_AIO_ABI := $(shell [ -r /usr/include/linux/aio_abi.h ] && \ diff --git a/arch/um/os-Linux/drivers/ethertap_kern.c b/arch/um/os-Linux/drivers/ethertap_kern.c index 6ae4b19d9f5..768606bec23 100644 --- a/arch/um/os-Linux/drivers/ethertap_kern.c +++ b/arch/um/os-Linux/drivers/ethertap_kern.c @@ -102,18 +102,7 @@ static struct transport ethertap_transport = { static int register_ethertap(void) { register_transport(ðertap_transport); - return(1); + return 0; } __initcall(register_ethertap); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/os-Linux/drivers/tuntap_kern.c b/arch/um/os-Linux/drivers/tuntap_kern.c index 4202b9ebad4..190009a6f89 100644 --- a/arch/um/os-Linux/drivers/tuntap_kern.c +++ b/arch/um/os-Linux/drivers/tuntap_kern.c @@ -87,18 +87,7 @@ static struct transport tuntap_transport = { static int register_tuntap(void) { register_transport(&tuntap_transport); - return(1); + return 0; } __initcall(register_tuntap); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c index 9d7d69a523b..6ab372da965 100644 --- a/arch/um/os-Linux/mem.c +++ b/arch/um/os-Linux/mem.c @@ -121,36 +121,11 @@ int create_tmp_file(unsigned long long len) return(fd); } -static int create_anon_file(unsigned long long len) -{ - void *addr; - int fd; - - fd = open("/dev/anon", O_RDWR); - if(fd < 0) { - perror("opening /dev/anon"); - exit(1); - } - - addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - if(addr == MAP_FAILED){ - perror("mapping physmem file"); - exit(1); - } - munmap(addr, len); - - return(fd); -} - -extern int have_devanon; - int create_mem_file(unsigned long long len) { int err, fd; - if(have_devanon) - fd = create_anon_file(len); - else fd = create_tmp_file(len); + fd = create_tmp_file(len); err = os_set_exec_close(fd, 1); if(err < 0){ diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index d261888f39c..8176b0b5204 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c @@ -11,6 +11,7 @@ #include <linux/unistd.h> #include <sys/mman.h> #include <sys/wait.h> +#include <sys/mman.h> #include "ptrace_user.h" #include "os.h" #include "user.h" @@ -20,6 +21,7 @@ #include "kern_util.h" #include "longjmp.h" #include "skas_ptrace.h" +#include "kern_constants.h" #define ARBITRARY_ADDR -1 #define FAILURE_PID -1 @@ -187,6 +189,48 @@ int os_unmap_memory(void *addr, int len) return(0); } +#ifndef MADV_REMOVE +#define MADV_REMOVE 0x5 /* remove these pages & resources */ +#endif + +int os_drop_memory(void *addr, int length) +{ + int err; + + err = madvise(addr, length, MADV_REMOVE); + if(err < 0) + err = -errno; + return err; +} + +int can_drop_memory(void) +{ + void *addr; + int fd; + + printk("Checking host MADV_REMOVE support..."); + fd = create_mem_file(UM_KERN_PAGE_SIZE); + if(fd < 0){ + printk("Creating test memory file failed, err = %d\n", -fd); + return 0; + } + + addr = mmap64(NULL, UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE, + MAP_PRIVATE, fd, 0); + if(addr == MAP_FAILED){ + printk("Mapping test memory file failed, err = %d\n", -errno); + return 0; + } + + if(madvise(addr, UM_KERN_PAGE_SIZE, MADV_REMOVE) != 0){ + printk("MADV_REMOVE failed, err = %d\n", -errno); + return 0; + } + + printk("OK\n"); + return 1; +} + void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)) { int flags = 0, pages; diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index 32753131f8d..387e26af301 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c @@ -470,25 +470,6 @@ int can_do_skas(void) } #endif -int have_devanon = 0; - -/* Runs on boot kernel stack - already safe to use printk. */ - -void check_devanon(void) -{ - int fd; - - printk("Checking for /dev/anon on the host..."); - fd = open("/dev/anon", O_RDWR); - if(fd < 0){ - printk("Not available (open failed with errno %d)\n", errno); - return; - } - - printk("OK\n"); - have_devanon = 1; -} - int __init parse_iomem(char *str, int *add) { struct iomem_region *new; @@ -664,6 +645,5 @@ void os_check_bugs(void) { check_ptrace(); check_sigio(); - check_devanon(); } diff --git a/arch/um/os-Linux/sys-i386/Makefile b/arch/um/os-Linux/sys-i386/Makefile index 340ef26f594..b3213613c41 100644 --- a/arch/um/os-Linux/sys-i386/Makefile +++ b/arch/um/os-Linux/sys-i386/Makefile @@ -3,7 +3,7 @@ # Licensed under the GPL # -obj-$(CONFIG_MODE_SKAS) = registers.o +obj-$(CONFIG_MODE_SKAS) = registers.o tls.o USER_OBJS := $(obj-y) diff --git a/arch/um/os-Linux/sys-i386/tls.c b/arch/um/os-Linux/sys-i386/tls.c new file mode 100644 index 00000000000..ba21f0e04a2 --- /dev/null +++ b/arch/um/os-Linux/sys-i386/tls.c @@ -0,0 +1,33 @@ +#include <linux/unistd.h> +#include "sysdep/tls.h" +#include "user_util.h" + +static _syscall1(int, get_thread_area, user_desc_t *, u_info); + +/* Checks whether host supports TLS, and sets *tls_min according to the value + * valid on the host. + * i386 host have it == 6; x86_64 host have it == 12, for i386 emulation. */ +void check_host_supports_tls(int *supports_tls, int *tls_min) { + /* Values for x86 and x86_64.*/ + int val[] = {GDT_ENTRY_TLS_MIN_I386, GDT_ENTRY_TLS_MIN_X86_64}; + int i; + + for (i = 0; i < ARRAY_SIZE(val); i++) { + user_desc_t info; + info.entry_number = val[i]; + + if (get_thread_area(&info) == 0) { + *tls_min = val[i]; + *supports_tls = 1; + return; + } else { + if (errno == EINVAL) + continue; + else if (errno == ENOSYS) + *supports_tls = 0; + return; + } + } + + *supports_tls = 0; +} diff --git a/arch/um/os-Linux/tls.c b/arch/um/os-Linux/tls.c new file mode 100644 index 00000000000..9cb09a45546 --- /dev/null +++ b/arch/um/os-Linux/tls.c @@ -0,0 +1,76 @@ +#include <errno.h> +#include <sys/ptrace.h> +#include <asm/ldt.h> +#include "sysdep/tls.h" +#include "uml-config.h" + +/* TLS support - we basically rely on the host's one.*/ + +/* In TT mode, this should be called only by the tracing thread, and makes sense + * only for PTRACE_SET_THREAD_AREA. In SKAS mode, it's used normally. + * + */ + +#ifndef PTRACE_GET_THREAD_AREA +#define PTRACE_GET_THREAD_AREA 25 +#endif + +#ifndef PTRACE_SET_THREAD_AREA +#define PTRACE_SET_THREAD_AREA 26 +#endif + +int os_set_thread_area(user_desc_t *info, int pid) +{ + int ret; + + ret = ptrace(PTRACE_SET_THREAD_AREA, pid, info->entry_number, + (unsigned long) info); + if (ret < 0) + ret = -errno; + return ret; +} + +#ifdef UML_CONFIG_MODE_SKAS + +int os_get_thread_area(user_desc_t *info, int pid) +{ + int ret; + + ret = ptrace(PTRACE_GET_THREAD_AREA, pid, info->entry_number, + (unsigned long) info); + if (ret < 0) + ret = -errno; + return ret; +} + +#endif + +#ifdef UML_CONFIG_MODE_TT +#include "linux/unistd.h" + +static _syscall1(int, get_thread_area, user_desc_t *, u_info); +static _syscall1(int, set_thread_area, user_desc_t *, u_info); + +int do_set_thread_area_tt(user_desc_t *info) +{ + int ret; + + ret = set_thread_area(info); + if (ret < 0) { + ret = -errno; + } + return ret; +} + +int do_get_thread_area_tt(user_desc_t *info) +{ + int ret; + + ret = get_thread_area(info); + if (ret < 0) { + ret = -errno; + } + return ret; +} + +#endif /* UML_CONFIG_MODE_TT */ diff --git a/arch/um/scripts/Makefile.rules b/arch/um/scripts/Makefile.rules index 2e41cabd3d9..b696b451774 100644 --- a/arch/um/scripts/Makefile.rules +++ b/arch/um/scripts/Makefile.rules @@ -20,25 +20,7 @@ define unprofile $(patsubst -pg,,$(patsubst -fprofile-arcs -ftest-coverage,,$(1))) endef - -# cmd_make_link checks to see if the $(foo-dir) variable starts with a /. If -# so, it's considered to be a path relative to $(srcdir) rather than -# $(srcdir)/arch/$(SUBARCH). This is because x86_64 wants to get ldt.c from -# arch/um/sys-i386 rather than arch/i386 like the other borrowed files. So, -# it sets $(ldt.c-dir) to /arch/um/sys-i386. -quiet_cmd_make_link = SYMLINK $@ -cmd_make_link = rm -f $@; ln -sf $(srctree)$(if $(filter-out /%,$($(notdir $@)-dir)),/arch/$(SUBARCH))/$($(notdir $@)-dir)/$(notdir $@) $@ - -# this needs to be before the foreach, because targets does not accept -# complete paths like $(obj)/$(f). To make sure this works, use a := assignment -# or we will get $(obj)/$(f) in the "targets" value. -# Also, this forces you to use the := syntax when assigning to targets. -# Otherwise the line below will cause an infinite loop (if you don't know why, -# just do it). - -targets := $(targets) $(SYMLINKS) - -SYMLINKS := $(foreach f,$(SYMLINKS),$(obj)/$(f)) - -$(SYMLINKS): FORCE - $(call if_changed,make_link) +ifdef subarch-obj-y +obj-y += subarch.o +subarch-y = $(addprefix ../../$(SUBARCH)/,$(subarch-obj-y)) +endif diff --git a/arch/um/scripts/Makefile.unmap b/arch/um/scripts/Makefile.unmap deleted file mode 100644 index b2165188d94..00000000000 --- a/arch/um/scripts/Makefile.unmap +++ /dev/null @@ -1,22 +0,0 @@ -clean-files += unmap_tmp.o unmap_fin.o unmap.o - -ifdef CONFIG_MODE_TT - -#Always build unmap_fin.o -extra-y += unmap_fin.o -#Do dependency tracking for unmap.o (it will be always built, but won't get the tracking unless we use this). -targets += unmap.o - -#XXX: partially copied from arch/um/scripts/Makefile.rules -$(obj)/unmap.o: _c_flags = $(call unprofile,$(CFLAGS)) - -quiet_cmd_wrapld = LD $@ -define cmd_wrapld - $(LD) $(LDFLAGS) -r -o $(obj)/unmap_tmp.o $< ; \ - $(OBJCOPY) $(UML_OBJCOPYFLAGS) $(obj)/unmap_tmp.o $@ -G switcheroo -endef - -$(obj)/unmap_fin.o : $(obj)/unmap.o FORCE - $(call if_changed,wrapld) - -endif diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile index f5fd5b0156d..98b20b7bba4 100644 --- a/arch/um/sys-i386/Makefile +++ b/arch/um/sys-i386/Makefile @@ -1,23 +1,18 @@ -obj-y := bitops.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \ - ptrace_user.o semaphore.o signal.o sigcontext.o syscalls.o sysrq.o \ - sys_call_table.o +obj-y = bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \ + ptrace_user.o signal.o sigcontext.o syscalls.o sysrq.o \ + sys_call_table.o tls.o obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o -obj-$(CONFIG_HIGHMEM) += highmem.o -obj-$(CONFIG_MODULES) += module.o +subarch-obj-y = lib/bitops.o kernel/semaphore.o +subarch-obj-$(CONFIG_HIGHMEM) += mm/highmem.o +subarch-obj-$(CONFIG_MODULES) += kernel/module.o USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o stub_segv.o -SYMLINKS = bitops.c semaphore.c highmem.c module.c - include arch/um/scripts/Makefile.rules -bitops.c-dir = lib -semaphore.c-dir = kernel -highmem.c-dir = mm -module.c-dir = kernel - -$(obj)/stub_segv.o : _c_flags = $(call unprofile,$(CFLAGS)) +extra-$(CONFIG_MODE_TT) += unmap.o -include arch/um/scripts/Makefile.unmap +$(obj)/stub_segv.o $(obj)/unmap.o: \ + _c_flags = $(call unprofile,$(CFLAGS)) diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c index 8032a105949..6028bc7cc01 100644 --- a/arch/um/sys-i386/ptrace.c +++ b/arch/um/sys-i386/ptrace.c @@ -15,9 +15,22 @@ #include "sysdep/sigcontext.h" #include "sysdep/sc.h" -void arch_switch(void) +void arch_switch_to_tt(struct task_struct *from, struct task_struct *to) { - update_debugregs(current->thread.arch.debugregs_seq); + update_debugregs(to->thread.arch.debugregs_seq); + arch_switch_tls_tt(from, to); +} + +void arch_switch_to_skas(struct task_struct *from, struct task_struct *to) +{ + int err = arch_switch_tls_skas(from, to); + if (!err) + return; + + if (err != -EINVAL) + printk(KERN_WARNING "arch_switch_tls_skas failed, errno %d, not EINVAL\n", -err); + else + printk(KERN_WARNING "arch_switch_tls_skas failed, errno = EINVAL\n"); } int is_syscall(unsigned long addr) @@ -124,22 +137,22 @@ unsigned long getreg(struct task_struct *child, int regno) int peek_user(struct task_struct *child, long addr, long data) { /* read the word at location addr in the USER area. */ - unsigned long tmp; + unsigned long tmp; - if ((addr & 3) || addr < 0) - return -EIO; + if ((addr & 3) || addr < 0) + return -EIO; - tmp = 0; /* Default return condition */ - if(addr < MAX_REG_OFFSET){ - tmp = getreg(child, addr); - } - else if((addr >= offsetof(struct user, u_debugreg[0])) && - (addr <= offsetof(struct user, u_debugreg[7]))){ - addr -= offsetof(struct user, u_debugreg[0]); - addr = addr >> 2; - tmp = child->thread.arch.debugregs[addr]; - } - return put_user(tmp, (unsigned long *) data); + tmp = 0; /* Default return condition */ + if(addr < MAX_REG_OFFSET){ + tmp = getreg(child, addr); + } + else if((addr >= offsetof(struct user, u_debugreg[0])) && + (addr <= offsetof(struct user, u_debugreg[7]))){ + addr -= offsetof(struct user, u_debugreg[0]); + addr = addr >> 2; + tmp = child->thread.arch.debugregs[addr]; + } + return put_user(tmp, (unsigned long __user *) data); } struct i387_fxsave_struct { diff --git a/arch/um/sys-i386/ptrace_user.c b/arch/um/sys-i386/ptrace_user.c index 7c376c95de5..9f3bd8ed78f 100644 --- a/arch/um/sys-i386/ptrace_user.c +++ b/arch/um/sys-i386/ptrace_user.c @@ -14,6 +14,7 @@ #include "sysdep/thread.h" #include "user.h" #include "os.h" +#include "uml-config.h" int ptrace_getregs(long pid, unsigned long *regs_out) { @@ -43,6 +44,7 @@ int ptrace_setfpregs(long pid, unsigned long *regs) return 0; } +/* All the below stuff is of interest for TT mode only */ static void write_debugregs(int pid, unsigned long *regs) { struct user *dummy; @@ -75,7 +77,6 @@ static void read_debugregs(int pid, unsigned long *regs) /* Accessed only by the tracing thread */ static unsigned long kernel_debugregs[8] = { [ 0 ... 7 ] = 0 }; -static int debugregs_seq = 0; void arch_enter_kernel(void *task, int pid) { @@ -89,6 +90,11 @@ void arch_leave_kernel(void *task, int pid) write_debugregs(pid, TASK_DEBUGREGS(task)); } +#ifdef UML_CONFIG_PT_PROXY +/* Accessed only by the tracing thread */ +static int debugregs_seq; + +/* Only called by the ptrace proxy */ void ptrace_pokeuser(unsigned long addr, unsigned long data) { if((addr < offsetof(struct user, u_debugreg[0])) || @@ -109,6 +115,7 @@ static void update_debugregs_cb(void *arg) write_debugregs(pid, kernel_debugregs); } +/* Optimized out in its header when not defined */ void update_debugregs(int seq) { int me; @@ -118,6 +125,7 @@ void update_debugregs(int seq) me = os_getpid(); initial_thread_cb(update_debugregs_cb, &me); } +#endif /* * Overrides for Emacs so that we follow Linus's tabbing style. diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c index 33a40f5ef0d..f5d0e1c37ea 100644 --- a/arch/um/sys-i386/signal.c +++ b/arch/um/sys-i386/signal.c @@ -19,7 +19,7 @@ #include "skas.h" static int copy_sc_from_user_skas(struct pt_regs *regs, - struct sigcontext *from) + struct sigcontext __user *from) { struct sigcontext sc; unsigned long fpregs[HOST_FP_SIZE]; @@ -57,7 +57,7 @@ static int copy_sc_from_user_skas(struct pt_regs *regs, return(0); } -int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, +int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate __user *to_fp, struct pt_regs *regs, unsigned long sp) { struct sigcontext sc; @@ -92,7 +92,7 @@ int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, "errno = %d\n", err); return(1); } - to_fp = (to_fp ? to_fp : (struct _fpstate *) (to + 1)); + to_fp = (to_fp ? to_fp : (struct _fpstate __user *) (to + 1)); sc.fpstate = to_fp; if(err) @@ -113,10 +113,11 @@ int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, * saved pointer is in the kernel, but the sigcontext is in userspace, so we * copy_to_user it. */ -int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from, +int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext __user *from, int fpsize) { - struct _fpstate *to_fp, *from_fp; + struct _fpstate *to_fp; + struct _fpstate __user *from_fp; unsigned long sigs; int err; @@ -131,13 +132,14 @@ int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from, return(err); } -int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, +int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate __user *fp, struct sigcontext *from, int fpsize, unsigned long sp) { - struct _fpstate *to_fp, *from_fp; + struct _fpstate __user *to_fp; + struct _fpstate *from_fp; int err; - to_fp = (fp ? fp : (struct _fpstate *) (to + 1)); + to_fp = (fp ? fp : (struct _fpstate __user *) (to + 1)); from_fp = from->fpstate; err = copy_to_user(to, from, sizeof(*to)); @@ -165,7 +167,7 @@ static int copy_sc_from_user(struct pt_regs *to, void __user *from) return(ret); } -static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp, +static int copy_sc_to_user(struct sigcontext *to, struct _fpstate __user *fp, struct pt_regs *from, unsigned long sp) { return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), @@ -173,7 +175,7 @@ static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp, copy_sc_to_user_skas(to, fp, from, sp))); } -static int copy_ucontext_to_user(struct ucontext *uc, struct _fpstate *fp, +static int copy_ucontext_to_user(struct ucontext __user *uc, struct _fpstate __user *fp, sigset_t *set, unsigned long sp) { int err = 0; @@ -188,7 +190,7 @@ static int copy_ucontext_to_user(struct ucontext *uc, struct _fpstate *fp, struct sigframe { - char *pretcode; + char __user *pretcode; int sig; struct sigcontext sc; struct _fpstate fpstate; @@ -198,10 +200,10 @@ struct sigframe struct rt_sigframe { - char *pretcode; + char __user *pretcode; int sig; - struct siginfo *pinfo; - void *puc; + struct siginfo __user *pinfo; + void __user *puc; struct siginfo info; struct ucontext uc; struct _fpstate fpstate; @@ -213,16 +215,16 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig, sigset_t *mask) { struct sigframe __user *frame; - void *restorer; + void __user *restorer; unsigned long save_sp = PT_REGS_SP(regs); int err = 0; stack_top &= -8UL; - frame = (struct sigframe *) stack_top - 1; + frame = (struct sigframe __user *) stack_top - 1; if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) return 1; - restorer = (void *) frame->retcode; + restorer = frame->retcode; if(ka->sa.sa_flags & SA_RESTORER) restorer = ka->sa.sa_restorer; @@ -278,16 +280,16 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, siginfo_t *info, sigset_t *mask) { struct rt_sigframe __user *frame; - void *restorer; + void __user *restorer; unsigned long save_sp = PT_REGS_SP(regs); int err = 0; stack_top &= -8UL; - frame = (struct rt_sigframe *) stack_top - 1; + frame = (struct rt_sigframe __user *) stack_top - 1; if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) return 1; - restorer = (void *) frame->retcode; + restorer = frame->retcode; if(ka->sa.sa_flags & SA_RESTORER) restorer = ka->sa.sa_restorer; @@ -333,7 +335,7 @@ err: long sys_sigreturn(struct pt_regs regs) { unsigned long sp = PT_REGS_SP(¤t->thread.regs); - struct sigframe __user *frame = (struct sigframe *)(sp - 8); + struct sigframe __user *frame = (struct sigframe __user *)(sp - 8); sigset_t set; struct sigcontext __user *sc = &frame->sc; unsigned long __user *oldmask = &sc->oldmask; @@ -365,8 +367,8 @@ long sys_sigreturn(struct pt_regs regs) long sys_rt_sigreturn(struct pt_regs regs) { - unsigned long __user sp = PT_REGS_SP(¤t->thread.regs); - struct rt_sigframe __user *frame = (struct rt_sigframe *) (sp - 4); + unsigned long sp = PT_REGS_SP(¤t->thread.regs); + struct rt_sigframe __user *frame = (struct rt_sigframe __user *) (sp - 4); sigset_t set; struct ucontext __user *uc = &frame->uc; int sig_size = _NSIG_WORDS * sizeof(unsigned long); diff --git a/arch/um/sys-i386/sys_call_table.S b/arch/um/sys-i386/sys_call_table.S index ad75c27afe3..1ff61474b25 100644 --- a/arch/um/sys-i386/sys_call_table.S +++ b/arch/um/sys-i386/sys_call_table.S @@ -6,8 +6,6 @@ #define sys_vm86old sys_ni_syscall #define sys_vm86 sys_ni_syscall -#define sys_set_thread_area sys_ni_syscall -#define sys_get_thread_area sys_ni_syscall #define sys_stime um_stime #define sys_time um_time diff --git a/arch/um/sys-i386/syscalls.c b/arch/um/sys-i386/syscalls.c index 83e9be820a8..749dd1bfe60 100644 --- a/arch/um/sys-i386/syscalls.c +++ b/arch/um/sys-i386/syscalls.c @@ -61,21 +61,27 @@ long old_select(struct sel_arg_struct __user *arg) return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); } -/* The i386 version skips reading from %esi, the fourth argument. So we must do - * this, too. +/* + * The prototype on i386 is: + * + * int clone(int flags, void * child_stack, int * parent_tidptr, struct user_desc * newtls, int * child_tidptr) + * + * and the "newtls" arg. on i386 is read by copy_thread directly from the + * register saved on the stack. */ long sys_clone(unsigned long clone_flags, unsigned long newsp, - int __user *parent_tid, int unused, int __user *child_tid) + int __user *parent_tid, void *newtls, int __user *child_tid) { long ret; if (!newsp) newsp = UPT_SP(¤t->thread.regs.regs); + current->thread.forking = 1; ret = do_fork(clone_flags, newsp, ¤t->thread.regs, 0, parent_tid, child_tid); current->thread.forking = 0; - return(ret); + return ret; } /* @@ -104,7 +110,7 @@ long sys_ipc (uint call, int first, int second, union semun fourth; if (!ptr) return -EINVAL; - if (get_user(fourth.__pad, (void **) ptr)) + if (get_user(fourth.__pad, (void __user * __user *) ptr)) return -EFAULT; return sys_semctl (first, second, third, fourth); } diff --git a/arch/um/sys-i386/tls.c b/arch/um/sys-i386/tls.c new file mode 100644 index 00000000000..a3188e861cc --- /dev/null +++ b/arch/um/sys-i386/tls.c @@ -0,0 +1,384 @@ +/* + * Copyright (C) 2005 Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> + * Licensed under the GPL + */ + +#include "linux/config.h" +#include "linux/kernel.h" +#include "linux/sched.h" +#include "linux/slab.h" +#include "linux/types.h" +#include "asm/uaccess.h" +#include "asm/ptrace.h" +#include "asm/segment.h" +#include "asm/smp.h" +#include "asm/desc.h" +#include "choose-mode.h" +#include "kern.h" +#include "kern_util.h" +#include "mode_kern.h" +#include "os.h" +#include "mode.h" + +#ifdef CONFIG_MODE_SKAS +#include "skas.h" +#endif + +/* If needed we can detect when it's uninitialized. */ +static int host_supports_tls = -1; +int host_gdt_entry_tls_min = -1; + +#ifdef CONFIG_MODE_SKAS +int do_set_thread_area_skas(struct user_desc *info) +{ + int ret; + u32 cpu; + + cpu = get_cpu(); + ret = os_set_thread_area(info, userspace_pid[cpu]); + put_cpu(); + return ret; +} + +int do_get_thread_area_skas(struct user_desc *info) +{ + int ret; + u32 cpu; + + cpu = get_cpu(); + ret = os_get_thread_area(info, userspace_pid[cpu]); + put_cpu(); + return ret; +} +#endif + +/* + * sys_get_thread_area: get a yet unused TLS descriptor index. + * XXX: Consider leaving one free slot for glibc usage at first place. This must + * be done here (and by changing GDT_ENTRY_TLS_* macros) and nowhere else. + * + * Also, this must be tested when compiling in SKAS mode with dinamic linking + * and running against NPTL. + */ +static int get_free_idx(struct task_struct* task) +{ + struct thread_struct *t = &task->thread; + int idx; + + if (!t->arch.tls_array) + return GDT_ENTRY_TLS_MIN; + + for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++) + if (!t->arch.tls_array[idx].present) + return idx + GDT_ENTRY_TLS_MIN; + return -ESRCH; +} + +static inline void clear_user_desc(struct user_desc* info) +{ + /* Postcondition: LDT_empty(info) returns true. */ + memset(info, 0, sizeof(*info)); + + /* Check the LDT_empty or the i386 sys_get_thread_area code - we obtain + * indeed an empty user_desc. + */ + info->read_exec_only = 1; + info->seg_not_present = 1; +} + +#define O_FORCE 1 + +static int load_TLS(int flags, struct task_struct *to) +{ + int ret = 0; + int idx; + + for (idx = GDT_ENTRY_TLS_MIN; idx < GDT_ENTRY_TLS_MAX; idx++) { + struct uml_tls_struct* curr = &to->thread.arch.tls_array[idx - GDT_ENTRY_TLS_MIN]; + + /* Actually, now if it wasn't flushed it gets cleared and + * flushed to the host, which will clear it.*/ + if (!curr->present) { + if (!curr->flushed) { + clear_user_desc(&curr->tls); + curr->tls.entry_number = idx; + } else { + WARN_ON(!LDT_empty(&curr->tls)); + continue; + } + } + + if (!(flags & O_FORCE) && curr->flushed) + continue; + + ret = do_set_thread_area(&curr->tls); + if (ret) + goto out; + + curr->flushed = 1; + } +out: + return ret; +} + +/* Verify if we need to do a flush for the new process, i.e. if there are any + * present desc's, only if they haven't been flushed. + */ +static inline int needs_TLS_update(struct task_struct *task) +{ + int i; + int ret = 0; + + for (i = GDT_ENTRY_TLS_MIN; i < GDT_ENTRY_TLS_MAX; i++) { + struct uml_tls_struct* curr = &task->thread.arch.tls_array[i - GDT_ENTRY_TLS_MIN]; + + /* Can't test curr->present, we may need to clear a descriptor + * which had a value. */ + if (curr->flushed) + continue; + ret = 1; + break; + } + return ret; +} + +/* On a newly forked process, the TLS descriptors haven't yet been flushed. So + * we mark them as such and the first switch_to will do the job. + */ +void clear_flushed_tls(struct task_struct *task) +{ + int i; + + for (i = GDT_ENTRY_TLS_MIN; i < GDT_ENTRY_TLS_MAX; i++) { + struct uml_tls_struct* curr = &task->thread.arch.tls_array[i - GDT_ENTRY_TLS_MIN]; + + /* Still correct to do this, if it wasn't present on the host it + * will remain as flushed as it was. */ + if (!curr->present) + continue; + + curr->flushed = 0; + } +} + +/* In SKAS0 mode, currently, multiple guest threads sharing the same ->mm have a + * common host process. So this is needed in SKAS0 too. + * + * However, if each thread had a different host process (and this was discussed + * for SMP support) this won't be needed. + * + * And this will not need be used when (and if) we'll add support to the host + * SKAS patch. */ + +int arch_switch_tls_skas(struct task_struct *from, struct task_struct *to) +{ + if (!host_supports_tls) + return 0; + + /* We have no need whatsoever to switch TLS for kernel threads; beyond + * that, that would also result in us calling os_set_thread_area with + * userspace_pid[cpu] == 0, which gives an error. */ + if (likely(to->mm)) + return load_TLS(O_FORCE, to); + + return 0; +} + +int arch_switch_tls_tt(struct task_struct *from, struct task_struct *to) +{ + if (!host_supports_tls) + return 0; + + if (needs_TLS_update(to)) + return load_TLS(0, to); + + return 0; +} + +static int set_tls_entry(struct task_struct* task, struct user_desc *info, + int idx, int flushed) +{ + struct thread_struct *t = &task->thread; + + if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) + return -EINVAL; + + t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].tls = *info; + t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].present = 1; + t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].flushed = flushed; + + return 0; +} + +int arch_copy_tls(struct task_struct *new) +{ + struct user_desc info; + int idx, ret = -EFAULT; + + if (copy_from_user(&info, + (void __user *) UPT_ESI(&new->thread.regs.regs), + sizeof(info))) + goto out; + + ret = -EINVAL; + if (LDT_empty(&info)) + goto out; + + idx = info.entry_number; + + ret = set_tls_entry(new, &info, idx, 0); +out: + return ret; +} + +/* XXX: use do_get_thread_area to read the host value? I'm not at all sure! */ +static int get_tls_entry(struct task_struct* task, struct user_desc *info, int idx) +{ + struct thread_struct *t = &task->thread; + + if (!t->arch.tls_array) + goto clear; + + if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) + return -EINVAL; + + if (!t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].present) + goto clear; + + *info = t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].tls; + +out: + /* Temporary debugging check, to make sure that things have been + * flushed. This could be triggered if load_TLS() failed. + */ + if (unlikely(task == current && !t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].flushed)) { + printk(KERN_ERR "get_tls_entry: task with pid %d got here " + "without flushed TLS.", current->pid); + } + + return 0; +clear: + /* When the TLS entry has not been set, the values read to user in the + * tls_array are 0 (because it's cleared at boot, see + * arch/i386/kernel/head.S:cpu_gdt_table). Emulate that. + */ + clear_user_desc(info); + info->entry_number = idx; + goto out; +} + +asmlinkage int sys_set_thread_area(struct user_desc __user *user_desc) +{ + struct user_desc info; + int idx, ret; + + if (!host_supports_tls) + return -ENOSYS; + + if (copy_from_user(&info, user_desc, sizeof(info))) + return -EFAULT; + + idx = info.entry_number; + + if (idx == -1) { + idx = get_free_idx(current); + if (idx < 0) + return idx; + info.entry_number = idx; + /* Tell the user which slot we chose for him.*/ + if (put_user(idx, &user_desc->entry_number)) + return -EFAULT; + } + + ret = CHOOSE_MODE_PROC(do_set_thread_area_tt, do_set_thread_area_skas, &info); + if (ret) + return ret; + return set_tls_entry(current, &info, idx, 1); +} + +/* + * Perform set_thread_area on behalf of the traced child. + * Note: error handling is not done on the deferred load, and this differ from + * i386. However the only possible error are caused by bugs. + */ +int ptrace_set_thread_area(struct task_struct *child, int idx, + struct user_desc __user *user_desc) +{ + struct user_desc info; + + if (!host_supports_tls) + return -EIO; + + if (copy_from_user(&info, user_desc, sizeof(info))) + return -EFAULT; + + return set_tls_entry(child, &info, idx, 0); +} + +asmlinkage int sys_get_thread_area(struct user_desc __user *user_desc) +{ + struct user_desc info; + int idx, ret; + + if (!host_supports_tls) + return -ENOSYS; + + if (get_user(idx, &user_desc->entry_number)) + return -EFAULT; + + ret = get_tls_entry(current, &info, idx); + if (ret < 0) + goto out; + + if (copy_to_user(user_desc, &info, sizeof(info))) + ret = -EFAULT; + +out: + return ret; +} + +/* + * Perform get_thread_area on behalf of the traced child. + */ +int ptrace_get_thread_area(struct task_struct *child, int idx, + struct user_desc __user *user_desc) +{ + struct user_desc info; + int ret; + + if (!host_supports_tls) + return -EIO; + + ret = get_tls_entry(child, &info, idx); + if (ret < 0) + goto out; + + if (copy_to_user(user_desc, &info, sizeof(info))) + ret = -EFAULT; +out: + return ret; +} + + +/* XXX: This part is probably common to i386 and x86-64. Don't create a common + * file for now, do that when implementing x86-64 support.*/ +static int __init __setup_host_supports_tls(void) { + check_host_supports_tls(&host_supports_tls, &host_gdt_entry_tls_min); + if (host_supports_tls) { + printk(KERN_INFO "Host TLS support detected\n"); + printk(KERN_INFO "Detected host type: "); + switch (host_gdt_entry_tls_min) { + case GDT_ENTRY_TLS_MIN_I386: + printk("i386\n"); + break; + case GDT_ENTRY_TLS_MIN_X86_64: + printk("x86_64\n"); + break; + } + } else + printk(KERN_ERR " Host TLS support NOT detected! " + "TLS support inside UML will not work\n"); + return 1; +} + +__initcall(__setup_host_supports_tls); diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile index a351091fbd9..b5fc22babdd 100644 --- a/arch/um/sys-x86_64/Makefile +++ b/arch/um/sys-x86_64/Makefile @@ -4,31 +4,23 @@ # Licensed under the GPL # -#XXX: why into lib-y? -lib-y = bitops.o bugs.o csum-partial.o delay.o fault.o ldt.o mem.o memcpy.o \ - ptrace.o ptrace_user.o sigcontext.o signal.o syscalls.o \ - syscall_table.o sysrq.o thunk.o -lib-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o +obj-y = bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \ + sigcontext.o signal.o syscalls.o syscall_table.o sysrq.o ksyms.o \ + tls.o -obj-y := ksyms.o -obj-$(CONFIG_MODULES) += module.o um_module.o +obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o +obj-$(CONFIG_MODULES) += um_module.o -USER_OBJS := ptrace_user.o sigcontext.o stub_segv.o +subarch-obj-y = lib/bitops.o lib/csum-partial.o lib/memcpy.o lib/thunk.o +subarch-obj-$(CONFIG_MODULES) += kernel/module.o -SYMLINKS = bitops.c csum-copy.S csum-partial.c csum-wrappers.c ldt.c memcpy.S \ - thunk.S module.c +ldt-y = ../sys-i386/ldt.o -include arch/um/scripts/Makefile.rules +USER_OBJS := ptrace_user.o sigcontext.o stub_segv.o -bitops.c-dir = lib -csum-copy.S-dir = lib -csum-partial.c-dir = lib -csum-wrappers.c-dir = lib -ldt.c-dir = /arch/um/sys-i386 -memcpy.S-dir = lib -thunk.S-dir = lib -module.c-dir = kernel +include arch/um/scripts/Makefile.rules -$(obj)/stub_segv.o: _c_flags = $(call unprofile,$(CFLAGS)) +extra-$(CONFIG_MODE_TT) += unmap.o -include arch/um/scripts/Makefile.unmap +$(obj)/stub_segv.o $(obj)/unmap.o: \ + _c_flags = $(call unprofile,$(CFLAGS)) diff --git a/arch/um/sys-x86_64/tls.c b/arch/um/sys-x86_64/tls.c new file mode 100644 index 00000000000..ce1bf1b81c4 --- /dev/null +++ b/arch/um/sys-x86_64/tls.c @@ -0,0 +1,14 @@ +#include "linux/sched.h" + +void debug_arch_force_load_TLS(void) +{ +} + +void clear_flushed_tls(struct task_struct *task) +{ +} + +int arch_copy_tls(struct task_struct *t) +{ + return 0; +} diff --git a/arch/x86_64/ia32/vsyscall-sigreturn.S b/arch/x86_64/ia32/vsyscall-sigreturn.S index d90321fe9bb..1384367cdbe 100644 --- a/arch/x86_64/ia32/vsyscall-sigreturn.S +++ b/arch/x86_64/ia32/vsyscall-sigreturn.S @@ -32,9 +32,28 @@ __kernel_rt_sigreturn: .size __kernel_rt_sigreturn,.-.LSTART_rt_sigreturn .section .eh_frame,"a",@progbits +.LSTARTFRAMES: + .long .LENDCIES-.LSTARTCIES +.LSTARTCIES: + .long 0 /* CIE ID */ + .byte 1 /* Version number */ + .string "zRS" /* NUL-terminated augmentation string */ + .uleb128 1 /* Code alignment factor */ + .sleb128 -4 /* Data alignment factor */ + .byte 8 /* Return address register column */ + .uleb128 1 /* Augmentation value length */ + .byte 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4. */ + .byte 0x0c /* DW_CFA_def_cfa */ + .uleb128 4 + .uleb128 4 + .byte 0x88 /* DW_CFA_offset, column 0x8 */ + .uleb128 1 + .align 4 +.LENDCIES: + .long .LENDFDE2-.LSTARTFDE2 /* Length FDE */ .LSTARTFDE2: - .long .LSTARTFDE2-.LSTARTFRAME /* CIE pointer */ + .long .LSTARTFDE2-.LSTARTFRAMES /* CIE pointer */ /* HACK: The dwarf2 unwind routines will subtract 1 from the return address to get an address in the middle of the presumed call instruction. Since we didn't get here via @@ -97,7 +116,7 @@ __kernel_rt_sigreturn: .long .LENDFDE3-.LSTARTFDE3 /* Length FDE */ .LSTARTFDE3: - .long .LSTARTFDE3-.LSTARTFRAME /* CIE pointer */ + .long .LSTARTFDE3-.LSTARTFRAMES /* CIE pointer */ /* HACK: See above wrt unwind library assumptions. */ .long .LSTART_rt_sigreturn-1-. /* PC-relative start address */ .long .LEND_rt_sigreturn-.LSTART_rt_sigreturn+1 diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c index d54620147e8..100a30c4004 100644 --- a/arch/x86_64/kernel/apic.c +++ b/arch/x86_64/kernel/apic.c @@ -615,7 +615,7 @@ static int __init apic_set_verbosity(char *str) printk(KERN_WARNING "APIC Verbosity level %s not recognised" " use apic=verbose or apic=debug", str); - return 0; + return 1; } __setup("apic=", apic_set_verbosity); @@ -1137,35 +1137,35 @@ int __init APIC_init_uniprocessor (void) static __init int setup_disableapic(char *str) { disable_apic = 1; - return 0; + return 1; } static __init int setup_nolapic(char *str) { disable_apic = 1; - return 0; + return 1; } static __init int setup_noapictimer(char *str) { if (str[0] != ' ' && str[0] != 0) - return -1; + return 0; disable_apic_timer = 1; - return 0; + return 1; } static __init int setup_apicmaintimer(char *str) { apic_runs_main_timer = 1; nohpet = 1; - return 0; + return 1; } __setup("apicmaintimer", setup_apicmaintimer); static __init int setup_noapicmaintimer(char *str) { apic_runs_main_timer = -1; - return 0; + return 1; } __setup("noapicmaintimer", setup_noapicmaintimer); diff --git a/arch/x86_64/kernel/early_printk.c b/arch/x86_64/kernel/early_printk.c index 13af920b659..b93ef5b5198 100644 --- a/arch/x86_64/kernel/early_printk.c +++ b/arch/x86_64/kernel/early_printk.c @@ -221,7 +221,7 @@ int __init setup_early_printk(char *opt) char buf[256]; if (early_console_initialized) - return -1; + return 1; strlcpy(buf,opt,sizeof(buf)); space = strchr(buf, ' '); diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c index 04282ef9fbd..10b3e348fc9 100644 --- a/arch/x86_64/kernel/mce.c +++ b/arch/x86_64/kernel/mce.c @@ -501,7 +501,7 @@ static struct miscdevice mce_log_device = { static int __init mcheck_disable(char *str) { mce_dont_init = 1; - return 0; + return 1; } /* mce=off disables machine check. Note you can reenable it later @@ -521,7 +521,7 @@ static int __init mcheck_enable(char *str) get_option(&str, &tolerant); else printk("mce= argument %s ignored. Please use /sys", str); - return 0; + return 1; } __setup("nomce", mcheck_disable); diff --git a/arch/x86_64/kernel/pmtimer.c b/arch/x86_64/kernel/pmtimer.c index ee5ee4891f3..b0444a415bd 100644 --- a/arch/x86_64/kernel/pmtimer.c +++ b/arch/x86_64/kernel/pmtimer.c @@ -121,7 +121,7 @@ unsigned int do_gettimeoffset_pm(void) static int __init nopmtimer_setup(char *s) { pmtmr_ioport = 0; - return 0; + return 1; } __setup("nopmtimer", nopmtimer_setup); diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c index d1f3e9272c0..0856ad444f9 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c @@ -540,7 +540,7 @@ void __init alternative_instructions(void) static int __init noreplacement_setup(char *s) { no_replacement = 1; - return 0; + return 1; } __setup("noreplacement", noreplacement_setup); diff --git a/arch/x86_64/kernel/setup64.c b/arch/x86_64/kernel/setup64.c index eabdb63fec3..8a691fa6d39 100644 --- a/arch/x86_64/kernel/setup64.c +++ b/arch/x86_64/kernel/setup64.c @@ -55,7 +55,7 @@ int __init nonx_setup(char *str) do_not_nx = 1; __supported_pte_mask &= ~_PAGE_NX; } - return 0; + return 1; } __setup("noexec=", nonx_setup); /* parsed early actually */ @@ -74,7 +74,7 @@ static int __init nonx32_setup(char *str) force_personality32 &= ~READ_IMPLIES_EXEC; else if (!strcmp(str, "off")) force_personality32 |= READ_IMPLIES_EXEC; - return 0; + return 1; } __setup("noexec32=", nonx32_setup); diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c index ea48fa63807..71a7222cf9c 100644 --- a/arch/x86_64/kernel/smpboot.c +++ b/arch/x86_64/kernel/smpboot.c @@ -353,7 +353,7 @@ static void __cpuinit tsc_sync_wait(void) static __init int notscsync_setup(char *s) { notscsync = 1; - return 0; + return 1; } __setup("notscsync", notscsync_setup); diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c index 473b514b66e..ef8bc46dc14 100644 --- a/arch/x86_64/kernel/time.c +++ b/arch/x86_64/kernel/time.c @@ -1306,7 +1306,7 @@ irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) static int __init nohpet_setup(char *s) { nohpet = 1; - return 0; + return 1; } __setup("nohpet", nohpet_setup); @@ -1314,7 +1314,7 @@ __setup("nohpet", nohpet_setup); int __init notsc_setup(char *s) { notsc = 1; - return 0; + return 1; } __setup("notsc", notsc_setup); diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index edaa9fe654d..6bda322d3ca 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c @@ -973,14 +973,14 @@ void __init trap_init(void) static int __init oops_dummy(char *s) { panic_on_oops = 1; - return -1; + return 1; } __setup("oops=", oops_dummy); static int __init kstack_setup(char *s) { kstack_depth_to_print = simple_strtoul(s,NULL,0); - return 0; + return 1; } __setup("kstack=", kstack_setup); diff --git a/arch/x86_64/kernel/x8664_ksyms.c b/arch/x86_64/kernel/x8664_ksyms.c index d96a9348e5a..d78f46056bd 100644 --- a/arch/x86_64/kernel/x8664_ksyms.c +++ b/arch/x86_64/kernel/x8664_ksyms.c @@ -102,8 +102,6 @@ EXPORT_SYMBOL(cpu_callout_map); EXPORT_SYMBOL(screen_info); #endif -EXPORT_SYMBOL(get_wchan); - EXPORT_SYMBOL(rtc_lock); EXPORT_SYMBOL_GPL(set_nmi_callback); diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c index 316c53de47b..55250593d8c 100644 --- a/arch/x86_64/mm/fault.c +++ b/arch/x86_64/mm/fault.c @@ -623,6 +623,6 @@ void vmalloc_sync_all(void) static int __init enable_pagefaulttrace(char *str) { page_fault_trace = 1; - return 0; + return 1; } __setup("pagefaulttrace", enable_pagefaulttrace); diff --git a/arch/xtensa/kernel/xtensa_ksyms.c b/arch/xtensa/kernel/xtensa_ksyms.c index efae56a5147..152b9370789 100644 --- a/arch/xtensa/kernel/xtensa_ksyms.c +++ b/arch/xtensa/kernel/xtensa_ksyms.c @@ -113,8 +113,6 @@ EXPORT_SYMBOL(__xtensa_copy_user); // FIXME EXPORT_SYMBOL(screen_info); #endif -EXPORT_SYMBOL(get_wchan); - EXPORT_SYMBOL(outsb); EXPORT_SYMBOL(outsw); EXPORT_SYMBOL(outsl); |