]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge git://git.kernel.org/pub/scm/linux/kernel/git/hskinnemoen/avr32-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 14 Jul 2008 20:37:29 +0000 (13:37 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 14 Jul 2008 20:37:29 +0000 (13:37 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/hskinnemoen/avr32-2.6: (31 commits)
  avr32: Fix typo of IFSR in a comment in the PIO header file
  avr32: Power Management support ("standby" and "mem" modes)
  avr32: Add system device for the internal interrupt controller (intc)
  avr32: Add simple SRAM allocator
  avr32: Enable SDRAMC clock at startup
  rtc-at32ap700x: Enable wakeup
  macb: Basic suspend/resume support
  atmel_serial: Drain console TX shifter before suspending
  atmel_serial: Fix build on avr32 with CONFIG_PM enabled
  avr32: Use a quicklist for PTE allocation as well
  avr32: Use a quicklist for PGD allocation
  avr32: Cover the kernel page tables in the user PGDs
  avr32: Store virtual addresses in the PGD
  avr32: Remove useless zeroing of swapper_pg_dir at startup
  avr32: Clean up and optimize the TLB operations
  avr32: Rename at32ap.c -> pdc.c
  avr32: Move setup_platform() into chip-specific file
  avr32: Kill special exception handler sections
  avr32: Kill unneeded #include <asm/pgalloc.h> from asm/mmu_context.h
  avr32: Clean up time.c #includes
  ...

36 files changed:
arch/avr32/Kconfig
arch/avr32/boards/atngw100/setup.c
arch/avr32/boards/atstk1000/atstk1002.c
arch/avr32/boards/atstk1000/atstk1003.c
arch/avr32/boards/atstk1000/atstk1004.c
arch/avr32/kernel/entry-avr32b.S
arch/avr32/kernel/signal.c
arch/avr32/kernel/time.c
arch/avr32/kernel/vmlinux.lds.S
arch/avr32/lib/io-readsb.S
arch/avr32/mach-at32ap/Makefile
arch/avr32/mach-at32ap/at32ap700x.c
arch/avr32/mach-at32ap/intc.c
arch/avr32/mach-at32ap/pdc.c [moved from arch/avr32/mach-at32ap/at32ap.c with 90% similarity]
arch/avr32/mach-at32ap/pio.c
arch/avr32/mach-at32ap/pio.h
arch/avr32/mach-at32ap/pm-at32ap700x.S
arch/avr32/mach-at32ap/pm.c [new file with mode: 0644]
arch/avr32/mach-at32ap/sdramc.h [new file with mode: 0644]
arch/avr32/mm/init.c
arch/avr32/mm/tlb.c
drivers/misc/atmel_pwm.c
drivers/net/macb.c
drivers/rtc/rtc-at32ap700x.c
drivers/serial/atmel_serial.c
include/asm-avr32/arch-at32ap/board.h
include/asm-avr32/arch-at32ap/init.h
include/asm-avr32/arch-at32ap/pm.h
include/asm-avr32/arch-at32ap/sram.h [new file with mode: 0644]
include/asm-avr32/mmu_context.h
include/asm-avr32/pci.h
include/asm-avr32/pgalloc.h
include/asm-avr32/pgtable.h
include/asm-avr32/thread_info.h
include/asm-avr32/tlbflush.h
mm/Kconfig

index 09ad7995080c879cc4b944cf671484ac24746830..45d63c9860150fd70d566b8a032ccebda568f954 100644 (file)
@@ -88,6 +88,7 @@ config PLATFORM_AT32AP
        select MMU
        select PERFORMANCE_COUNTERS
        select HAVE_GPIO_LIB
+       select GENERIC_ALLOCATOR
 
 #
 # CPU types
@@ -147,6 +148,9 @@ config PHYS_OFFSET
 
 source "kernel/Kconfig.preempt"
 
+config QUICKLIST
+       def_bool y
+
 config HAVE_ARCH_BOOTMEM_NODE
        def_bool n
 
@@ -201,6 +205,11 @@ endmenu
 
 menu "Power management options"
 
+source "kernel/power/Kconfig"
+
+config ARCH_SUSPEND_POSSIBLE
+       def_bool y
+
 menu "CPU Frequency scaling"
 
 source "drivers/cpufreq/Kconfig"
index a398be2849666bf974696ba383800df885ee3cf7..a51bb9fb3c89d2047151a5da22d14c7582a43643 100644 (file)
@@ -9,6 +9,8 @@
  */
 #include <linux/clk.h>
 #include <linux/etherdevice.h>
+#include <linux/irq.h>
+#include <linux/i2c.h>
 #include <linux/i2c-gpio.h>
 #include <linux/init.h>
 #include <linux/linkage.h>
 #include <asm/arch/init.h>
 #include <asm/arch/portmux.h>
 
+/* Oscillator frequencies. These are board-specific */
+unsigned long at32_board_osc_rates[3] = {
+       [0] = 32768,    /* 32.768 kHz on RTC osc */
+       [1] = 20000000, /* 20 MHz on osc0 */
+       [2] = 12000000, /* 12 MHz on osc1 */
+};
+
 /* Initialized by bootloader-specific startup code. */
 struct tag *bootloader_tags __initdata;
 
@@ -140,6 +149,10 @@ static struct platform_device i2c_gpio_device = {
        },
 };
 
+static struct i2c_board_info __initdata i2c_info[] = {
+       /* NOTE:  original ATtiny24 firmware is at address 0x0b */
+};
+
 static int __init atngw100_init(void)
 {
        unsigned        i;
@@ -165,12 +178,28 @@ static int __init atngw100_init(void)
        }
        platform_device_register(&ngw_gpio_leds);
 
+       /* all these i2c/smbus pins should have external pullups for
+        * open-drain sharing among all I2C devices.  SDA and SCL do;
+        * PB28/EXTINT3 doesn't; it should be SMBALERT# (for PMBus),
+        * but it's not available off-board.
+        */
+       at32_select_periph(GPIO_PIN_PB(28), 0, AT32_GPIOF_PULLUP);
        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);
+       i2c_register_board_info(0, i2c_info, ARRAY_SIZE(i2c_info));
 
        return 0;
 }
 postcore_initcall(atngw100_init);
+
+static int __init atngw100_arch_init(void)
+{
+       /* set_irq_type() after the arch_initcall for EIC has run, and
+        * before the I2C subsystem could try using this IRQ.
+        */
+       return set_irq_type(AT32_EXTINT(3), IRQ_TYPE_EDGE_FALLING);
+}
+arch_initcall(atngw100_arch_init);
index 000eb4220a12619b4e9b9922f5ed7d9e4c958064..86b363c1c25bea00dfe011425c044d6d91edd0f9 100644 (file)
 
 #include "atstk1000.h"
 
+/* Oscillator frequencies. These are board specific */
+unsigned long at32_board_osc_rates[3] = {
+       [0] = 32768,    /* 32.768 kHz on RTC osc */
+       [1] = 20000000, /* 20 MHz on osc0 */
+       [2] = 12000000, /* 12 MHz on osc1 */
+};
 
 struct eth_addr {
        u8 addr[6];
@@ -232,7 +238,7 @@ static int __init atstk1002_init(void)
        set_hw_addr(at32_add_device_eth(1, &eth_data[1]));
 #else
        at32_add_device_lcdc(0, &atstk1000_lcdc_data,
-                            fbmem_start, fbmem_size);
+                            fbmem_start, fbmem_size, 0);
 #endif
        at32_add_device_usba(0, NULL);
 #ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
index a0b223df35a253ed1afa45106864dc47ade6b744..ea109f435a83adc6ffb67cd8264d8a84552f52c9 100644 (file)
 
 #include "atstk1000.h"
 
+/* Oscillator frequencies. These are board specific */
+unsigned long at32_board_osc_rates[3] = {
+       [0] = 32768,    /* 32.768 kHz on RTC osc */
+       [1] = 20000000, /* 20 MHz on osc0 */
+       [2] = 12000000, /* 12 MHz on osc1 */
+};
+
 #ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
 static struct at73c213_board_info at73c213_data = {
        .ssc_id         = 0,
index e765a8652b3ee58480847302923170ed668150d3..c7236df74d7422125d6048c33804f8d167c1c91c 100644 (file)
 
 #include "atstk1000.h"
 
+/* Oscillator frequencies. These are board specific */
+unsigned long at32_board_osc_rates[3] = {
+       [0] = 32768,    /* 32.768 kHz on RTC osc */
+       [1] = 20000000, /* 20 MHz on osc0 */
+       [2] = 12000000, /* 12 MHz on osc1 */
+};
+
 #ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
 static struct at73c213_board_info at73c213_data = {
        .ssc_id         = 0,
@@ -133,7 +140,7 @@ static int __init atstk1004_init(void)
        at32_add_device_mci(0);
 #endif
        at32_add_device_lcdc(0, &atstk1000_lcdc_data,
-                            fbmem_start, fbmem_size);
+                            fbmem_start, fbmem_size, 0);
        at32_add_device_usba(0, NULL);
 #ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
        at32_add_device_ssc(0, ATMEL_SSC_TX);
index 5f31702d6b1c9e3ffc55ee4866b8ac4f7b2dfdcb..2b398cae110c839fc5b3c3be3d9d7a48fcf3a2ec 100644 (file)
@@ -74,50 +74,41 @@ exception_vectors:
        .align  2
        bral    do_dtlb_modified
 
-       /*
-        * r0 : PGD/PT/PTE
-        * r1 : Offending address
-        * r2 : Scratch register
-        * r3 : Cause (5, 12 or 13)
-        */
 #define        tlbmiss_save    pushm   r0-r3
 #define tlbmiss_restore        popm    r0-r3
 
-       .section .tlbx.ex.text,"ax",@progbits
+       .org    0x50
        .global itlb_miss
 itlb_miss:
        tlbmiss_save
        rjmp    tlb_miss_common
 
-       .section .tlbr.ex.text,"ax",@progbits
+       .org    0x60
 dtlb_miss_read:
        tlbmiss_save
        rjmp    tlb_miss_common
 
-       .section .tlbw.ex.text,"ax",@progbits
+       .org    0x70
 dtlb_miss_write:
        tlbmiss_save
 
        .global tlb_miss_common
+       .align  2
 tlb_miss_common:
        mfsr    r0, SYSREG_TLBEAR
        mfsr    r1, SYSREG_PTBR
 
-       /* Is it the vmalloc space? */
-       bld     r0, 31
-       brcs    handle_vmalloc_miss
-
-       /* First level lookup */
+       /*
+        * First level lookup: The PGD contains virtual pointers to
+        * the second-level page tables, but they may be NULL if not
+        * present.
+        */
 pgtbl_lookup:
        lsr     r2, r0, PGDIR_SHIFT
        ld.w    r3, r1[r2 << 2]
        bfextu  r1, r0, PAGE_SHIFT, PGDIR_SHIFT - PAGE_SHIFT
-       bld     r3, _PAGE_BIT_PRESENT
-       brcc    page_table_not_present
-
-       /* Translate to virtual address in P1. */
-       andl    r3, 0xf000
-       sbr     r3, 31
+       cp.w    r3, 0
+       breq    page_table_not_present
 
        /* Second level lookup */
        ld.w    r2, r3[r1 << 2]
@@ -148,16 +139,55 @@ pgtbl_lookup:
        tlbmiss_restore
        rete
 
-handle_vmalloc_miss:
-       /* Simply do the lookup in init's page table */
+       /* The slow path of the TLB miss handler */
+       .align  2
+page_table_not_present:
+       /* Do we need to synchronize with swapper_pg_dir? */
+       bld     r0, 31
+       brcs    sync_with_swapper_pg_dir
+
+page_not_present:
+       tlbmiss_restore
+       sub     sp, 4
+       stmts   --sp, r0-lr
+       rcall   save_full_context_ex
+       mfsr    r12, SYSREG_ECR
+       mov     r11, sp
+       rcall   do_page_fault
+       rjmp    ret_from_exception
+
+       .align  2
+sync_with_swapper_pg_dir:
+       /*
+        * If swapper_pg_dir contains a non-NULL second-level page
+        * table pointer, copy it into the current PGD. If not, we
+        * must handle it as a full-blown page fault.
+        *
+        * Jumping back to pgtbl_lookup causes an unnecessary lookup,
+        * but it is guaranteed to be a cache hit, it won't happen
+        * very often, and we absolutely do not want to sacrifice any
+        * performance in the fast path in order to improve this.
+        */
        mov     r1, lo(swapper_pg_dir)
        orh     r1, hi(swapper_pg_dir)
+       ld.w    r3, r1[r2 << 2]
+       cp.w    r3, 0
+       breq    page_not_present
+       mfsr    r1, SYSREG_PTBR
+       st.w    r1[r2 << 2], r3
        rjmp    pgtbl_lookup
 
+       /*
+        * We currently have two bytes left at this point until we
+        * crash into the system call handler...
+        *
+        * Don't worry, the assembler will let us know.
+        */
+
 
        /* ---                    System Call                    --- */
 
-       .section .scall.text,"ax",@progbits
+       .org    0x100
 system_call:
 #ifdef CONFIG_PREEMPT
        mask_interrupts
@@ -266,18 +296,6 @@ syscall_exit_work:
        brcc    syscall_exit_cont
        rjmp    enter_monitor_mode
 
-       /* The slow path of the TLB miss handler */
-page_table_not_present:
-page_not_present:
-       tlbmiss_restore
-       sub     sp, 4
-       stmts   --sp, r0-lr
-       rcall   save_full_context_ex
-       mfsr    r12, SYSREG_ECR
-       mov     r11, sp
-       rcall   do_page_fault
-       rjmp    ret_from_exception
-
        /* This function expects to find offending PC in SYSREG_RAR_EX */
        .type   save_full_context_ex, @function
        .align  2
index 5616a00c10ba2f3a9660b63a25e57d021c00da92..c5b11f9067f104bf7dafca6e3bbb1ac89a38bc4f 100644 (file)
@@ -93,6 +93,9 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
        if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
                goto badframe;
 
+       if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT)
+               goto badframe;
+
        pr_debug("Context restored: pc = %08lx, lr = %08lx, sp = %08lx\n",
                 regs->pc, regs->lr, regs->sp);
 
index 00a9862380ff3e10e3fc0dd73137197ad1982fe0..abd954fb7ba0ccbf37b1494b93c1600045fd1a88 100644 (file)
@@ -7,21 +7,13 @@
  */
 #include <linux/clk.h>
 #include <linux/clockchips.h>
-#include <linux/time.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
-#include <linux/kernel_stat.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/profile.h>
-#include <linux/sysdev.h>
-#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/time.h>
 
-#include <asm/div64.h>
 #include <asm/sysreg.h>
-#include <asm/io.h>
-#include <asm/sections.h>
 
 #include <asm/arch/pm.h>
 
index 481cfd40c0539e85297ed33366ec579041d95680..5d25d8eeb750fd148ddb1cefdd2dcdc4e8204e69 100644 (file)
@@ -68,14 +68,6 @@ SECTIONS
                _evba = .;
                _text = .;
                *(.ex.text)
-               . = 0x50;
-               *(.tlbx.ex.text)
-               . = 0x60;
-               *(.tlbr.ex.text)
-               . = 0x70;
-               *(.tlbw.ex.text)
-               . = 0x100;
-               *(.scall.text)
                *(.irq.text)
                KPROBES_TEXT
                TEXT_TEXT
@@ -107,6 +99,10 @@ SECTIONS
                 */
                *(.data.init_task)
 
+               /* Then, the page-aligned data */
+               . = ALIGN(PAGE_SIZE);
+               *(.data.page_aligned)
+
                /* Then, the cacheline aligned data */
                . = ALIGN(L1_CACHE_BYTES);
                *(.data.cacheline_aligned)
index 2be5da7ed26b7f0b42269f073dfcdb5f15ba788a..cb2d8694555964d90606838d450d95499d33da7a 100644 (file)
@@ -41,7 +41,7 @@ __raw_readsb:
 2:     sub     r10, -4
        reteq   r12
 
-3:     ld.uh   r8, r12[0]
+3:     ld.ub   r8, r12[0]
        sub     r10, 1
        st.b    r11++, r8
        brne    3b
index e89009439e4aebf043bf335561ba7b1f93e7d4db..d5018e2eed255232309f6de74358604a96856f91 100644 (file)
@@ -1,3 +1,8 @@
-obj-y                          += at32ap.o clock.o intc.o extint.o pio.o hsmc.o
+obj-y                          += pdc.o clock.o intc.o extint.o pio.o hsmc.o
 obj-$(CONFIG_CPU_AT32AP700X)   += at32ap700x.o pm-at32ap700x.o
 obj-$(CONFIG_CPU_FREQ_AT32AP)  += cpufreq.o
+obj-$(CONFIG_PM)               += pm.o
+
+ifeq ($(CONFIG_PM_DEBUG),y)
+CFLAGS_pm.o    += -DDEBUG
+endif
index 0f24b4f85c17c6022b4dccf624532ec7e4aeb7db..07b21b121eef995726a6e8a981f3c416497e997e 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/arch/at32ap700x.h>
 #include <asm/arch/board.h>
 #include <asm/arch/portmux.h>
+#include <asm/arch/sram.h>
 
 #include <video/atmel_lcdc.h>
 
@@ -93,19 +94,12 @@ static struct clk devname##_##_name = {                             \
 
 static DEFINE_SPINLOCK(pm_lock);
 
-unsigned long at32ap7000_osc_rates[3] = {
-       [0] = 32768,
-       /* FIXME: these are ATSTK1002-specific */
-       [1] = 20000000,
-       [2] = 12000000,
-};
-
 static struct clk osc0;
 static struct clk osc1;
 
 static unsigned long osc_get_rate(struct clk *clk)
 {
-       return at32ap7000_osc_rates[clk->index];
+       return at32_board_osc_rates[clk->index];
 }
 
 static unsigned long pll_get_rate(struct clk *clk, unsigned long control)
@@ -682,6 +676,14 @@ static struct clk hramc_clk = {
        .users          = 1,
        .index          = 3,
 };
+static struct clk sdramc_clk = {
+       .name           = "sdramc_clk",
+       .parent         = &pbb_clk,
+       .mode           = pbb_clk_mode,
+       .get_rate       = pbb_clk_get_rate,
+       .users          = 1,
+       .index          = 14,
+};
 
 static struct resource smc0_resource[] = {
        PBMEM(0xfff03400),
@@ -840,6 +842,81 @@ void __init at32_add_system_devices(void)
        platform_device_register(&pio4_device);
 }
 
+/* --------------------------------------------------------------------
+ *  PSIF
+ * -------------------------------------------------------------------- */
+static struct resource atmel_psif0_resource[] __initdata = {
+       {
+               .start  = 0xffe03c00,
+               .end    = 0xffe03cff,
+               .flags  = IORESOURCE_MEM,
+       },
+       IRQ(18),
+};
+static struct clk atmel_psif0_pclk = {
+       .name           = "pclk",
+       .parent         = &pba_clk,
+       .mode           = pba_clk_mode,
+       .get_rate       = pba_clk_get_rate,
+       .index          = 15,
+};
+
+static struct resource atmel_psif1_resource[] __initdata = {
+       {
+               .start  = 0xffe03d00,
+               .end    = 0xffe03dff,
+               .flags  = IORESOURCE_MEM,
+       },
+       IRQ(18),
+};
+static struct clk atmel_psif1_pclk = {
+       .name           = "pclk",
+       .parent         = &pba_clk,
+       .mode           = pba_clk_mode,
+       .get_rate       = pba_clk_get_rate,
+       .index          = 15,
+};
+
+struct platform_device *__init at32_add_device_psif(unsigned int id)
+{
+       struct platform_device *pdev;
+
+       if (!(id == 0 || id == 1))
+               return NULL;
+
+       pdev = platform_device_alloc("atmel_psif", id);
+       if (!pdev)
+               return NULL;
+
+       switch (id) {
+       case 0:
+               if (platform_device_add_resources(pdev, atmel_psif0_resource,
+                                       ARRAY_SIZE(atmel_psif0_resource)))
+                       goto err_add_resources;
+               atmel_psif0_pclk.dev = &pdev->dev;
+               select_peripheral(PA(8), PERIPH_A, 0); /* CLOCK */
+               select_peripheral(PA(9), PERIPH_A, 0); /* DATA  */
+               break;
+       case 1:
+               if (platform_device_add_resources(pdev, atmel_psif1_resource,
+                                       ARRAY_SIZE(atmel_psif1_resource)))
+                       goto err_add_resources;
+               atmel_psif1_pclk.dev = &pdev->dev;
+               select_peripheral(PB(11), PERIPH_A, 0); /* CLOCK */
+               select_peripheral(PB(12), PERIPH_A, 0); /* DATA  */
+               break;
+       default:
+               return NULL;
+       }
+
+       platform_device_add(pdev);
+       return pdev;
+
+err_add_resources:
+       platform_device_put(pdev);
+       return NULL;
+}
+
 /* --------------------------------------------------------------------
  *  USART
  * -------------------------------------------------------------------- */
@@ -1113,7 +1190,8 @@ at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n)
        switch (id) {
        case 0:
                pdev = &atmel_spi0_device;
-               select_peripheral(PA(0),  PERIPH_A, 0); /* MISO  */
+               /* pullup MISO so a level is always defined */
+               select_peripheral(PA(0),  PERIPH_A, AT32_GPIOF_PULLUP);
                select_peripheral(PA(1),  PERIPH_A, 0); /* MOSI  */
                select_peripheral(PA(2),  PERIPH_A, 0); /* SCK   */
                at32_spi_setup_slaves(0, b, n, spi0_pins);
@@ -1121,7 +1199,8 @@ at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n)
 
        case 1:
                pdev = &atmel_spi1_device;
-               select_peripheral(PB(0),  PERIPH_B, 0); /* MISO  */
+               /* pullup MISO so a level is always defined */
+               select_peripheral(PB(0),  PERIPH_B, AT32_GPIOF_PULLUP);
                select_peripheral(PB(1),  PERIPH_B, 0); /* MOSI  */
                select_peripheral(PB(5),  PERIPH_B, 0); /* SCK   */
                at32_spi_setup_slaves(1, b, n, spi1_pins);
@@ -1264,7 +1343,8 @@ static struct clk atmel_lcdfb0_pixclk = {
 
 struct platform_device *__init
 at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
-                    unsigned long fbmem_start, unsigned long fbmem_len)
+                    unsigned long fbmem_start, unsigned long fbmem_len,
+                    unsigned int pin_config)
 {
        struct platform_device *pdev;
        struct atmel_lcdfb_info *info;
@@ -1291,37 +1371,77 @@ at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
        switch (id) {
        case 0:
                pdev = &atmel_lcdfb0_device;
-               select_peripheral(PC(19), PERIPH_A, 0); /* CC     */
-               select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC  */
-               select_peripheral(PC(21), PERIPH_A, 0); /* PCLK   */
-               select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC  */
-               select_peripheral(PC(23), PERIPH_A, 0); /* DVAL   */
-               select_peripheral(PC(24), PERIPH_A, 0); /* MODE   */
-               select_peripheral(PC(25), PERIPH_A, 0); /* PWR    */
-               select_peripheral(PC(26), PERIPH_A, 0); /* DATA0  */
-               select_peripheral(PC(27), PERIPH_A, 0); /* DATA1  */
-               select_peripheral(PC(28), PERIPH_A, 0); /* DATA2  */
-               select_peripheral(PC(29), PERIPH_A, 0); /* DATA3  */
-               select_peripheral(PC(30), PERIPH_A, 0); /* DATA4  */
-               select_peripheral(PC(31), PERIPH_A, 0); /* DATA5  */
-               select_peripheral(PD(0),  PERIPH_A, 0); /* DATA6  */
-               select_peripheral(PD(1),  PERIPH_A, 0); /* DATA7  */
-               select_peripheral(PD(2),  PERIPH_A, 0); /* DATA8  */
-               select_peripheral(PD(3),  PERIPH_A, 0); /* DATA9  */
-               select_peripheral(PD(4),  PERIPH_A, 0); /* DATA10 */
-               select_peripheral(PD(5),  PERIPH_A, 0); /* DATA11 */
-               select_peripheral(PD(6),  PERIPH_A, 0); /* DATA12 */
-               select_peripheral(PD(7),  PERIPH_A, 0); /* DATA13 */
-               select_peripheral(PD(8),  PERIPH_A, 0); /* DATA14 */
-               select_peripheral(PD(9),  PERIPH_A, 0); /* DATA15 */
-               select_peripheral(PD(10), PERIPH_A, 0); /* DATA16 */
-               select_peripheral(PD(11), PERIPH_A, 0); /* DATA17 */
-               select_peripheral(PD(12), PERIPH_A, 0); /* DATA18 */
-               select_peripheral(PD(13), PERIPH_A, 0); /* DATA19 */
-               select_peripheral(PD(14), PERIPH_A, 0); /* DATA20 */
-               select_peripheral(PD(15), PERIPH_A, 0); /* DATA21 */
-               select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
-               select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
+
+               switch (pin_config) {
+               case 0:
+                       select_peripheral(PC(19), PERIPH_A, 0); /* CC     */
+                       select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC  */
+                       select_peripheral(PC(21), PERIPH_A, 0); /* PCLK   */
+                       select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC  */
+                       select_peripheral(PC(23), PERIPH_A, 0); /* DVAL   */
+                       select_peripheral(PC(24), PERIPH_A, 0); /* MODE   */
+                       select_peripheral(PC(25), PERIPH_A, 0); /* PWR    */
+                       select_peripheral(PC(26), PERIPH_A, 0); /* DATA0  */
+                       select_peripheral(PC(27), PERIPH_A, 0); /* DATA1  */
+                       select_peripheral(PC(28), PERIPH_A, 0); /* DATA2  */
+                       select_peripheral(PC(29), PERIPH_A, 0); /* DATA3  */
+                       select_peripheral(PC(30), PERIPH_A, 0); /* DATA4  */
+                       select_peripheral(PC(31), PERIPH_A, 0); /* DATA5  */
+                       select_peripheral(PD(0),  PERIPH_A, 0); /* DATA6  */
+                       select_peripheral(PD(1),  PERIPH_A, 0); /* DATA7  */
+                       select_peripheral(PD(2),  PERIPH_A, 0); /* DATA8  */
+                       select_peripheral(PD(3),  PERIPH_A, 0); /* DATA9  */
+                       select_peripheral(PD(4),  PERIPH_A, 0); /* DATA10 */
+                       select_peripheral(PD(5),  PERIPH_A, 0); /* DATA11 */
+                       select_peripheral(PD(6),  PERIPH_A, 0); /* DATA12 */
+                       select_peripheral(PD(7),  PERIPH_A, 0); /* DATA13 */
+                       select_peripheral(PD(8),  PERIPH_A, 0); /* DATA14 */
+                       select_peripheral(PD(9),  PERIPH_A, 0); /* DATA15 */
+                       select_peripheral(PD(10), PERIPH_A, 0); /* DATA16 */
+                       select_peripheral(PD(11), PERIPH_A, 0); /* DATA17 */
+                       select_peripheral(PD(12), PERIPH_A, 0); /* DATA18 */
+                       select_peripheral(PD(13), PERIPH_A, 0); /* DATA19 */
+                       select_peripheral(PD(14), PERIPH_A, 0); /* DATA20 */
+                       select_peripheral(PD(15), PERIPH_A, 0); /* DATA21 */
+                       select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
+                       select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
+                       break;
+               case 1:
+                       select_peripheral(PE(0),  PERIPH_B, 0); /* CC     */
+                       select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC  */
+                       select_peripheral(PC(21), PERIPH_A, 0); /* PCLK   */
+                       select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC  */
+                       select_peripheral(PE(1),  PERIPH_B, 0); /* DVAL   */
+                       select_peripheral(PE(2),  PERIPH_B, 0); /* MODE   */
+                       select_peripheral(PC(25), PERIPH_A, 0); /* PWR    */
+                       select_peripheral(PE(3),  PERIPH_B, 0); /* DATA0  */
+                       select_peripheral(PE(4),  PERIPH_B, 0); /* DATA1  */
+                       select_peripheral(PE(5),  PERIPH_B, 0); /* DATA2  */
+                       select_peripheral(PE(6),  PERIPH_B, 0); /* DATA3  */
+                       select_peripheral(PE(7),  PERIPH_B, 0); /* DATA4  */
+                       select_peripheral(PC(31), PERIPH_A, 0); /* DATA5  */
+                       select_peripheral(PD(0),  PERIPH_A, 0); /* DATA6  */
+                       select_peripheral(PD(1),  PERIPH_A, 0); /* DATA7  */
+                       select_peripheral(PE(8),  PERIPH_B, 0); /* DATA8  */
+                       select_peripheral(PE(9),  PERIPH_B, 0); /* DATA9  */
+                       select_peripheral(PE(10), PERIPH_B, 0); /* DATA10 */
+                       select_peripheral(PE(11), PERIPH_B, 0); /* DATA11 */
+                       select_peripheral(PE(12), PERIPH_B, 0); /* DATA12 */
+                       select_peripheral(PD(7),  PERIPH_A, 0); /* DATA13 */
+                       select_peripheral(PD(8),  PERIPH_A, 0); /* DATA14 */
+                       select_peripheral(PD(9),  PERIPH_A, 0); /* DATA15 */
+                       select_peripheral(PE(13), PERIPH_B, 0); /* DATA16 */
+                       select_peripheral(PE(14), PERIPH_B, 0); /* DATA17 */
+                       select_peripheral(PE(15), PERIPH_B, 0); /* DATA18 */
+                       select_peripheral(PE(16), PERIPH_B, 0); /* DATA19 */
+                       select_peripheral(PE(17), PERIPH_B, 0); /* DATA20 */
+                       select_peripheral(PE(18), PERIPH_B, 0); /* DATA21 */
+                       select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
+                       select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
+                       break;
+               default:
+                       goto err_invalid_id;
+               }
 
                clk_set_parent(&atmel_lcdfb0_pixclk, &pll0);
                clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0));
@@ -1360,7 +1480,7 @@ static struct resource atmel_pwm0_resource[] __initdata = {
        IRQ(24),
 };
 static struct clk atmel_pwm0_mck = {
-       .name           = "mck",
+       .name           = "pwm_clk",
        .parent         = &pbb_clk,
        .mode           = pbb_clk_mode,
        .get_rate       = pbb_clk_get_rate,
@@ -1887,6 +2007,7 @@ struct clk *at32_clock_list[] = {
        &hmatrix_clk,
        &ebi_clk,
        &hramc_clk,
+       &sdramc_clk,
        &smc0_pclk,
        &smc0_mck,
        &pdc_hclk,
@@ -1900,6 +2021,8 @@ struct clk *at32_clock_list[] = {
        &pio4_mck,
        &at32_tcb0_t0_clk,
        &at32_tcb1_t0_clk,
+       &atmel_psif0_pclk,
+       &atmel_psif1_pclk,
        &atmel_usart0_usart,
        &atmel_usart1_usart,
        &atmel_usart2_usart,
@@ -1935,16 +2058,7 @@ struct clk *at32_clock_list[] = {
 };
 unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list);
 
-void __init at32_portmux_init(void)
-{
-       at32_init_pio(&pio0_device);
-       at32_init_pio(&pio1_device);
-       at32_init_pio(&pio2_device);
-       at32_init_pio(&pio3_device);
-       at32_init_pio(&pio4_device);
-}
-
-void __init at32_clock_init(void)
+void __init setup_platform(void)
 {
        u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0;
        int i;
@@ -1999,4 +2113,36 @@ void __init at32_clock_init(void)
        pm_writel(HSB_MASK, hsb_mask);
        pm_writel(PBA_MASK, pba_mask);
        pm_writel(PBB_MASK, pbb_mask);
+
+       /* Initialize the port muxes */
+       at32_init_pio(&pio0_device);
+       at32_init_pio(&pio1_device);
+       at32_init_pio(&pio2_device);
+       at32_init_pio(&pio3_device);
+       at32_init_pio(&pio4_device);
+}
+
+struct gen_pool *sram_pool;
+
+static int __init sram_init(void)
+{
+       struct gen_pool *pool;
+
+       /* 1KiB granularity */
+       pool = gen_pool_create(10, -1);
+       if (!pool)
+               goto fail;
+
+       if (gen_pool_add(pool, 0x24000000, 0x8000, -1))
+               goto err_pool_add;
+
+       sram_pool = pool;
+       return 0;
+
+err_pool_add:
+       gen_pool_destroy(pool);
+fail:
+       pr_err("Failed to create SRAM pool\n");
+       return -ENOMEM;
 }
+core_initcall(sram_init);
index 097cf4e8405260e738ee02dcec3dd29b7c5dbd33..994c4545e2b7ecac3bc50b95db9e871aebf7d8e4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 Atmel Corporation
+ * Copyright (C) 2006, 2008 Atmel Corporation
  *
  * 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
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/platform_device.h>
+#include <linux/sysdev.h>
 
 #include <asm/io.h>
 
 #include "intc.h"
 
 struct intc {
-       void __iomem    *regs;
-       struct irq_chip chip;
+       void __iomem            *regs;
+       struct irq_chip         chip;
+       struct sys_device       sysdev;
+#ifdef CONFIG_PM
+       unsigned long           suspend_ipr;
+       unsigned long           saved_ipr[64];
+#endif
 };
 
 extern struct platform_device at32_intc0_device;
@@ -136,6 +142,74 @@ fail:
        panic("Interrupt controller initialization failed!\n");
 }
 
+#ifdef CONFIG_PM
+void intc_set_suspend_handler(unsigned long offset)
+{
+       intc0.suspend_ipr = offset;
+}
+
+static int intc_suspend(struct sys_device *sdev, pm_message_t state)
+{
+       struct intc *intc = container_of(sdev, struct intc, sysdev);
+       int i;
+
+       if (unlikely(!irqs_disabled())) {
+               pr_err("intc_suspend: called with interrupts enabled\n");
+               return -EINVAL;
+       }
+
+       if (unlikely(!intc->suspend_ipr)) {
+               pr_err("intc_suspend: suspend_ipr not initialized\n");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < 64; i++) {
+               intc->saved_ipr[i] = intc_readl(intc, INTPR0 + 4 * i);
+               intc_writel(intc, INTPR0 + 4 * i, intc->suspend_ipr);
+       }
+
+       return 0;
+}
+
+static int intc_resume(struct sys_device *sdev)
+{
+       struct intc *intc = container_of(sdev, struct intc, sysdev);
+       int i;
+
+       WARN_ON(!irqs_disabled());
+
+       for (i = 0; i < 64; i++)
+               intc_writel(intc, INTPR0 + 4 * i, intc->saved_ipr[i]);
+
+       return 0;
+}
+#else
+#define intc_suspend   NULL
+#define intc_resume    NULL
+#endif
+
+static struct sysdev_class intc_class = {
+       .name           = "intc",
+       .suspend        = intc_suspend,
+       .resume         = intc_resume,
+};
+
+static int __init intc_init_sysdev(void)
+{
+       int ret;
+
+       ret = sysdev_class_register(&intc_class);
+       if (ret)
+               return ret;
+
+       intc0.sysdev.id = 0;
+       intc0.sysdev.cls = &intc_class;
+       ret = sysdev_register(&intc0.sysdev);
+
+       return ret;
+}
+device_initcall(intc_init_sysdev);
+
 unsigned long intc_get_pending(unsigned int group)
 {
        return intc_readl(&intc0, INTREQ0 + 4 * group);
similarity index 90%
rename from arch/avr32/mach-at32ap/at32ap.c
rename to arch/avr32/mach-at32ap/pdc.c
index 7c4987f3287a7ca52d944ee30bc435225bdaac56..1040bda4fda7c843ea0d4955129f17cc94ab79bd 100644 (file)
 #include <linux/init.h>
 #include <linux/platform_device.h>
 
-#include <asm/arch/init.h>
-
-void __init setup_platform(void)
-{
-       at32_clock_init();
-       at32_portmux_init();
-}
-
 static int __init pdc_probe(struct platform_device *pdev)
 {
        struct clk *pclk, *hclk;
index 38a8fa31c0b5c8de591ae8f39a08c2e90d2a862b..60da03ba7117e0c9a62ad4756ac5fa0aecf7d756 100644 (file)
@@ -318,6 +318,8 @@ static void pio_bank_show(struct seq_file *s, struct gpio_chip *chip)
                const char *label;
 
                label = gpiochip_is_requested(chip, i);
+               if (!label && (imr & mask))
+                       label = "[irq]";
                if (!label)
                        continue;
 
index 7795116a483af37707a66ae57c1f1da49e59a41a..9484dfcc08f224e925a8408c1b5d9edd30ccb6f6 100644 (file)
@@ -57,7 +57,7 @@
 
 /* Bitfields in IFDR */
 
-/* Bitfields in ISFR */
+/* Bitfields in IFSR */
 
 /* Bitfields in SODR */
 
index 949e2485e2788bc440f2b4242a66e763be33eb2f..0a53ad314ff429a54bfcc16e48898cd523a82b38 100644 (file)
 #include <asm/thread_info.h>
 #include <asm/arch/pm.h>
 
+#include "pm.h"
+#include "sdramc.h"
+
+/* Same as 0xfff00000 but fits in a 21 bit signed immediate */
+#define PM_BASE        -0x100000
+
        .section .bss, "wa", @nobits
        .global disable_idle_sleep
        .type   disable_idle_sleep, @object
@@ -64,3 +70,105 @@ cpu_idle_skip_sleep:
        unmask_interrupts
        retal   r12
        .size   cpu_idle_skip_sleep, . - cpu_idle_skip_sleep
+
+#ifdef CONFIG_PM
+       .section .init.text, "ax", @progbits
+
+       .global pm_exception
+       .type   pm_exception, @function
+pm_exception:
+       /*
+        * Exceptions are masked when we switch to this handler, so
+        * we'll only get "unrecoverable" exceptions (offset 0.)
+        */
+       sub     r12, pc, . - .Lpanic_msg
+       lddpc   pc, .Lpanic_addr
+
+       .align  2
+.Lpanic_addr:
+       .long   panic
+.Lpanic_msg:
+       .asciz  "Unrecoverable exception during suspend\n"
+       .size   pm_exception, . - pm_exception
+
+       .global pm_irq0
+       .type   pm_irq0, @function
+pm_irq0:
+       /* Disable interrupts and return after the sleep instruction */
+       mfsr    r9, SYSREG_RSR_INT0
+       mtsr    SYSREG_RAR_INT0, r8
+       sbr     r9, SYSREG_GM_OFFSET
+       mtsr    SYSREG_RSR_INT0, r9
+       rete
+
+       /*
+        * void cpu_enter_standby(unsigned long sdramc_base)
+        *
+        * Enter PM_SUSPEND_STANDBY mode. At this point, all drivers
+        * are suspended and interrupts are disabled. Interrupts
+        * marked as 'wakeup' event sources may still come along and
+        * get us out of here.
+        *
+        * The SDRAM will be put into self-refresh mode (which does
+        * not require a clock from the CPU), and the CPU will be put
+        * into "frozen" mode (HSB bus stopped). The SDRAM controller
+        * will automatically bring the SDRAM into normal mode on the
+        * first access, and the power manager will automatically
+        * start the HSB and CPU clocks upon a wakeup event.
+        *
+        * This code uses the same "skip sleep" technique as above.
+        * It is very important that we jump directly to
+        * cpu_after_sleep after the sleep instruction since that's
+        * where we'll end up if the interrupt handler decides that we
+        * need to skip the sleep instruction.
+        */
+       .global pm_standby
+       .type   pm_standby, @function
+pm_standby:
+       /*
+        * interrupts are already masked at this point, and EVBA
+        * points to pm_exception above.
+        */
+       ld.w    r10, r12[SDRAMC_LPR]
+       sub     r8, pc, . - 1f          /* return address for irq handler */
+       mov     r11, SDRAMC_LPR_LPCB_SELF_RFR
+       bfins   r10, r11, 0, 2          /* LPCB <- self Refresh */
+       sync    0                       /* flush write buffer */
+       st.w    r12[SDRAMC_LPR], r11    /* put SDRAM in self-refresh mode */
+       ld.w    r11, r12[SDRAMC_LPR]
+       unmask_interrupts
+       sleep   CPU_SLEEP_FROZEN
+1:     mask_interrupts
+       retal   r12
+       .size   pm_standby, . - pm_standby
+
+       .global pm_suspend_to_ram
+       .type   pm_suspend_to_ram, @function
+pm_suspend_to_ram:
+       /*
+        * interrupts are already masked at this point, and EVBA
+        * points to pm_exception above.
+        */
+       mov     r11, 0
+       cache   r11[2], 8               /* clean all dcache lines */
+       sync    0                       /* flush write buffer */
+       ld.w    r10, r12[SDRAMC_LPR]
+       sub     r8, pc, . - 1f          /* return address for irq handler */
+       mov     r11, SDRAMC_LPR_LPCB_SELF_RFR
+       bfins   r10, r11, 0, 2          /* LPCB <- self refresh */
+       st.w    r12[SDRAMC_LPR], r10    /* put SDRAM in self-refresh mode */
+       ld.w    r11, r12[SDRAMC_LPR]
+
+       unmask_interrupts
+       sleep   CPU_SLEEP_STOP
+1:     mask_interrupts
+
+       retal   r12
+       .size   pm_suspend_to_ram, . - pm_suspend_to_ram
+
+       .global pm_sram_end
+       .type   pm_sram_end, @function
+pm_sram_end:
+       .size   pm_sram_end, 0
+
+#endif /* CONFIG_PM */
diff --git a/arch/avr32/mach-at32ap/pm.c b/arch/avr32/mach-at32ap/pm.c
new file mode 100644 (file)
index 0000000..0b76432
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * AVR32 AP Power Management
+ *
+ * Copyright (C) 2008 Atmel Corporation
+ *
+ * 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/io.h>
+#include <linux/suspend.h>
+#include <linux/vmalloc.h>
+
+#include <asm/cacheflush.h>
+#include <asm/sysreg.h>
+
+#include <asm/arch/pm.h>
+#include <asm/arch/sram.h>
+
+/* FIXME: This is only valid for AP7000 */
+#define SDRAMC_BASE    0xfff03800
+
+#include "sdramc.h"
+
+#define SRAM_PAGE_FLAGS        (SYSREG_BIT(TLBELO_D) | SYSREG_BF(SZ, 1)        \
+                               | SYSREG_BF(AP, 3) | SYSREG_BIT(G))
+
+
+static unsigned long   pm_sram_start;
+static size_t          pm_sram_size;
+static struct vm_struct        *pm_sram_area;
+
+static void (*avr32_pm_enter_standby)(unsigned long sdramc_base);
+static void (*avr32_pm_enter_str)(unsigned long sdramc_base);
+
+/*
+ * Must be called with interrupts disabled. Exceptions will be masked
+ * on return (i.e. all exceptions will be "unrecoverable".)
+ */
+static void *avr32_pm_map_sram(void)
+{
+       unsigned long   vaddr;
+       unsigned long   page_addr;
+       u32             tlbehi;
+       u32             mmucr;
+
+       vaddr = (unsigned long)pm_sram_area->addr;
+       page_addr = pm_sram_start & PAGE_MASK;
+
+       /*
+        * Mask exceptions and grab the first TLB entry. We won't be
+        * needing it while sleeping.
+        */
+       asm volatile("ssrf      %0" : : "i"(SYSREG_EM_OFFSET) : "memory");
+
+       mmucr = sysreg_read(MMUCR);
+       tlbehi = sysreg_read(TLBEHI);
+       sysreg_write(MMUCR, SYSREG_BFINS(DRP, 0, mmucr));
+
+       tlbehi = SYSREG_BF(ASID, SYSREG_BFEXT(ASID, tlbehi));
+       tlbehi |= vaddr & PAGE_MASK;
+       tlbehi |= SYSREG_BIT(TLBEHI_V);
+
+       sysreg_write(TLBELO, page_addr | SRAM_PAGE_FLAGS);
+       sysreg_write(TLBEHI, tlbehi);
+       __builtin_tlbw();
+
+       return (void *)(vaddr + pm_sram_start - page_addr);
+}
+
+/*
+ * Must be called with interrupts disabled. Exceptions will be
+ * unmasked on return.
+ */
+static void avr32_pm_unmap_sram(void)
+{
+       u32     mmucr;
+       u32     tlbehi;
+       u32     tlbarlo;
+
+       /* Going to update TLB entry at index 0 */
+       mmucr = sysreg_read(MMUCR);
+       tlbehi = sysreg_read(TLBEHI);
+       sysreg_write(MMUCR, SYSREG_BFINS(DRP, 0, mmucr));
+
+       /* Clear the "valid" bit */
+       tlbehi = SYSREG_BF(ASID, SYSREG_BFEXT(ASID, tlbehi));
+       sysreg_write(TLBEHI, tlbehi);
+
+       /* Mark it as "not accessed" */
+       tlbarlo = sysreg_read(TLBARLO);
+       sysreg_write(TLBARLO, tlbarlo | 0x80000000U);
+
+       /* Update the TLB */
+       __builtin_tlbw();
+
+       /* Unmask exceptions */
+       asm volatile("csrf      %0" : : "i"(SYSREG_EM_OFFSET) : "memory");
+}
+
+static int avr32_pm_valid_state(suspend_state_t state)
+{
+       switch (state) {
+       case PM_SUSPEND_ON:
+       case PM_SUSPEND_STANDBY:
+       case PM_SUSPEND_MEM:
+               return 1;
+
+       default:
+               return 0;
+       }
+}
+
+static int avr32_pm_enter(suspend_state_t state)
+{
+       u32             lpr_saved;
+       u32             evba_saved;
+       void            *sram;
+
+       switch (state) {
+       case PM_SUSPEND_STANDBY:
+               sram = avr32_pm_map_sram();
+
+               /* Switch to in-sram exception handlers */
+               evba_saved = sysreg_read(EVBA);
+               sysreg_write(EVBA, (unsigned long)sram);
+
+               /*
+                * Save the LPR register so that we can re-enable
+                * SDRAM Low Power mode on resume.
+                */
+               lpr_saved = sdramc_readl(LPR);
+               pr_debug("%s: Entering standby...\n", __func__);
+               avr32_pm_enter_standby(SDRAMC_BASE);
+               sdramc_writel(LPR, lpr_saved);
+
+               /* Switch back to regular exception handlers */
+               sysreg_write(EVBA, evba_saved);
+
+               avr32_pm_unmap_sram();
+               break;
+
+       case PM_SUSPEND_MEM:
+               sram = avr32_pm_map_sram();
+
+               /* Switch to in-sram exception handlers */
+               evba_saved = sysreg_read(EVBA);
+               sysreg_write(EVBA, (unsigned long)sram);
+
+               /*
+                * Save the LPR register so that we can re-enable
+                * SDRAM Low Power mode on resume.
+                */
+               lpr_saved = sdramc_readl(LPR);
+               pr_debug("%s: Entering suspend-to-ram...\n", __func__);
+               avr32_pm_enter_str(SDRAMC_BASE);
+               sdramc_writel(LPR, lpr_saved);
+
+               /* Switch back to regular exception handlers */
+               sysreg_write(EVBA, evba_saved);
+
+               avr32_pm_unmap_sram();
+               break;
+
+       case PM_SUSPEND_ON:
+               pr_debug("%s: Entering idle...\n", __func__);
+               cpu_enter_idle();
+               break;
+
+       default:
+               pr_debug("%s: Invalid suspend state %d\n", __func__, state);
+               goto out;
+       }
+
+       pr_debug("%s: wakeup\n", __func__);
+
+out:
+       return 0;
+}
+
+static struct platform_suspend_ops avr32_pm_ops = {
+       .valid  = avr32_pm_valid_state,
+       .enter  = avr32_pm_enter,
+};
+
+static unsigned long avr32_pm_offset(void *symbol)
+{
+       extern u8 pm_exception[];
+
+       return (unsigned long)symbol - (unsigned long)pm_exception;
+}
+
+static int __init avr32_pm_init(void)
+{
+       extern u8 pm_exception[];
+       extern u8 pm_irq0[];
+       extern u8 pm_standby[];
+       extern u8 pm_suspend_to_ram[];
+       extern u8 pm_sram_end[];
+       void *dst;
+
+       /*
+        * To keep things simple, we depend on not needing more than a
+        * single page.
+        */
+       pm_sram_size = avr32_pm_offset(pm_sram_end);
+       if (pm_sram_size > PAGE_SIZE)
+               goto err;
+
+       pm_sram_start = sram_alloc(pm_sram_size);
+       if (!pm_sram_start)
+               goto err_alloc_sram;
+
+       /* Grab a virtual area we can use later on. */
+       pm_sram_area = get_vm_area(pm_sram_size, VM_IOREMAP);
+       if (!pm_sram_area)
+               goto err_vm_area;
+       pm_sram_area->phys_addr = pm_sram_start;
+
+       local_irq_disable();
+       dst = avr32_pm_map_sram();
+       memcpy(dst, pm_exception, pm_sram_size);
+       flush_dcache_region(dst, pm_sram_size);
+       invalidate_icache_region(dst, pm_sram_size);
+       avr32_pm_unmap_sram();
+       local_irq_enable();
+
+       avr32_pm_enter_standby = dst + avr32_pm_offset(pm_standby);
+       avr32_pm_enter_str = dst + avr32_pm_offset(pm_suspend_to_ram);
+       intc_set_suspend_handler(avr32_pm_offset(pm_irq0));
+
+       suspend_set_ops(&avr32_pm_ops);
+
+       printk("AVR32 AP Power Management enabled\n");
+
+       return 0;
+
+err_vm_area:
+       sram_free(pm_sram_start, pm_sram_size);
+err_alloc_sram:
+err:
+       pr_err("AVR32 Power Management initialization failed\n");
+       return -ENOMEM;
+}
+arch_initcall(avr32_pm_init);
diff --git a/arch/avr32/mach-at32ap/sdramc.h b/arch/avr32/mach-at32ap/sdramc.h
new file mode 100644 (file)
index 0000000..66eeaed
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Register definitions for the AT32AP SDRAM Controller
+ *
+ * Copyright (C) 2008 Atmel Corporation
+ *
+ * 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.
+ */
+
+/* Register offsets */
+#define SDRAMC_MR                      0x0000
+#define SDRAMC_TR                      0x0004
+#define SDRAMC_CR                      0x0008
+#define SDRAMC_HSR                     0x000c
+#define SDRAMC_LPR                     0x0010
+#define SDRAMC_IER                     0x0014
+#define SDRAMC_IDR                     0x0018
+#define SDRAMC_IMR                     0x001c
+#define SDRAMC_ISR                     0x0020
+#define SDRAMC_MDR                     0x0024
+
+/* MR - Mode Register */
+#define SDRAMC_MR_MODE_NORMAL          (  0 <<  0)
+#define SDRAMC_MR_MODE_NOP             (  1 <<  0)
+#define SDRAMC_MR_MODE_BANKS_PRECHARGE (  2 <<  0)
+#define SDRAMC_MR_MODE_LOAD_MODE       (  3 <<  0)
+#define SDRAMC_MR_MODE_AUTO_REFRESH    (  4 <<  0)
+#define SDRAMC_MR_MODE_EXT_LOAD_MODE   (  5 <<  0)
+#define SDRAMC_MR_MODE_POWER_DOWN      (  6 <<  0)
+
+/* CR - Configuration Register */
+#define SDRAMC_CR_NC_8_BITS            (  0 <<  0)
+#define SDRAMC_CR_NC_9_BITS            (  1 <<  0)
+#define SDRAMC_CR_NC_10_BITS           (  2 <<  0)
+#define SDRAMC_CR_NC_11_BITS           (  3 <<  0)
+#define SDRAMC_CR_NR_11_BITS           (  0 <<  2)
+#define SDRAMC_CR_NR_12_BITS           (  1 <<  2)
+#define SDRAMC_CR_NR_13_BITS           (  2 <<  2)
+#define SDRAMC_CR_NB_2_BANKS           (  0 <<  4)
+#define SDRAMC_CR_NB_4_BANKS           (  1 <<  4)
+#define SDRAMC_CR_CAS(x)               ((x) <<  5)
+#define SDRAMC_CR_DBW_32_BITS          (  0 <<  7)
+#define SDRAMC_CR_DBW_16_BITS          (  1 <<  7)
+#define SDRAMC_CR_TWR(x)               ((x) <<  8)
+#define SDRAMC_CR_TRC(x)               ((x) << 12)
+#define SDRAMC_CR_TRP(x)               ((x) << 16)
+#define SDRAMC_CR_TRCD(x)              ((x) << 20)
+#define SDRAMC_CR_TRAS(x)              ((x) << 24)
+#define SDRAMC_CR_TXSR(x)              ((x) << 28)
+
+/* HSR - High Speed Register */
+#define SDRAMC_HSR_DA                  (  1 <<  0)
+
+/* LPR - Low Power Register */
+#define SDRAMC_LPR_LPCB_INHIBIT                (  0 <<  0)
+#define SDRAMC_LPR_LPCB_SELF_RFR       (  1 <<  0)
+#define SDRAMC_LPR_LPCB_PDOWN          (  2 <<  0)
+#define SDRAMC_LPR_LPCB_DEEP_PDOWN     (  3 <<  0)
+#define SDRAMC_LPR_PASR(x)             ((x) <<  4)
+#define SDRAMC_LPR_TCSR(x)             ((x) <<  8)
+#define SDRAMC_LPR_DS(x)               ((x) << 10)
+#define SDRAMC_LPR_TIMEOUT(x)          ((x) << 12)
+
+/* IER/IDR/IMR/ISR - Interrupt Enable/Disable/Mask/Status Register */
+#define SDRAMC_ISR_RES                 (  1 <<  0)
+
+/* MDR - Memory Device Register */
+#define SDRAMC_MDR_MD_SDRAM            (  0 <<  0)
+#define SDRAMC_MDR_MD_LOW_PWR_SDRAM    (  1 <<  0)
+
+/* Register access macros */
+#define sdramc_readl(reg) \
+       __raw_readl((void __iomem __force *)SDRAMC_BASE + SDRAMC_##reg)
+#define sdramc_writel(reg, value) \
+       __raw_writel(value, (void __iomem __force *)SDRAMC_BASE + SDRAMC_##reg)
index 0e64ddc45e3750f17e33b5be98789c9bed6176cc..3f90a87527bb27fe6ce997c0881a1ecfcbbdcc87 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/swap.h>
 #include <linux/init.h>
 #include <linux/mmzone.h>
+#include <linux/module.h>
 #include <linux/bootmem.h>
 #include <linux/pagemap.h>
 #include <linux/nodemask.h>
 #include <asm/setup.h>
 #include <asm/sections.h>
 
+#define __page_aligned __attribute__((section(".data.page_aligned")))
+
 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 
-pgd_t swapper_pg_dir[PTRS_PER_PGD];
+pgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned;
 
 struct page *empty_zero_page;
+EXPORT_SYMBOL(empty_zero_page);
 
 /*
  * Cache of MMU context last used.
@@ -106,19 +110,9 @@ void __init paging_init(void)
        zero_page = alloc_bootmem_low_pages_node(NODE_DATA(0),
                                                 PAGE_SIZE);
 
-       {
-               pgd_t *pg_dir;
-               int i;
-
-               pg_dir = swapper_pg_dir;
-               sysreg_write(PTBR, (unsigned long)pg_dir);
-
-               for (i = 0; i < PTRS_PER_PGD; i++)
-                       pgd_val(pg_dir[i]) = 0;
-
-               enable_mmu();
-               printk ("CPU: Paging enabled\n");
-       }
+       sysreg_write(PTBR, (unsigned long)swapper_pg_dir);
+       enable_mmu();
+       printk ("CPU: Paging enabled\n");
 
        for_each_online_node(nid) {
                pg_data_t *pgdat = NODE_DATA(nid);
index cd12edbea9f26c403bdc5a3c85f034e76766fc9a..06677be98ffba5fcb0143dac626bf96235fd1e16 100644 (file)
 
 #include <asm/mmu_context.h>
 
-#define _TLBEHI_I      0x100
+/* TODO: Get the correct number from the CONFIG1 system register */
+#define NR_TLB_ENTRIES 32
 
-void show_dtlb_entry(unsigned int index)
+static void show_dtlb_entry(unsigned int index)
 {
-       unsigned int tlbehi, tlbehi_save, tlbelo, mmucr, mmucr_save;
+       u32 tlbehi, tlbehi_save, tlbelo, mmucr, mmucr_save;
        unsigned long flags;
 
        local_irq_save(flags);
        mmucr_save = sysreg_read(MMUCR);
        tlbehi_save = sysreg_read(TLBEHI);
-       mmucr = mmucr_save & 0x13;
-       mmucr |= index << 14;
+       mmucr = SYSREG_BFINS(DRP, index, mmucr_save);
        sysreg_write(MMUCR, mmucr);
 
-       asm volatile("tlbr" : : : "memory");
+       __builtin_tlbr();
        cpu_sync_pipeline();
 
        tlbehi = sysreg_read(TLBEHI);
@@ -33,15 +33,17 @@ void show_dtlb_entry(unsigned int index)
 
        printk("%2u: %c %c %02x   %05x %05x %o  %o  %c %c %c %c\n",
               index,
-              (tlbehi & 0x200)?'1':'0',
-              (tlbelo & 0x100)?'1':'0',
-              (tlbehi & 0xff),
-              (tlbehi >> 12), (tlbelo >> 12),
-              (tlbelo >> 4) & 7, (tlbelo >> 2) & 3,
-              (tlbelo & 0x200)?'1':'0',
-              (tlbelo & 0x080)?'1':'0',
-              (tlbelo & 0x001)?'1':'0',
-              (tlbelo & 0x002)?'1':'0');
+              SYSREG_BFEXT(TLBEHI_V, tlbehi) ? '1' : '0',
+              SYSREG_BFEXT(G, tlbelo) ? '1' : '0',
+              SYSREG_BFEXT(ASID, tlbehi),
+              SYSREG_BFEXT(VPN, tlbehi) >> 2,
+              SYSREG_BFEXT(PFN, tlbelo) >> 2,
+              SYSREG_BFEXT(AP, tlbelo),
+              SYSREG_BFEXT(SZ, tlbelo),
+              SYSREG_BFEXT(TLBELO_C, tlbelo) ? 'C' : ' ',
+              SYSREG_BFEXT(B, tlbelo) ? 'B' : ' ',
+              SYSREG_BFEXT(W, tlbelo) ? 'W' : ' ',
+              SYSREG_BFEXT(TLBELO_D, tlbelo) ? 'D' : ' ');
 
        sysreg_write(MMUCR, mmucr_save);
        sysreg_write(TLBEHI, tlbehi_save);
@@ -54,29 +56,33 @@ void dump_dtlb(void)
        unsigned int i;
 
        printk("ID  V G ASID VPN   PFN   AP SZ C B W D\n");
-       for (i = 0; i < 32; i++)
+       for (i = 0; i < NR_TLB_ENTRIES; i++)
                show_dtlb_entry(i);
 }
 
-static unsigned long last_mmucr;
-
-static inline void set_replacement_pointer(unsigned shift)
+static void update_dtlb(unsigned long address, pte_t pte)
 {
-       unsigned long mmucr, mmucr_save;
+       u32 tlbehi;
+       u32 mmucr;
 
-       mmucr = mmucr_save = sysreg_read(MMUCR);
+       /*
+        * We're not changing the ASID here, so no need to flush the
+        * pipeline.
+        */
+       tlbehi = sysreg_read(TLBEHI);
+       tlbehi = SYSREG_BF(ASID, SYSREG_BFEXT(ASID, tlbehi));
+       tlbehi |= address & MMU_VPN_MASK;
+       tlbehi |= SYSREG_BIT(TLBEHI_V);
+       sysreg_write(TLBEHI, tlbehi);
 
        /* Does this mapping already exist? */
-       __asm__ __volatile__(
-               "       tlbs\n"
-               "       mfsr %0, %1"
-               : "=r"(mmucr)
-               : "i"(SYSREG_MMUCR));
+       __builtin_tlbs();
+       mmucr = sysreg_read(MMUCR);
 
        if (mmucr & SYSREG_BIT(MMUCR_N)) {
                /* Not found -- pick a not-recently-accessed entry */
-               unsigned long rp;
-               unsigned long tlbar = sysreg_read(TLBARLO);
+               unsigned int rp;
+               u32 tlbar = sysreg_read(TLBARLO);
 
                rp = 32 - fls(tlbar);
                if (rp == 32) {
@@ -84,30 +90,14 @@ static inline void set_replacement_pointer(unsigned shift)
                        sysreg_write(TLBARLO, -1L);
                }
 
-               mmucr &= 0x13;
-               mmucr |= (rp << shift);
-
+               mmucr = SYSREG_BFINS(DRP, rp, mmucr);
                sysreg_write(MMUCR, mmucr);
        }
 
-       last_mmucr = mmucr;
-}
-
-static void update_dtlb(unsigned long address, pte_t pte, unsigned long asid)
-{
-       unsigned long vpn;
-
-       vpn = (address & MMU_VPN_MASK) | _TLBEHI_VALID | asid;
-       sysreg_write(TLBEHI, vpn);
-       cpu_sync_pipeline();
-
-       set_replacement_pointer(14);
-
        sysreg_write(TLBELO, pte_val(pte) & _PAGE_FLAGS_HARDWARE_MASK);
 
        /* Let's go */
-       asm volatile("nop\n\ttlbw" : : : "memory");
-       cpu_sync_pipeline();
+       __builtin_tlbw();
 }
 
 void update_mmu_cache(struct vm_area_struct *vma,
@@ -120,39 +110,40 @@ void update_mmu_cache(struct vm_area_struct *vma,
                return;
 
        local_irq_save(flags);
-       update_dtlb(address, pte, get_asid());
+       update_dtlb(address, pte);
        local_irq_restore(flags);
 }
 
-void __flush_tlb_page(unsigned long asid, unsigned long page)
+static void __flush_tlb_page(unsigned long asid, unsigned long page)
 {
-       unsigned long mmucr, tlbehi;
+       u32 mmucr, tlbehi;
 
-       page |= asid;
-       sysreg_write(TLBEHI, page);
-       cpu_sync_pipeline();
-       asm volatile("tlbs");
+       /*
+        * Caller is responsible for masking out non-PFN bits in page
+        * and changing the current ASID if necessary. This means that
+        * we don't need to flush the pipeline after writing TLBEHI.
+        */
+       tlbehi = page | asid;
+       sysreg_write(TLBEHI, tlbehi);
+
+       __builtin_tlbs();
        mmucr = sysreg_read(MMUCR);
 
        if (!(mmucr & SYSREG_BIT(MMUCR_N))) {
-               unsigned long tlbarlo;
-               unsigned long entry;
+               unsigned int entry;
+               u32 tlbarlo;
 
                /* Clear the "valid" bit */
-               tlbehi = sysreg_read(TLBEHI);
-               tlbehi &= ~_TLBEHI_VALID;
                sysreg_write(TLBEHI, tlbehi);
-               cpu_sync_pipeline();
 
                /* mark the entry as "not accessed" */
-               entry = (mmucr >> 14) & 0x3f;
+               entry = SYSREG_BFEXT(DRP, mmucr);
                tlbarlo = sysreg_read(TLBARLO);
-               tlbarlo |= (0x80000000 >> entry);
+               tlbarlo |= (0x80000000UL >> entry);
                sysreg_write(TLBARLO, tlbarlo);
 
                /* update the entry with valid bit clear */
-               asm volatile("tlbw");
-               cpu_sync_pipeline();
+               __builtin_tlbw();
        }
 }
 
@@ -190,17 +181,22 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 
                local_irq_save(flags);
                size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+
                if (size > (MMU_DTLB_ENTRIES / 4)) { /* Too many entries to flush */
                        mm->context = NO_CONTEXT;
                        if (mm == current->mm)
                                activate_context(mm);
                } else {
-                       unsigned long asid = mm->context & MMU_CONTEXT_ASID_MASK;
-                       unsigned long saved_asid = MMU_NO_ASID;
+                       unsigned long asid;
+                       unsigned long saved_asid;
+
+                       asid = mm->context & MMU_CONTEXT_ASID_MASK;
+                       saved_asid = MMU_NO_ASID;
 
                        start &= PAGE_MASK;
                        end += (PAGE_SIZE - 1);
                        end &= PAGE_MASK;
+
                        if (mm != current->mm) {
                                saved_asid = get_asid();
                                set_asid(asid);
@@ -218,33 +214,34 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 }
 
 /*
- * TODO: If this is only called for addresses > TASK_SIZE, we can probably
- * skip the ASID stuff and just use the Global bit...
+ * This function depends on the pages to be flushed having the G
+ * (global) bit set in their pte. This is true for all
+ * PAGE_KERNEL(_RO) pages.
  */
 void flush_tlb_kernel_range(unsigned long start, unsigned long end)
 {
        unsigned long flags;
        int size;
 
-       local_irq_save(flags);
        size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
        if (size > (MMU_DTLB_ENTRIES / 4)) { /* Too many entries to flush */
                flush_tlb_all();
        } else {
-               unsigned long asid = init_mm.context & MMU_CONTEXT_ASID_MASK;
-               unsigned long saved_asid = get_asid();
+               unsigned long asid;
+
+               local_irq_save(flags);
+               asid = get_asid();
 
                start &= PAGE_MASK;
                end += (PAGE_SIZE - 1);
                end &= PAGE_MASK;
-               set_asid(asid);
+
                while (start < end) {
                        __flush_tlb_page(asid, start);
                        start += PAGE_SIZE;
                }
-               set_asid(saved_asid);
+               local_irq_restore(flags);
        }
-       local_irq_restore(flags);
 }
 
 void flush_tlb_mm(struct mm_struct *mm)
@@ -280,7 +277,7 @@ static void *tlb_start(struct seq_file *tlb, loff_t *pos)
 {
        static unsigned long tlb_index;
 
-       if (*pos >= 32)
+       if (*pos >= NR_TLB_ENTRIES)
                return NULL;
 
        tlb_index = 0;
@@ -291,7 +288,7 @@ static void *tlb_next(struct seq_file *tlb, void *v, loff_t *pos)
 {
        unsigned long *index = v;
 
-       if (*index >= 31)
+       if (*index >= NR_TLB_ENTRIES - 1)
                return NULL;
 
        ++*pos;
@@ -313,16 +310,16 @@ static int tlb_show(struct seq_file *tlb, void *v)
        if (*index == 0)
                seq_puts(tlb, "ID  V G ASID VPN   PFN   AP SZ C B W D\n");
 
-       BUG_ON(*index >= 32);
+       BUG_ON(*index >= NR_TLB_ENTRIES);
 
        local_irq_save(flags);
        mmucr_save = sysreg_read(MMUCR);
        tlbehi_save = sysreg_read(TLBEHI);
-       mmucr = mmucr_save & 0x13;
-       mmucr |= *index << 14;
+       mmucr = SYSREG_BFINS(DRP, *index, mmucr_save);
        sysreg_write(MMUCR, mmucr);
 
-       asm volatile("tlbr" : : : "memory");
+       /* TLBR might change the ASID */
+       __builtin_tlbr();
        cpu_sync_pipeline();
 
        tlbehi = sysreg_read(TLBEHI);
@@ -334,16 +331,18 @@ static int tlb_show(struct seq_file *tlb, void *v)
        local_irq_restore(flags);
 
        seq_printf(tlb, "%2lu: %c %c %02x   %05x %05x %o  %o  %c %c %c %c\n",
-              *index,
-              (tlbehi & 0x200)?'1':'0',
-              (tlbelo & 0x100)?'1':'0',
-              (tlbehi & 0xff),
-              (tlbehi >> 12), (tlbelo >> 12),
-              (tlbelo >> 4) & 7, (tlbelo >> 2) & 3,
-              (tlbelo & 0x200)?'1':'0',
-              (tlbelo & 0x080)?'1':'0',
-              (tlbelo & 0x001)?'1':'0',
-              (tlbelo & 0x002)?'1':'0');
+                  *index,
+                  SYSREG_BFEXT(TLBEHI_V, tlbehi) ? '1' : '0',
+                  SYSREG_BFEXT(G, tlbelo) ? '1' : '0',
+                  SYSREG_BFEXT(ASID, tlbehi),
+                  SYSREG_BFEXT(VPN, tlbehi) >> 2,
+                  SYSREG_BFEXT(PFN, tlbelo) >> 2,
+                  SYSREG_BFEXT(AP, tlbelo),
+                  SYSREG_BFEXT(SZ, tlbelo),
+                  SYSREG_BFEXT(TLBELO_C, tlbelo) ? '1' : '0',
+                  SYSREG_BFEXT(B, tlbelo) ? '1' : '0',
+                  SYSREG_BFEXT(W, tlbelo) ? '1' : '0',
+                  SYSREG_BFEXT(TLBELO_D, tlbelo) ? '1' : '0');
 
        return 0;
 }
index 0d5ce03cdff24cf5d683a3750bb2a56ba397b6e1..5b5a14dab3d38d5e77a26381f849d2e26822934c 100644 (file)
@@ -332,7 +332,7 @@ static int __init pwm_probe(struct platform_device *pdev)
        p->base = ioremap(r->start, r->end - r->start + 1);
        if (!p->base)
                goto fail;
-       p->clk = clk_get(&pdev->dev, "mck");
+       p->clk = clk_get(&pdev->dev, "pwm_clk");
        if (IS_ERR(p->clk)) {
                status = PTR_ERR(p->clk);
                p->clk = NULL;
index 92dccd43bdcab39fbd0bcd374d3447a33961443c..0a5745a854c7bbbe562a5f4e7b88e464a8891b0d 100644 (file)
@@ -1277,8 +1277,45 @@ static int __exit macb_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int macb_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct net_device *netdev = platform_get_drvdata(pdev);
+       struct macb *bp = netdev_priv(netdev);
+
+       netif_device_detach(netdev);
+
+#ifndef CONFIG_ARCH_AT91
+       clk_disable(bp->hclk);
+#endif
+       clk_disable(bp->pclk);
+
+       return 0;
+}
+
+static int macb_resume(struct platform_device *pdev)
+{
+       struct net_device *netdev = platform_get_drvdata(pdev);
+       struct macb *bp = netdev_priv(netdev);
+
+       clk_enable(bp->pclk);
+#ifndef CONFIG_ARCH_AT91
+       clk_enable(bp->hclk);
+#endif
+
+       netif_device_attach(netdev);
+
+       return 0;
+}
+#else
+#define macb_suspend   NULL
+#define macb_resume    NULL
+#endif
+
 static struct platform_driver macb_driver = {
        .remove         = __exit_p(macb_remove),
+       .suspend        = macb_suspend,
+       .resume         = macb_resume,
        .driver         = {
                .name           = "macb",
                .owner  = THIS_MODULE,
index 2ef8cdfda4a74fd506cae8b5cd2d9d14971b4cc4..90b9a6503e1561d2576dbb4ab74bd830bc40e4b4 100644 (file)
@@ -265,6 +265,7 @@ static int __init at32_rtc_probe(struct platform_device *pdev)
        }
 
        platform_set_drvdata(pdev, rtc);
+       device_init_wakeup(&pdev->dev, 1);
 
        dev_info(&pdev->dev, "Atmel RTC for AT32AP700x at %08lx irq %ld\n",
                        (unsigned long)rtc->regs, rtc->irq);
@@ -284,6 +285,8 @@ static int __exit at32_rtc_remove(struct platform_device *pdev)
 {
        struct rtc_at32ap700x *rtc = platform_get_drvdata(pdev);
 
+       device_init_wakeup(&pdev->dev, 0);
+
        free_irq(rtc->irq, rtc);
        iounmap(rtc->regs);
        rtc_device_unregister(rtc->rtc);
index 42be8b01a40f33210541c0c6bd1528e0314e6678..6aeef22bd2039ea41fbfc2cc6062dbb4c03cd83e 100644 (file)
@@ -1439,14 +1439,29 @@ static struct uart_driver atmel_uart = {
 };
 
 #ifdef CONFIG_PM
+static bool atmel_serial_clk_will_stop(void)
+{
+#ifdef CONFIG_ARCH_AT91
+       return at91_suspend_entering_slow_clock();
+#else
+       return false;
+#endif
+}
+
 static int atmel_serial_suspend(struct platform_device *pdev,
                                pm_message_t state)
 {
        struct uart_port *port = platform_get_drvdata(pdev);
        struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 
+       if (atmel_is_console_port(port) && console_suspend_enabled) {
+               /* Drain the TX shifter */
+               while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY))
+                       cpu_relax();
+       }
+
        if (device_may_wakeup(&pdev->dev)
-           && !at91_suspend_entering_slow_clock())
+           && !atmel_serial_clk_will_stop())
                enable_irq_wake(port->irq);
        else {
                uart_suspend_port(&atmel_uart, port);
index a4e2d28bfb5884c52af09f110fa543d776386f57..b4cddfaca90ec7d42b7637eb7a46c86887d8657f 100644 (file)
@@ -8,6 +8,12 @@
 
 #define GPIO_PIN_NONE  (-1)
 
+/*
+ * Clock rates for various on-board oscillators. The number of entries
+ * in this array is chip-dependent.
+ */
+extern unsigned long at32_board_osc_rates[];
+  
 /* Add basic devices: system manager, interrupt controller, portmuxes, etc. */
 void at32_add_system_devices(void);
 
@@ -36,7 +42,8 @@ at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n);
 struct atmel_lcdfb_info;
 struct platform_device *
 at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
-                    unsigned long fbmem_start, unsigned long fbmem_len);
+                    unsigned long fbmem_start, unsigned long fbmem_len,
+                    unsigned int pin_config);
 
 struct usba_platform_data;
 struct platform_device *
@@ -73,6 +80,7 @@ struct platform_device *at32_add_device_twi(unsigned int id,
 struct platform_device *at32_add_device_mci(unsigned int id);
 struct platform_device *at32_add_device_ac97c(unsigned int id);
 struct platform_device *at32_add_device_abdac(unsigned int id);
+struct platform_device *at32_add_device_psif(unsigned int id);
 
 struct cf_platform_data {
        int     detect_pin;
index 5e75d850d7076409ecd6fea47adfb36412736886..bc40e3d461503aa9a77c344e8d9aba520d7dc541 100644 (file)
 void setup_platform(void);
 void setup_board(void);
 
-/* Called by setup_platform */
-void at32_clock_init(void);
-void at32_portmux_init(void);
-
 void at32_setup_serial_console(unsigned int usart_id);
 
 #endif /* __ASM_AVR32_AT32AP_INIT_H__ */
index 356e43064903cdb48d9b2d8f00468585a16bc970..979b355b77b652c3946d0e22db820c4d3dd142cd 100644 (file)
@@ -19,6 +19,7 @@
 
 #ifndef __ASSEMBLY__
 extern void cpu_enter_idle(void);
+extern void cpu_enter_standby(unsigned long sdramc_base);
 
 extern bool disable_idle_sleep;
 
@@ -43,6 +44,8 @@ static inline void cpu_idle_sleep(void)
        else
                cpu_enter_idle();
 }
+
+void intc_set_suspend_handler(unsigned long offset);
 #endif
 
 #endif /* __ASM_AVR32_ARCH_PM_H */
diff --git a/include/asm-avr32/arch-at32ap/sram.h b/include/asm-avr32/arch-at32ap/sram.h
new file mode 100644 (file)
index 0000000..4838dae
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Simple SRAM allocator
+ *
+ * Copyright (C) 2008 Atmel Corporation
+ *
+ * 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 __ASM_AVR32_ARCH_SRAM_H
+#define __ASM_AVR32_ARCH_SRAM_H
+
+#include <linux/genalloc.h>
+
+extern struct gen_pool *sram_pool;
+
+static inline unsigned long sram_alloc(size_t len)
+{
+       if (!sram_pool)
+               return 0UL;
+
+       return gen_pool_alloc(sram_pool, len);
+}
+
+static inline void sram_free(unsigned long addr, size_t len)
+{
+       return gen_pool_free(sram_pool, addr, len);
+}
+
+#endif /* __ASM_AVR32_ARCH_SRAM_H */
index c37c391faef6b0f67d50cbe1bfed504dbdc9d36f..27ff234071009b19e9f5f5dbeeadc52cefbcf0e1 100644 (file)
@@ -13,7 +13,6 @@
 #define __ASM_AVR32_MMU_CONTEXT_H
 
 #include <asm/tlbflush.h>
-#include <asm/pgalloc.h>
 #include <asm/sysreg.h>
 #include <asm-generic/mm_hooks.h>
 
index 0f5f134b896a132635b412c83a772ba86ea78fa6..a32a02372017443d24db8848d2a559c548b1f13e 100644 (file)
@@ -5,4 +5,6 @@
 
 #define PCI_DMA_BUS_IS_PHYS    (1)
 
+#include <asm-generic/pci-dma-compat.h>
+
 #endif /* __ASM_AVR32_PCI_H__ */
index 51fc1f6e4b17afb9d73b7065ad6bea459549d205..64082132394312a4c861abdc6b110f58517a7a40 100644 (file)
@@ -8,65 +8,79 @@
 #ifndef __ASM_AVR32_PGALLOC_H
 #define __ASM_AVR32_PGALLOC_H
 
-#include <asm/processor.h>
-#include <linux/threads.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
+#include <linux/quicklist.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
 
-#define pmd_populate_kernel(mm, pmd, pte) \
-       set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte)))
+#define QUICK_PGD      0       /* Preserve kernel mappings over free */
+#define QUICK_PT       1       /* Zero on free */
 
-static __inline__ void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
+static inline void pmd_populate_kernel(struct mm_struct *mm,
+                                      pmd_t *pmd, pte_t *pte)
+{
+       set_pmd(pmd, __pmd((unsigned long)pte));
+}
+
+static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
                                    pgtable_t pte)
 {
-       set_pmd(pmd, __pmd(_PAGE_TABLE + page_to_phys(pte)));
+       set_pmd(pmd, __pmd((unsigned long)page_address(pte)));
 }
 #define pmd_pgtable(pmd) pmd_page(pmd)
 
+static inline void pgd_ctor(void *x)
+{
+       pgd_t *pgd = x;
+
+       memcpy(pgd + USER_PTRS_PER_PGD,
+               swapper_pg_dir + USER_PTRS_PER_PGD,
+               (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+}
+
 /*
  * Allocate and free page tables
  */
-static __inline__ pgd_t *pgd_alloc(struct mm_struct *mm)
+static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 {
-       return kcalloc(USER_PTRS_PER_PGD, sizeof(pgd_t), GFP_KERNEL);
+       return quicklist_alloc(QUICK_PGD, GFP_KERNEL | __GFP_REPEAT, pgd_ctor);
 }
 
 static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
-       kfree(pgd);
+       quicklist_free(QUICK_PGD, NULL, pgd);
 }
 
 static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
                                          unsigned long address)
 {
-       pte_t *pte;
-
-       pte = (pte_t *)get_zeroed_page(GFP_KERNEL | __GFP_REPEAT);
-
-       return pte;
+       return quicklist_alloc(QUICK_PT, GFP_KERNEL | __GFP_REPEAT, NULL);
 }
 
-static inline struct page *pte_alloc_one(struct mm_struct *mm,
+static inline pgtable_t pte_alloc_one(struct mm_struct *mm,
                                         unsigned long address)
 {
-       struct page *pte;
+       struct page *page;
+       void *pg;
 
-       pte = alloc_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
-       if (!pte)
+       pg = quicklist_alloc(QUICK_PT, GFP_KERNEL | __GFP_REPEAT, NULL);
+       if (!pg)
                return NULL;
-       pgtable_page_ctor(pte);
-       return pte;
+
+       page = virt_to_page(pg);
+       pgtable_page_ctor(page);
+
+       return page;
 }
 
 static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
 {
-       free_page((unsigned long)pte);
+       quicklist_free(QUICK_PT, NULL, pte);
 }
 
 static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
 {
        pgtable_page_dtor(pte);
-       __free_page(pte);
+       quicklist_free_page(QUICK_PT, NULL, pte);
 }
 
 #define __pte_free_tlb(tlb,pte)                                \
@@ -75,6 +89,10 @@ do {                                                 \
        tlb_remove_page((tlb), pte);                    \
 } while (0)
 
-#define check_pgt_cache() do { } while(0)
+static inline void check_pgt_cache(void)
+{
+       quicklist_trim(QUICK_PGD, NULL, 25, 16);
+       quicklist_trim(QUICK_PT, NULL, 25, 16);
+}
 
 #endif /* __ASM_AVR32_PGALLOC_H */
index c0e5e29417df5454d9b286d32d326010ebcef463..fecdda16f4443a7ed957690eeb5ec57cd5d4f5ae 100644 (file)
@@ -129,13 +129,6 @@ extern struct page *empty_zero_page;
 
 #define _PAGE_FLAGS_CACHE_MASK (_PAGE_CACHABLE | _PAGE_BUFFER | _PAGE_WT)
 
-/* TODO: Check for saneness */
-/* User-mode page table flags (to be set in a pgd or pmd entry) */
-#define _PAGE_TABLE            (_PAGE_PRESENT | _PAGE_TYPE_SMALL | _PAGE_RW \
-                                | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
-/* Kernel-mode page table flags */
-#define _KERNPG_TABLE          (_PAGE_PRESENT | _PAGE_TYPE_SMALL | _PAGE_RW \
-                                | _PAGE_ACCESSED | _PAGE_DIRTY)
 /* Flags that may be modified by software */
 #define _PAGE_CHG_MASK         (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY \
                                 | _PAGE_FLAGS_CACHE_MASK)
@@ -262,10 +255,14 @@ static inline pte_t pte_mkspecial(pte_t pte)
 }
 
 #define pmd_none(x)    (!pmd_val(x))
-#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT)
-#define pmd_clear(xp)  do { set_pmd(xp, __pmd(0)); } while (0)
-#define        pmd_bad(x)      ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER))      \
-                        != _KERNPG_TABLE)
+#define pmd_present(x) (pmd_val(x))
+
+static inline void pmd_clear(pmd_t *pmdp)
+{
+       set_pmd(pmdp, __pmd(0));
+}
+
+#define        pmd_bad(x)      (pmd_val(x) & ~PAGE_MASK)
 
 /*
  * Permanent address of a page. We don't support highmem, so this is
@@ -303,19 +300,16 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 
 #define page_pte(page) page_pte_prot(page, __pgprot(0))
 
-#define pmd_page_vaddr(pmd)                                    \
-       ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
-
-#define pmd_page(pmd)  (phys_to_page(pmd_val(pmd)))
+#define pmd_page_vaddr(pmd)    pmd_val(pmd)
+#define pmd_page(pmd)          (virt_to_page(pmd_val(pmd)))
 
 /* to find an entry in a page-table-directory. */
-#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
-#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address))
-#define pgd_offset_current(address)                            \
-       ((pgd_t *)__mfsr(SYSREG_PTBR) + pgd_index(address))
+#define pgd_index(address)     (((address) >> PGDIR_SHIFT)     \
+                                & (PTRS_PER_PGD - 1))
+#define pgd_offset(mm, address)        ((mm)->pgd + pgd_index(address))
 
 /* to find an entry in a kernel page-table-directory */
-#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+#define pgd_offset_k(address)  pgd_offset(&init_mm, address)
 
 /* Find an entry in the third-level page table.. */
 #define pte_index(address)                             \
index 07049f6c0d41a168ba057eae80247a0f8727b03e..df68631b7b27f98f63e579a3a20940a544f84f6a 100644 (file)
@@ -88,6 +88,7 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_MEMDIE             6
 #define TIF_RESTORE_SIGMASK    7       /* restore signal mask in do_signal */
 #define TIF_CPU_GOING_TO_SLEEP 8       /* CPU is entering sleep 0 mode */
+#define TIF_FREEZE             29
 #define TIF_DEBUG              30      /* debugging enabled */
 #define TIF_USERSPACE          31      /* true if FS sets userspace */
 
index 5bc7c88a5770a9c211d8aa6d32c2b04ed4186166..bf90a786f6be93dcda8aa4f1a1c06697a87f8b8f 100644 (file)
@@ -26,7 +26,6 @@ extern void flush_tlb_mm(struct mm_struct *mm);
 extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
                            unsigned long end);
 extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
-extern void __flush_tlb_page(unsigned long asid, unsigned long page);
 
 extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
 
index 4242743b981bcd2e8a864e43769831701e0fa44c..c4de85285bb43cd2ab9810d42c67c8001d9adb1b 100644 (file)
@@ -199,7 +199,7 @@ config BOUNCE
 config NR_QUICK
        int
        depends on QUICKLIST
-       default "2" if SUPERH
+       default "2" if SUPERH || AVR32
        default "1"
 
 config VIRT_TO_BUS