diff options
Diffstat (limited to 'arch')
57 files changed, 2503 insertions, 366 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 50d9f3e4e0f..a0fa1ce9ad6 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -241,6 +241,9 @@ config ARCH_H720X config ARCH_IMX bool "IMX" + select GENERIC_GPIO + select GENERIC_TIME + select GENERIC_CLOCKEVENTS help Support for Motorola's i.MX family of processors (MX1, MXL). @@ -308,6 +311,7 @@ config ARCH_L7200 config ARCH_KS8695 bool "Micrel/Kendin KS8695" + select GENERIC_GPIO help Support for Micrel/Kendin KS8695 "Centaur" (ARM922T) based System-on-Chip devices. @@ -384,6 +388,7 @@ config ARCH_DAVINCI bool "TI DaVinci" select GENERIC_TIME select GENERIC_CLOCKEVENTS + select GENERIC_GPIO help Support for TI's DaVinci platform. diff --git a/arch/arm/boot/compressed/.gitignore b/arch/arm/boot/compressed/.gitignore index aefee20cbf9..b15f927a592 100644 --- a/arch/arm/boot/compressed/.gitignore +++ b/arch/arm/boot/compressed/.gitignore @@ -1 +1,2 @@ piggy.gz +font.c diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index adddc713168..a1f1691b67f 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -6,15 +6,13 @@ HEAD = head.o OBJS = misc.o -FONTC = drivers/video/console/font_acorn_8x8.c - -FONT = $(addprefix ../../../../drivers/video/console/, font_acorn_8x8.o) +FONTC = $(srctree)/drivers/video/console/font_acorn_8x8.c # # Architecture dependencies # ifeq ($(CONFIG_ARCH_ACORN),y) -OBJS += ll_char_wr.o $(FONT) +OBJS += ll_char_wr.o font.o endif ifeq ($(CONFIG_ARCH_SHARK),y) @@ -73,7 +71,7 @@ endif SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/ -targets := vmlinux vmlinux.lds piggy.gz piggy.o $(FONT) \ +targets := vmlinux vmlinux.lds piggy.gz piggy.o font.o font.c \ head.o misc.o $(OBJS) EXTRA_CFLAGS := -fpic EXTRA_AFLAGS := @@ -105,7 +103,10 @@ $(obj)/piggy.gz: $(obj)/../Image FORCE $(obj)/piggy.o: $(obj)/piggy.gz FORCE -CFLAGS_font_acorn_8x8.o := -Dstatic= +CFLAGS_font.o := -Dstatic= + +$(obj)/font.c: $(FONTC) + $(call cmd,shipped) $(obj)/vmlinux.lds: $(obj)/vmlinux.lds.in arch/arm/boot/Makefile .config @sed "$(SEDFLAGS)" < $< > $@ diff --git a/arch/arm/boot/compressed/head-xscale.S b/arch/arm/boot/compressed/head-xscale.S index 73c5d9e0201..236bbe57831 100644 --- a/arch/arm/boot/compressed/head-xscale.S +++ b/arch/arm/boot/compressed/head-xscale.S @@ -41,11 +41,6 @@ __XScale_start: mov r7, #MACH_TYPE_COTULLA_IDP #endif -#ifdef CONFIG_MACH_GTWX5715 - mov r7, #(MACH_TYPE_GTWX5715 & 0xff) - orr r7, r7, #(MACH_TYPE_GTWX5715 & 0xff00) -#endif - #ifdef CONFIG_ARCH_IXP2000 mov r1, #-1 mov r0, #0xd6000000 diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 680ea6ed77b..d7fb5ee1637 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -436,6 +436,28 @@ __armv4_mmu_cache_on: mcr p15, 0, r0, c8, c7, 0 @ flush I,D TLBs mov pc, r12 +__armv7_mmu_cache_on: + mov r12, lr + mrc p15, 0, r11, c0, c1, 4 @ read ID_MMFR0 + tst r11, #0xf @ VMSA + blne __setup_mmu + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer + tst r11, #0xf @ VMSA + mcrne p15, 0, r0, c8, c7, 0 @ flush I,D TLBs + mrc p15, 0, r0, c1, c0, 0 @ read control reg + orr r0, r0, #0x5000 @ I-cache enable, RR cache replacement + orr r0, r0, #0x003c @ write buffer + orrne r0, r0, #1 @ MMU enabled + movne r1, #-1 + mcrne p15, 0, r3, c2, c0, 0 @ load page table pointer + mcrne p15, 0, r1, c3, c0, 0 @ load domain access control + mcr p15, 0, r0, c1, c0, 0 @ load control register + mrc p15, 0, r0, c1, c0, 0 @ and read it back + mov r0, #0 + mcr p15, 0, r0, c7, c5, 4 @ ISB + mov pc, r12 + __arm6_mmu_cache_on: mov r12, lr bl __setup_mmu @@ -622,11 +644,17 @@ proc_types: b __armv4_mmu_cache_flush .word 0x0007b000 @ ARMv6 - .word 0x0007f000 + .word 0x000ff000 b __armv4_mmu_cache_on b __armv4_mmu_cache_off b __armv6_mmu_cache_flush + .word 0x000f0000 @ new CPU Id + .word 0x000f0000 + b __armv7_mmu_cache_on + b __armv7_mmu_cache_off + b __armv7_mmu_cache_flush + .word 0 @ unrecognised type .word 0 mov pc, lr @@ -674,6 +702,16 @@ __armv4_mmu_cache_off: mcr p15, 0, r0, c8, c7 @ invalidate whole TLB v4 mov pc, lr +__armv7_mmu_cache_off: + mrc p15, 0, r0, c1, c0 + bic r0, r0, #0x000d + mcr p15, 0, r0, c1, c0 @ turn MMU and cache off + mov r12, lr + bl __armv7_mmu_cache_flush + mov r0, #0 + mcr p15, 0, r0, c8, c7, 0 @ invalidate whole TLB + mov pc, r12 + __arm6_mmu_cache_off: mov r0, #0x00000030 @ ARM6 control reg. b __armv3_mmu_cache_off @@ -730,6 +768,59 @@ __armv6_mmu_cache_flush: mcr p15, 0, r1, c7, c10, 4 @ drain WB mov pc, lr +__armv7_mmu_cache_flush: + mrc p15, 0, r10, c0, c1, 5 @ read ID_MMFR1 + tst r10, #0xf << 16 @ hierarchical cache (ARMv7) + beq hierarchical + mov r10, #0 + mcr p15, 0, r10, c7, c14, 0 @ clean+invalidate D + b iflush +hierarchical: + stmfd sp!, {r0-r5, r7, r9-r11} + mrc p15, 1, r0, c0, c0, 1 @ read clidr + ands r3, r0, #0x7000000 @ extract loc from clidr + mov r3, r3, lsr #23 @ left align loc bit field + beq finished @ if loc is 0, then no need to clean + mov r10, #0 @ start clean at cache level 0 +loop1: + add r2, r10, r10, lsr #1 @ work out 3x current cache level + mov r1, r0, lsr r2 @ extract cache type bits from clidr + and r1, r1, #7 @ mask of the bits for current cache only + cmp r1, #2 @ see what cache we have at this level + blt skip @ skip if no cache, or just i-cache + mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr + mcr p15, 0, r10, c7, c5, 4 @ isb to sych the new cssr&csidr + mrc p15, 1, r1, c0, c0, 0 @ read the new csidr + and r2, r1, #7 @ extract the length of the cache lines + add r2, r2, #4 @ add 4 (line length offset) + ldr r4, =0x3ff + ands r4, r4, r1, lsr #3 @ find maximum number on the way size + .word 0xe16f5f14 @ clz r5, r4 - find bit position of way size increment + ldr r7, =0x7fff + ands r7, r7, r1, lsr #13 @ extract max number of the index size +loop2: + mov r9, r4 @ create working copy of max way size +loop3: + orr r11, r10, r9, lsl r5 @ factor way and cache number into r11 + orr r11, r11, r7, lsl r2 @ factor index number into r11 + mcr p15, 0, r11, c7, c14, 2 @ clean & invalidate by set/way + subs r9, r9, #1 @ decrement the way + bge loop3 + subs r7, r7, #1 @ decrement the index + bge loop2 +skip: + add r10, r10, #2 @ increment cache number + cmp r3, r10 + bgt loop1 +finished: + mov r10, #0 @ swith back to cache level 0 + mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr + ldmfd sp!, {r0-r5, r7, r9-r11} +iflush: + mcr p15, 0, r10, c7, c5, 0 @ invalidate I+BTB + mcr p15, 0, r10, c7, c10, 4 @ drain WB + mov pc, lr + __armv4_mmu_cache_flush: mov r2, #64*1024 @ default: 32K dcache size (*2) mov r11, #32 @ default: 32 byte line size diff --git a/arch/arm/common/sharpsl_pm.c b/arch/arm/common/sharpsl_pm.c index 3bf3a927ae2..111a7fa5deb 100644 --- a/arch/arm/common/sharpsl_pm.c +++ b/arch/arm/common/sharpsl_pm.c @@ -766,9 +766,7 @@ static void sharpsl_apm_get_power_status(struct apm_power_info *info) } static struct pm_ops sharpsl_pm_ops = { - .prepare = pxa_pm_prepare, .enter = corgi_pxa_pm_enter, - .finish = pxa_pm_finish, .valid = pm_valid_only_mem, }; diff --git a/arch/arm/kernel/head-common.S b/arch/arm/kernel/head-common.S index a52da0ddb43..024a9cf469b 100644 --- a/arch/arm/kernel/head-common.S +++ b/arch/arm/kernel/head-common.S @@ -20,7 +20,8 @@ __switch_data: .long _end @ r7 .long processor_id @ r4 .long __machine_arch_type @ r5 - .long cr_alignment @ r6 + .long __atags_pointer @ r6 + .long cr_alignment @ r7 .long init_thread_union + THREAD_START_SP @ sp /* @@ -29,6 +30,7 @@ __switch_data: * * r0 = cp#15 control register * r1 = machine ID + * r2 = atags pointer * r9 = processor ID */ .type __mmap_switched, %function @@ -47,11 +49,12 @@ __mmap_switched: strcc fp, [r6],#4 bcc 1b - ldmia r3, {r4, r5, r6, sp} + ldmia r3, {r4, r5, r6, r7, sp} str r9, [r4] @ Save processor ID str r1, [r5] @ Save machine type + str r2, [r6] @ Save atags pointer bic r4, r0, #CR_A @ Clear 'A' bit - stmia r6, {r0, r4} @ Save control register values + stmia r7, {r0, r4} @ Save control register values b start_kernel /* @@ -215,3 +218,34 @@ ENTRY(lookup_machine_type) bl __lookup_machine_type mov r0, r5 ldmfd sp!, {r4 - r6, pc} + +/* Determine validity of the r2 atags pointer. The heuristic requires + * that the pointer be aligned, in the first 16k of physical RAM and + * that the ATAG_CORE marker is first and present. Future revisions + * of this function may be more lenient with the physical address and + * may also be able to move the ATAGS block if necessary. + * + * r8 = machinfo + * + * Returns: + * r2 either valid atags pointer, or zero + * r5, r6 corrupted + */ + + .type __vet_atags, %function +__vet_atags: + tst r2, #0x3 @ aligned? + bne 1f + + ldr r5, [r2, #0] @ is first tag ATAG_CORE? + subs r5, r5, #ATAG_CORE_SIZE + bne 1f + ldr r5, [r2, #4] + ldr r6, =ATAG_CORE + cmp r5, r6 + bne 1f + + mov pc, lr @ atag pointer is ok + +1: mov r2, #0 + mov pc, lr diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 41f98b4ba2e..7898cbc9861 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -29,6 +29,10 @@ #define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET) #define KERNEL_RAM_PADDR (PHYS_OFFSET + TEXT_OFFSET) +#define ATAG_CORE 0x54410001 +#define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2) + + /* * swapper_pg_dir is the virtual address of the initial page table. * We place the page tables 16K below KERNEL_RAM_VADDR. Therefore, we must @@ -61,7 +65,7 @@ * * 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. + * r1 = machine nr, r2 = atags pointer. * * This code is mostly position independent, so if you link the kernel at * 0xc0008000, you call this at __pa(0xc0008000). @@ -85,6 +89,7 @@ ENTRY(stext) bl __lookup_machine_type @ r5=machinfo movs r8, r5 @ invalid machine (r5=0)? beq __error_a @ yes, error 'a' + bl __vet_atags bl __create_page_tables /* diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 842361777d4..93b7f8e22dc 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -44,6 +44,10 @@ static const char *processor_modes[] = { "UK8_32" , "UK9_32" , "UK10_32", "UND_32" , "UK12_32", "UK13_32", "UK14_32", "SYS_32" }; +static const char *isa_modes[] = { + "ARM" , "Thumb" , "Jazelle", "ThumbEE" +}; + extern void setup_mm_for_reboot(char mode); static volatile int hlt_counter; @@ -230,11 +234,11 @@ void __show_regs(struct pt_regs *regs) buf[3] = flags & PSR_V_BIT ? 'V' : 'v'; buf[4] = '\0'; - printk("Flags: %s IRQs o%s FIQs o%s Mode %s%s Segment %s\n", + printk("Flags: %s IRQs o%s FIQs o%s Mode %s ISA %s Segment %s\n", buf, interrupts_enabled(regs) ? "n" : "ff", fast_interrupts_enabled(regs) ? "n" : "ff", processor_modes[processor_mode(regs)], - thumb_mode(regs) ? " (T)" : "", + isa_modes[isa_mode(regs)], get_fs() == get_ds() ? "kernel" : "user"); #ifdef CONFIG_CPU_CP15 { diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 650eac1bc0a..5be2e987b84 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -63,6 +63,8 @@ unsigned int processor_id; unsigned int __machine_arch_type; EXPORT_SYMBOL(__machine_arch_type); +unsigned int __atags_pointer __initdata; + unsigned int system_rev; EXPORT_SYMBOL(system_rev); @@ -780,7 +782,9 @@ void __init setup_arch(char **cmdline_p) if (mdesc->soft_reboot) reboot_setup("s"); - if (mdesc->boot_params) + if (__atags_pointer) + tags = phys_to_virt(__atags_pointer); + else if (mdesc->boot_params) tags = phys_to_virt(mdesc->boot_params); /* diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c index 26ca8ab3f62..42e172cb0f4 100644 --- a/arch/arm/mach-at91/board-sam9261ek.c +++ b/arch/arm/mach-at91/board-sam9261ek.c @@ -27,6 +27,11 @@ #include <linux/spi/spi.h> #include <linux/spi/ads7846.h> #include <linux/dm9000.h> +#include <linux/fb.h> +#include <linux/gpio_keys.h> +#include <linux/input.h> + +#include <video/atmel_lcdc.h> #include <asm/hardware.h> #include <asm/setup.h> @@ -271,6 +276,127 @@ static struct spi_board_info ek_spi_devices[] = { }; +/* + * LCD Controller + */ +#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE) +static struct fb_videomode at91_tft_vga_modes[] = { + { + .name = "TX09D50VM1CCA @ 60", + .refresh = 60, + .xres = 240, .yres = 320, + .pixclock = KHZ2PICOS(4965), + + .left_margin = 1, .right_margin = 33, + .upper_margin = 1, .lower_margin = 0, + .hsync_len = 5, .vsync_len = 1, + + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED, + }, +}; + +static struct fb_monspecs at91fb_default_monspecs = { + .manufacturer = "HIT", + .monitor = "TX09D50VM1CCA", + + .modedb = at91_tft_vga_modes, + .modedb_len = ARRAY_SIZE(at91_tft_vga_modes), + .hfmin = 15000, + .hfmax = 64000, + .vfmin = 50, + .vfmax = 150, +}; + +#define AT91SAM9261_DEFAULT_LCDCON2 (ATMEL_LCDC_MEMOR_LITTLE \ + | ATMEL_LCDC_DISTYPE_TFT \ + | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE) + +static void at91_lcdc_power_control(int on) +{ + if (on) + at91_set_gpio_value(AT91_PIN_PA12, 0); /* power up */ + else + at91_set_gpio_value(AT91_PIN_PA12, 1); /* power down */ +} + +/* Driver datas */ +static struct atmel_lcdfb_info __initdata ek_lcdc_data = { + .default_bpp = 16, + .default_dmacon = ATMEL_LCDC_DMAEN, + .default_lcdcon2 = AT91SAM9261_DEFAULT_LCDCON2, + .default_monspecs = &at91fb_default_monspecs, + .atmel_lcdfb_power_control = at91_lcdc_power_control, + .guard_time = 1, +}; + +#else +static struct atmel_lcdfb_info __initdata ek_lcdc_data; +#endif + + +/* + * GPIO Buttons + */ +#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE) +static struct gpio_keys_button ek_buttons[] = { + { + .gpio = AT91_PIN_PA27, + .keycode = BTN_0, + .desc = "Button 0", + .active_low = 1, + }, + { + .gpio = AT91_PIN_PA26, + .keycode = BTN_1, + .desc = "Button 1", + .active_low = 1, + }, + { + .gpio = AT91_PIN_PA25, + .keycode = BTN_2, + .desc = "Button 2", + .active_low = 1, + }, + { + .gpio = AT91_PIN_PA24, + .keycode = BTN_3, + .desc = "Button 3", + .active_low = 1, + } +}; + +static struct gpio_keys_platform_data ek_button_data = { + .buttons = ek_buttons, + .nbuttons = ARRAY_SIZE(ek_buttons), +}; + +static struct platform_device ek_button_device = { + .name = "gpio-keys", + .id = -1, + .num_resources = 0, + .dev = { + .platform_data = &ek_button_data, + } +}; + +static void __init ek_add_device_buttons(void) +{ + at91_set_gpio_input(AT91_PIN_PB27, 0); /* btn0 */ + at91_set_deglitch(AT91_PIN_PB27, 1); + at91_set_gpio_input(AT91_PIN_PB26, 0); /* btn1 */ + at91_set_deglitch(AT91_PIN_PB26, 1); + at91_set_gpio_input(AT91_PIN_PB25, 0); /* btn2 */ + at91_set_deglitch(AT91_PIN_PB25, 1); + at91_set_gpio_input(AT91_PIN_PB24, 0); /* btn3 */ + at91_set_deglitch(AT91_PIN_PB24, 1); + + platform_device_register(&ek_button_device); +} +#else +static void __init ek_add_device_buttons(void) {} +#endif + static void __init ek_board_init(void) { /* Serial */ @@ -296,6 +422,10 @@ static void __init ek_board_init(void) /* MMC */ at91_add_device_mmc(0, &ek_mmc_data); #endif + /* LCD Controller */ + at91_add_device_lcdc(&ek_lcdc_data); + /* Push Buttons */ + ek_add_device_buttons(); } MACHINE_START(AT91SAM9261EK, "Atmel AT91SAM9261-EK") diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c index c164c8e58ae..2a1cc73390b 100644 --- a/arch/arm/mach-at91/board-sam9263ek.c +++ b/arch/arm/mach-at91/board-sam9263ek.c @@ -26,6 +26,9 @@ #include <linux/platform_device.h> #include <linux/spi/spi.h> #include <linux/spi/ads7846.h> +#include <linux/fb.h> + +#include <video/atmel_lcdc.h> #include <asm/hardware.h> #include <asm/setup.h> @@ -202,6 +205,65 @@ static struct at91_nand_data __initdata ek_nand_data = { /* + * LCD Controller + */ +#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE) +static struct fb_videomode at91_tft_vga_modes[] = { + { + .name = "TX09D50VM1CCA @ 60", + .refresh = 60, + .xres = 240, .yres = 320, + .pixclock = KHZ2PICOS(4965), + + .left_margin = 1, .right_margin = 33, + .upper_margin = 1, .lower_margin = 0, + .hsync_len = 5, .vsync_len = 1, + + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED, + }, +}; + +static struct fb_monspecs at91fb_default_monspecs = { + .manufacturer = "HIT", + .monitor = "TX09D70VM1CCA", + + .modedb = at91_tft_vga_modes, + .modedb_len = ARRAY_SIZE(at91_tft_vga_modes), + .hfmin = 15000, + .hfmax = 64000, + .vfmin = 50, + .vfmax = 150, +}; + +#define AT91SAM9263_DEFAULT_LCDCON2 (ATMEL_LCDC_MEMOR_LITTLE \ + | ATMEL_LCDC_DISTYPE_TFT \ + | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE) + +static void at91_lcdc_power_control(int on) +{ + if (on) + at91_set_gpio_value(AT91_PIN_PD12, 0); /* power up */ + else + at91_set_gpio_value(AT91_PIN_PD12, 1); /* power down */ +} + +/* Driver datas */ +static struct atmel_lcdfb_info __initdata ek_lcdc_data = { + .default_bpp = 16, + .default_dmacon = ATMEL_LCDC_DMAEN, + .default_lcdcon2 = AT91SAM9263_DEFAULT_LCDCON2, + .default_monspecs = &at91fb_default_monspecs, + .atmel_lcdfb_power_control = at91_lcdc_power_control, + .guard_time = 1, +}; + +#else +static struct atmel_lcdfb_info __initdata ek_lcdc_data; +#endif + + +/* * AC97 */ static struct atmel_ac97_data ek_ac97_data = { @@ -230,6 +292,8 @@ static void __init ek_board_init(void) at91_add_device_nand(&ek_nand_data); /* I2C */ at91_add_device_i2c(); + /* LCD Controller */ + at91_add_device_lcdc(&ek_lcdc_data); /* AC97 */ at91_add_device_ac97(&ek_ac97_data); } diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile index a8f88cd2990..99ac2e55774 100644 --- a/arch/arm/mach-davinci/Makefile +++ b/arch/arm/mach-davinci/Makefile @@ -4,7 +4,8 @@ # # Common objects -obj-y := time.o irq.o serial.o io.o id.o psc.o +obj-y := time.o irq.o clock.o serial.o io.o id.o psc.o \ + gpio.o mux.o # Board specific obj-$(CONFIG_MACH_DAVINCI_EVM) += board-evm.o diff --git a/arch/arm/mach-davinci/board-evm.c b/arch/arm/mach-davinci/board-evm.c index 633c12e4304..9e4024c4965 100644 --- a/arch/arm/mach-davinci/board-evm.c +++ b/arch/arm/mach-davinci/board-evm.c @@ -32,6 +32,7 @@ void __init davinci_psc_init(void); void __init davinci_irq_init(void); void __init davinci_map_common_io(void); +void __init davinci_init_common_hw(void); /* NOR Flash base address set to CS0 by default */ #define NOR_FLASH_PHYS 0x02000000 @@ -116,6 +117,7 @@ static __init void davinci_evm_init(void) static __init void davinci_evm_irq_init(void) { + davinci_init_common_hw(); davinci_irq_init(); } diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c new file mode 100644 index 00000000000..139ceaa35e2 --- /dev/null +++ b/arch/arm/mach-davinci/clock.c @@ -0,0 +1,323 @@ +/* + * TI DaVinci clock config file + * + * Copyright (C) 2006 Texas Instruments. + * + * 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/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> + +#include <asm/hardware.h> +#include <asm/io.h> + +#include <asm/arch/psc.h> +#include "clock.h" + +/* PLL/Reset register offsets */ +#define PLLM 0x110 + +static LIST_HEAD(clocks); +static DEFINE_MUTEX(clocks_mutex); +static DEFINE_SPINLOCK(clockfw_lock); + +static unsigned int commonrate; +static unsigned int armrate; +static unsigned int fixedrate = 27000000; /* 27 MHZ */ + +extern void davinci_psc_config(unsigned int domain, unsigned int id, char enable); + +/* + * 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; + goto found; + } + } + + list_for_each_entry(p, &clocks, node) { + if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { + clk = p; + break; + } + } + +found: + mutex_unlock(&clocks_mutex); + + return clk; +} +EXPORT_SYMBOL(clk_get); + +void clk_put(struct clk *clk) +{ + if (clk && !IS_ERR(clk)) + module_put(clk->owner); +} +EXPORT_SYMBOL(clk_put); + +static int __clk_enable(struct clk *clk) +{ + if (clk->flags & ALWAYS_ENABLED) + return 0; + + davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, clk->lpsc, 1); + return 0; +} + +static void __clk_disable(struct clk *clk) +{ + if (clk->usecount) + return; + + davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, clk->lpsc, 0); +} + +int clk_enable(struct clk *clk) +{ + unsigned long flags; + int ret = 0; + + if (clk == NULL || IS_ERR(clk)) + return -EINVAL; + + if (clk->usecount++ == 0) { + spin_lock_irqsave(&clockfw_lock, flags); + ret = __clk_enable(clk); + spin_unlock_irqrestore(&clockfw_lock, flags); + } + + return ret; +} +EXPORT_SYMBOL(clk_enable); + +void clk_disable(struct clk *clk) +{ + unsigned long flags; + + if (clk == NULL || IS_ERR(clk)) + return; + + if (clk->usecount > 0 && !(--clk->usecount)) { + spin_lock_irqsave(&clockfw_lock, flags); + __clk_disable(clk); + spin_unlock_irqrestore(&clockfw_lock, flags); + } +} +EXPORT_SYMBOL(clk_disable); + +unsigned long clk_get_rate(struct clk *clk) +{ + if (clk == NULL || IS_ERR(clk)) + return -EINVAL; + + return *(clk->rate); +} +EXPORT_SYMBOL(clk_get_rate); + +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + if (clk == NULL || IS_ERR(clk)) + return -EINVAL; + + return *(clk->rate); +} +EXPORT_SYMBOL(clk_round_rate); + +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + if (clk == NULL || IS_ERR(clk)) + return -EINVAL; + + /* changing the clk rate is not supported */ + return -EINVAL; +} +EXPORT_SYMBOL(clk_set_rate); + +int clk_register(struct clk *clk) +{ + if (clk == NULL || IS_ERR(clk)) + return -EINVAL; + + mutex_lock(&clocks_mutex); + list_add(&clk->node, &clocks); + mutex_unlock(&clocks_mutex); + + return 0; +} +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); +} +EXPORT_SYMBOL(clk_unregister); + +static struct clk davinci_clks[] = { + { + .name = "ARMCLK", + .rate = &armrate, + .lpsc = -1, + .flags = ALWAYS_ENABLED, + }, + { + .name = "UART", + .rate = &fixedrate, + .lpsc = DAVINCI_LPSC_UART0, + }, + { + .name = "EMACCLK", + .rate = &commonrate, + .lpsc = DAVINCI_LPSC_EMAC_WRAPPER, + }, + { + .name = "I2CCLK", + .rate = &fixedrate, + .lpsc = DAVINCI_LPSC_I2C, + }, + { + .name = "IDECLK", + .rate = &commonrate, + .lpsc = DAVINCI_LPSC_ATA, + }, + { + .name = "McBSPCLK", + .rate = &commonrate, + .lpsc = DAVINCI_LPSC_McBSP, + }, + { + .name = "MMCSDCLK", + .rate = &commonrate, + .lpsc = DAVINCI_LPSC_MMC_SD, + }, + { + .name = "SPICLK", + .rate = &commonrate, + .lpsc = DAVINCI_LPSC_SPI, + }, + { + .name = "gpio", + .rate = &commonrate, + .lpsc = DAVINCI_LPSC_GPIO, + }, + { + .name = "AEMIFCLK", + .rate = &commonrate, + .lpsc = DAVINCI_LPSC_AEMIF, + .usecount = 1, + } +}; + +int __init davinci_clk_init(void) +{ + struct clk *clkp; + int count = 0; + u32 pll_mult; + + pll_mult = davinci_readl(DAVINCI_PLL_CNTRL0_BASE + PLLM); + commonrate = ((pll_mult + 1) * 27000000) / 6; + armrate = ((pll_mult + 1) * 27000000) / 2; + + for (clkp = davinci_clks; count < ARRAY_SIZE(davinci_clks); + count++, clkp++) { + clk_register(clkp); + + /* Turn on clocks that have been enabled in the + * table above */ + if (clkp->usecount) + clk_enable(clkp); + } + + return 0; +} + +#ifdef CONFIG_PROC_FS +#include <linux/proc_fs.h> +#include <linux/seq_file.h> + +static void *davinci_ck_start(struct seq_file *m, loff_t *pos) +{ + return *pos < 1 ? (void *)1 : NULL; +} + +static void *davinci_ck_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return NULL; +} + +static void davinci_ck_stop(struct seq_file *m, void *v) +{ +} + +static int davinci_ck_show(struct seq_file *m, void *v) +{ + struct clk *cp; + + list_for_each_entry(cp, &clocks, node) + seq_printf(m,"%s %d %d\n", cp->name, *(cp->rate), cp->usecount); + + return 0; +} + +static struct seq_operations davinci_ck_op = { + .start = davinci_ck_start, + .next = davinci_ck_next, + .stop = davinci_ck_stop, + .show = davinci_ck_show +}; + +static int davinci_ck_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &davinci_ck_op); +} + +static struct file_operations proc_davinci_ck_operations = { + .open = davinci_ck_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int __init davinci_ck_proc_init(void) +{ + struct proc_dir_entry *entry; + + entry = create_proc_entry("davinci_clocks", 0, NULL); + if (entry) + entry->proc_fops = &proc_davinci_ck_operations; + return 0; + +} +__initcall(davinci_ck_proc_init); +#endif /* CONFIG_DEBUG_PROC_FS */ diff --git a/arch/arm/mach-davinci/clock.h b/arch/arm/mach-davinci/clock.h new file mode 100644 index 00000000000..ed47079a52e --- /dev/null +++ b/arch/arm/mach-davinci/clock.h @@ -0,0 +1,33 @@ +/* + * TI DaVinci clock definitions + * + * Copyright (C) 2006 Texas Instruments. + * + * 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. + */ + +#ifndef __ARCH_ARM_DAVINCI_CLOCK_H +#define __ARCH_ARM_DAVINCI_CLOCK_H + +struct clk { + struct list_head node; + struct module *owner; + const char *name; + unsigned int *rate; + int id; + __s8 usecount; + __u8 flags; + __u8 lpsc; +}; + +/* Clock flags */ +#define RATE_CKCTL 1 +#define RATE_FIXED 2 +#define RATE_PROPAGATES 4 +#define VIRTUAL_CLOCK 8 +#define ALWAYS_ENABLED 16 +#define ENABLE_REG_32BIT 32 + +#endif diff --git a/arch/arm/mach-davinci/gpio.c b/arch/arm/mach-davinci/gpio.c new file mode 100644 index 00000000000..9c67886e718 --- /dev/null +++ b/arch/arm/mach-davinci/gpio.c @@ -0,0 +1,286 @@ +/* + * TI DaVinci GPIO Support + * + * Copyright (c) 2006 David Brownell + * Copyright (c) 2007, MontaVista Software, Inc. <source@mvista.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. + */ + +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/bitops.h> + +#include <asm/arch/irqs.h> +#include <asm/arch/hardware.h> +#include <asm/arch/gpio.h> + +#include <asm/mach/irq.h> + +static DEFINE_SPINLOCK(gpio_lock); +static DECLARE_BITMAP(gpio_in_use, DAVINCI_N_GPIO); + +int gpio_request(unsigned gpio, const char *tag) +{ + if (gpio >= DAVINCI_N_GPIO) + return -EINVAL; + + if (test_and_set_bit(gpio, gpio_in_use)) + return -EBUSY; + + return 0; +} +EXPORT_SYMBOL(gpio_request); + +void gpio_free(unsigned gpio) +{ + if (gpio >= DAVINCI_N_GPIO) + return; + + clear_bit(gpio, gpio_in_use); +} +EXPORT_SYMBOL(gpio_free); + +/* create a non-inlined version */ +static struct gpio_controller *__iomem gpio2controller(unsigned gpio) +{ + return __gpio_to_controller(gpio); +} + +/* + * Assuming the pin is muxed as a gpio output, set its output value. + */ +void __gpio_set(unsigned gpio, int value) +{ + struct gpio_controller *__iomem g = gpio2controller(gpio); + + __raw_writel(__gpio_mask(gpio), value ? &g->set_data : &g->clr_data); +} +EXPORT_SYMBOL(__gpio_set); + + +/* + * Read the pin's value (works even if it's set up as output); + * returns zero/nonzero. + * + * Note that changes are synched to the GPIO clock, so reading values back + * right after you've set them may give old values. + */ +int __gpio_get(unsigned gpio) +{ + struct gpio_controller *__iomem g = gpio2controller(gpio); + + return !!(__gpio_mask(gpio) & __raw_readl(&g->in_data)); +} +EXPORT_SYMBOL(__gpio_get); + + +/*--------------------------------------------------------------------------*/ + +/* + * board setup code *MUST* set PINMUX0 and PINMUX1 as + * needed, and enable the GPIO clock. + */ + +int gpio_direction_input(unsigned gpio) +{ + struct gpio_controller *__iomem g = gpio2controller(gpio); + u32 temp; + u32 mask; + + if (!g) + return -EINVAL; + + spin_lock(&gpio_lock); + mask = __gpio_mask(gpio); + temp = __raw_readl(&g->dir); + temp |= mask; + __raw_writel(temp, &g->dir); + spin_unlock(&gpio_lock); + return 0; +} +EXPORT_SYMBOL(gpio_direction_input); + +int gpio_direction_output(unsigned gpio, int value) +{ + struct gpio_controller *__iomem g = gpio2controller(gpio); + u32 temp; + u32 mask; + + if (!g) + return -EINVAL; + + spin_lock(&gpio_lock); + mask = __gpio_mask(gpio); + temp = __raw_readl(&g->dir); + temp &= ~mask; + __raw_writel(mask, value ? &g->set_data : &g->clr_data); + __raw_writel(temp, &g->dir); + spin_unlock(&gpio_lock); + return 0; +} +EXPORT_SYMBOL(gpio_direction_output); + +/* + * We expect irqs will normally be set up as input pins, but they can also be + * used as output pins ... which is convenient for testing. + * + * NOTE: GPIO0..GPIO7 also have direct INTC hookups, which work in addition + * to their GPIOBNK0 irq (but with a bit less overhead). But we don't have + * a good way to hook those up ... + * + * All those INTC hookups (GPIO0..GPIO7 plus five IRQ banks) can also + * serve as EDMA event triggers. + */ + +static void gpio_irq_disable(unsigned irq) +{ + struct gpio_controller *__iomem g = get_irq_chip_data(irq); + u32 mask = __gpio_mask(irq_to_gpio(irq)); + + __raw_writel(mask, &g->clr_falling); + __raw_writel(mask, &g->clr_rising); +} + +static void gpio_irq_enable(unsigned irq) +{ + struct gpio_controller *__iomem g = get_irq_chip_data(irq); + u32 mask = __gpio_mask(irq_to_gpio(irq)); + + if (irq_desc[irq].status & IRQ_TYPE_EDGE_FALLING) + __raw_writel(mask, &g->set_falling); + if (irq_desc[irq].status & IRQ_TYPE_EDGE_RISING) + __raw_writel(mask, &g->set_rising); +} + +static int gpio_irq_type(unsigned irq, unsigned trigger) +{ + struct gpio_controller *__iomem g = get_irq_chip_data(irq); + u32 mask = __gpio_mask(irq_to_gpio(irq)); + + if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) + return -EINVAL; + + irq_desc[irq].status &= ~IRQ_TYPE_SENSE_MASK; + irq_desc[irq].status |= trigger; + + __raw_writel(mask, (trigger & IRQ_TYPE_EDGE_FALLING) + ? &g->set_falling : &g->clr_falling); + __raw_writel(mask, (trigger & IRQ_TYPE_EDGE_RISING) + ? &g->set_rising : &g->clr_rising); + return 0; +} + +static struct irq_chip gpio_irqchip = { + .name = "GPIO", + .enable = gpio_irq_enable, + .disable = gpio_irq_disable, + .set_type = gpio_irq_type, +}; + +static void +gpio_irq_handler(unsigned irq, struct irq_desc *desc) +{ + struct gpio_controller *__iomem g = get_irq_chip_data(irq); + u32 mask = 0xffff; + + /* we only care about one bank */ + if (irq & 1) + mask <<= 16; + + /* temporarily mask (level sensitive) parent IRQ */ + desc->chip->ack(irq); + while (1) { + u32 status; + struct irq_desc *gpio; + int n; + int res; + + /* ack any irqs */ + status = __raw_readl(&g->intstat) & mask; + if (!status) + break; + __raw_writel(status, &g->intstat); + if (irq & 1) + status >>= 16; + + /* now demux them to the right lowlevel handler */ + n = (int)get_irq_data(irq); + gpio = &irq_desc[n]; + while (status) { + res = ffs(status); + n += res; + gpio += res; + desc_handle_irq(n - 1, gpio - 1); + status >>= res; + } + } + desc->chip->unmask(irq); + /* now it may re-trigger */ +} + +/* + * NOTE: for suspend/resume, probably best to make a sysdev (and class) + * with its suspend/resume calls hooking into the results of the set_wake() + * calls ... so if no gpios are wakeup events the clock can be disabled, + * with outputs left at previously set levels, and so that VDD3P3V.IOPWDN0 + * can be set appropriately for GPIOV33 pins. + */ + +static int __init davinci_gpio_irq_setup(void) +{ + unsigned gpio, irq, bank; + struct clk *clk; + + clk = clk_get(NULL, "gpio"); + if (IS_ERR(clk)) { + printk(KERN_ERR "Error %ld getting gpio clock?\n", + PTR_ERR(clk)); + return 0; + } + + clk_enable(clk); + + for (gpio = 0, irq = gpio_to_irq(0), bank = IRQ_GPIOBNK0; + gpio < DAVINCI_N_GPIO; bank++) { + struct gpio_controller *__iomem g = gpio2controller(gpio); + unsigned i; + + __raw_writel(~0, &g->clr_falling); + __raw_writel(~0, &g->clr_rising); + + /* set up all irqs in this bank */ + set_irq_chained_handler(bank, gpio_irq_handler); + set_irq_chip_data(bank, g); + set_irq_data(bank, (void *)irq); + + for (i = 0; i < 16 && gpio < DAVINCI_N_GPIO; + i++, irq++, gpio++) { + set_irq_chip(irq, &gpio_irqchip); + set_irq_chip_data(irq, g); + set_irq_handler(irq, handle_simple_irq); + set_irq_flags(irq, IRQF_VALID); + } + } + + /* BINTEN -- per-bank interrupt enable. genirq would also let these + * bits be set/cleared dynamically. + */ + __raw_writel(0x1f, (void *__iomem) + IO_ADDRESS(DAVINCI_GPIO_BASE + 0x08)); + + printk(KERN_INFO "DaVinci: %d gpio irqs\n", irq - gpio_to_irq(0)); + + return 0; +} + +arch_initcall(davinci_gpio_irq_setup); diff --git a/arch/arm/mach-davinci/io.c b/arch/arm/mach-davinci/io.c index 87fae6fb6ec..47787ff84a6 100644 --- a/arch/arm/mach-davinci/io.c +++ b/arch/arm/mach-davinci/io.c @@ -17,6 +17,7 @@ #include <asm/memory.h> #include <asm/mach/map.h> +#include <asm/arch/clock.h> extern void davinci_check_revision(void); @@ -49,3 +50,8 @@ void __init davinci_map_common_io(void) */ davinci_check_revision(); } + +void __init davinci_init_common_hw(void) +{ + davinci_clk_init(); +} diff --git a/arch/arm/mach-davinci/mux.c b/arch/arm/mach-davinci/mux.c new file mode 100644 index 00000000000..92d26bd305b --- /dev/null +++ b/arch/arm/mach-davinci/mux.c @@ -0,0 +1,41 @@ +/* + * DaVinci pin multiplexing configurations + * + * Author: Vladimir Barinov, MontaVista Software, Inc. <source@mvista.com> + * + * 2007 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ +#include <linux/io.h> +#include <linux/spinlock.h> + +#include <asm/hardware.h> + +#include <asm/arch/mux.h> + +/* System control register offsets */ +#define PINMUX0 0x00 +#define PINMUX1 0x04 + +static DEFINE_SPINLOCK(mux_lock); + +void davinci_mux_peripheral(unsigned int mux, unsigned int enable) +{ + u32 pinmux, muxreg = PINMUX0; + + if (mux >= DAVINCI_MUX_LEVEL2) { + muxreg = PINMUX1; + mux -= DAVINCI_MUX_LEVEL2; + } + + spin_lock(&mux_lock); + pinmux = davinci_readl(DAVINCI_SYSTEM_MODULE_BASE + muxreg); + if (enable) + pinmux |= (1 << mux); + else + pinmux &= ~(1 << mux); + davinci_writel(pinmux, DAVINCI_SYSTEM_MODULE_BASE + muxreg); + spin_unlock(&mux_lock); +} diff --git a/arch/arm/mach-davinci/psc.c b/arch/arm/mach-davinci/psc.c index e1b0050283a..1334416559a 100644 --- a/arch/arm/mach-davinci/psc.c +++ b/arch/arm/mach-davinci/psc.c @@ -25,39 +25,40 @@ #include <asm/io.h> #include <asm/hardware.h> #include <asm/arch/psc.h> +#include <asm/arch/mux.h> -#define PTCMD __REG(0x01C41120) -#define PDSTAT __REG(0x01C41200) -#define PDCTL1 __REG(0x01C41304) -#define EPCPR __REG(0x01C41070) -#define PTSTAT __REG(0x01C41128) +/* PSC register offsets */ +#define EPCPR 0x070 +#define PTCMD 0x120 +#define PTSTAT 0x128 +#define PDSTAT 0x200 +#define PDCTL1 0x304 +#define MDSTAT 0x800 +#define MDCTL 0xA00 -#define MDSTAT IO_ADDRESS(0x01C41800) -#define MDCTL IO_ADDRESS(0x01C41A00) - -#define PINMUX0 __REG(0x01c40000) -#define PINMUX1 __REG(0x01c40004) -#define VDD3P3V_PWDN __REG(0x01C40048) +/* System control register offsets */ +#define VDD3P3V_PWDN 0x48 static void davinci_psc_mux(unsigned int id) { switch (id) { case DAVINCI_LPSC_ATA: - PINMUX0 |= (1 << 17) | (1 << 16); + davinci_mux_peripheral(DAVINCI_MUX_HDIREN, 1); + davinci_mux_peripheral(DAVINCI_MUX_ATAEN, 1); break; case DAVINCI_LPSC_MMC_SD: /* VDD power manupulations are done in U-Boot for CPMAC * so applies to MMC as well */ /*Set up the pull regiter for MMC */ - VDD3P3V_PWDN = 0x0; - PINMUX1 &= (~(1 << 9)); + davinci_writel(0, DAVINCI_SYSTEM_MODULE_BASE + VDD3P3V_PWDN); + davinci_mux_peripheral(DAVINCI_MUX_MSTK, 0); break; case DAVINCI_LPSC_I2C: - PINMUX1 |= (1 << 7); + davinci_mux_peripheral(DAVINCI_MUX_I2C, 1); break; case DAVINCI_LPSC_McBSP: - PINMUX1 |= (1 << 10); + davinci_mux_peripheral(DAVINCI_MUX_ASP, 1); break; default: break; @@ -67,33 +68,59 @@ static void davinci_psc_mux(unsigned int id) /* Enable or disable a PSC domain */ void davinci_psc_config(unsigned int domain, unsigned int id, char enable) { - volatile unsigned int *mdstat = (unsigned int *)((int)MDSTAT + 4 * id); - volatile unsigned int *mdctl = (unsigned int *)((int)MDCTL + 4 * id); + u32 epcpr, ptcmd, ptstat, pdstat, pdctl1, mdstat, mdctl, mdstat_mask; if (id < 0) return; + mdctl = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + MDCTL + 4 * id); if (enable) - *mdctl |= 0x00000003; /* Enable Module */ + mdctl |= 0x00000003; /* Enable Module */ else - *mdctl &= 0xFFFFFFF2; /* Disable Module */ + mdctl &= 0xFFFFFFF2; /* Disable Module */ + davinci_writel(mdctl, DAVINCI_PWR_SLEEP_CNTRL_BASE + MDCTL + 4 * id); + + pdstat = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + PDSTAT); + if ((pdstat & 0x00000001) == 0) { + pdctl1 = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + PDCTL1); + pdctl1 |= 0x1; + davinci_writel(pdctl1, DAVINCI_PWR_SLEEP_CNTRL_BASE + PDCTL1); + + ptcmd = 1 << domain; + davinci_writel(ptcmd, DAVINCI_PWR_SLEEP_CNTRL_BASE + PTCMD); - if ((PDSTAT & 0x00000001) == 0) { - PDCTL1 |= 0x1; - PTCMD = (1 << domain); - while ((((EPCPR >> domain) & 1) == 0)); + do { + epcpr = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + + EPCPR); + } while ((((epcpr >> domain) & 1) == 0)); - PDCTL1 |= 0x100; - while (!(((PTSTAT >> domain) & 1) == 0)); + pdctl1 = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + PDCTL1); + pdctl1 |= 0x100; + davinci_writel(pdctl1, DAVINCI_PWR_SLEEP_CNTRL_BASE + PDCTL1); + + do { + ptstat = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + + PTSTAT); + } while (!(((ptstat >> domain) & 1) == 0)); } else { - PTCMD = (1 << domain); - while (!(((PTSTAT >> domain) & 1) == 0)); + ptcmd = 1 << domain; + davinci_writel(ptcmd, DAVINCI_PWR_SLEEP_CNTRL_BASE + PTCMD); + + do { + ptstat = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + + PTSTAT); + } while (!(((ptstat >> domain) & 1) == 0)); } if (enable) - while (!((*mdstat & 0x0000001F) == 0x3)); + mdstat_mask = 0x3; else - while (!((*mdstat & 0x0000001F) == 0x2)); + mdstat_mask = 0x2; + + do { + mdstat = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + + MDSTAT + 4 * id); + } while (!((mdstat & 0x0000001F) == mdstat_mask)); if (enable) davinci_psc_mux(id); diff --git a/arch/arm/mach-imx/generic.c b/arch/arm/mach-imx/generic.c index 1c474cf709c..a58b678006d 100644 --- a/arch/arm/mach-imx/generic.c +++ b/arch/arm/mach-imx/generic.c @@ -28,12 +28,16 @@ #include <linux/module.h> #include <linux/string.h> +#include <asm/errno.h> #include <asm/arch/imxfb.h> #include <asm/hardware.h> #include <asm/arch/imx-regs.h> #include <asm/mach/map.h> #include <asm/arch/mmc.h> +#include <asm/arch/gpio.h> + +unsigned long imx_gpio_alloc_map[(GPIO_PORT_MAX + 1) * 32 / BITS_PER_LONG]; void imx_gpio_mode(int gpio_mode) { @@ -95,6 +99,120 @@ void imx_gpio_mode(int gpio_mode) EXPORT_SYMBOL(imx_gpio_mode); +int imx_gpio_request(unsigned gpio, const char *label) +{ + if(gpio >= (GPIO_PORT_MAX + 1) * 32) + printk(KERN_ERR "imx_gpio: Attempt to request nonexistent GPIO %d for \"%s\"\n", + gpio, label ? label : "?"); + return -EINVAL; + + if(test_and_set_bit(gpio, imx_gpio_alloc_map)) { + printk(KERN_ERR "imx_gpio: GPIO %d already used. Allocation for \"%s\" failed\n", + gpio, label ? label : "?"); + return -EBUSY; + } + + return 0; +} + +EXPORT_SYMBOL(imx_gpio_request); + +void imx_gpio_free(unsigned gpio) +{ + if(gpio >= (GPIO_PORT_MAX + 1) * 32) + return; + + clear_bit(gpio, imx_gpio_alloc_map); +} + +EXPORT_SYMBOL(imx_gpio_free); + +int imx_gpio_direction_input(unsigned gpio) +{ + imx_gpio_mode(gpio| GPIO_IN); + return 0; +} + +EXPORT_SYMBOL(imx_gpio_direction_input); + +int imx_gpio_direction_output(unsigned gpio, int value) +{ + imx_gpio_set_value(gpio, value); + imx_gpio_mode(gpio| GPIO_OUT); + return 0; +} + +EXPORT_SYMBOL(imx_gpio_direction_output); + +int imx_gpio_setup_multiple_pins(const int *pin_list, unsigned count, + int alloc_mode, const char *label) +{ + const int *p = pin_list; + int i; + unsigned gpio; + unsigned mode; + + for (i = 0; i < count; i++) { + gpio = *p & (GPIO_PIN_MASK | GPIO_PORT_MASK); + mode = *p & ~(GPIO_PIN_MASK | GPIO_PORT_MASK); + + if (gpio >= (GPIO_PORT_MAX + 1) * 32) + goto setup_error; + + if (alloc_mode & IMX_GPIO_ALLOC_MODE_RELEASE) + imx_gpio_free(gpio); + else if (!(alloc_mode & IMX_GPIO_ALLOC_MODE_NO_ALLOC)) + if (imx_gpio_request(gpio, label)) + if (!(alloc_mode & IMX_GPIO_ALLOC_MODE_TRY_ALLOC)) + goto setup_error; + + if (!(alloc_mode & (IMX_GPIO_ALLOC_MODE_ALLOC_ONLY | + IMX_GPIO_ALLOC_MODE_RELEASE))) + imx_gpio_mode(gpio | mode); + + p++; + } + return 0; + +setup_error: + if(alloc_mode & (IMX_GPIO_ALLOC_MODE_NO_ALLOC | + IMX_GPIO_ALLOC_MODE_TRY_ALLOC)) + return -EINVAL; + + while (p != pin_list) { + p--; + gpio = *p & (GPIO_PIN_MASK | GPIO_PORT_MASK); + imx_gpio_free(gpio); + } + + return -EINVAL; +} + +EXPORT_SYMBOL(imx_gpio_setup_multiple_pins); + +void __imx_gpio_set_value(unsigned gpio, int value) +{ + imx_gpio_set_value_inline(gpio, value); +} + +EXPORT_SYMBOL(__imx_gpio_set_value); + +int imx_gpio_to_irq(unsigned gpio) +{ + return IRQ_GPIOA(0) + gpio; +} + +EXPORT_SYMBOL(imx_gpio_to_irq); + +int imx_irq_to_gpio(unsigned irq) +{ + if (irq < IRQ_GPIOA(0)) + return -EINVAL; + return irq - IRQ_GPIOA(0); +} + +EXPORT_SYMBOL(imx_irq_to_gpio); + /* * get the system pll clock in Hz * diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c index 6960a9d0421..010f6fa984a 100644 --- a/arch/arm/mach-imx/time.c +++ b/arch/arm/mach-imx/time.c @@ -3,6 +3,7 @@ * * Copyright (C) 2000-2001 Deep Blue Solutions * Copyright (C) 2002 Shane Nay (shane@minirl.com) + * Copyright (C) 2006-2007 Pavel Pisa (ppisa@pikron.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 @@ -15,6 +16,7 @@ #include <linux/irq.h> #include <linux/time.h> #include <linux/clocksource.h> +#include <linux/clockchips.h> #include <asm/hardware.h> #include <asm/io.h> @@ -25,7 +27,8 @@ /* Use timer 1 as system timer */ #define TIMER_BASE IMX_TIM1_BASE -static unsigned long evt_diff; +static struct clock_event_device clockevent_imx; +static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED; /* * IRQ handler for the timer @@ -33,25 +36,20 @@ static unsigned long evt_diff; static irqreturn_t imx_timer_interrupt(int irq, void *dev_id) { + struct clock_event_device *evt = &clockevent_imx; uint32_t tstat; + irqreturn_t ret = IRQ_NONE; /* clear the interrupt */ tstat = IMX_TSTAT(TIMER_BASE); IMX_TSTAT(TIMER_BASE) = 0; if (tstat & TSTAT_COMP) { - do { - - write_seqlock(&xtime_lock); - timer_tick(); - write_sequnlock(&xtime_lock); - IMX_TCMP(TIMER_BASE) += evt_diff; - - } while (unlikely((int32_t)(IMX_TCMP(TIMER_BASE) - - IMX_TCN(TIMER_BASE)) < 0)); + evt->event_handler(evt); + ret = IRQ_HANDLED; } - return IRQ_HANDLED; + return ret; } static struct irqaction imx_timer_irq = { @@ -70,10 +68,8 @@ static void __init imx_timer_hardware_init(void) */ IMX_TCTL(TIMER_BASE) = 0; IMX_TPRER(TIMER_BASE) = 0; - IMX_TCMP(TIMER_BASE) = LATCH - 1; - IMX_TCTL(TIMER_BASE) = TCTL_FRR | TCTL_CLK_PCLK1 | TCTL_IRQEN | TCTL_TEN; - evt_diff = LATCH; + IMX_TCTL(TIMER_BASE) = TCTL_FRR | TCTL_CLK_PCLK1 | TCTL_TEN; } cycle_t imx_get_cycles(void) @@ -99,11 +95,108 @@ static int __init imx_clocksource_init(void) return 0; } +static int imx_set_next_event(unsigned long evt, + struct clock_event_device *unused) +{ + unsigned long tcmp; + + tcmp = IMX_TCN(TIMER_BASE) + evt; + IMX_TCMP(TIMER_BASE) = tcmp; + + return (int32_t)(tcmp - IMX_TCN(TIMER_BASE)) < 0 ? -ETIME : 0; +} + +#ifdef DEBUG +static const char *clock_event_mode_label[]={ + [CLOCK_EVT_MODE_PERIODIC] = "CLOCK_EVT_MODE_PERIODIC", + [CLOCK_EVT_MODE_ONESHOT] = "CLOCK_EVT_MODE_ONESHOT", + [CLOCK_EVT_MODE_SHUTDOWN] = "CLOCK_EVT_MODE_SHUTDOWN", + [CLOCK_EVT_MODE_UNUSED] = "CLOCK_EVT_MODE_UNUSED" +}; +#endif /*DEBUG*/ + +static void imx_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) +{ + unsigned long flags; + + /* + * The timer interrupt generation is disabled at least + * for enough time to call imx_set_next_event() + */ + local_irq_save(flags); + /* Disable interrupt in GPT module */ + IMX_TCTL(TIMER_BASE) &= ~TCTL_IRQEN; + if (mode != clockevent_mode) { + /* Set event time into far-far future */ + IMX_TCMP(TIMER_BASE) = IMX_TCN(TIMER_BASE) - 3; + /* Clear pending interrupt */ + IMX_TSTAT(TIMER_BASE) &= ~TSTAT_COMP; + } + +#ifdef DEBUG + printk(KERN_INFO "imx_set_mode: changing mode from %s to %s\n", + clock_event_mode_label[clockevent_mode], clock_event_mode_label[mode]); +#endif /*DEBUG*/ + + /* Remember timer mode */ + clockevent_mode = mode; + local_irq_restore(flags); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + printk(KERN_ERR "imx_set_mode: Periodic mode is not supported for i.MX\n"); + break; + case CLOCK_EVT_MODE_ONESHOT: + /* + * Do not put overhead of interrupt enable/disable into + * imx_set_next_event(), the core has about 4 minutes + * to call imx_set_next_event() or shutdown clock after + * mode switching + */ + local_irq_save(flags); + IMX_TCTL(TIMER_BASE) |= TCTL_IRQEN; + local_irq_restore(flags); + break; + case CLOCK_EVT_MODE_SHUTDOWN: + case CLOCK_EVT_MODE_UNUSED: + /* Left event sources disabled, no more interrupts appears */ + break; + } +} + +static struct clock_event_device clockevent_imx = { + .name = "imx_timer1", + .features = CLOCK_EVT_FEAT_ONESHOT, + .shift = 32, + .set_mode = imx_set_mode, + .set_next_event = imx_set_next_event, + .rating = 200, +}; + +static int __init imx_clockevent_init(void) +{ + clockevent_imx.mult = div_sc(imx_get_perclk1(), NSEC_PER_SEC, + clockevent_imx.shift); + clockevent_imx.max_delta_ns = + clockevent_delta2ns(0xfffffffe, &clockevent_imx); + clockevent_imx.min_delta_ns = + clockevent_delta2ns(0xf, &clockevent_imx); + + clockevent_imx.cpumask = cpumask_of_cpu(0); + + clockevents_register_device(&clockevent_imx); + + return 0; +} + + static void __init imx_timer_init(void) { imx_timer_hardware_init(); imx_clocksource_init(); + imx_clockevent_init(); + /* * Make irqs happen for the system timer */ diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig index 060909870b5..61b2dfcb89d 100644 --- a/arch/arm/mach-ixp4xx/Kconfig +++ b/arch/arm/mach-ixp4xx/Kconfig @@ -41,6 +41,22 @@ config ARCH_ADI_COYOTE Engineering Coyote Gateway Reference Platform. For more information on this platform, see <file:Documentation/arm/IXP4xx>. +config MACH_GATEWAY7001 + bool "Gateway 7001" + select PCI + help + Say 'Y' here if you want your kernel to support Gateway's + 7001 Access Point. For more information on this platform, + see http://openwrt.org + +config MACH_WG302V2 + bool "Netgear WG302 v2 / WAG302 v2" + select PCI + help + Say 'Y' here if you want your kernel to support Netgear's + WG302 v2 or WAG302 v2 Access Points. For more information + on this platform, see http://openwrt.org + config ARCH_IXDP425 bool "IXDP425" help diff --git a/arch/arm/mach-ixp4xx/Makefile b/arch/arm/mach-ixp4xx/Makefile index 3b87c47e06c..77e00ade558 100644 --- a/arch/arm/mach-ixp4xx/Makefile +++ b/arch/arm/mach-ixp4xx/Makefile @@ -13,6 +13,8 @@ obj-pci-$(CONFIG_MACH_GTWX5715) += gtwx5715-pci.o obj-pci-$(CONFIG_MACH_NSLU2) += nslu2-pci.o obj-pci-$(CONFIG_MACH_NAS100D) += nas100d-pci.o obj-pci-$(CONFIG_MACH_DSMG600) += dsmg600-pci.o +obj-pci-$(CONFIG_MACH_GATEWAY7001) += gateway7001-pci.o +obj-pci-$(CONFIG_MACH_WG302V2) += wg302v2-pci.o obj-y += common.o @@ -24,5 +26,7 @@ obj-$(CONFIG_MACH_GTWX5715) += gtwx5715-setup.o obj-$(CONFIG_MACH_NSLU2) += nslu2-setup.o nslu2-power.o obj-$(CONFIG_MACH_NAS100D) += nas100d-setup.o nas100d-power.o obj-$(CONFIG_MACH_DSMG600) += dsmg600-setup.o dsmg600-power.o +obj-$(CONFIG_MACH_GATEWAY7001) += gateway7001-setup.o +obj-$(CONFIG_MACH_WG302V2) += wg302v2-setup.o obj-$(CONFIG_PCI) += $(obj-pci-$(CONFIG_PCI)) common-pci.o diff --git a/arch/arm/mach-ixp4xx/gateway7001-pci.c b/arch/arm/mach-ixp4xx/gateway7001-pci.c new file mode 100644 index 00000000000..6abf568322d --- /dev/null +++ b/arch/arm/mach-ixp4xx/gateway7001-pci.c @@ -0,0 +1,63 @@ +/* + * arch/arch/mach-ixp4xx/gateway7001-pci.c + * + * PCI setup routines for Gateway 7001 + * + * Copyright (C) 2007 Imre Kaloz <kaloz@openwrt.org> + * + * based on coyote-pci.c: + * Copyright (C) 2002 Jungo Software Technologies. + * Copyright (C) 2003 MontaVista Softwrae, Inc. + * + * Maintainer: Imre Kaloz <kaloz@openwrt.org> + * + * 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/pci.h> +#include <linux/init.h> +#include <linux/irq.h> + +#include <asm/mach-types.h> +#include <asm/hardware.h> + +#include <asm/mach/pci.h> + +void __init gateway7001_pci_preinit(void) +{ + set_irq_type(IRQ_IXP4XX_GPIO10, IRQT_LOW); + set_irq_type(IRQ_IXP4XX_GPIO11, IRQT_LOW); + + ixp4xx_pci_preinit(); +} + +static int __init gateway7001_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + if (slot == 1) + return IRQ_IXP4XX_GPIO11; + else if (slot == 2) + return IRQ_IXP4XX_GPIO10; + else return -1; +} + +struct hw_pci gateway7001_pci __initdata = { + .nr_controllers = 1, + .preinit = gateway7001_pci_preinit, + .swizzle = pci_std_swizzle, + .setup = ixp4xx_setup, + .scan = ixp4xx_scan_bus, + .map_irq = gateway7001_map_irq, +}; + +int __init gateway7001_pci_init(void) +{ + if (machine_is_gateway7001()) + pci_common_init(&gateway7001_pci); + return 0; +} + +subsys_initcall(gateway7001_pci_init); diff --git a/arch/arm/mach-ixp4xx/gateway7001-setup.c b/arch/arm/mach-ixp4xx/gateway7001-setup.c new file mode 100644 index 00000000000..37876832e14 --- /dev/null +++ b/arch/arm/mach-ixp4xx/gateway7001-setup.c @@ -0,0 +1,108 @@ +/* + * arch/arm/mach-ixp4xx/gateway7001-setup.c + * + * Board setup for the Gateway 7001 board + * + * Copyright (C) 2007 Imre Kaloz <kaloz@openwrt.org> + * + * based on coyote-setup.c: + * Copyright (C) 2003-2005 MontaVista Software, Inc. + * + * Author: Imre Kaloz <Kaloz@openwrt.org> + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/serial.h> +#include <linux/tty.h> +#include <linux/serial_8250.h> +#include <linux/slab.h> + +#include <asm/types.h> +#include <asm/setup.h> +#include <asm/memory.h> +#include <asm/hardware.h> +#include <asm/irq.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/flash.h> + +static struct flash_platform_data gateway7001_flash_data = { + .map_name = "cfi_probe", + .width = 2, +}; + +static struct resource gateway7001_flash_resource = { + .flags = IORESOURCE_MEM, +}; + +static struct platform_device gateway7001_flash = { + .name = "IXP4XX-Flash", + .id = 0, + .dev = { + .platform_data = &gateway7001_flash_data, + }, + .num_resources = 1, + .resource = &gateway7001_flash_resource, +}; + +static struct resource gateway7001_uart_resource = { + .start = IXP4XX_UART2_BASE_PHYS, + .end = IXP4XX_UART2_BASE_PHYS + 0x0fff, + .flags = IORESOURCE_MEM, +}; + +static struct plat_serial8250_port gateway7001_uart_data[] = { + { + .mapbase = IXP4XX_UART2_BASE_PHYS, + .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET, + .irq = IRQ_IXP4XX_UART2, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, + .iotype = UPIO_MEM, + .regshift = 2, + .uartclk = IXP4XX_UART_XTAL, + }, + { }, +}; + +static struct platform_device gateway7001_uart = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = gateway7001_uart_data, + }, + .num_resources = 1, + .resource = &gateway7001_uart_resource, +}; + +static struct platform_device *gateway7001_devices[] __initdata = { + &gateway7001_flash, + &gateway7001_uart +}; + +static void __init gateway7001_init(void) +{ + ixp4xx_sys_init(); + + gateway7001_flash_resource.start = IXP4XX_EXP_BUS_BASE(0); + gateway7001_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + SZ_32M - 1; + + *IXP4XX_EXP_CS0 |= IXP4XX_FLASH_WRITABLE; + *IXP4XX_EXP_CS1 = *IXP4XX_EXP_CS0; + + platform_add_devices(gateway7001_devices, ARRAY_SIZE(gateway7001_devices)); +} + +#ifdef CONFIG_MACH_GATEWAY7001 +MACHINE_START(GATEWAY7001, "Gateway 7001 AP") + /* Maintainer: Imre Kaloz <kaloz@openwrt.org> */ + .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS, + .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc, + .map_io = ixp4xx_map_io, + .init_irq = ixp4xx_init_irq, + .timer = &ixp4xx_timer, + .boot_params = 0x0100, + .init_machine = gateway7001_init, +MACHINE_END +#endif diff --git a/arch/arm/mach-ixp4xx/gtwx5715-pci.c b/arch/arm/mach-ixp4xx/gtwx5715-pci.c index a66484b63d3..0d5a4245582 100644 --- a/arch/arm/mach-ixp4xx/gtwx5715-pci.c +++ b/arch/arm/mach-ixp4xx/gtwx5715-pci.c @@ -25,17 +25,13 @@ #include <linux/pci.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/irq.h> + #include <asm/mach-types.h> #include <asm/hardware.h> -#include <asm/irq.h> #include <asm/arch/gtwx5715.h> #include <asm/mach/pci.h> -extern void ixp4xx_pci_preinit(void); -extern int ixp4xx_setup(int nr, struct pci_sys_data *sys); -extern struct pci_bus *ixp4xx_scan_bus(int nr, struct pci_sys_data *sys); - - /* * The exact GPIO pins and IRQs are defined in arch-ixp4xx/gtwx5715.h * Slot 0 isn't actually populated with a card connector but diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c index ec4f07950ec..d5008d8fc9a 100644 --- a/arch/arm/mach-ixp4xx/ixdp425-setup.c +++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c @@ -15,6 +15,10 @@ #include <linux/tty.h> #include <linux/serial_8250.h> #include <linux/slab.h> +#include <linux/io.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> #include <asm/types.h> #include <asm/setup.h> @@ -24,6 +28,7 @@ #include <asm/irq.h> #include <asm/mach/arch.h> #include <asm/mach/flash.h> +#include <asm/delay.h> static struct flash_platform_data ixdp425_flash_data = { .map_name = "cfi_probe", @@ -44,6 +49,77 @@ static struct platform_device ixdp425_flash = { .resource = &ixdp425_flash_resource, }; +#if defined(CONFIG_MTD_NAND_PLATFORM) || \ + defined(CONFIG_MTD_NAND_PLATFORM_MODULE) + +#ifdef CONFIG_MTD_PARTITIONS +const char *part_probes[] = { "cmdlinepart", NULL }; + +static struct mtd_partition ixdp425_partitions[] = { + { + .name = "ixp400 NAND FS 0", + .offset = 0, + .size = SZ_8M + }, { + .name = "ixp400 NAND FS 1", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL + }, +}; +#endif + +static void +ixdp425_flash_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) +{ + struct nand_chip *this = mtd->priv; + int offset = (int)this->priv; + + if (ctrl & NAND_CTRL_CHANGE) { + if (ctrl & NAND_NCE) { + gpio_line_set(IXDP425_NAND_NCE_PIN, IXP4XX_GPIO_LOW); + udelay(5); + } else + gpio_line_set(IXDP425_NAND_NCE_PIN, IXP4XX_GPIO_HIGH); + + offset = (ctrl & NAND_CLE) ? IXDP425_NAND_CMD_BYTE : 0; + offset |= (ctrl & NAND_ALE) ? IXDP425_NAND_ADDR_BYTE : 0; + this->priv = (void *)offset; + } + + if (cmd != NAND_CMD_NONE) + writeb(cmd, this->IO_ADDR_W + offset); +} + +static struct platform_nand_data ixdp425_flash_nand_data = { + .chip = { + .chip_delay = 30, + .options = NAND_NO_AUTOINCR, +#ifdef CONFIG_MTD_PARTITIONS + .part_probe_types = part_probes, + .partitions = ixdp425_partitions, + .nr_partitions = ARRAY_SIZE(ixdp425_partitions), +#endif + }, + .ctrl = { + .cmd_ctrl = ixdp425_flash_nand_cmd_ctrl + } +}; + +static struct resource ixdp425_flash_nand_resource = { + .flags = IORESOURCE_MEM, +}; + +static struct platform_device ixdp425_flash_nand = { + .name = "gen_nand", + .id = -1, + .dev = { + .platform_data = &ixdp425_flash_nand_data, + }, + .num_resources = 1, + .resource = &ixdp425_flash_nand_resource, +}; +#endif /* CONFIG_MTD_NAND_PLATFORM */ + static struct ixp4xx_i2c_pins ixdp425_i2c_gpio_pins = { .sda_pin = IXDP425_SDA_PIN, .scl_pin = IXDP425_SCL_PIN, @@ -104,6 +180,10 @@ static struct platform_device ixdp425_uart = { static struct platform_device *ixdp425_devices[] __initdata = { &ixdp425_i2c_controller, &ixdp425_flash, +#if defined(CONFIG_MTD_NAND_PLATFORM) || \ + defined(CONFIG_MTD_NAND_PLATFORM_MODULE) + &ixdp425_flash_nand, +#endif &ixdp425_uart }; @@ -115,6 +195,22 @@ static void __init ixdp425_init(void) ixdp425_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1; +#if defined(CONFIG_MTD_NAND_PLATFORM) || \ + defined(CONFIG_MTD_NAND_PLATFORM_MODULE) + ixdp425_flash_nand_resource.start = IXP4XX_EXP_BUS_BASE(3), + ixdp425_flash_nand_resource.end = IXP4XX_EXP_BUS_BASE(3) + 0x10 - 1; + + gpio_line_config(IXDP425_NAND_NCE_PIN, IXP4XX_GPIO_OUT); + + /* Configure expansion bus for NAND Flash */ + *IXP4XX_EXP_CS3 = IXP4XX_EXP_BUS_CS_EN | + IXP4XX_EXP_BUS_STROBE_T(1) | /* extend by 1 clock */ + IXP4XX_EXP_BUS_CYCLES(0) | /* Intel cycles */ + IXP4XX_EXP_BUS_SIZE(0) | /* 512bytes addr space*/ + IXP4XX_EXP_BUS_WR_EN | + IXP4XX_EXP_BUS_BYTE_EN; /* 8 bit data bus */ +#endif + if (cpu_is_ixp43x()) { ixdp425_uart.num_resources = 1; ixdp425_uart_data[1].flags = 0; diff --git a/arch/arm/mach-ixp4xx/wg302v2-pci.c b/arch/arm/mach-ixp4xx/wg302v2-pci.c new file mode 100644 index 00000000000..6588f2c758e --- /dev/null +++ b/arch/arm/mach-ixp4xx/wg302v2-pci.c @@ -0,0 +1,63 @@ +/* + * arch/arch/mach-ixp4xx/wg302v2-pci.c + * + * PCI setup routines for the Netgear WG302 v2 and WAG302 v2 + * + * Copyright (C) 2007 Imre Kaloz <kaloz@openwrt.org> + * + * based on coyote-pci.c: + * Copyright (C) 2002 Jungo Software Technologies. + * Copyright (C) 2003 MontaVista Software, Inc. + * + * Maintainer: Imre Kaloz <kaloz@openwrt.org> + * + * 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/pci.h> +#include <linux/init.h> +#include <linux/irq.h> + +#include <asm/mach-types.h> +#include <asm/hardware.h> + +#include <asm/mach/pci.h> + +void __init wg302v2_pci_preinit(void) +{ + set_irq_type(IRQ_IXP4XX_GPIO8, IRQT_LOW); + set_irq_type(IRQ_IXP4XX_GPIO9, IRQT_LOW); + + ixp4xx_pci_preinit(); +} + +static int __init wg302v2_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + if (slot == 1) + return IRQ_IXP4XX_GPIO8; + else if (slot == 2) + return IRQ_IXP4XX_GPIO9; + else return -1; +} + +struct hw_pci wg302v2_pci __initdata = { + .nr_controllers = 1, + .preinit = wg302v2_pci_preinit, + .swizzle = pci_std_swizzle, + .setup = ixp4xx_setup, + .scan = ixp4xx_scan_bus, + .map_irq = wg302v2_map_irq, +}; + +int __init wg302v2_pci_init(void) +{ + if (machine_is_wg302v2()) + pci_common_init(&wg302v2_pci); + return 0; +} + +subsys_initcall(wg302v2_pci_init); diff --git a/arch/arm/mach-ixp4xx/wg302v2-setup.c b/arch/arm/mach-ixp4xx/wg302v2-setup.c new file mode 100644 index 00000000000..f7e09ad804e --- /dev/null +++ b/arch/arm/mach-ixp4xx/wg302v2-setup.c @@ -0,0 +1,109 @@ +/* + * arch/arm/mach-ixp4xx/wg302-setup.c + * + * Board setup for the Netgear WG302 v2 and WAG302 v2 + * + * Copyright (C) 2007 Imre Kaloz <Kaloz@openwrt.org> + * + * based on coyote-setup.c: + * Copyright (C) 2003-2005 MontaVista Software, Inc. + * + * Author: Imre Kaloz <kaloz@openwrt.org> + * + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/serial.h> +#include <linux/tty.h> +#include <linux/serial_8250.h> +#include <linux/slab.h> + +#include <asm/types.h> +#include <asm/setup.h> +#include <asm/memory.h> +#include <asm/hardware.h> +#include <asm/irq.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/flash.h> + +static struct flash_platform_data wg302v2_flash_data = { + .map_name = "cfi_probe", + .width = 2, +}; + +static struct resource wg302v2_flash_resource = { + .flags = IORESOURCE_MEM, +}; + +static struct platform_device wg302v2_flash = { + .name = "IXP4XX-Flash", + .id = 0, + .dev = { + .platform_data = &wg302v2_flash_data, + }, + .num_resources = 1, + .resource = &wg302v2_flash_resource, +}; + +static struct resource wg302v2_uart_resource = { + .start = IXP4XX_UART2_BASE_PHYS, + .end = IXP4XX_UART2_BASE_PHYS + 0x0fff, + .flags = IORESOURCE_MEM, +}; + +static struct plat_serial8250_port wg302v2_uart_data[] = { + { + .mapbase = IXP4XX_UART2_BASE_PHYS, + .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET, + .irq = IRQ_IXP4XX_UART2, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, + .iotype = UPIO_MEM, + .regshift = 2, + .uartclk = IXP4XX_UART_XTAL, + }, + { }, +}; + +static struct platform_device wg302v2_uart = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = wg302v2_uart_data, + }, + .num_resources = 1, + .resource = &wg302v2_uart_resource, +}; + +static struct platform_device *wg302v2_devices[] __initdata = { + &wg302v2_flash, + &wg302v2_uart, +}; + +static void __init wg302v2_init(void) +{ + ixp4xx_sys_init(); + + wg302v2_flash_resource.start = IXP4XX_EXP_BUS_BASE(0); + wg302v2_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + SZ_32M - 1; + + *IXP4XX_EXP_CS0 |= IXP4XX_FLASH_WRITABLE; + *IXP4XX_EXP_CS1 = *IXP4XX_EXP_CS0; + + platform_add_devices(wg302v2_devices, ARRAY_SIZE(wg302v2_devices)); +} + +#ifdef CONFIG_MACH_WG302V2 +MACHINE_START(WG302V2, "Netgear WG302 v2 / WAG302 v2") + /* Maintainer: Imre Kaloz <kaloz@openwrt.org> */ + .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS, + .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc, + .map_io = ixp4xx_map_io, + .init_irq = ixp4xx_init_irq, + .timer = &ixp4xx_timer, + .boot_params = 0x0100, + .init_machine = wg302v2_init, +MACHINE_END +#endif diff --git a/arch/arm/mach-ks8695/Makefile b/arch/arm/mach-ks8695/Makefile index 56b7d337333..2a07a281fa8 100644 --- a/arch/arm/mach-ks8695/Makefile +++ b/arch/arm/mach-ks8695/Makefile @@ -3,7 +3,7 @@ # Makefile for KS8695 architecture support # -obj-y := cpu.o irq.o time.o devices.o +obj-y := cpu.o irq.o time.o gpio.o devices.o obj-m := obj-n := obj- := diff --git a/arch/arm/mach-ks8695/gpio.c b/arch/arm/mach-ks8695/gpio.c new file mode 100644 index 00000000000..b1aa3cb3d4a --- /dev/null +++ b/arch/arm/mach-ks8695/gpio.c @@ -0,0 +1,218 @@ +/* + * arch/arm/mach-ks8695/gpio.c + * + * Copyright (C) 2006 Andrew Victor + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/init.h> +#include <linux/module.h> + +#include <asm/io.h> +#include <asm/hardware.h> +#include <asm/mach/irq.h> + +#include <asm/arch/regs-gpio.h> +#include <asm/arch/gpio.h> + +/* + * Configure a GPIO line for either GPIO function, or its internal + * function (Interrupt, Timer, etc). + */ +static void __init_or_module ks8695_gpio_mode(unsigned int pin, short gpio) +{ + unsigned int enable[] = { IOPC_IOEINT0EN, IOPC_IOEINT1EN, IOPC_IOEINT2EN, IOPC_IOEINT3EN, IOPC_IOTIM0EN, IOPC_IOTIM1EN }; + unsigned long x, flags; + + if (pin > KS8695_GPIO_5) /* only GPIO 0..5 have internal functions */ + return; + + local_irq_save(flags); + + x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPC); + if (gpio) /* GPIO: set bit to 0 */ + x &= ~enable[pin]; + else /* Internal function: set bit to 1 */ + x |= enable[pin]; + __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPC); + + local_irq_restore(flags); +} + + +static unsigned short gpio_irq[] = { KS8695_IRQ_EXTERN0, KS8695_IRQ_EXTERN1, KS8695_IRQ_EXTERN2, KS8695_IRQ_EXTERN3 }; + +/* + * Configure GPIO pin as external interrupt source. + */ +int __init_or_module ks8695_gpio_interrupt(unsigned int pin, unsigned int type) +{ + unsigned long x, flags; + + if (pin > KS8695_GPIO_3) /* only GPIO 0..3 can generate IRQ */ + return -EINVAL; + + local_irq_save(flags); + + /* set pin as input */ + x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM); + x &= ~IOPM_(pin); + __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM); + + local_irq_restore(flags); + + /* Set IRQ triggering type */ + set_irq_type(gpio_irq[pin], type); + + /* enable interrupt mode */ + ks8695_gpio_mode(pin, 0); + + return 0; +} +EXPORT_SYMBOL(ks8695_gpio_interrupt); + + + +/* .... Generic GPIO interface .............................................. */ + +/* + * Configure the GPIO line as an input. + */ +int __init_or_module gpio_direction_input(unsigned int pin) +{ + unsigned long x, flags; + + if (pin > KS8695_GPIO_15) + return -EINVAL; + + /* set pin to GPIO mode */ + ks8695_gpio_mode(pin, 1); + + local_irq_save(flags); + + /* set pin as input */ + x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM); + x &= ~IOPM_(pin); + __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM); + + local_irq_restore(flags); + + return 0; +} +EXPORT_SYMBOL(gpio_direction_input); + + +/* + * Configure the GPIO line as an output, with default state. + */ +int __init_or_module gpio_direction_output(unsigned int pin, unsigned int state) +{ + unsigned long x, flags; + + if (pin > KS8695_GPIO_15) + return -EINVAL; + + /* set pin to GPIO mode */ + ks8695_gpio_mode(pin, 1); + + local_irq_save(flags); + + /* set line state */ + x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD); + if (state) + x |= (1 << pin); + else + x &= ~(1 << pin); + __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPD); + + /* set pin as output */ + x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM); + x |= IOPM_(pin); + __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM); + + local_irq_restore(flags); + + return 0; +} +EXPORT_SYMBOL(gpio_direction_output); + + +/* + * Set the state of an output GPIO line. + */ +void gpio_set_value(unsigned int pin, unsigned int state) +{ + unsigned long x, flags; + + if (pin > KS8695_GPIO_15) + return; + + local_irq_save(flags); + + /* set output line state */ + x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD); + if (state) + x |= (1 << pin); + else + x &= ~(1 << pin); + __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPD); + + local_irq_restore(flags); +} +EXPORT_SYMBOL(gpio_set_value); + + +/* + * Read the state of a GPIO line. + */ +int gpio_get_value(unsigned int pin) +{ + unsigned long x; + + if (pin > KS8695_GPIO_15) + return -EINVAL; + + x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD); + return (x & (1 << pin)) != 0; +} +EXPORT_SYMBOL(gpio_get_value); + + +/* + * Map GPIO line to IRQ number. + */ +int gpio_to_irq(unsigned int pin) +{ + if (pin > KS8695_GPIO_3) /* only GPIO 0..3 can generate IRQ */ + return -EINVAL; + + return gpio_irq[pin]; +} +EXPORT_SYMBOL(gpio_to_irq); + + +/* + * Map IRQ number to GPIO line. + */ +int irq_to_gpio(unsigned int irq) +{ + if ((irq < KS8695_IRQ_EXTERN0) || (irq > KS8695_IRQ_EXTERN3)) + return -EINVAL; + + return (irq - KS8695_IRQ_EXTERN0); +} +EXPORT_SYMBOL(irq_to_gpio); diff --git a/arch/arm/mach-pxa/clock.c b/arch/arm/mach-pxa/clock.c index 8f7c90a0593..34a31caa6f9 100644 --- a/arch/arm/mach-pxa/clock.c +++ b/arch/arm/mach-pxa/clock.c @@ -12,7 +12,6 @@ #include <asm/arch/pxa-regs.h> #include <asm/hardware.h> -#include <asm/semaphore.h> struct clk { struct list_head node; @@ -25,21 +24,21 @@ struct clk { }; static LIST_HEAD(clocks); -static DECLARE_MUTEX(clocks_sem); +static DEFINE_MUTEX(clocks_mutex); static DEFINE_SPINLOCK(clocks_lock); struct clk *clk_get(struct device *dev, const char *id) { struct clk *p, *clk = ERR_PTR(-ENOENT); - down(&clocks_sem); + mutex_lock(&clocks_mutex); list_for_each_entry(p, &clocks, node) { if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { clk = p; break; } } - up(&clocks_sem); + mutex_unlock(&clocks_mutex); return clk; } @@ -101,18 +100,18 @@ static struct clk clk_gpio27 = { int clk_register(struct clk *clk) { - down(&clocks_sem); + mutex_lock(&clocks_mutex); list_add(&clk->node, &clocks); - up(&clocks_sem); + mutex_unlock(&clocks_mutex); return 0; } EXPORT_SYMBOL(clk_register); void clk_unregister(struct clk *clk) { - down(&clocks_sem); + mutex_lock(&clocks_mutex); list_del(&clk->node); - up(&clocks_sem); + mutex_unlock(&clocks_mutex); } EXPORT_SYMBOL(clk_unregister); diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c index a1a900d1666..aab27297b3c 100644 --- a/arch/arm/mach-pxa/corgi.c +++ b/arch/arm/mach-pxa/corgi.c @@ -44,6 +44,7 @@ #include <asm/hardware/scoop.h> #include "generic.h" +#include "devices.h" #include "sharpsl.h" @@ -368,7 +369,7 @@ MACHINE_START(CORGI, "SHARP Corgi") .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, .fixup = fixup_corgi, .map_io = pxa_map_io, - .init_irq = pxa_init_irq, + .init_irq = pxa25x_init_irq, .init_machine = corgi_init, .timer = &pxa_timer, MACHINE_END @@ -380,7 +381,7 @@ MACHINE_START(SHEPHERD, "SHARP Shepherd") .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, .fixup = fixup_corgi, .map_io = pxa_map_io, - .init_irq = pxa_init_irq, + .init_irq = pxa25x_init_irq, .init_machine = corgi_init, .timer = &pxa_timer, MACHINE_END @@ -392,7 +393,7 @@ MACHINE_START(HUSKY, "SHARP Husky") .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, .fixup = fixup_corgi, .map_io = pxa_map_io, - .init_irq = pxa_init_irq, + .init_irq = pxa25x_init_irq, .init_machine = corgi_init, .timer = &pxa_timer, MACHINE_END diff --git a/arch/arm/mach-pxa/devices.h b/arch/arm/mach-pxa/devices.h new file mode 100644 index 00000000000..9a6faff8e5a --- /dev/null +++ b/arch/arm/mach-pxa/devices.h @@ -0,0 +1,11 @@ +extern struct platform_device pxamci_device; +extern struct platform_device pxaudc_device; +extern struct platform_device pxafb_device; +extern struct platform_device ffuart_device; +extern struct platform_device btuart_device; +extern struct platform_device stuart_device; +extern struct platform_device hwuart_device; +extern struct platform_device pxai2c_device; +extern struct platform_device pxai2s_device; +extern struct platform_device pxaficp_device; +extern struct platform_device pxartc_device; diff --git a/arch/arm/mach-pxa/dma.c b/arch/arm/mach-pxa/dma.c index 4440babe7b9..93c4f31f127 100644 --- a/arch/arm/mach-pxa/dma.c +++ b/arch/arm/mach-pxa/dma.c @@ -25,12 +25,15 @@ #include <asm/arch/pxa-regs.h> -static struct dma_channel { +struct dma_channel { char *name; + pxa_dma_prio prio; void (*irq_handler)(int, void *); void *data; -} dma_channels[PXA_DMA_CHANNELS]; +}; +static struct dma_channel *dma_channels; +static int num_dma_channels; int pxa_request_dma (char *name, pxa_dma_prio prio, void (*irq_handler)(int, void *), @@ -47,8 +50,9 @@ int pxa_request_dma (char *name, pxa_dma_prio prio, do { /* try grabbing a DMA channel with the requested priority */ - pxa_for_each_dma_prio (i, prio) { - if (!dma_channels[i].name) { + for (i = 0; i < num_dma_channels; i++) { + if ((dma_channels[i].prio == prio) && + !dma_channels[i].name) { found = 1; break; } @@ -91,7 +95,7 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id) { int i, dint = DINT; - for (i = 0; i < PXA_DMA_CHANNELS; i++) { + for (i = 0; i < num_dma_channels; i++) { if (dint & (1 << i)) { struct dma_channel *channel = &dma_channels[i]; if (channel->name && channel->irq_handler) { @@ -109,18 +113,32 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } -static int __init pxa_dma_init (void) +int __init pxa_init_dma(int num_ch) { - int ret; + int i, ret; - ret = request_irq (IRQ_DMA, dma_irq_handler, 0, "DMA", NULL); - if (ret) + dma_channels = kzalloc(sizeof(struct dma_channel) * num_ch, GFP_KERNEL); + if (dma_channels == NULL) + return -ENOMEM; + + ret = request_irq(IRQ_DMA, dma_irq_handler, IRQF_DISABLED, "DMA", NULL); + if (ret) { printk (KERN_CRIT "Wow! Can't register IRQ for DMA\n"); - return ret; -} + kfree(dma_channels); + return ret; + } -arch_initcall(pxa_dma_init); + /* dma channel priorities on pxa2xx processors: + * ch 0 - 3, 16 - 19 <--> (0) DMA_PRIO_HIGH + * ch 4 - 7, 20 - 23 <--> (1) DMA_PRIO_MEDIUM + * ch 8 - 15, 24 - 31 <--> (2) DMA_PRIO_LOW + */ + for (i = 0; i < num_ch; i++) + dma_channels[i].prio = min((i & 0xf) >> 2, DMA_PRIO_LOW); + + num_dma_channels = num_ch; + return 0; +} EXPORT_SYMBOL(pxa_request_dma); EXPORT_SYMBOL(pxa_free_dma); - diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c index 64b08b744f9..296539b6359 100644 --- a/arch/arm/mach-pxa/generic.c +++ b/arch/arm/mach-pxa/generic.c @@ -43,6 +43,7 @@ #include <asm/arch/irda.h> #include <asm/arch/i2c.h> +#include "devices.h" #include "generic.h" /* @@ -242,7 +243,7 @@ static struct resource pxamci_resources[] = { static u64 pxamci_dmamask = 0xffffffffUL; -static struct platform_device pxamci_device = { +struct platform_device pxamci_device = { .name = "pxa2xx-mci", .id = -1, .dev = { @@ -281,7 +282,7 @@ static struct resource pxa2xx_udc_resources[] = { static u64 udc_dma_mask = ~(u32)0; -static struct platform_device udc_device = { +struct platform_device pxaudc_device = { .name = "pxa2xx-udc", .id = -1, .resource = pxa2xx_udc_resources, @@ -307,7 +308,7 @@ static struct resource pxafb_resources[] = { static u64 fb_dma_mask = ~(u64)0; -static struct platform_device pxafb_device = { +struct platform_device pxafb_device = { .name = "pxa2xx-fb", .id = -1, .dev = { @@ -328,24 +329,24 @@ void __init set_pxa_fb_parent(struct device *parent_dev) pxafb_device.dev.parent = parent_dev; } -static struct platform_device ffuart_device = { +struct platform_device ffuart_device = { .name = "pxa2xx-uart", .id = 0, }; -static struct platform_device btuart_device = { +struct platform_device btuart_device = { .name = "pxa2xx-uart", .id = 1, }; -static struct platform_device stuart_device = { +struct platform_device stuart_device = { .name = "pxa2xx-uart", .id = 2, }; -static struct platform_device hwuart_device = { +struct platform_device hwuart_device = { .name = "pxa2xx-uart", .id = 3, }; -static struct resource i2c_resources[] = { +static struct resource pxai2c_resources[] = { { .start = 0x40301680, .end = 0x403016a3, @@ -357,40 +358,19 @@ static struct resource i2c_resources[] = { }, }; -static struct platform_device i2c_device = { +struct platform_device pxai2c_device = { .name = "pxa2xx-i2c", .id = 0, - .resource = i2c_resources, - .num_resources = ARRAY_SIZE(i2c_resources), + .resource = pxai2c_resources, + .num_resources = ARRAY_SIZE(pxai2c_resources), }; -#ifdef CONFIG_PXA27x -static struct resource i2c_power_resources[] = { - { - .start = 0x40f00180, - .end = 0x40f001a3, - .flags = IORESOURCE_MEM, - }, { - .start = IRQ_PWRI2C, - .end = IRQ_PWRI2C, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device i2c_power_device = { - .name = "pxa2xx-i2c", - .id = 1, - .resource = i2c_power_resources, - .num_resources = ARRAY_SIZE(i2c_resources), -}; -#endif - void __init pxa_set_i2c_info(struct i2c_pxa_platform_data *info) { - i2c_device.dev.platform_data = info; + pxai2c_device.dev.platform_data = info; } -static struct resource i2s_resources[] = { +static struct resource pxai2s_resources[] = { { .start = 0x40400000, .end = 0x40400083, @@ -402,16 +382,16 @@ static struct resource i2s_resources[] = { }, }; -static struct platform_device i2s_device = { +struct platform_device pxai2s_device = { .name = "pxa2xx-i2s", .id = -1, - .resource = i2s_resources, - .num_resources = ARRAY_SIZE(i2s_resources), + .resource = pxai2s_resources, + .num_resources = ARRAY_SIZE(pxai2s_resources), }; static u64 pxaficp_dmamask = ~(u32)0; -static struct platform_device pxaficp_device = { +struct platform_device pxaficp_device = { .name = "pxa2xx-ir", .id = -1, .dev = { @@ -425,42 +405,7 @@ void __init pxa_set_ficp_info(struct pxaficp_platform_data *info) pxaficp_device.dev.platform_data = info; } -static struct platform_device pxartc_device = { +struct platform_device pxartc_device = { .name = "sa1100-rtc", .id = -1, }; - -static struct platform_device *devices[] __initdata = { - &pxamci_device, - &udc_device, - &pxafb_device, - &ffuart_device, - &btuart_device, - &stuart_device, - &pxaficp_device, - &i2c_device, -#ifdef CONFIG_PXA27x - &i2c_power_device, -#endif - &i2s_device, - &pxartc_device, -}; - -static int __init pxa_init(void) -{ - int cpuid, ret; - - ret = platform_add_devices(devices, ARRAY_SIZE(devices)); - if (ret) - return ret; - - /* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */ - cpuid = read_cpuid(CPUID_ID); - if (((cpuid >> 4) & 0xfff) == 0x2d0 || - ((cpuid >> 4) & 0xfff) == 0x290) - ret = platform_device_register(&hwuart_device); - - return ret; -} - -subsys_initcall(pxa_init); diff --git a/arch/arm/mach-pxa/generic.h b/arch/arm/mach-pxa/generic.h index e54a8dd63c1..91ab2ad8b34 100644 --- a/arch/arm/mach-pxa/generic.h +++ b/arch/arm/mach-pxa/generic.h @@ -12,8 +12,12 @@ struct sys_timer; extern struct sys_timer pxa_timer; +extern void __init pxa_init_irq_low(void); +extern void __init pxa_init_irq_high(void); +extern void __init pxa_init_irq_gpio(int gpio_nr); +extern void __init pxa25x_init_irq(void); +extern void __init pxa27x_init_irq(void); extern void __init pxa_map_io(void); -extern void __init pxa_init_irq(void); extern unsigned int get_clk_frequency_khz(int info); diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c index 64df44043a6..465108da285 100644 --- a/arch/arm/mach-pxa/idp.c +++ b/arch/arm/mach-pxa/idp.c @@ -38,6 +38,7 @@ #include <asm/arch/mmc.h> #include "generic.h" +#include "devices.h" /* TODO: * - add pxa2xx_audio_ops_t device structure @@ -152,7 +153,7 @@ static void __init idp_init(void) static void __init idp_init_irq(void) { - pxa_init_irq(); + pxa25x_init_irq(); set_irq_type(TOUCH_PANEL_IRQ, TOUCH_PANEL_IRQ_EDGE); } diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c index 4619d5fe606..4b867b0789d 100644 --- a/arch/arm/mach-pxa/irq.c +++ b/arch/arm/mach-pxa/irq.c @@ -30,12 +30,12 @@ static void pxa_mask_low_irq(unsigned int irq) { - ICMR &= ~(1 << (irq + PXA_IRQ_SKIP)); + ICMR &= ~(1 << irq); } static void pxa_unmask_low_irq(unsigned int irq) { - ICMR |= (1 << (irq + PXA_IRQ_SKIP)); + ICMR |= (1 << irq); } static int pxa_set_wake(unsigned int irq, unsigned int on) @@ -67,7 +67,27 @@ static struct irq_chip pxa_internal_chip_low = { .set_wake = pxa_set_wake, }; -#if PXA_INTERNAL_IRQS > 32 +void __init pxa_init_irq_low(void) +{ + int irq; + + /* disable all IRQs */ + ICMR = 0; + + /* all IRQs are IRQ, not FIQ */ + ICLR = 0; + + /* only unmasked interrupts kick us out of idle */ + ICCR = 1; + + for (irq = PXA_IRQ(0); irq <= PXA_IRQ(31); irq++) { + set_irq_chip(irq, &pxa_internal_chip_low); + set_irq_handler(irq, handle_level_irq); + set_irq_flags(irq, IRQF_VALID); + } +} + +#ifdef CONFIG_PXA27x /* * This is for the second set of internal IRQs as found on the PXA27x. @@ -75,12 +95,12 @@ static struct irq_chip pxa_internal_chip_low = { static void pxa_mask_high_irq(unsigned int irq) { - ICMR2 &= ~(1 << (irq - 32 + PXA_IRQ_SKIP)); + ICMR2 &= ~(1 << (irq - 32)); } static void pxa_unmask_high_irq(unsigned int irq) { - ICMR2 |= (1 << (irq - 32 + PXA_IRQ_SKIP)); + ICMR2 |= (1 << (irq - 32)); } static struct irq_chip pxa_internal_chip_high = { @@ -90,6 +110,19 @@ static struct irq_chip pxa_internal_chip_high = { .unmask = pxa_unmask_high_irq, }; +void __init pxa_init_irq_high(void) +{ + int irq; + + ICMR2 = 0; + ICLR2 = 0; + + for (irq = PXA_IRQ(32); irq < PXA_IRQ(64); irq++) { + set_irq_chip(irq, &pxa_internal_chip_high); + set_irq_handler(irq, handle_level_irq); + set_irq_flags(irq, IRQF_VALID); + } +} #endif /* Note that if an input/irq line ever gets changed to an output during @@ -217,7 +250,7 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc) do { loop = 0; - mask = GEDR0 & ~3; + mask = GEDR0 & GPIO_IRQ_mask[0] & ~3; if (mask) { GEDR0 = mask; irq = IRQ_GPIO(2); @@ -233,7 +266,7 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc) loop = 1; } - mask = GEDR1; + mask = GEDR1 & GPIO_IRQ_mask[1]; if (mask) { GEDR1 = mask; irq = IRQ_GPIO(32); @@ -248,7 +281,7 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc) loop = 1; } - mask = GEDR2; + mask = GEDR2 & GPIO_IRQ_mask[2]; if (mask) { GEDR2 = mask; irq = IRQ_GPIO(64); @@ -263,8 +296,7 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc) loop = 1; } -#if PXA_LAST_GPIO >= 96 - mask = GEDR3; + mask = GEDR3 & GPIO_IRQ_mask[3]; if (mask) { GEDR3 = mask; irq = IRQ_GPIO(96); @@ -278,7 +310,6 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc) } while (mask); loop = 1; } -#endif } while (loop); } @@ -314,64 +345,27 @@ static struct irq_chip pxa_muxed_gpio_chip = { .set_wake = pxa_set_gpio_wake, }; - -void __init pxa_init_irq(void) +void __init pxa_init_irq_gpio(int gpio_nr) { - int irq; - - /* disable all IRQs */ - ICMR = 0; - - /* all IRQs are IRQ, not FIQ */ - ICLR = 0; + int irq, i; /* clear all GPIO edge detects */ - GFER0 = 0; - GFER1 = 0; - GFER2 = 0; - GRER0 = 0; - GRER1 = 0; - GRER2 = 0; - GEDR0 = GEDR0; - GEDR1 = GEDR1; - GEDR2 = GEDR2; - -#ifdef CONFIG_PXA27x - /* And similarly for the extra regs on the PXA27x */ - ICMR2 = 0; - ICLR2 = 0; - GFER3 = 0; - GRER3 = 0; - GEDR3 = GEDR3; -#endif - - /* only unmasked interrupts kick us out of idle */ - ICCR = 1; + for (i = 0; i < gpio_nr; i += 32) { + GFER(i) = 0; + GRER(i) = 0; + GEDR(i) = GEDR(i); + } /* GPIO 0 and 1 must have their mask bit always set */ GPIO_IRQ_mask[0] = 3; - for (irq = PXA_IRQ(PXA_IRQ_SKIP); irq <= PXA_IRQ(31); irq++) { - set_irq_chip(irq, &pxa_internal_chip_low); - set_irq_handler(irq, handle_level_irq); - set_irq_flags(irq, IRQF_VALID); - } - -#if PXA_INTERNAL_IRQS > 32 - for (irq = PXA_IRQ(32); irq < PXA_IRQ(PXA_INTERNAL_IRQS); irq++) { - set_irq_chip(irq, &pxa_internal_chip_high); - set_irq_handler(irq, handle_level_irq); - set_irq_flags(irq, IRQF_VALID); - } -#endif - for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) { set_irq_chip(irq, &pxa_low_gpio_chip); set_irq_handler(irq, handle_edge_irq); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } - for (irq = IRQ_GPIO(2); irq <= IRQ_GPIO(PXA_LAST_GPIO); irq++) { + for (irq = IRQ_GPIO(2); irq <= IRQ_GPIO(gpio_nr); irq++) { set_irq_chip(irq, &pxa_muxed_gpio_chip); set_irq_handler(irq, handle_edge_irq); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); diff --git a/arch/arm/mach-pxa/lpd270.c b/arch/arm/mach-pxa/lpd270.c index e3097664ffe..26116440a7c 100644 --- a/arch/arm/mach-pxa/lpd270.c +++ b/arch/arm/mach-pxa/lpd270.c @@ -46,6 +46,7 @@ #include <asm/arch/ohci.h> #include "generic.h" +#include "devices.h" static unsigned int lpd270_irq_enabled; @@ -97,7 +98,7 @@ static void __init lpd270_init_irq(void) { int irq; - pxa_init_irq(); + pxa27x_init_irq(); __raw_writew(0, LPD270_INT_MASK); __raw_writew(0, LPD270_INT_STATUS); diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index 6377b2e29ff..e70048fd00a 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c @@ -48,6 +48,7 @@ #include <asm/arch/mmc.h> #include "generic.h" +#include "devices.h" #define LUB_MISC_WR __LUB_REG(LUBBOCK_FPGA_PHYS + 0x080) @@ -103,7 +104,7 @@ static void __init lubbock_init_irq(void) { int irq; - pxa_init_irq(); + pxa25x_init_irq(); /* setup extra lubbock irqs */ for (irq = LUBBOCK_IRQ(0); irq <= LUBBOCK_LAST_IRQ; irq++) { diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c index ed99a81b98f..b02c79c7e6a 100644 --- a/arch/arm/mach-pxa/mainstone.c +++ b/arch/arm/mach-pxa/mainstone.c @@ -46,6 +46,7 @@ #include <asm/arch/ohci.h> #include "generic.h" +#include "devices.h" static unsigned long mainstone_irq_enabled; @@ -89,7 +90,7 @@ static void __init mainstone_init_irq(void) { int irq; - pxa_init_irq(); + pxa27x_init_irq(); /* setup extra Mainstone irqs */ for(irq = MAINSTONE_IRQ(0); irq <= MAINSTONE_IRQ(15); irq++) { diff --git a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c index 6bf15ae7384..e66dbc26add 100644 --- a/arch/arm/mach-pxa/pm.c +++ b/arch/arm/mach-pxa/pm.c @@ -77,7 +77,6 @@ int pxa_pm_enter(suspend_state_t state) { unsigned long sleep_save[SLEEP_SAVE_SIZE]; unsigned long checksum = 0; - struct timespec delta, rtc; int i; extern void pxa_cpu_pm_enter(suspend_state_t state); @@ -87,11 +86,6 @@ int pxa_pm_enter(suspend_state_t state) iwmmxt_task_disable(NULL); #endif - /* preserve current time */ - rtc.tv_sec = RCNR; - rtc.tv_nsec = 0; - save_time_delta(&delta, &rtc); - SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2); SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2); SAVE(GRER0); SAVE(GRER1); SAVE(GRER2); @@ -183,10 +177,6 @@ int pxa_pm_enter(suspend_state_t state) RESTORE(PSTR); - /* restore current time */ - rtc.tv_sec = RCNR; - restore_time_delta(&delta, &rtc); - #ifdef DEBUG printk(KERN_DEBUG "*** made it back from resume\n"); #endif @@ -200,40 +190,3 @@ unsigned long sleep_phys_sp(void *sp) { return virt_to_phys(sp); } - -/* - * Called after processes are frozen, but before we shut down devices. - */ -int pxa_pm_prepare(suspend_state_t state) -{ - extern int pxa_cpu_pm_prepare(suspend_state_t state); - - return pxa_cpu_pm_prepare(state); -} - -EXPORT_SYMBOL_GPL(pxa_pm_prepare); - -/* - * Called after devices are re-setup, but before processes are thawed. - */ -int pxa_pm_finish(suspend_state_t state) -{ - return 0; -} - -EXPORT_SYMBOL_GPL(pxa_pm_finish); - -static struct pm_ops pxa_pm_ops = { - .prepare = pxa_pm_prepare, - .enter = pxa_pm_enter, - .finish = pxa_pm_finish, - .valid = pm_valid_only_mem, -}; - -static int __init pxa_pm_init(void) -{ - pm_set_ops(&pxa_pm_ops); - return 0; -} - -device_initcall(pxa_pm_init); diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c index 34fb80b3702..655668d4d0e 100644 --- a/arch/arm/mach-pxa/poodle.c +++ b/arch/arm/mach-pxa/poodle.c @@ -45,6 +45,7 @@ #include <asm/mach/sharpsl_param.h> #include "generic.h" +#include "devices.h" #include "sharpsl.h" static struct resource poodle_scoop_resources[] = { @@ -412,7 +413,7 @@ MACHINE_START(POODLE, "SHARP Poodle") .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, .fixup = fixup_poodle, .map_io = pxa_map_io, - .init_irq = pxa_init_irq, + .init_irq = pxa25x_init_irq, .timer = &pxa_timer, .init_machine = poodle_init, MACHINE_END diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c index c1f21739bf7..f36ca448338 100644 --- a/arch/arm/mach-pxa/pxa25x.c +++ b/arch/arm/mach-pxa/pxa25x.c @@ -19,12 +19,17 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> +#include <linux/platform_device.h> #include <linux/pm.h> #include <asm/hardware.h> +#include <asm/arch/irqs.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/pm.h> +#include <asm/arch/dma.h> #include "generic.h" +#include "devices.h" /* * Various clock factors driven by the CCCR register. @@ -105,18 +110,6 @@ EXPORT_SYMBOL(get_lcdclk_frequency_10khz); #ifdef CONFIG_PM -int pxa_cpu_pm_prepare(suspend_state_t state) -{ - switch (state) { - case PM_SUSPEND_MEM: - break; - default: - return -EINVAL; - } - - return 0; -} - void pxa_cpu_pm_enter(suspend_state_t state) { extern void pxa_cpu_suspend(unsigned int); @@ -133,4 +126,49 @@ void pxa_cpu_pm_enter(suspend_state_t state) } } +static struct pm_ops pxa25x_pm_ops = { + .enter = pxa_pm_enter, + .valid = pm_valid_only_mem, +}; +#endif + +void __init pxa25x_init_irq(void) +{ + pxa_init_irq_low(); + pxa_init_irq_gpio(85); +} + +static struct platform_device *pxa25x_devices[] __initdata = { + &pxamci_device, + &pxaudc_device, + &pxafb_device, + &ffuart_device, + &btuart_device, + &stuart_device, + &pxai2c_device, + &pxai2s_device, + &pxaficp_device, + &pxartc_device, +}; + +static int __init pxa25x_init(void) +{ + int ret = 0; + + if (cpu_is_pxa21x() || cpu_is_pxa25x()) { + if ((ret = pxa_init_dma(16))) + return ret; +#ifdef CONFIG_PM + pm_set_ops(&pxa25x_pm_ops); #endif + ret = platform_add_devices(pxa25x_devices, + ARRAY_SIZE(pxa25x_devices)); + } + /* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */ + if (cpu_is_pxa25x()) + ret = platform_device_register(&hwuart_device); + + return ret; +} + +subsys_initcall(pxa25x_init); diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index 1939acc3f9f..aa5bb02c897 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c @@ -19,10 +19,14 @@ #include <asm/hardware.h> #include <asm/irq.h> +#include <asm/arch/irqs.h> #include <asm/arch/pxa-regs.h> #include <asm/arch/ohci.h> +#include <asm/arch/pm.h> +#include <asm/arch/dma.h> #include "generic.h" +#include "devices.h" /* Crystal clock: 13MHz */ #define BASE_CLK 13000000 @@ -122,17 +126,6 @@ EXPORT_SYMBOL(get_lcdclk_frequency_10khz); #ifdef CONFIG_PM -int pxa_cpu_pm_prepare(suspend_state_t state) -{ - switch (state) { - case PM_SUSPEND_MEM: - case PM_SUSPEND_STANDBY: - return 0; - default: - return -EINVAL; - } -} - void pxa_cpu_pm_enter(suspend_state_t state) { extern void pxa_cpu_standby(void); @@ -162,6 +155,15 @@ void pxa_cpu_pm_enter(suspend_state_t state) } } +static int pxa27x_pm_valid(suspend_state_t state) +{ + return state == PM_SUSPEND_MEM || state == PM_SUSPEND_STANDBY; +} + +static struct pm_ops pxa27x_pm_ops = { + .enter = pxa_pm_enter, + .valid = pxa27x_pm_valid, +}; #endif /* @@ -183,7 +185,7 @@ static struct resource pxa27x_ohci_resources[] = { }, }; -static struct platform_device ohci_device = { +static struct platform_device pxaohci_device = { .name = "pxa27x-ohci", .id = -1, .dev = { @@ -196,16 +198,62 @@ static struct platform_device ohci_device = { void __init pxa_set_ohci_info(struct pxaohci_platform_data *info) { - ohci_device.dev.platform_data = info; + pxaohci_device.dev.platform_data = info; } +static struct resource i2c_power_resources[] = { + { + .start = 0x40f00180, + .end = 0x40f001a3, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_PWRI2C, + .end = IRQ_PWRI2C, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device pxai2c_power_device = { + .name = "pxa2xx-i2c", + .id = 1, + .resource = i2c_power_resources, + .num_resources = ARRAY_SIZE(i2c_power_resources), +}; + static struct platform_device *devices[] __initdata = { - &ohci_device, + &pxamci_device, + &pxaudc_device, + &pxafb_device, + &ffuart_device, + &btuart_device, + &stuart_device, + &pxai2c_device, + &pxai2c_power_device, + &pxai2s_device, + &pxaficp_device, + &pxartc_device, + &pxaohci_device, }; +void __init pxa27x_init_irq(void) +{ + pxa_init_irq_low(); + pxa_init_irq_high(); + pxa_init_irq_gpio(128); +} + static int __init pxa27x_init(void) { - return platform_add_devices(devices, ARRAY_SIZE(devices)); + int ret = 0; + if (cpu_is_pxa27x()) { + if ((ret = pxa_init_dma(32))) + return ret; +#ifdef CONFIG_PM + pm_set_ops(&pxa27x_pm_ops); +#endif + ret = platform_add_devices(devices, ARRAY_SIZE(devices)); + } + return ret; } subsys_initcall(pxa27x_init); diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index 3cbac63bed3..bae47e145de 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -48,6 +48,7 @@ #include <asm/hardware/scoop.h> #include "generic.h" +#include "devices.h" #include "sharpsl.h" /* @@ -560,7 +561,7 @@ MACHINE_START(SPITZ, "SHARP Spitz") .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, .fixup = fixup_spitz, .map_io = pxa_map_io, - .init_irq = pxa_init_irq, + .init_irq = pxa27x_init_irq, .init_machine = spitz_init, .timer = &pxa_timer, MACHINE_END @@ -572,7 +573,7 @@ MACHINE_START(BORZOI, "SHARP Borzoi") .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, .fixup = fixup_spitz, .map_io = pxa_map_io, - .init_irq = pxa_init_irq, + .init_irq = pxa27x_init_irq, .init_machine = spitz_init, .timer = &pxa_timer, MACHINE_END @@ -584,7 +585,7 @@ MACHINE_START(AKITA, "SHARP Akita") .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, .fixup = fixup_spitz, .map_io = pxa_map_io, - .init_irq = pxa_init_irq, + .init_irq = pxa27x_init_irq, .init_machine = akita_init, .timer = &pxa_timer, MACHINE_END diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c index 5248abe334d..6f91fd2d061 100644 --- a/arch/arm/mach-pxa/time.c +++ b/arch/arm/mach-pxa/time.c @@ -30,11 +30,6 @@ #include <asm/arch/pxa-regs.h> -static inline unsigned long pxa_get_rtc_time(void) -{ - return RCNR; -} - static int pxa_set_rtc(void) { unsigned long current_time = xtime.tv_sec; @@ -122,10 +117,6 @@ static void __init pxa_timer_init(void) set_rtc = pxa_set_rtc; - tv.tv_nsec = 0; - tv.tv_sec = pxa_get_rtc_time(); - do_settimeofday(&tv); - OIER = 0; /* disable any timer interrupts */ OSSR = 0xf; /* clear status on all timers */ setup_irq(IRQ_OST0, &pxa_timer_irq); diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c index 72738771fb5..240fd042083 100644 --- a/arch/arm/mach-pxa/tosa.c +++ b/arch/arm/mach-pxa/tosa.c @@ -42,7 +42,7 @@ #include <asm/mach/sharpsl_param.h> #include "generic.h" - +#include "devices.h" /* * SCOOP Device @@ -332,7 +332,7 @@ MACHINE_START(TOSA, "SHARP Tosa") .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, .fixup = fixup_tosa, .map_io = pxa_map_io, - .init_irq = pxa_init_irq, + .init_irq = pxa25x_init_irq, .init_machine = tosa_init, .timer = &pxa_timer, MACHINE_END diff --git a/arch/arm/mach-pxa/trizeps4.c b/arch/arm/mach-pxa/trizeps4.c index 28c79bd0a3a..e4ba43bdf85 100644 --- a/arch/arm/mach-pxa/trizeps4.c +++ b/arch/arm/mach-pxa/trizeps4.c @@ -49,6 +49,7 @@ #include <asm/arch/ohci.h> #include "generic.h" +#include "devices.h" /******************************************************************************************** * ONBOARD FLASH @@ -503,7 +504,7 @@ MACHINE_START(TRIZEPS4, "Keith und Koep Trizeps IV module") .boot_params = TRIZEPS4_SDRAM_BASE + 0x100, .init_machine = trizeps4_init, .map_io = trizeps4_map_io, - .init_irq = pxa_init_irq, + .init_irq = pxa27x_init_irq, .timer = &pxa_timer, MACHINE_END diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c index f01de807b72..8b52ea95d4f 100644 --- a/arch/arm/mach-s3c2410/mach-bast.c +++ b/arch/arm/mach-s3c2410/mach-bast.c @@ -20,6 +20,8 @@ #include <linux/platform_device.h> #include <linux/dm9000.h> +#include <net/ax88796.h> + #include <asm/mach/arch.h> #include <asm/mach/map.h> #include <asm/mach/irq.h> @@ -409,6 +411,61 @@ static struct s3c2410_platform_i2c bast_i2c_info = { .max_freq = 130*1000, }; +/* Asix AX88796 10/100 ethernet controller */ + +static struct ax_plat_data bast_asix_platdata = { + .flags = AXFLG_MAC_FROMDEV, + .wordlength = 2, + .dcr_val = 0x48, + .rcr_val = 0x40, +}; + +static struct resource bast_asix_resource[] = { + [0] = { + .start = S3C2410_CS5 + BAST_PA_ASIXNET, + .end = S3C2410_CS5 + BAST_PA_ASIXNET + (0x18 * 0x20) - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = S3C2410_CS5 + BAST_PA_ASIXNET + (0x1f * 0x20), + .end = S3C2410_CS5 + BAST_PA_ASIXNET + (0x1f * 0x20), + .flags = IORESOURCE_MEM, + }, + [2] = { + .start = IRQ_ASIX, + .end = IRQ_ASIX, + .flags = IORESOURCE_IRQ + } +}; + +static struct platform_device bast_device_asix = { + .name = "ax88796", + .id = 0, + .num_resources = ARRAY_SIZE(bast_asix_resource), + .resource = bast_asix_resource, + .dev = { + .platform_data = &bast_asix_platdata + } +}; + +/* Asix AX88796 10/100 ethernet controller parallel port */ + +static struct resource bast_asixpp_resource[] = { + [0] = { + .start = S3C2410_CS5 + BAST_PA_ASIXNET + (0x18 * 0x20), + .end = S3C2410_CS5 + BAST_PA_ASIXNET + (0x1b * 0x20) - 1, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device bast_device_axpp = { + .name = "ax88796-pp", + .id = 0, + .num_resources = ARRAY_SIZE(bast_asixpp_resource), + .resource = bast_asixpp_resource, +}; + +/* LCD/VGA controller */ static struct s3c2410fb_mach_info __initdata bast_lcd_info = { .width = 640, @@ -453,6 +510,8 @@ static struct platform_device *bast_devices[] __initdata = { &s3c_device_nand, &bast_device_nor, &bast_device_dm9k, + &bast_device_asix, + &bast_device_axpp, &bast_sio, }; diff --git a/arch/arm/mach-s3c2440/mach-anubis.c b/arch/arm/mach-s3c2440/mach-anubis.c index bff7ddd06a5..29c163d300d 100644 --- a/arch/arm/mach-s3c2440/mach-anubis.c +++ b/arch/arm/mach-s3c2440/mach-anubis.c @@ -18,6 +18,9 @@ #include <linux/serial_core.h> #include <linux/platform_device.h> +#include <linux/sm501.h> +#include <linux/sm501-regs.h> + #include <asm/mach/arch.h> #include <asm/mach/map.h> #include <asm/mach/irq.h> @@ -42,6 +45,8 @@ #include <linux/mtd/nand_ecc.h> #include <linux/mtd/partitions.h> +#include <net/ax88796.h> + #include <asm/plat-s3c24xx/clock.h> #include <asm/plat-s3c24xx/devs.h> #include <asm/plat-s3c24xx/cpu.h> @@ -153,6 +158,29 @@ static struct mtd_partition anubis_default_nand_part[] = { } }; +static struct mtd_partition anubis_default_nand_part_large[] = { + [0] = { + .name = "Boot Agent", + .size = SZ_128K, + .offset = 0, + }, + [1] = { + .name = "/boot", + .size = SZ_4M - SZ_128K, + .offset = SZ_128K, + }, + [2] = { + .name = "user1", + .offset = SZ_4M, + .size = SZ_32M - SZ_4M, + }, + [3] = { + .name = "user2", + .offset = SZ_32M, + .size = MTDPART_SIZ_FULL, + } +}; + /* the Anubis has 3 selectable slots for nand-flash, the two * on-board chip areas, as well as the external slot. * @@ -260,6 +288,104 @@ static struct platform_device anubis_device_ide1 = { .resource = anubis_ide1_resource, }; +/* Asix AX88796 10/100 ethernet controller */ + +static struct ax_plat_data anubis_asix_platdata = { + .flags = AXFLG_MAC_FROMDEV, + .wordlength = 2, + .dcr_val = 0x48, + .rcr_val = 0x40, +}; + +static struct resource anubis_asix_resource[] = { + [0] = { + .start = S3C2410_CS5, + .end = S3C2410_CS5 + (0x20 * 0x20) -1, + .flags = IORESOURCE_MEM + }, + [1] = { + .start = IRQ_ASIX, + .end = IRQ_ASIX, + .flags = IORESOURCE_IRQ + } +}; + +static struct platform_device anubis_device_asix = { + .name = "ax88796", + .id = 0, + .num_resources = ARRAY_SIZE(anubis_asix_resource), + .resource = anubis_asix_resource, + .dev = { + .platform_data = &anubis_asix_platdata, + } +}; + +/* SM501 */ + +static struct resource anubis_sm501_resource[] = { + [0] = { + .start = S3C2410_CS2, + .end = S3C2410_CS2 + SZ_8M, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = S3C2410_CS2 + SZ_64M - SZ_2M, + .end = S3C2410_CS2 + SZ_64M - 1, + .flags = IORESOURCE_MEM, + }, + [2] = { + .start = IRQ_EINT0, + .end = IRQ_EINT0, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct sm501_initdata anubis_sm501_initdata = { + .gpio_high = { + .set = 0x3F000000, /* 24bit panel */ + .mask = 0x0, + }, + .misc_timing = { + .set = 0x010100, /* SDRAM timing */ + .mask = 0x1F1F00, + }, + .misc_control = { + .set = SM501_MISC_PNL_24BIT, + .mask = 0, + }, + + /* set the SDRAM and bus clocks */ + .mclk = 72 * MHZ, + .m1xclk = 144 * MHZ, +}; + +static struct sm501_platdata_gpio_i2c anubis_sm501_gpio_i2c[] = { + [0] = { + .pin_scl = 44, + .pin_sda = 45, + }, + [1] = { + .pin_scl = 40, + .pin_sda = 41, + }, +}; + +static struct sm501_platdata anubis_sm501_platdata = { + .init = &anubis_sm501_initdata, + .gpio_i2c = anubis_sm501_gpio_i2c, + .gpio_i2c_nr = ARRAY_SIZE(anubis_sm501_gpio_i2c), +}; + +static struct platform_device anubis_device_sm501 = { + .name = "sm501", + .id = 0, + .num_resources = ARRAY_SIZE(anubis_sm501_resource), + .resource = anubis_sm501_resource, + .dev = { + .platform_data = &anubis_sm501_platdata, + }, +}; + /* Standard Anubis devices */ static struct platform_device *anubis_devices[] __initdata = { @@ -271,6 +397,8 @@ static struct platform_device *anubis_devices[] __initdata = { &s3c_device_nand, &anubis_device_ide0, &anubis_device_ide1, + &anubis_device_asix, + &anubis_device_sm501, }; static struct clk *anubis_clocks[] = { @@ -304,8 +432,17 @@ static void __init anubis_map_io(void) s3c24xx_init_clocks(0); s3c24xx_init_uarts(anubis_uartcfgs, ARRAY_SIZE(anubis_uartcfgs)); - /* ensure that the GPIO is setup */ - s3c2410_gpio_setpin(S3C2410_GPA0, 1); + /* check for the newer revision boards with large page nand */ + + if ((__raw_readb(ANUBIS_VA_IDREG) & ANUBIS_IDREG_REVMASK) >= 4) { + printk(KERN_INFO "ANUBIS-B detected (revision %d)\n", + __raw_readb(ANUBIS_VA_IDREG) & ANUBIS_IDREG_REVMASK); + anubis_nand_sets[0].partitions = anubis_default_nand_part_large; + anubis_nand_sets[0].nr_partitions = ARRAY_SIZE(anubis_default_nand_part_large); + } else { + /* ensure that the GPIO is setup */ + s3c2410_gpio_setpin(S3C2410_GPA0, 1); + } } static void __init anubis_init(void) diff --git a/arch/arm/mach-s3c2440/mach-osiris.c b/arch/arm/mach-s3c2440/mach-osiris.c index 15811601f03..89f4c9c5777 100644 --- a/arch/arm/mach-s3c2440/mach-osiris.c +++ b/arch/arm/mach-s3c2440/mach-osiris.c @@ -166,6 +166,29 @@ static struct mtd_partition osiris_default_nand_part[] = { } }; +static struct mtd_partition osiris_default_nand_part_large[] = { + [0] = { + .name = "Boot Agent", + .size = SZ_128K, + .offset = 0, + }, + [1] = { + .name = "/boot", + .size = SZ_4M - SZ_128K, + .offset = SZ_128K, + }, + [2] = { + .name = "user1", + .offset = SZ_4M, + .size = SZ_32M - SZ_4M, + }, + [3] = { + .name = "user2", + .offset = SZ_32M, + .size = MTDPART_SIZ_FULL, + } +}; + /* the Osiris has 3 selectable slots for nand-flash, the two * on-board chip areas, as well as the external slot. * @@ -322,14 +345,23 @@ static void __init osiris_map_io(void) s3c24xx_init_clocks(0); s3c24xx_init_uarts(osiris_uartcfgs, ARRAY_SIZE(osiris_uartcfgs)); + /* check for the newer revision boards with large page nand */ + + if ((__raw_readb(OSIRIS_VA_IDREG) & OSIRIS_ID_REVMASK) >= 4) { + printk(KERN_INFO "OSIRIS-B detected (revision %d)\n", + __raw_readb(OSIRIS_VA_IDREG) & OSIRIS_ID_REVMASK); + osiris_nand_sets[0].partitions = osiris_default_nand_part_large; + osiris_nand_sets[0].nr_partitions = ARRAY_SIZE(osiris_default_nand_part_large); + } else { + /* write-protect line to the NAND */ + s3c2410_gpio_setpin(S3C2410_GPA0, 1); + } + /* fix bus configuration (nBE settings wrong on ABLE pre v2.20) */ local_irq_save(flags); __raw_writel(__raw_readl(S3C2410_BWSCON) | S3C2410_BWSCON_ST1 | S3C2410_BWSCON_ST2 | S3C2410_BWSCON_ST3 | S3C2410_BWSCON_ST4 | S3C2410_BWSCON_ST5, S3C2410_BWSCON); local_irq_restore(flags); - - /* write-protect line to the NAND */ - s3c2410_gpio_setpin(S3C2410_GPA0, 1); } static void __init osiris_init(void) diff --git a/arch/arm/mach-sa1100/pm.c b/arch/arm/mach-sa1100/pm.c index d674cf34315..01a37d3c072 100644 --- a/arch/arm/mach-sa1100/pm.c +++ b/arch/arm/mach-sa1100/pm.c @@ -57,12 +57,7 @@ enum { SLEEP_SAVE_SP = 0, static int sa11x0_pm_enter(suspend_state_t state) { unsigned long gpio, sleep_save[SLEEP_SAVE_SIZE]; - struct timespec delta, rtc; - /* preserve current time */ - rtc.tv_sec = RCNR; - rtc.tv_nsec = 0; - save_time_delta(&delta, &rtc); gpio = GPLR; /* save vital registers */ @@ -119,10 +114,6 @@ static int sa11x0_pm_enter(suspend_state_t state) */ PSSR = PSSR_PH; - /* restore current time */ - rtc.tv_sec = RCNR; - restore_time_delta(&delta, &rtc); - return 0; } diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c index 29cb0c1604a..fdf7b016e7a 100644 --- a/arch/arm/mach-sa1100/time.c +++ b/arch/arm/mach-sa1100/time.c @@ -21,25 +21,6 @@ #define RTC_DEF_DIVIDER (32768 - 1) #define RTC_DEF_TRIM 0 -static unsigned long __init sa1100_get_rtc_time(void) -{ - /* - * According to the manual we should be able to let RTTR be zero - * and then a default divisor for a 32.768KHz clock is used. - * Apparently this doesn't work, at least for my SA1110 rev 5. - * If the clock divider is uninitialized then reset it to the - * default value to get the 1Hz clock. - */ - if (RTTR == 0) { - RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16); - printk(KERN_WARNING "Warning: uninitialized Real Time Clock\n"); - /* The current RTC value probably doesn't make sense either */ - RCNR = 0; - return 0; - } - return RCNR; -} - static int sa1100_set_rtc(void) { unsigned long current_time = xtime.tv_sec; @@ -117,15 +98,10 @@ static struct irqaction sa1100_timer_irq = { static void __init sa1100_timer_init(void) { - struct timespec tv; unsigned long flags; set_rtc = sa1100_set_rtc; - tv.tv_nsec = 0; - tv.tv_sec = sa1100_get_rtc_time(); - do_settimeofday(&tv); - OIER = 0; /* disable any timer interrupts */ OSSR = 0xf; /* clear status on all timers */ setup_irq(IRQ_OST0, &sa1100_timer_irq); diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c index f3ade18862a..75952779ce1 100644 --- a/arch/arm/mm/ioremap.c +++ b/arch/arm/mm/ioremap.c @@ -280,7 +280,10 @@ __arm_ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size, if (!type) return NULL; - size = PAGE_ALIGN(size); + /* + * Page align the mapping size, taking account of any offset. + */ + size = PAGE_ALIGN(offset + size); area = get_vm_area(size, VM_IOREMAP); if (!area) @@ -325,11 +328,6 @@ __arm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype) if (!size || last_addr < phys_addr) return NULL; - /* - * Page align the mapping size - */ - size = PAGE_ALIGN(last_addr + 1) - phys_addr; - return __arm_ioremap_pfn(pfn, offset, size, mtype); } EXPORT_SYMBOL(__arm_ioremap); |