From 2417a130bd4013f804983c62cb116bc9ec7f8e2d Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Thu, 16 Aug 2007 11:12:47 +0200 Subject: [PATCH 01/16] [AVR32] Move AT32_PM_BASE definition into pm.h We don't want to redefine this in every file that needs to access the PM. Signed-off-by: Haavard Skinnemoen --- arch/avr32/mach-at32ap/at32ap7000.c | 6 ------ arch/avr32/mach-at32ap/pm.h | 8 ++++++++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c index 64cc5583ddf..373242aab97 100644 --- a/arch/avr32/mach-at32ap/at32ap7000.c +++ b/arch/avr32/mach-at32ap/at32ap7000.c @@ -25,12 +25,6 @@ #include "pio.h" #include "pm.h" -/* - * We can reduce the code size a bit by using a constant here. Since - * this file is completely chip-specific, it's safe to not use - * ioremap. Generic drivers should of course never do this. - */ -#define AT32_PM_BASE 0xfff00000 #define PBMEM(base) \ { \ diff --git a/arch/avr32/mach-at32ap/pm.h b/arch/avr32/mach-at32ap/pm.h index a1f8aced0a8..47efd0d1951 100644 --- a/arch/avr32/mach-at32ap/pm.h +++ b/arch/avr32/mach-at32ap/pm.h @@ -4,6 +4,14 @@ #ifndef __ARCH_AVR32_MACH_AT32AP_PM_H__ #define __ARCH_AVR32_MACH_AT32AP_PM_H__ +/* + * We can reduce the code size a bit by using a constant here. Since + * this file is only used on AVR32 AP CPUs with segmentation enabled, + * it's safe to not use ioremap. Generic drivers should of course + * never do this. + */ +#define AT32_PM_BASE 0xfff00000 + /* PM register offsets */ #define PM_MCCTRL 0x0000 #define PM_CKSEL 0x0004 From d938b89392bd3ff64e0610d8c4e0d3f7091d98db Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 9 Aug 2007 20:56:07 -0700 Subject: [PATCH 02/16] [AVR32] /sys/kernel/debug/at32ap_clk When debugfs is available, /sys/kernel/debug/at32ap_clk will provide a dump of the power manager registers and of the current clock tree. This can help sorting out various surprises, and when making runtime PM work. Signed-off-by: David Brownell Signed-off-by: Haavard Skinnemoen --- arch/avr32/mach-at32ap/clock.c | 116 +++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/arch/avr32/mach-at32ap/clock.c b/arch/avr32/mach-at32ap/clock.c index 0f8c89c9f83..4642117cc9a 100644 --- a/arch/avr32/mach-at32ap/clock.c +++ b/arch/avr32/mach-at32ap/clock.c @@ -150,3 +150,119 @@ struct clk *clk_get_parent(struct clk *clk) return clk->parent; } EXPORT_SYMBOL(clk_get_parent); + + + +#ifdef CONFIG_DEBUG_FS + +/* /sys/kernel/debug/at32ap_clk */ + +#include +#include +#include +#include "pm.h" + + +#define NEST_DELTA 2 +#define NEST_MAX 6 + +struct clkinf { + struct seq_file *s; + unsigned nest; +}; + +static void +dump_clock(struct clk *parent, struct clkinf *r) +{ + unsigned nest = r->nest; + char buf[16 + NEST_MAX]; + struct clk *clk; + unsigned i; + + /* skip clocks coupled to devices that aren't registered */ + if (parent->dev && !parent->dev->bus_id[0] && !parent->users) + return; + + /* name */ + memset(buf, ' ', sizeof(buf) - 1); + buf[sizeof(buf) - 1] = 0; + i = strlen(parent->name); + memcpy(buf + nest, parent->name, + min(i, (unsigned)(sizeof(buf) - 1 - nest))); + + seq_printf(r->s, "%s%c users=%2d %-3s %9ld Hz", + buf, parent->set_parent ? '*' : ' ', + parent->users, + parent->users ? "on" : "off", /* NOTE: not-paranoid!! */ + clk_get_rate(parent)); + if (parent->dev) + seq_printf(r->s, ", for %s", parent->dev->bus_id); + seq_printf(r->s, "\n"); + + /* cost of this scan is small, but not linear... */ + r->nest = nest + NEST_DELTA; + for (i = 3; i < at32_nr_clocks; i++) { + clk = at32_clock_list[i]; + if (clk->parent == parent) + dump_clock(clk, r); + } + r->nest = nest; +} + +static int clk_show(struct seq_file *s, void *unused) +{ + struct clkinf r; + int i; + + /* show all the power manager registers */ + seq_printf(s, "MCCTRL = %8x\n", pm_readl(MCCTRL)); + seq_printf(s, "CKSEL = %8x\n", pm_readl(CKSEL)); + seq_printf(s, "CPUMASK = %8x\n", pm_readl(CPU_MASK)); + seq_printf(s, "HSBMASK = %8x\n", pm_readl(HSB_MASK)); + seq_printf(s, "PBAMASK = %8x\n", pm_readl(PBA_MASK)); + seq_printf(s, "PBBMASK = %8x\n", pm_readl(PBB_MASK)); + seq_printf(s, "PLL0 = %8x\n", pm_readl(PLL0)); + seq_printf(s, "PLL1 = %8x\n", pm_readl(PLL1)); + seq_printf(s, "IMR = %8x\n", pm_readl(IMR)); + for (i = 0; i < 8; i++) { + if (i == 5) + continue; + seq_printf(s, "GCCTRL%d = %8x\n", i, pm_readl(GCCTRL(i))); + } + + seq_printf(s, "\n"); + + /* show clock tree as derived from the three oscillators + * we "know" are at the head of the list + */ + r.s = s; + r.nest = 0; + dump_clock(at32_clock_list[0], &r); + dump_clock(at32_clock_list[1], &r); + dump_clock(at32_clock_list[2], &r); + + return 0; +} + +static int clk_open(struct inode *inode, struct file *file) +{ + return single_open(file, clk_show, NULL); +} + +static const struct file_operations clk_operations = { + .open = clk_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init clk_debugfs_init(void) +{ + (void) debugfs_create_file("at32ap_clk", S_IFREG | S_IRUGO, + NULL, NULL, &clk_operations); + + return 0; +} +postcore_initcall(clk_debugfs_init); + +#endif From 7808fa4853728a776d7e76d68fb406f515a4119c Mon Sep 17 00:00:00 2001 From: Matteo Vit Date: Thu, 9 Aug 2007 14:55:34 +0200 Subject: [PATCH 03/16] [AVR32] add multidrive support for pio driver This patch add multidrive support for pio driver Signed-off-by: Matteo Vit - Dave S.r.l. Signed-off-by: Haavard Skinnemoen --- arch/avr32/mach-at32ap/pio.c | 4 ++++ include/asm-avr32/arch-at32ap/portmux.h | 1 + 2 files changed, 5 insertions(+) diff --git a/arch/avr32/mach-at32ap/pio.c b/arch/avr32/mach-at32ap/pio.c index 1eb99b814f5..d61a02da898 100644 --- a/arch/avr32/mach-at32ap/pio.c +++ b/arch/avr32/mach-at32ap/pio.c @@ -110,6 +110,10 @@ void __init at32_select_gpio(unsigned int pin, unsigned long flags) pio_writel(pio, SODR, mask); else pio_writel(pio, CODR, mask); + if (flags & AT32_GPIOF_MULTIDRV) + pio_writel(pio, MDER, mask); + else + pio_writel(pio, MDDR, mask); pio_writel(pio, PUDR, mask); pio_writel(pio, OER, mask); } else { diff --git a/include/asm-avr32/arch-at32ap/portmux.h b/include/asm-avr32/arch-at32ap/portmux.h index 9930871decd..b1abe6b4e4e 100644 --- a/include/asm-avr32/arch-at32ap/portmux.h +++ b/include/asm-avr32/arch-at32ap/portmux.h @@ -19,6 +19,7 @@ #define AT32_GPIOF_OUTPUT 0x00000002 /* (OUT) Enable output driver */ #define AT32_GPIOF_HIGH 0x00000004 /* (OUT) Set output high */ #define AT32_GPIOF_DEGLITCH 0x00000008 /* (IN) Filter glitches */ +#define AT32_GPIOF_MULTIDRV 0x00000010 /* Enable multidriver option */ void at32_select_periph(unsigned int pin, unsigned int periph, unsigned long flags); From 6fcf0615117dcfa126083f2163c4dcea3098bbe3 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Thu, 14 Jun 2007 17:37:31 +0200 Subject: [PATCH 04/16] [AVR32] Wire up USBA device Implement at32_add_device_usba() and use it to wire up the USBA device on ATSTK1000 and ATNGW100. Signed-off-by: Haavard Skinnemoen --- arch/avr32/boards/atngw100/setup.c | 1 + arch/avr32/boards/atstk1000/atstk1002.c | 1 + arch/avr32/mach-at32ap/at32ap7000.c | 68 +++++++++++++++++++++++++ include/asm-avr32/arch-at32ap/board.h | 8 +++ 4 files changed, 78 insertions(+) diff --git a/arch/avr32/boards/atngw100/setup.c b/arch/avr32/boards/atngw100/setup.c index ef801563bbf..6e180f43525 100644 --- a/arch/avr32/boards/atngw100/setup.c +++ b/arch/avr32/boards/atngw100/setup.c @@ -154,6 +154,7 @@ static int __init atngw100_init(void) set_hw_addr(at32_add_device_eth(1, ð_data[1])); at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info)); + at32_add_device_usba(0, NULL); for (i = 0; i < ARRAY_SIZE(ngw_leds); i++) { at32_select_gpio(ngw_leds[i].gpio, diff --git a/arch/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c index c9981b731ef..6b9e466104a 100644 --- a/arch/avr32/boards/atstk1000/atstk1002.c +++ b/arch/avr32/boards/atstk1000/atstk1002.c @@ -241,6 +241,7 @@ static int __init atstk1002_init(void) at32_add_device_lcdc(0, &atstk1000_lcdc_data, fbmem_start, fbmem_size); #endif + at32_add_device_usba(0, NULL); #ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM at32_add_device_ssc(0, ATMEL_SSC_TX); #endif diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c index 373242aab97..f6d154ca4d2 100644 --- a/arch/avr32/mach-at32ap/at32ap7000.c +++ b/arch/avr32/mach-at32ap/at32ap7000.c @@ -1161,6 +1161,72 @@ at32_add_device_ssc(unsigned int id, unsigned int flags) return pdev; } +/* -------------------------------------------------------------------- + * USB Device Controller + * -------------------------------------------------------------------- */ +static struct resource usba0_resource[] __initdata = { + { + .start = 0xff300000, + .end = 0xff3fffff, + .flags = IORESOURCE_MEM, + }, { + .start = 0xfff03000, + .end = 0xfff033ff, + .flags = IORESOURCE_MEM, + }, + IRQ(31), +}; +static struct clk usba0_pclk = { + .name = "pclk", + .parent = &pbb_clk, + .mode = pbb_clk_mode, + .get_rate = pbb_clk_get_rate, + .index = 12, +}; +static struct clk usba0_hclk = { + .name = "hclk", + .parent = &hsb_clk, + .mode = hsb_clk_mode, + .get_rate = hsb_clk_get_rate, + .index = 6, +}; + +struct platform_device *__init +at32_add_device_usba(unsigned int id, struct usba_platform_data *data) +{ + struct platform_device *pdev; + + if (id != 0) + return NULL; + + pdev = platform_device_alloc("atmel_usba_udc", 0); + if (!pdev) + return NULL; + + if (platform_device_add_resources(pdev, usba0_resource, + ARRAY_SIZE(usba0_resource))) + goto out_free_pdev; + + if (data) { + if (platform_device_add_data(pdev, data, sizeof(*data))) + goto out_free_pdev; + + if (data->vbus_pin != GPIO_PIN_NONE) + at32_select_gpio(data->vbus_pin, 0); + } + + usba0_pclk.dev = &pdev->dev; + usba0_hclk.dev = &pdev->dev; + + platform_device_add(pdev); + + return pdev; + +out_free_pdev: + platform_device_put(pdev); + return NULL; +} + /* -------------------------------------------------------------------- * GCLK * -------------------------------------------------------------------- */ @@ -1246,6 +1312,8 @@ struct clk *at32_clock_list[] = { &ssc0_pclk, &ssc1_pclk, &ssc2_pclk, + &usba0_hclk, + &usba0_pclk, &gclk0, &gclk1, &gclk2, diff --git a/include/asm-avr32/arch-at32ap/board.h b/include/asm-avr32/arch-at32ap/board.h index 0215965dc58..7dbd603c38c 100644 --- a/include/asm-avr32/arch-at32ap/board.h +++ b/include/asm-avr32/arch-at32ap/board.h @@ -6,6 +6,8 @@ #include +#define GPIO_PIN_NONE (-1) + /* Add basic devices: system manager, interrupt controller, portmuxes, etc. */ void at32_add_system_devices(void); @@ -36,6 +38,12 @@ struct platform_device * at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data, unsigned long fbmem_start, unsigned long fbmem_len); +struct usba_platform_data { + int vbus_pin; +}; +struct platform_device * +at32_add_device_usba(unsigned int id, struct usba_platform_data *data); + /* depending on what's hooked up, not all SSC pins will be used */ #define ATMEL_SSC_TK 0x01 #define ATMEL_SSC_TF 0x02 From 0367d89274d47941b1bc02e35ddad24077de3ce7 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Wed, 4 Jan 2006 16:58:49 +0100 Subject: [PATCH 05/16] [AVR32] checkstack support Add regexes to recognize stack frame adjustments in AVR32 code. Signed-off-by: Haavard Skinnemoen --- scripts/checkstack.pl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl index f7844f6aa48..66315862715 100755 --- a/scripts/checkstack.pl +++ b/scripts/checkstack.pl @@ -12,6 +12,7 @@ # sh64 port by Paul Mundt # Random bits by Matt Mackall # M68k port by Geert Uytterhoeven and Andreas Schwab +# AVR32 port by Haavard Skinnemoen # # Usage: # objdump -d vmlinux | stackcheck.pl [arch] @@ -37,6 +38,10 @@ my (@stack, $re, $x, $xs); if ($arch eq 'arm') { #c0008ffc: e24dd064 sub sp, sp, #100 ; 0x64 $re = qr/.*sub.*sp, sp, #(([0-9]{2}|[3-9])[0-9]{2})/o; + } elsif ($arch eq 'avr32') { + #8000008a: 20 1d sub sp,4 + #80000ca8: fa cd 05 b0 sub sp,sp,1456 + $re = qr/^.*sub.*sp.*,([0-9]{1,8})/o; } elsif ($arch =~ /^i[3456]86$/) { #c0105234: 81 ec ac 05 00 00 sub $0x5ac,%esp $re = qr/^.*[as][du][db] \$(0x$x{1,8}),\%esp$/o; From fe57f84efe3165a1e2ec477b256870f3d43b698a Mon Sep 17 00:00:00 2001 From: Matteo Vit Date: Wed, 29 Aug 2007 10:19:40 +0200 Subject: [PATCH 06/16] [AVR32] fix command line parsing in early_parse_fbmem Signed-off-by: Matteo Vit - Dave S.r.l. Signed-off-by: Haavard Skinnemoen --- arch/avr32/kernel/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/avr32/kernel/setup.c b/arch/avr32/kernel/setup.c index d08b0bc6b2b..4b4c1884e1c 100644 --- a/arch/avr32/kernel/setup.c +++ b/arch/avr32/kernel/setup.c @@ -248,7 +248,7 @@ static int __init early_parse_fbmem(char *p) fbmem_size = memparse(p, &p); if (*p == '@') { - fbmem_start = memparse(p, &p); + fbmem_start = memparse(p + 1, &p); ret = add_reserved_region(fbmem_start, fbmem_start + fbmem_size - 1, "Framebuffer"); From 4e59629bf68e8a6f19b806f8ace3d0f31221c4a4 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Sat, 15 Sep 2007 22:47:02 +0200 Subject: [PATCH 07/16] [AVR32] rename vmlinux.lds Rename vmlinux.lds to a .S file to match other architectures. Simplify Makefile to match the rename and deleted the unused USE_STANDARD_AS_RULE Signed-off-by: Sam Ravnborg Signed-off-by: Haavard Skinnemoen --- arch/avr32/kernel/Makefile | 5 ----- arch/avr32/kernel/{vmlinux.lds.c => vmlinux.lds.S} | 0 2 files changed, 5 deletions(-) rename arch/avr32/kernel/{vmlinux.lds.c => vmlinux.lds.S} (100%) diff --git a/arch/avr32/kernel/Makefile b/arch/avr32/kernel/Makefile index 90e5afff54a..989fcd1fef7 100644 --- a/arch/avr32/kernel/Makefile +++ b/arch/avr32/kernel/Makefile @@ -11,8 +11,3 @@ obj-y += signal.o sys_avr32.o process.o time.o obj-y += init_task.o switch_to.o cpu.o obj-$(CONFIG_MODULES) += module.o avr32_ksyms.o obj-$(CONFIG_KPROBES) += kprobes.o - -USE_STANDARD_AS_RULE := true - -%.lds: %.lds.c FORCE - $(call if_changed_dep,cpp_lds_S) diff --git a/arch/avr32/kernel/vmlinux.lds.c b/arch/avr32/kernel/vmlinux.lds.S similarity index 100% rename from arch/avr32/kernel/vmlinux.lds.c rename to arch/avr32/kernel/vmlinux.lds.S From 7cf6ac2ae240e02ebdd2717a09d083d47cb60251 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Mon, 17 Sep 2007 11:08:28 +0200 Subject: [PATCH 08/16] [AVR32] Kill a few hardcoded constants in vmlinux.lds Use PAGE_SIZE, THREAD_SIZE and L1_CACHE_BYTES instead of harcoded constants in places where that's what we really mean. Signed-off-by: Haavard Skinnemoen --- arch/avr32/kernel/vmlinux.lds.S | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/avr32/kernel/vmlinux.lds.S b/arch/avr32/kernel/vmlinux.lds.S index db0438f35c0..fef0e6d322f 100644 --- a/arch/avr32/kernel/vmlinux.lds.S +++ b/arch/avr32/kernel/vmlinux.lds.S @@ -9,6 +9,8 @@ */ #define LOAD_OFFSET 0x00000000 #include +#include +#include OUTPUT_FORMAT("elf32-avr32", "elf32-avr32", "elf32-avr32") OUTPUT_ARCH(avr32) @@ -58,7 +60,7 @@ SECTIONS *(.init.ramfs) __initramfs_end = .; #endif - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE); __init_end = .; } @@ -96,7 +98,7 @@ SECTIONS RODATA - . = ALIGN(8192); + . = ALIGN(THREAD_SIZE); .data : AT(ADDR(.data) - LOAD_OFFSET) { _data = .; @@ -107,7 +109,7 @@ SECTIONS *(.data.init_task) /* Then, the cacheline aligned data */ - . = ALIGN(32); + . = ALIGN(L1_CACHE_BYTES); *(.data.cacheline_aligned) /* And the rest... */ From 0d2372e5d61ccc1c618aaf5099700c8dc76e234a Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Mon, 17 Sep 2007 11:13:45 +0200 Subject: [PATCH 09/16] [AVR32] Remove unneeded 8K alignment of .text section __init_end, which comes immediately before .text, is already page aligned, and that should be more than enough for the .text section. The reason why we need to align the .text section is because the interrupt handler offset is ORed with EVBA, so we need to provide enough alignment of EVBA that this OR operation works as an ADD. Currently, the last interrupt handler is not nearly a full page away from EVBA, so it won't be a problem. Signed-off-by: Haavard Skinnemoen --- arch/avr32/kernel/vmlinux.lds.S | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/avr32/kernel/vmlinux.lds.S b/arch/avr32/kernel/vmlinux.lds.S index fef0e6d322f..ce9ac965988 100644 --- a/arch/avr32/kernel/vmlinux.lds.S +++ b/arch/avr32/kernel/vmlinux.lds.S @@ -64,7 +64,6 @@ SECTIONS __init_end = .; } - . = ALIGN(8192); .text : AT(ADDR(.text) - LOAD_OFFSET) { _evba = .; _text = .; From b5a8e7362a0a5088ac080086d41cd98a54e0791b Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Fri, 7 Sep 2007 16:00:25 +0100 Subject: [PATCH 10/16] [AVR32] Make dma_sync_*_for_cpu no-ops I don't think the dma_sync_*_for_cpu ever did anything useful. We flush the relevant cache lines when mapping the buffer or when calling dma_sync_*_for_device(), and the CPU isn't allowed to touch the buffer after that. In other words, if these functions actually have anything to flush from the caches, we're already in trouble. Signed-off-by: Haavard Skinnemoen --- include/asm-avr32/dma-mapping.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/include/asm-avr32/dma-mapping.h b/include/asm-avr32/dma-mapping.h index 21bb60bbb9a..81e342636ac 100644 --- a/include/asm-avr32/dma-mapping.h +++ b/include/asm-avr32/dma-mapping.h @@ -264,7 +264,11 @@ static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, enum dma_data_direction direction) { - dma_cache_sync(dev, bus_to_virt(dma_handle), size, direction); + /* + * No need to do anything since the CPU isn't supposed to + * touch this memory after we flushed it at mapping- or + * sync-for-device time. + */ } static inline void @@ -309,12 +313,11 @@ static inline void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction direction) { - int i; - - for (i = 0; i < nents; i++) { - dma_cache_sync(dev, page_address(sg[i].page) + sg[i].offset, - sg[i].length, direction); - } + /* + * No need to do anything since the CPU isn't supposed to + * touch this memory after we flushed it at mapping- or + * sync-for-device time. + */ } static inline void From 193fdd1a99db8623697cb18a13dbcaa4eadbb1f2 Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Wed, 19 Sep 2007 08:43:42 -0400 Subject: [PATCH 11/16] [AVR32] Drop support for redundant "keepinitrd" boot-time parm. Given the existing "retain_initrd" boot-time parameter defined in init/initramfs.c, there appears to be no need for the equivalent "keepinitrd" parameter. Signed-off-by: Robert P. J. Day Signed-off-by: Haavard Skinnemoen --- arch/avr32/mm/init.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/arch/avr32/mm/init.c b/arch/avr32/mm/init.c index 82cf70854b9..480760bde63 100644 --- a/arch/avr32/mm/init.c +++ b/arch/avr32/mm/init.c @@ -224,19 +224,9 @@ void free_initmem(void) #ifdef CONFIG_BLK_DEV_INITRD -static int keep_initrd; - void free_initrd_mem(unsigned long start, unsigned long end) { - if (!keep_initrd) - free_area(start, end, "initrd"); + free_area(start, end, "initrd"); } -static int __init keepinitrd_setup(char *__unused) -{ - keep_initrd = 1; - return 1; -} - -__setup("keepinitrd", keepinitrd_setup); #endif From af8184718a322ae589efa583aa69ffdae61bf266 Mon Sep 17 00:00:00 2001 From: Kristoffer Nyborg Gregertsen Date: Fri, 17 Aug 2007 16:59:57 +0200 Subject: [PATCH 12/16] [AVR32] SMC configuration in clock cycles This patch makes the SMC configuration take timings in clock cycles instead of nanoseconds. A function to calculate timings in clock cycles is added. This patch removes the rounding troubles of the previous SMC configuration method. [hskinnemoen@atmel.com: fix atstk1002/atngw100 flash config] Signed-off-by: Kristoffer Nyborg Gregertsen Signed-off-by: Haavard Skinnemoen --- arch/avr32/boards/atngw100/flash.c | 5 +- arch/avr32/boards/atstk1000/flash.c | 5 +- arch/avr32/mach-at32ap/hsmc.c | 131 ++++++++++++++++++++++++---- include/asm-avr32/arch-at32ap/smc.h | 53 ++++++++--- 4 files changed, 163 insertions(+), 31 deletions(-) diff --git a/arch/avr32/boards/atngw100/flash.c b/arch/avr32/boards/atngw100/flash.c index f9b32a8eab9..b07ae63aa54 100644 --- a/arch/avr32/boards/atngw100/flash.c +++ b/arch/avr32/boards/atngw100/flash.c @@ -15,7 +15,7 @@ #include -static struct smc_config flash_config __initdata = { +static struct smc_timing flash_timing __initdata = { .ncs_read_setup = 0, .nrd_setup = 40, .ncs_write_setup = 0, @@ -28,7 +28,9 @@ static struct smc_config flash_config __initdata = { .read_cycle = 120, .write_cycle = 120, +}; +static struct smc_config flash_config __initdata = { .bus_width = 2, .nrd_controlled = 1, .nwe_controlled = 1, @@ -82,6 +84,7 @@ static int __init atngw100_flash_init(void) { int ret; + smc_set_timing(&flash_config, &flash_timing); ret = smc_set_configuration(0, &flash_config); if (ret < 0) { printk(KERN_ERR "atngw100: failed to set NOR flash timing\n"); diff --git a/arch/avr32/boards/atstk1000/flash.c b/arch/avr32/boards/atstk1000/flash.c index aac4300cca1..3d0a102ad45 100644 --- a/arch/avr32/boards/atstk1000/flash.c +++ b/arch/avr32/boards/atstk1000/flash.c @@ -15,7 +15,7 @@ #include -static struct smc_config flash_config __initdata = { +static struct smc_timing flash_timing __initdata = { .ncs_read_setup = 0, .nrd_setup = 40, .ncs_write_setup = 0, @@ -28,7 +28,9 @@ static struct smc_config flash_config __initdata = { .read_cycle = 120, .write_cycle = 120, +}; +static struct smc_config flash_config __initdata = { .bus_width = 2, .nrd_controlled = 1, .nwe_controlled = 1, @@ -82,6 +84,7 @@ static int __init atstk1000_flash_init(void) { int ret; + smc_set_timing(&flash_config, &flash_timing); ret = smc_set_configuration(0, &flash_config); if (ret < 0) { printk(KERN_ERR "atstk1000: failed to set NOR flash timing\n"); diff --git a/arch/avr32/mach-at32ap/hsmc.c b/arch/avr32/mach-at32ap/hsmc.c index 5e22a750632..704607fbcc6 100644 --- a/arch/avr32/mach-at32ap/hsmc.c +++ b/arch/avr32/mach-at32ap/hsmc.c @@ -29,16 +29,25 @@ struct hsmc { static struct hsmc *hsmc; -int smc_set_configuration(int cs, const struct smc_config *config) +void smc_set_timing(struct smc_config *config, + const struct smc_timing *timing) { - unsigned long mul; - unsigned long offset; - u32 setup, pulse, cycle, mode; + int recover; + int cycle; - if (!hsmc) - return -ENODEV; - if (cs >= NR_CHIP_SELECTS) - return -EINVAL; + unsigned long mul; + + /* Reset all SMC timings */ + config->ncs_read_setup = 0; + config->nrd_setup = 0; + config->ncs_write_setup = 0; + config->nwe_setup = 0; + config->ncs_read_pulse = 0; + config->nrd_pulse = 0; + config->ncs_write_pulse = 0; + config->nwe_pulse = 0; + config->read_cycle = 0; + config->write_cycle = 0; /* * cycles = x / T = x * f @@ -50,16 +59,102 @@ int smc_set_configuration(int cs, const struct smc_config *config) #define ns2cyc(x) ((((x) * mul) + 65535) >> 16) - setup = (HSMC_BF(NWE_SETUP, ns2cyc(config->nwe_setup)) - | HSMC_BF(NCS_WR_SETUP, ns2cyc(config->ncs_write_setup)) - | HSMC_BF(NRD_SETUP, ns2cyc(config->nrd_setup)) - | HSMC_BF(NCS_RD_SETUP, ns2cyc(config->ncs_read_setup))); - pulse = (HSMC_BF(NWE_PULSE, ns2cyc(config->nwe_pulse)) - | HSMC_BF(NCS_WR_PULSE, ns2cyc(config->ncs_write_pulse)) - | HSMC_BF(NRD_PULSE, ns2cyc(config->nrd_pulse)) - | HSMC_BF(NCS_RD_PULSE, ns2cyc(config->ncs_read_pulse))); - cycle = (HSMC_BF(NWE_CYCLE, ns2cyc(config->write_cycle)) - | HSMC_BF(NRD_CYCLE, ns2cyc(config->read_cycle))); + if (timing->ncs_read_setup > 0) + config->ncs_read_setup = ns2cyc(timing->ncs_read_setup); + + if (timing->nrd_setup > 0) + config->nrd_setup = ns2cyc(timing->nrd_setup); + + if (timing->ncs_write_setup > 0) + config->ncs_write_setup = ns2cyc(timing->ncs_write_setup); + + if (timing->nwe_setup > 0) + config->nwe_setup = ns2cyc(timing->nwe_setup); + + if (timing->ncs_read_pulse > 0) + config->ncs_read_pulse = ns2cyc(timing->ncs_read_pulse); + + if (timing->nrd_pulse > 0) + config->nrd_pulse = ns2cyc(timing->nrd_pulse); + + if (timing->ncs_write_pulse > 0) + config->ncs_write_pulse = ns2cyc(timing->ncs_write_pulse); + + if (timing->nwe_pulse > 0) + config->nwe_pulse = ns2cyc(timing->nwe_pulse); + + if (timing->read_cycle > 0) + config->read_cycle = ns2cyc(timing->read_cycle); + + if (timing->write_cycle > 0) + config->write_cycle = ns2cyc(timing->write_cycle); + + /* Extend read cycle in needed */ + if (timing->ncs_read_recover > 0) + recover = ns2cyc(timing->ncs_read_recover); + else + recover = 1; + + cycle = config->ncs_read_setup + config->ncs_read_pulse + recover; + + if (config->read_cycle < cycle) + config->read_cycle = cycle; + + /* Extend read cycle in needed */ + if (timing->nrd_recover > 0) + recover = ns2cyc(timing->nrd_recover); + else + recover = 1; + + cycle = config->nrd_setup + config->nrd_pulse + recover; + + if (config->read_cycle < cycle) + config->read_cycle = cycle; + + /* Extend write cycle in needed */ + if (timing->ncs_write_recover > 0) + recover = ns2cyc(timing->ncs_write_recover); + else + recover = 1; + + cycle = config->ncs_write_setup + config->ncs_write_pulse + recover; + + if (config->write_cycle < cycle) + config->write_cycle = cycle; + + /* Extend write cycle in needed */ + if (timing->nwe_recover > 0) + recover = ns2cyc(timing->nwe_recover); + else + recover = 1; + + cycle = config->nwe_setup + config->nwe_pulse + recover; + + if (config->write_cycle < cycle) + config->write_cycle = cycle; +} +EXPORT_SYMBOL(smc_set_timing); + +int smc_set_configuration(int cs, const struct smc_config *config) +{ + unsigned long offset; + u32 setup, pulse, cycle, mode; + + if (!hsmc) + return -ENODEV; + if (cs >= NR_CHIP_SELECTS) + return -EINVAL; + + setup = (HSMC_BF(NWE_SETUP, config->nwe_setup) + | HSMC_BF(NCS_WR_SETUP, config->ncs_write_setup) + | HSMC_BF(NRD_SETUP, config->nrd_setup) + | HSMC_BF(NCS_RD_SETUP, config->ncs_read_setup)); + pulse = (HSMC_BF(NWE_PULSE, config->nwe_pulse) + | HSMC_BF(NCS_WR_PULSE, config->ncs_write_pulse) + | HSMC_BF(NRD_PULSE, config->nrd_pulse) + | HSMC_BF(NCS_RD_PULSE, config->ncs_read_pulse)); + cycle = (HSMC_BF(NWE_CYCLE, config->write_cycle) + | HSMC_BF(NRD_CYCLE, config->read_cycle)); switch (config->bus_width) { case 1: diff --git a/include/asm-avr32/arch-at32ap/smc.h b/include/asm-avr32/arch-at32ap/smc.h index 07152b7fd9c..c98eea44a70 100644 --- a/include/asm-avr32/arch-at32ap/smc.h +++ b/include/asm-avr32/arch-at32ap/smc.h @@ -15,22 +15,50 @@ /* * All timing parameters are in nanoseconds. */ -struct smc_config { +struct smc_timing { /* Delay from address valid to assertion of given strobe */ - u16 ncs_read_setup; - u16 nrd_setup; - u16 ncs_write_setup; - u16 nwe_setup; + int ncs_read_setup; + int nrd_setup; + int ncs_write_setup; + int nwe_setup; /* Pulse length of given strobe */ - u16 ncs_read_pulse; - u16 nrd_pulse; - u16 ncs_write_pulse; - u16 nwe_pulse; + int ncs_read_pulse; + int nrd_pulse; + int ncs_write_pulse; + int nwe_pulse; /* Total cycle length of given operation */ - u16 read_cycle; - u16 write_cycle; + int read_cycle; + int write_cycle; + + /* Minimal recovery times, will extend cycle if needed */ + int ncs_read_recover; + int nrd_recover; + int ncs_write_recover; + int nwe_recover; +}; + +/* + * All timing parameters are in clock cycles. + */ +struct smc_config { + + /* Delay from address valid to assertion of given strobe */ + u8 ncs_read_setup; + u8 nrd_setup; + u8 ncs_write_setup; + u8 nwe_setup; + + /* Pulse length of given strobe */ + u8 ncs_read_pulse; + u8 nrd_pulse; + u8 ncs_write_pulse; + u8 nwe_pulse; + + /* Total cycle length of given operation */ + u8 read_cycle; + u8 write_cycle; /* Bus width in bytes */ u8 bus_width; @@ -76,6 +104,9 @@ struct smc_config { unsigned int tdf_mode:1; }; +extern void smc_set_timing(struct smc_config *config, + const struct smc_timing *timing); + extern int smc_set_configuration(int cs, const struct smc_config *config); extern struct smc_config *smc_get_configuration(int cs); From a7ff43b808f077e7aae2772b2f1a06a39e6b0cf8 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Sat, 22 Sep 2007 23:31:39 +0200 Subject: [PATCH 13/16] [AVR32] Ignore a few irrelevant syscalls Ignore a few syscalls that are irrelevant because they're either old, depends on NUMA or depends on SMP. Signed-off-by: Haavard Skinnemoen --- include/asm-avr32/unistd.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/asm-avr32/unistd.h b/include/asm-avr32/unistd.h index 3b4e35b55c8..de09009593f 100644 --- a/include/asm-avr32/unistd.h +++ b/include/asm-avr32/unistd.h @@ -303,6 +303,19 @@ #ifdef __KERNEL__ #define NR_syscalls 282 +/* Old stuff */ +#define __IGNORE_uselib +#define __IGNORE_mmap + +/* NUMA stuff */ +#define __IGNORE_mbind +#define __IGNORE_get_mempolicy +#define __IGNORE_set_mempolicy +#define __IGNORE_migrate_pages +#define __IGNORE_move_pages + +/* SMP stuff */ +#define __IGNORE_getcpu #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_STAT64 From 82c54f864fea26c4c44f27e2b4c4d9a811dde299 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 25 Sep 2007 07:17:48 -0700 Subject: [PATCH 14/16] [AVR32] ngw100 i2c-gpio tweaks Make the NGW100 bitbang i2c use open drain signaling. Also, speed it up, so it's closer to 100 kHz ... the code paths seem to be long enough that the udelay isn't dominating bit times. The peak bit rate I observed was around 125 kHz, but that's with large delays (usually before ACK/NAK) which hold the overall rate down to around 80 kHz (call it 100 usec/byte on average). Signed-off-by: David Brownell Signed-off-by: Haavard Skinnemoen --- arch/avr32/boards/atngw100/setup.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/arch/avr32/boards/atngw100/setup.c b/arch/avr32/boards/atngw100/setup.c index 6e180f43525..52987c81d66 100644 --- a/arch/avr32/boards/atngw100/setup.c +++ b/arch/avr32/boards/atngw100/setup.c @@ -125,8 +125,11 @@ static struct platform_device ngw_gpio_leds = { }; static struct i2c_gpio_platform_data i2c_gpio_data = { - .sda_pin = GPIO_PIN_PA(6), - .scl_pin = GPIO_PIN_PA(7), + .sda_pin = GPIO_PIN_PA(6), + .scl_pin = GPIO_PIN_PA(7), + .sda_is_open_drain = 1, + .scl_is_open_drain = 1, + .udelay = 2, /* close to 100 kHz */ }; static struct platform_device i2c_gpio_device = { @@ -162,8 +165,10 @@ static int __init atngw100_init(void) } platform_device_register(&ngw_gpio_leds); - at32_select_gpio(i2c_gpio_data.sda_pin, 0); - at32_select_gpio(i2c_gpio_data.scl_pin, 0); + at32_select_gpio(i2c_gpio_data.sda_pin, + AT32_GPIOF_MULTIDRV | AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH); + at32_select_gpio(i2c_gpio_data.scl_pin, + AT32_GPIOF_MULTIDRV | AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH); platform_device_register(&i2c_gpio_device); return 0; From bb7aa6d47fcd4f9ab18b4ade2ba078f7719f74ca Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Wed, 3 Oct 2007 15:05:20 +0200 Subject: [PATCH 15/16] [AVR32] Don't use __builtin_xchg() The implementation of __builtin_xchg() in at least some versions of avr32 gcc is buggy. Rather than find out exactly which versions that have this bug, let's just avoid the problem altogether by implementing xchg() in inline assembly. Also, in most architectures, xchg() seems to imply a memory barrier, while the existing avr32 implementation did not. This patch also fixes that discrepancy. Signed-off-by: Haavard Skinnemoen --- include/asm-avr32/system.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/include/asm-avr32/system.h b/include/asm-avr32/system.h index a8236bacc87..dc2d527cef4 100644 --- a/include/asm-avr32/system.h +++ b/include/asm-avr32/system.h @@ -73,11 +73,16 @@ extern struct task_struct *__switch_to(struct task_struct *, extern void __xchg_called_with_bad_pointer(void); -#ifdef __CHECKER__ -extern unsigned long __builtin_xchg(void *ptr, unsigned long x); -#endif +static inline unsigned long xchg_u32(u32 val, volatile u32 *m) +{ + u32 ret; -#define xchg_u32(val, m) __builtin_xchg((void *)m, val) + asm volatile("xchg %[ret], %[m], %[val]" + : [ret] "=&r"(ret), "=m"(*m) + : "m"(*m), [m] "r"(m), [val] "r"(val) + : "memory"); + return ret; +} static inline unsigned long __xchg(unsigned long x, volatile void *ptr, From a7e30b8d91d3291de4543d97849193ebc3ec4c1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20R=C3=A9tornaz?= Date: Wed, 10 Oct 2007 18:52:24 -0400 Subject: [PATCH 16/16] [AVR32] Fix random segfault with preemption MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As explained on: http://www.avrfreaks.net/index.php?nameÿphpBB2&fileÿewtopic&tS307 If the current process is preempted before it can copy RAR_SUP and RSR_SUP both register are lost and the process will segfault as soon as it return from the syscall since the return adress will be corrupted. This patch disable IRQ as soon as we enter the syscall path and reenable them when the copy is done. In the interrupt handlers, check if we are interrupting the srrf instruction, if so disable interrupts and return. The interrupt handler will be re-called immediatly when the interrupts are reenabled. After some stressing workload: - find / > /dev/null in loop - top (in ssh) - ping -f avr32 The segfaults are not seen anymore. Signed-off-by: Philippe Rétornaz Signed-off-by: Haavard Skinnemoen --- arch/avr32/kernel/entry-avr32b.S | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/arch/avr32/kernel/entry-avr32b.S b/arch/avr32/kernel/entry-avr32b.S index 42657f1703b..ccadfd9b438 100644 --- a/arch/avr32/kernel/entry-avr32b.S +++ b/arch/avr32/kernel/entry-avr32b.S @@ -159,11 +159,18 @@ handle_vmalloc_miss: .section .scall.text,"ax",@progbits system_call: +#ifdef CONFIG_PREEMPT + mask_interrupts +#endif pushm r12 /* r12_orig */ stmts --sp, r0-lr - zero_fp + mfsr r0, SYSREG_RAR_SUP mfsr r1, SYSREG_RSR_SUP +#ifdef CONFIG_PREEMPT + unmask_interrupts +#endif + zero_fp stm --sp, r0-r1 /* check for syscall tracing */ @@ -638,6 +645,13 @@ irq_level\level: stmts --sp,r0-lr mfsr r8, rar_int\level mfsr r9, rsr_int\level + +#ifdef CONFIG_PREEMPT + sub r11, pc, (. - system_call) + cp.w r11, r8 + breq 4f +#endif + pushm r8-r9 mov r11, sp @@ -668,6 +682,16 @@ irq_level\level: sub sp, -4 /* ignore r12_orig */ rete +#ifdef CONFIG_PREEMPT +4: mask_interrupts + mfsr r8, rsr_int\level + sbr r8, 16 + mtsr rsr_int\level, r8 + ldmts sp++, r0-lr + sub sp, -4 /* ignore r12_orig */ + rete +#endif + 2: get_thread_info r0 ld.w r1, r0[TI_flags] bld r1, TIF_CPU_GOING_TO_SLEEP