aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-07-14 16:37:29 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-14 16:37:29 -0400
commit6c118e43dc513a7118b49b9ff953fe61e14515dc (patch)
treeef654ba1982c17a516697d25b3d0405acb6aeac1 /arch
parent847106ff628805e1a0aa91e7f53381f3fdfcd839 (diff)
parent72f6befeea7dc634a83219287d5b874734b85637 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/hskinnemoen/avr32-2.6
* 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 ...
Diffstat (limited to 'arch')
-rw-r--r--arch/avr32/Kconfig9
-rw-r--r--arch/avr32/boards/atngw100/setup.c29
-rw-r--r--arch/avr32/boards/atstk1000/atstk1002.c8
-rw-r--r--arch/avr32/boards/atstk1000/atstk1003.c7
-rw-r--r--arch/avr32/boards/atstk1000/atstk1004.c9
-rw-r--r--arch/avr32/kernel/entry-avr32b.S88
-rw-r--r--arch/avr32/kernel/signal.c3
-rw-r--r--arch/avr32/kernel/time.c14
-rw-r--r--arch/avr32/kernel/vmlinux.lds.S12
-rw-r--r--arch/avr32/lib/io-readsb.S2
-rw-r--r--arch/avr32/mach-at32ap/Makefile7
-rw-r--r--arch/avr32/mach-at32ap/at32ap700x.c252
-rw-r--r--arch/avr32/mach-at32ap/intc.c80
-rw-r--r--arch/avr32/mach-at32ap/pdc.c (renamed from arch/avr32/mach-at32ap/at32ap.c)8
-rw-r--r--arch/avr32/mach-at32ap/pio.c2
-rw-r--r--arch/avr32/mach-at32ap/pio.h2
-rw-r--r--arch/avr32/mach-at32ap/pm-at32ap700x.S108
-rw-r--r--arch/avr32/mach-at32ap/pm.c245
-rw-r--r--arch/avr32/mach-at32ap/sdramc.h76
-rw-r--r--arch/avr32/mm/init.c22
-rw-r--r--arch/avr32/mm/tlb.c175
21 files changed, 933 insertions, 225 deletions
diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig
index 09ad7995080c..45d63c986015 100644
--- a/arch/avr32/Kconfig
+++ b/arch/avr32/Kconfig
@@ -88,6 +88,7 @@ config PLATFORM_AT32AP
88 select MMU 88 select MMU
89 select PERFORMANCE_COUNTERS 89 select PERFORMANCE_COUNTERS
90 select HAVE_GPIO_LIB 90 select HAVE_GPIO_LIB
91 select GENERIC_ALLOCATOR
91 92
92# 93#
93# CPU types 94# CPU types
@@ -147,6 +148,9 @@ config PHYS_OFFSET
147 148
148source "kernel/Kconfig.preempt" 149source "kernel/Kconfig.preempt"
149 150
151config QUICKLIST
152 def_bool y
153
150config HAVE_ARCH_BOOTMEM_NODE 154config HAVE_ARCH_BOOTMEM_NODE
151 def_bool n 155 def_bool n
152 156
@@ -201,6 +205,11 @@ endmenu
201 205
202menu "Power management options" 206menu "Power management options"
203 207
208source "kernel/power/Kconfig"
209
210config ARCH_SUSPEND_POSSIBLE
211 def_bool y
212
204menu "CPU Frequency scaling" 213menu "CPU Frequency scaling"
205 214
206source "drivers/cpufreq/Kconfig" 215source "drivers/cpufreq/Kconfig"
diff --git a/arch/avr32/boards/atngw100/setup.c b/arch/avr32/boards/atngw100/setup.c
index a398be284966..a51bb9fb3c89 100644
--- a/arch/avr32/boards/atngw100/setup.c
+++ b/arch/avr32/boards/atngw100/setup.c
@@ -9,6 +9,8 @@
9 */ 9 */
10#include <linux/clk.h> 10#include <linux/clk.h>
11#include <linux/etherdevice.h> 11#include <linux/etherdevice.h>
12#include <linux/irq.h>
13#include <linux/i2c.h>
12#include <linux/i2c-gpio.h> 14#include <linux/i2c-gpio.h>
13#include <linux/init.h> 15#include <linux/init.h>
14#include <linux/linkage.h> 16#include <linux/linkage.h>
@@ -25,6 +27,13 @@
25#include <asm/arch/init.h> 27#include <asm/arch/init.h>
26#include <asm/arch/portmux.h> 28#include <asm/arch/portmux.h>
27 29
30/* Oscillator frequencies. These are board-specific */
31unsigned long at32_board_osc_rates[3] = {
32 [0] = 32768, /* 32.768 kHz on RTC osc */
33 [1] = 20000000, /* 20 MHz on osc0 */
34 [2] = 12000000, /* 12 MHz on osc1 */
35};
36
28/* Initialized by bootloader-specific startup code. */ 37/* Initialized by bootloader-specific startup code. */
29struct tag *bootloader_tags __initdata; 38struct tag *bootloader_tags __initdata;
30 39
@@ -140,6 +149,10 @@ static struct platform_device i2c_gpio_device = {
140 }, 149 },
141}; 150};
142 151
152static struct i2c_board_info __initdata i2c_info[] = {
153 /* NOTE: original ATtiny24 firmware is at address 0x0b */
154};
155
143static int __init atngw100_init(void) 156static int __init atngw100_init(void)
144{ 157{
145 unsigned i; 158 unsigned i;
@@ -165,12 +178,28 @@ static int __init atngw100_init(void)
165 } 178 }
166 platform_device_register(&ngw_gpio_leds); 179 platform_device_register(&ngw_gpio_leds);
167 180
181 /* all these i2c/smbus pins should have external pullups for
182 * open-drain sharing among all I2C devices. SDA and SCL do;
183 * PB28/EXTINT3 doesn't; it should be SMBALERT# (for PMBus),
184 * but it's not available off-board.
185 */
186 at32_select_periph(GPIO_PIN_PB(28), 0, AT32_GPIOF_PULLUP);
168 at32_select_gpio(i2c_gpio_data.sda_pin, 187 at32_select_gpio(i2c_gpio_data.sda_pin,
169 AT32_GPIOF_MULTIDRV | AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH); 188 AT32_GPIOF_MULTIDRV | AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
170 at32_select_gpio(i2c_gpio_data.scl_pin, 189 at32_select_gpio(i2c_gpio_data.scl_pin,
171 AT32_GPIOF_MULTIDRV | AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH); 190 AT32_GPIOF_MULTIDRV | AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
172 platform_device_register(&i2c_gpio_device); 191 platform_device_register(&i2c_gpio_device);
192 i2c_register_board_info(0, i2c_info, ARRAY_SIZE(i2c_info));
173 193
174 return 0; 194 return 0;
175} 195}
176postcore_initcall(atngw100_init); 196postcore_initcall(atngw100_init);
197
198static int __init atngw100_arch_init(void)
199{
200 /* set_irq_type() after the arch_initcall for EIC has run, and
201 * before the I2C subsystem could try using this IRQ.
202 */
203 return set_irq_type(AT32_EXTINT(3), IRQ_TYPE_EDGE_FALLING);
204}
205arch_initcall(atngw100_arch_init);
diff --git a/arch/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c
index 000eb4220a12..86b363c1c25b 100644
--- a/arch/avr32/boards/atstk1000/atstk1002.c
+++ b/arch/avr32/boards/atstk1000/atstk1002.c
@@ -28,6 +28,12 @@
28 28
29#include "atstk1000.h" 29#include "atstk1000.h"
30 30
31/* Oscillator frequencies. These are board specific */
32unsigned long at32_board_osc_rates[3] = {
33 [0] = 32768, /* 32.768 kHz on RTC osc */
34 [1] = 20000000, /* 20 MHz on osc0 */
35 [2] = 12000000, /* 12 MHz on osc1 */
36};
31 37
32struct eth_addr { 38struct eth_addr {
33 u8 addr[6]; 39 u8 addr[6];
@@ -232,7 +238,7 @@ static int __init atstk1002_init(void)
232 set_hw_addr(at32_add_device_eth(1, &eth_data[1])); 238 set_hw_addr(at32_add_device_eth(1, &eth_data[1]));
233#else 239#else
234 at32_add_device_lcdc(0, &atstk1000_lcdc_data, 240 at32_add_device_lcdc(0, &atstk1000_lcdc_data,
235 fbmem_start, fbmem_size); 241 fbmem_start, fbmem_size, 0);
236#endif 242#endif
237 at32_add_device_usba(0, NULL); 243 at32_add_device_usba(0, NULL);
238#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM 244#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
diff --git a/arch/avr32/boards/atstk1000/atstk1003.c b/arch/avr32/boards/atstk1000/atstk1003.c
index a0b223df35a2..ea109f435a83 100644
--- a/arch/avr32/boards/atstk1000/atstk1003.c
+++ b/arch/avr32/boards/atstk1000/atstk1003.c
@@ -27,6 +27,13 @@
27 27
28#include "atstk1000.h" 28#include "atstk1000.h"
29 29
30/* Oscillator frequencies. These are board specific */
31unsigned long at32_board_osc_rates[3] = {
32 [0] = 32768, /* 32.768 kHz on RTC osc */
33 [1] = 20000000, /* 20 MHz on osc0 */
34 [2] = 12000000, /* 12 MHz on osc1 */
35};
36
30#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC 37#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
31static struct at73c213_board_info at73c213_data = { 38static struct at73c213_board_info at73c213_data = {
32 .ssc_id = 0, 39 .ssc_id = 0,
diff --git a/arch/avr32/boards/atstk1000/atstk1004.c b/arch/avr32/boards/atstk1000/atstk1004.c
index e765a8652b3e..c7236df74d74 100644
--- a/arch/avr32/boards/atstk1000/atstk1004.c
+++ b/arch/avr32/boards/atstk1000/atstk1004.c
@@ -29,6 +29,13 @@
29 29
30#include "atstk1000.h" 30#include "atstk1000.h"
31 31
32/* Oscillator frequencies. These are board specific */
33unsigned long at32_board_osc_rates[3] = {
34 [0] = 32768, /* 32.768 kHz on RTC osc */
35 [1] = 20000000, /* 20 MHz on osc0 */
36 [2] = 12000000, /* 12 MHz on osc1 */
37};
38
32#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC 39#ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
33static struct at73c213_board_info at73c213_data = { 40static struct at73c213_board_info at73c213_data = {
34 .ssc_id = 0, 41 .ssc_id = 0,
@@ -133,7 +140,7 @@ static int __init atstk1004_init(void)
133 at32_add_device_mci(0); 140 at32_add_device_mci(0);
134#endif 141#endif
135 at32_add_device_lcdc(0, &atstk1000_lcdc_data, 142 at32_add_device_lcdc(0, &atstk1000_lcdc_data,
136 fbmem_start, fbmem_size); 143 fbmem_start, fbmem_size, 0);
137 at32_add_device_usba(0, NULL); 144 at32_add_device_usba(0, NULL);
138#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM 145#ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
139 at32_add_device_ssc(0, ATMEL_SSC_TX); 146 at32_add_device_ssc(0, ATMEL_SSC_TX);
diff --git a/arch/avr32/kernel/entry-avr32b.S b/arch/avr32/kernel/entry-avr32b.S
index 5f31702d6b1c..2b398cae110c 100644
--- a/arch/avr32/kernel/entry-avr32b.S
+++ b/arch/avr32/kernel/entry-avr32b.S
@@ -74,50 +74,41 @@ exception_vectors:
74 .align 2 74 .align 2
75 bral do_dtlb_modified 75 bral do_dtlb_modified
76 76
77 /*
78 * r0 : PGD/PT/PTE
79 * r1 : Offending address
80 * r2 : Scratch register
81 * r3 : Cause (5, 12 or 13)
82 */
83#define tlbmiss_save pushm r0-r3 77#define tlbmiss_save pushm r0-r3
84#define tlbmiss_restore popm r0-r3 78#define tlbmiss_restore popm r0-r3
85 79
86 .section .tlbx.ex.text,"ax",@progbits 80 .org 0x50
87 .global itlb_miss 81 .global itlb_miss
88itlb_miss: 82itlb_miss:
89 tlbmiss_save 83 tlbmiss_save
90 rjmp tlb_miss_common 84 rjmp tlb_miss_common
91 85
92 .section .tlbr.ex.text,"ax",@progbits 86 .org 0x60
93dtlb_miss_read: 87dtlb_miss_read:
94 tlbmiss_save 88 tlbmiss_save
95 rjmp tlb_miss_common 89 rjmp tlb_miss_common
96 90
97 .section .tlbw.ex.text,"ax",@progbits 91 .org 0x70
98dtlb_miss_write: 92dtlb_miss_write:
99 tlbmiss_save 93 tlbmiss_save
100 94
101 .global tlb_miss_common 95 .global tlb_miss_common
96 .align 2
102tlb_miss_common: 97tlb_miss_common:
103 mfsr r0, SYSREG_TLBEAR 98 mfsr r0, SYSREG_TLBEAR
104 mfsr r1, SYSREG_PTBR 99 mfsr r1, SYSREG_PTBR
105 100
106 /* Is it the vmalloc space? */ 101 /*
107 bld r0, 31 102 * First level lookup: The PGD contains virtual pointers to
108 brcs handle_vmalloc_miss 103 * the second-level page tables, but they may be NULL if not
109 104 * present.
110 /* First level lookup */ 105 */
111pgtbl_lookup: 106pgtbl_lookup:
112 lsr r2, r0, PGDIR_SHIFT 107 lsr r2, r0, PGDIR_SHIFT
113 ld.w r3, r1[r2 << 2] 108 ld.w r3, r1[r2 << 2]
114 bfextu r1, r0, PAGE_SHIFT, PGDIR_SHIFT - PAGE_SHIFT 109 bfextu r1, r0, PAGE_SHIFT, PGDIR_SHIFT - PAGE_SHIFT
115 bld r3, _PAGE_BIT_PRESENT 110 cp.w r3, 0
116 brcc page_table_not_present 111 breq page_table_not_present
117
118 /* Translate to virtual address in P1. */
119 andl r3, 0xf000
120 sbr r3, 31
121 112
122 /* Second level lookup */ 113 /* Second level lookup */
123 ld.w r2, r3[r1 << 2] 114 ld.w r2, r3[r1 << 2]
@@ -148,16 +139,55 @@ pgtbl_lookup:
148 tlbmiss_restore 139 tlbmiss_restore
149 rete 140 rete
150 141
151handle_vmalloc_miss: 142 /* The slow path of the TLB miss handler */
152 /* Simply do the lookup in init's page table */ 143 .align 2
144page_table_not_present:
145 /* Do we need to synchronize with swapper_pg_dir? */
146 bld r0, 31
147 brcs sync_with_swapper_pg_dir
148
149page_not_present:
150 tlbmiss_restore
151 sub sp, 4
152 stmts --sp, r0-lr
153 rcall save_full_context_ex
154 mfsr r12, SYSREG_ECR
155 mov r11, sp
156 rcall do_page_fault
157 rjmp ret_from_exception
158
159 .align 2
160sync_with_swapper_pg_dir:
161 /*
162 * If swapper_pg_dir contains a non-NULL second-level page
163 * table pointer, copy it into the current PGD. If not, we
164 * must handle it as a full-blown page fault.
165 *
166 * Jumping back to pgtbl_lookup causes an unnecessary lookup,
167 * but it is guaranteed to be a cache hit, it won't happen
168 * very often, and we absolutely do not want to sacrifice any
169 * performance in the fast path in order to improve this.
170 */
153 mov r1, lo(swapper_pg_dir) 171 mov r1, lo(swapper_pg_dir)
154 orh r1, hi(swapper_pg_dir) 172 orh r1, hi(swapper_pg_dir)
173 ld.w r3, r1[r2 << 2]
174 cp.w r3, 0
175 breq page_not_present
176 mfsr r1, SYSREG_PTBR
177 st.w r1[r2 << 2], r3
155 rjmp pgtbl_lookup 178 rjmp pgtbl_lookup
156 179
180 /*
181 * We currently have two bytes left at this point until we
182 * crash into the system call handler...
183 *
184 * Don't worry, the assembler will let us know.
185 */
186
157 187
158 /* --- System Call --- */ 188 /* --- System Call --- */
159 189
160 .section .scall.text,"ax",@progbits 190 .org 0x100
161system_call: 191system_call:
162#ifdef CONFIG_PREEMPT 192#ifdef CONFIG_PREEMPT
163 mask_interrupts 193 mask_interrupts
@@ -266,18 +296,6 @@ syscall_exit_work:
266 brcc syscall_exit_cont 296 brcc syscall_exit_cont
267 rjmp enter_monitor_mode 297 rjmp enter_monitor_mode
268 298
269 /* The slow path of the TLB miss handler */
270page_table_not_present:
271page_not_present:
272 tlbmiss_restore
273 sub sp, 4
274 stmts --sp, r0-lr
275 rcall save_full_context_ex
276 mfsr r12, SYSREG_ECR
277 mov r11, sp
278 rcall do_page_fault
279 rjmp ret_from_exception
280
281 /* This function expects to find offending PC in SYSREG_RAR_EX */ 299 /* This function expects to find offending PC in SYSREG_RAR_EX */
282 .type save_full_context_ex, @function 300 .type save_full_context_ex, @function
283 .align 2 301 .align 2
diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c
index 5616a00c10ba..c5b11f9067f1 100644
--- a/arch/avr32/kernel/signal.c
+++ b/arch/avr32/kernel/signal.c
@@ -93,6 +93,9 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
93 if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) 93 if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
94 goto badframe; 94 goto badframe;
95 95
96 if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT)
97 goto badframe;
98
96 pr_debug("Context restored: pc = %08lx, lr = %08lx, sp = %08lx\n", 99 pr_debug("Context restored: pc = %08lx, lr = %08lx, sp = %08lx\n",
97 regs->pc, regs->lr, regs->sp); 100 regs->pc, regs->lr, regs->sp);
98 101
diff --git a/arch/avr32/kernel/time.c b/arch/avr32/kernel/time.c
index 00a9862380ff..abd954fb7ba0 100644
--- a/arch/avr32/kernel/time.c
+++ b/arch/avr32/kernel/time.c
@@ -7,21 +7,13 @@
7 */ 7 */
8#include <linux/clk.h> 8#include <linux/clk.h>
9#include <linux/clockchips.h> 9#include <linux/clockchips.h>
10#include <linux/time.h> 10#include <linux/init.h>
11#include <linux/module.h>
12#include <linux/interrupt.h> 11#include <linux/interrupt.h>
13#include <linux/irq.h> 12#include <linux/irq.h>
14#include <linux/kernel_stat.h> 13#include <linux/kernel.h>
15#include <linux/errno.h> 14#include <linux/time.h>
16#include <linux/init.h>
17#include <linux/profile.h>
18#include <linux/sysdev.h>
19#include <linux/err.h>
20 15
21#include <asm/div64.h>
22#include <asm/sysreg.h> 16#include <asm/sysreg.h>
23#include <asm/io.h>
24#include <asm/sections.h>
25 17
26#include <asm/arch/pm.h> 18#include <asm/arch/pm.h>
27 19
diff --git a/arch/avr32/kernel/vmlinux.lds.S b/arch/avr32/kernel/vmlinux.lds.S
index 481cfd40c053..5d25d8eeb750 100644
--- a/arch/avr32/kernel/vmlinux.lds.S
+++ b/arch/avr32/kernel/vmlinux.lds.S
@@ -68,14 +68,6 @@ SECTIONS
68 _evba = .; 68 _evba = .;
69 _text = .; 69 _text = .;
70 *(.ex.text) 70 *(.ex.text)
71 . = 0x50;
72 *(.tlbx.ex.text)
73 . = 0x60;
74 *(.tlbr.ex.text)
75 . = 0x70;
76 *(.tlbw.ex.text)
77 . = 0x100;
78 *(.scall.text)
79 *(.irq.text) 71 *(.irq.text)
80 KPROBES_TEXT 72 KPROBES_TEXT
81 TEXT_TEXT 73 TEXT_TEXT
@@ -107,6 +99,10 @@ SECTIONS
107 */ 99 */
108 *(.data.init_task) 100 *(.data.init_task)
109 101
102 /* Then, the page-aligned data */
103 . = ALIGN(PAGE_SIZE);
104 *(.data.page_aligned)
105
110 /* Then, the cacheline aligned data */ 106 /* Then, the cacheline aligned data */
111 . = ALIGN(L1_CACHE_BYTES); 107 . = ALIGN(L1_CACHE_BYTES);
112 *(.data.cacheline_aligned) 108 *(.data.cacheline_aligned)
diff --git a/arch/avr32/lib/io-readsb.S b/arch/avr32/lib/io-readsb.S
index 2be5da7ed26b..cb2d86945559 100644
--- a/arch/avr32/lib/io-readsb.S
+++ b/arch/avr32/lib/io-readsb.S
@@ -41,7 +41,7 @@ __raw_readsb:
412: sub r10, -4 412: sub r10, -4
42 reteq r12 42 reteq r12
43 43
443: ld.uh r8, r12[0] 443: ld.ub r8, r12[0]
45 sub r10, 1 45 sub r10, 1
46 st.b r11++, r8 46 st.b r11++, r8
47 brne 3b 47 brne 3b
diff --git a/arch/avr32/mach-at32ap/Makefile b/arch/avr32/mach-at32ap/Makefile
index e89009439e4a..d5018e2eed25 100644
--- a/arch/avr32/mach-at32ap/Makefile
+++ b/arch/avr32/mach-at32ap/Makefile
@@ -1,3 +1,8 @@
1obj-y += at32ap.o clock.o intc.o extint.o pio.o hsmc.o 1obj-y += pdc.o clock.o intc.o extint.o pio.o hsmc.o
2obj-$(CONFIG_CPU_AT32AP700X) += at32ap700x.o pm-at32ap700x.o 2obj-$(CONFIG_CPU_AT32AP700X) += at32ap700x.o pm-at32ap700x.o
3obj-$(CONFIG_CPU_FREQ_AT32AP) += cpufreq.o 3obj-$(CONFIG_CPU_FREQ_AT32AP) += cpufreq.o
4obj-$(CONFIG_PM) += pm.o
5
6ifeq ($(CONFIG_PM_DEBUG),y)
7CFLAGS_pm.o += -DDEBUG
8endif
diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c
index 0f24b4f85c17..07b21b121eef 100644
--- a/arch/avr32/mach-at32ap/at32ap700x.c
+++ b/arch/avr32/mach-at32ap/at32ap700x.c
@@ -20,6 +20,7 @@
20#include <asm/arch/at32ap700x.h> 20#include <asm/arch/at32ap700x.h>
21#include <asm/arch/board.h> 21#include <asm/arch/board.h>
22#include <asm/arch/portmux.h> 22#include <asm/arch/portmux.h>
23#include <asm/arch/sram.h>
23 24
24#include <video/atmel_lcdc.h> 25#include <video/atmel_lcdc.h>
25 26
@@ -93,19 +94,12 @@ static struct clk devname##_##_name = { \
93 94
94static DEFINE_SPINLOCK(pm_lock); 95static DEFINE_SPINLOCK(pm_lock);
95 96
96unsigned long at32ap7000_osc_rates[3] = {
97 [0] = 32768,
98 /* FIXME: these are ATSTK1002-specific */
99 [1] = 20000000,
100 [2] = 12000000,
101};
102
103static struct clk osc0; 97static struct clk osc0;
104static struct clk osc1; 98static struct clk osc1;
105 99
106static unsigned long osc_get_rate(struct clk *clk) 100static unsigned long osc_get_rate(struct clk *clk)
107{ 101{
108 return at32ap7000_osc_rates[clk->index]; 102 return at32_board_osc_rates[clk->index];
109} 103}
110 104
111static unsigned long pll_get_rate(struct clk *clk, unsigned long control) 105static unsigned long pll_get_rate(struct clk *clk, unsigned long control)
@@ -682,6 +676,14 @@ static struct clk hramc_clk = {
682 .users = 1, 676 .users = 1,
683 .index = 3, 677 .index = 3,
684}; 678};
679static struct clk sdramc_clk = {
680 .name = "sdramc_clk",
681 .parent = &pbb_clk,
682 .mode = pbb_clk_mode,
683 .get_rate = pbb_clk_get_rate,
684 .users = 1,
685 .index = 14,
686};
685 687
686static struct resource smc0_resource[] = { 688static struct resource smc0_resource[] = {
687 PBMEM(0xfff03400), 689 PBMEM(0xfff03400),
@@ -841,6 +843,81 @@ void __init at32_add_system_devices(void)
841} 843}
842 844
843/* -------------------------------------------------------------------- 845/* --------------------------------------------------------------------
846 * PSIF
847 * -------------------------------------------------------------------- */
848static struct resource atmel_psif0_resource[] __initdata = {
849 {
850 .start = 0xffe03c00,
851 .end = 0xffe03cff,
852 .flags = IORESOURCE_MEM,
853 },
854 IRQ(18),
855};
856static struct clk atmel_psif0_pclk = {
857 .name = "pclk",
858 .parent = &pba_clk,
859 .mode = pba_clk_mode,
860 .get_rate = pba_clk_get_rate,
861 .index = 15,
862};
863
864static struct resource atmel_psif1_resource[] __initdata = {
865 {
866 .start = 0xffe03d00,
867 .end = 0xffe03dff,
868 .flags = IORESOURCE_MEM,
869 },
870 IRQ(18),
871};
872static struct clk atmel_psif1_pclk = {
873 .name = "pclk",
874 .parent = &pba_clk,
875 .mode = pba_clk_mode,
876 .get_rate = pba_clk_get_rate,
877 .index = 15,
878};
879
880struct platform_device *__init at32_add_device_psif(unsigned int id)
881{
882 struct platform_device *pdev;
883
884 if (!(id == 0 || id == 1))
885 return NULL;
886
887 pdev = platform_device_alloc("atmel_psif", id);
888 if (!pdev)
889 return NULL;
890
891 switch (id) {
892 case 0:
893 if (platform_device_add_resources(pdev, atmel_psif0_resource,
894 ARRAY_SIZE(atmel_psif0_resource)))
895 goto err_add_resources;
896 atmel_psif0_pclk.dev = &pdev->dev;
897 select_peripheral(PA(8), PERIPH_A, 0); /* CLOCK */
898 select_peripheral(PA(9), PERIPH_A, 0); /* DATA */
899 break;
900 case 1:
901 if (platform_device_add_resources(pdev, atmel_psif1_resource,
902 ARRAY_SIZE(atmel_psif1_resource)))
903 goto err_add_resources;
904 atmel_psif1_pclk.dev = &pdev->dev;
905 select_peripheral(PB(11), PERIPH_A, 0); /* CLOCK */
906 select_peripheral(PB(12), PERIPH_A, 0); /* DATA */
907 break;
908 default:
909 return NULL;
910 }
911
912 platform_device_add(pdev);
913 return pdev;
914
915err_add_resources:
916 platform_device_put(pdev);
917 return NULL;
918}
919
920/* --------------------------------------------------------------------
844 * USART 921 * USART
845 * -------------------------------------------------------------------- */ 922 * -------------------------------------------------------------------- */
846 923
@@ -1113,7 +1190,8 @@ at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n)
1113 switch (id) { 1190 switch (id) {
1114 case 0: 1191 case 0:
1115 pdev = &atmel_spi0_device; 1192 pdev = &atmel_spi0_device;
1116 select_peripheral(PA(0), PERIPH_A, 0); /* MISO */ 1193 /* pullup MISO so a level is always defined */
1194 select_peripheral(PA(0), PERIPH_A, AT32_GPIOF_PULLUP);
1117 select_peripheral(PA(1), PERIPH_A, 0); /* MOSI */ 1195 select_peripheral(PA(1), PERIPH_A, 0); /* MOSI */
1118 select_peripheral(PA(2), PERIPH_A, 0); /* SCK */ 1196 select_peripheral(PA(2), PERIPH_A, 0); /* SCK */
1119 at32_spi_setup_slaves(0, b, n, spi0_pins); 1197 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)
1121 1199
1122 case 1: 1200 case 1:
1123 pdev = &atmel_spi1_device; 1201 pdev = &atmel_spi1_device;
1124 select_peripheral(PB(0), PERIPH_B, 0); /* MISO */ 1202 /* pullup MISO so a level is always defined */
1203 select_peripheral(PB(0), PERIPH_B, AT32_GPIOF_PULLUP);
1125 select_peripheral(PB(1), PERIPH_B, 0); /* MOSI */ 1204 select_peripheral(PB(1), PERIPH_B, 0); /* MOSI */
1126 select_peripheral(PB(5), PERIPH_B, 0); /* SCK */ 1205 select_peripheral(PB(5), PERIPH_B, 0); /* SCK */
1127 at32_spi_setup_slaves(1, b, n, spi1_pins); 1206 at32_spi_setup_slaves(1, b, n, spi1_pins);
@@ -1264,7 +1343,8 @@ static struct clk atmel_lcdfb0_pixclk = {
1264 1343
1265struct platform_device *__init 1344struct platform_device *__init
1266at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data, 1345at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
1267 unsigned long fbmem_start, unsigned long fbmem_len) 1346 unsigned long fbmem_start, unsigned long fbmem_len,
1347 unsigned int pin_config)
1268{ 1348{
1269 struct platform_device *pdev; 1349 struct platform_device *pdev;
1270 struct atmel_lcdfb_info *info; 1350 struct atmel_lcdfb_info *info;
@@ -1291,37 +1371,77 @@ at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
1291 switch (id) { 1371 switch (id) {
1292 case 0: 1372 case 0:
1293 pdev = &atmel_lcdfb0_device; 1373 pdev = &atmel_lcdfb0_device;
1294 select_peripheral(PC(19), PERIPH_A, 0); /* CC */ 1374
1295 select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC */ 1375 switch (pin_config) {
1296 select_peripheral(PC(21), PERIPH_A, 0); /* PCLK */ 1376 case 0:
1297 select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC */ 1377 select_peripheral(PC(19), PERIPH_A, 0); /* CC */
1298 select_peripheral(PC(23), PERIPH_A, 0); /* DVAL */ 1378 select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC */
1299 select_peripheral(PC(24), PERIPH_A, 0); /* MODE */ 1379 select_peripheral(PC(21), PERIPH_A, 0); /* PCLK */
1300 select_peripheral(PC(25), PERIPH_A, 0); /* PWR */ 1380 select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC */
1301 select_peripheral(PC(26), PERIPH_A, 0); /* DATA0 */ 1381 select_peripheral(PC(23), PERIPH_A, 0); /* DVAL */
1302 select_peripheral(PC(27), PERIPH_A, 0); /* DATA1 */ 1382 select_peripheral(PC(24), PERIPH_A, 0); /* MODE */
1303 select_peripheral(PC(28), PERIPH_A, 0); /* DATA2 */ 1383 select_peripheral(PC(25), PERIPH_A, 0); /* PWR */
1304 select_peripheral(PC(29), PERIPH_A, 0); /* DATA3 */ 1384 select_peripheral(PC(26), PERIPH_A, 0); /* DATA0 */
1305 select_peripheral(PC(30), PERIPH_A, 0); /* DATA4 */ 1385 select_peripheral(PC(27), PERIPH_A, 0); /* DATA1 */
1306 select_peripheral(PC(31), PERIPH_A, 0); /* DATA5 */ 1386 select_peripheral(PC(28), PERIPH_A, 0); /* DATA2 */
1307 select_peripheral(PD(0), PERIPH_A, 0); /* DATA6 */ 1387 select_peripheral(PC(29), PERIPH_A, 0); /* DATA3 */
1308 select_peripheral(PD(1), PERIPH_A, 0); /* DATA7 */ 1388 select_peripheral(PC(30), PERIPH_A, 0); /* DATA4 */
1309 select_peripheral(PD(2), PERIPH_A, 0); /* DATA8 */ 1389 select_peripheral(PC(31), PERIPH_A, 0); /* DATA5 */
1310 select_peripheral(PD(3), PERIPH_A, 0); /* DATA9 */ 1390 select_peripheral(PD(0), PERIPH_A, 0); /* DATA6 */
1311 select_peripheral(PD(4), PERIPH_A, 0); /* DATA10 */ 1391 select_peripheral(PD(1), PERIPH_A, 0); /* DATA7 */
1312 select_peripheral(PD(5), PERIPH_A, 0); /* DATA11 */ 1392 select_peripheral(PD(2), PERIPH_A, 0); /* DATA8 */
1313 select_peripheral(PD(6), PERIPH_A, 0); /* DATA12 */ 1393 select_peripheral(PD(3), PERIPH_A, 0); /* DATA9 */
1314 select_peripheral(PD(7), PERIPH_A, 0); /* DATA13 */ 1394 select_peripheral(PD(4), PERIPH_A, 0); /* DATA10 */
1315 select_peripheral(PD(8), PERIPH_A, 0); /* DATA14 */ 1395 select_peripheral(PD(5), PERIPH_A, 0); /* DATA11 */
1316 select_peripheral(PD(9), PERIPH_A, 0); /* DATA15 */ 1396 select_peripheral(PD(6), PERIPH_A, 0); /* DATA12 */
1317 select_peripheral(PD(10), PERIPH_A, 0); /* DATA16 */ 1397 select_peripheral(PD(7), PERIPH_A, 0); /* DATA13 */
1318 select_peripheral(PD(11), PERIPH_A, 0); /* DATA17 */ 1398 select_peripheral(PD(8), PERIPH_A, 0); /* DATA14 */
1319 select_peripheral(PD(12), PERIPH_A, 0); /* DATA18 */ 1399 select_peripheral(PD(9), PERIPH_A, 0); /* DATA15 */
1320 select_peripheral(PD(13), PERIPH_A, 0); /* DATA19 */ 1400 select_peripheral(PD(10), PERIPH_A, 0); /* DATA16 */
1321 select_peripheral(PD(14), PERIPH_A, 0); /* DATA20 */ 1401 select_peripheral(PD(11), PERIPH_A, 0); /* DATA17 */
1322 select_peripheral(PD(15), PERIPH_A, 0); /* DATA21 */ 1402 select_peripheral(PD(12), PERIPH_A, 0); /* DATA18 */
1323 select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */ 1403 select_peripheral(PD(13), PERIPH_A, 0); /* DATA19 */
1324 select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */ 1404 select_peripheral(PD(14), PERIPH_A, 0); /* DATA20 */
1405 select_peripheral(PD(15), PERIPH_A, 0); /* DATA21 */
1406 select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
1407 select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
1408 break;
1409 case 1:
1410 select_peripheral(PE(0), PERIPH_B, 0); /* CC */
1411 select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC */
1412 select_peripheral(PC(21), PERIPH_A, 0); /* PCLK */
1413 select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC */
1414 select_peripheral(PE(1), PERIPH_B, 0); /* DVAL */
1415 select_peripheral(PE(2), PERIPH_B, 0); /* MODE */
1416 select_peripheral(PC(25), PERIPH_A, 0); /* PWR */
1417 select_peripheral(PE(3), PERIPH_B, 0); /* DATA0 */
1418 select_peripheral(PE(4), PERIPH_B, 0); /* DATA1 */
1419 select_peripheral(PE(5), PERIPH_B, 0); /* DATA2 */
1420 select_peripheral(PE(6), PERIPH_B, 0); /* DATA3 */
1421 select_peripheral(PE(7), PERIPH_B, 0); /* DATA4 */
1422 select_peripheral(PC(31), PERIPH_A, 0); /* DATA5 */
1423 select_peripheral(PD(0), PERIPH_A, 0); /* DATA6 */
1424 select_peripheral(PD(1), PERIPH_A, 0); /* DATA7 */
1425 select_peripheral(PE(8), PERIPH_B, 0); /* DATA8 */
1426 select_peripheral(PE(9), PERIPH_B, 0); /* DATA9 */
1427 select_peripheral(PE(10), PERIPH_B, 0); /* DATA10 */
1428 select_peripheral(PE(11), PERIPH_B, 0); /* DATA11 */
1429 select_peripheral(PE(12), PERIPH_B, 0); /* DATA12 */
1430 select_peripheral(PD(7), PERIPH_A, 0); /* DATA13 */
1431 select_peripheral(PD(8), PERIPH_A, 0); /* DATA14 */
1432 select_peripheral(PD(9), PERIPH_A, 0); /* DATA15 */
1433 select_peripheral(PE(13), PERIPH_B, 0); /* DATA16 */
1434 select_peripheral(PE(14), PERIPH_B, 0); /* DATA17 */
1435 select_peripheral(PE(15), PERIPH_B, 0); /* DATA18 */
1436 select_peripheral(PE(16), PERIPH_B, 0); /* DATA19 */
1437 select_peripheral(PE(17), PERIPH_B, 0); /* DATA20 */
1438 select_peripheral(PE(18), PERIPH_B, 0); /* DATA21 */
1439 select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
1440 select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
1441 break;
1442 default:
1443 goto err_invalid_id;
1444 }
1325 1445
1326 clk_set_parent(&atmel_lcdfb0_pixclk, &pll0); 1446 clk_set_parent(&atmel_lcdfb0_pixclk, &pll0);
1327 clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0)); 1447 clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0));
@@ -1360,7 +1480,7 @@ static struct resource atmel_pwm0_resource[] __initdata = {
1360 IRQ(24), 1480 IRQ(24),
1361}; 1481};
1362static struct clk atmel_pwm0_mck = { 1482static struct clk atmel_pwm0_mck = {
1363 .name = "mck", 1483 .name = "pwm_clk",
1364 .parent = &pbb_clk, 1484 .parent = &pbb_clk,
1365 .mode = pbb_clk_mode, 1485 .mode = pbb_clk_mode,
1366 .get_rate = pbb_clk_get_rate, 1486 .get_rate = pbb_clk_get_rate,
@@ -1887,6 +2007,7 @@ struct clk *at32_clock_list[] = {
1887 &hmatrix_clk, 2007 &hmatrix_clk,
1888 &ebi_clk, 2008 &ebi_clk,
1889 &hramc_clk, 2009 &hramc_clk,
2010 &sdramc_clk,
1890 &smc0_pclk, 2011 &smc0_pclk,
1891 &smc0_mck, 2012 &smc0_mck,
1892 &pdc_hclk, 2013 &pdc_hclk,
@@ -1900,6 +2021,8 @@ struct clk *at32_clock_list[] = {
1900 &pio4_mck, 2021 &pio4_mck,
1901 &at32_tcb0_t0_clk, 2022 &at32_tcb0_t0_clk,
1902 &at32_tcb1_t0_clk, 2023 &at32_tcb1_t0_clk,
2024 &atmel_psif0_pclk,
2025 &atmel_psif1_pclk,
1903 &atmel_usart0_usart, 2026 &atmel_usart0_usart,
1904 &atmel_usart1_usart, 2027 &atmel_usart1_usart,
1905 &atmel_usart2_usart, 2028 &atmel_usart2_usart,
@@ -1935,16 +2058,7 @@ struct clk *at32_clock_list[] = {
1935}; 2058};
1936unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list); 2059unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list);
1937 2060
1938void __init at32_portmux_init(void) 2061void __init setup_platform(void)
1939{
1940 at32_init_pio(&pio0_device);
1941 at32_init_pio(&pio1_device);
1942 at32_init_pio(&pio2_device);
1943 at32_init_pio(&pio3_device);
1944 at32_init_pio(&pio4_device);
1945}
1946
1947void __init at32_clock_init(void)
1948{ 2062{
1949 u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0; 2063 u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0;
1950 int i; 2064 int i;
@@ -1999,4 +2113,36 @@ void __init at32_clock_init(void)
1999 pm_writel(HSB_MASK, hsb_mask); 2113 pm_writel(HSB_MASK, hsb_mask);
2000 pm_writel(PBA_MASK, pba_mask); 2114 pm_writel(PBA_MASK, pba_mask);
2001 pm_writel(PBB_MASK, pbb_mask); 2115 pm_writel(PBB_MASK, pbb_mask);
2116
2117 /* Initialize the port muxes */
2118 at32_init_pio(&pio0_device);
2119 at32_init_pio(&pio1_device);
2120 at32_init_pio(&pio2_device);
2121 at32_init_pio(&pio3_device);
2122 at32_init_pio(&pio4_device);
2123}
2124
2125struct gen_pool *sram_pool;
2126
2127static int __init sram_init(void)
2128{
2129 struct gen_pool *pool;
2130
2131 /* 1KiB granularity */
2132 pool = gen_pool_create(10, -1);
2133 if (!pool)
2134 goto fail;
2135
2136 if (gen_pool_add(pool, 0x24000000, 0x8000, -1))
2137 goto err_pool_add;
2138
2139 sram_pool = pool;
2140 return 0;
2141
2142err_pool_add:
2143 gen_pool_destroy(pool);
2144fail:
2145 pr_err("Failed to create SRAM pool\n");
2146 return -ENOMEM;
2002} 2147}
2148core_initcall(sram_init);
diff --git a/arch/avr32/mach-at32ap/intc.c b/arch/avr32/mach-at32ap/intc.c
index 097cf4e84052..994c4545e2b7 100644
--- a/arch/avr32/mach-at32ap/intc.c
+++ b/arch/avr32/mach-at32ap/intc.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2006 Atmel Corporation 2 * Copyright (C) 2006, 2008 Atmel Corporation
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -12,14 +12,20 @@
12#include <linux/interrupt.h> 12#include <linux/interrupt.h>
13#include <linux/irq.h> 13#include <linux/irq.h>
14#include <linux/platform_device.h> 14#include <linux/platform_device.h>
15#include <linux/sysdev.h>
15 16
16#include <asm/io.h> 17#include <asm/io.h>
17 18
18#include "intc.h" 19#include "intc.h"
19 20
20struct intc { 21struct intc {
21 void __iomem *regs; 22 void __iomem *regs;
22 struct irq_chip chip; 23 struct irq_chip chip;
24 struct sys_device sysdev;
25#ifdef CONFIG_PM
26 unsigned long suspend_ipr;
27 unsigned long saved_ipr[64];
28#endif
23}; 29};
24 30
25extern struct platform_device at32_intc0_device; 31extern struct platform_device at32_intc0_device;
@@ -136,6 +142,74 @@ fail:
136 panic("Interrupt controller initialization failed!\n"); 142 panic("Interrupt controller initialization failed!\n");
137} 143}
138 144
145#ifdef CONFIG_PM
146void intc_set_suspend_handler(unsigned long offset)
147{
148 intc0.suspend_ipr = offset;
149}
150
151static int intc_suspend(struct sys_device *sdev, pm_message_t state)
152{
153 struct intc *intc = container_of(sdev, struct intc, sysdev);
154 int i;
155
156 if (unlikely(!irqs_disabled())) {
157 pr_err("intc_suspend: called with interrupts enabled\n");
158 return -EINVAL;
159 }
160
161 if (unlikely(!intc->suspend_ipr)) {
162 pr_err("intc_suspend: suspend_ipr not initialized\n");
163 return -EINVAL;
164 }
165
166 for (i = 0; i < 64; i++) {
167 intc->saved_ipr[i] = intc_readl(intc, INTPR0 + 4 * i);
168 intc_writel(intc, INTPR0 + 4 * i, intc->suspend_ipr);
169 }
170
171 return 0;
172}
173
174static int intc_resume(struct sys_device *sdev)
175{
176 struct intc *intc = container_of(sdev, struct intc, sysdev);
177 int i;
178
179 WARN_ON(!irqs_disabled());
180
181 for (i = 0; i < 64; i++)
182 intc_writel(intc, INTPR0 + 4 * i, intc->saved_ipr[i]);
183
184 return 0;
185}
186#else
187#define intc_suspend NULL
188#define intc_resume NULL
189#endif
190
191static struct sysdev_class intc_class = {
192 .name = "intc",
193 .suspend = intc_suspend,
194 .resume = intc_resume,
195};
196
197static int __init intc_init_sysdev(void)
198{
199 int ret;
200
201 ret = sysdev_class_register(&intc_class);
202 if (ret)
203 return ret;
204
205 intc0.sysdev.id = 0;
206 intc0.sysdev.cls = &intc_class;
207 ret = sysdev_register(&intc0.sysdev);
208
209 return ret;
210}
211device_initcall(intc_init_sysdev);
212
139unsigned long intc_get_pending(unsigned int group) 213unsigned long intc_get_pending(unsigned int group)
140{ 214{
141 return intc_readl(&intc0, INTREQ0 + 4 * group); 215 return intc_readl(&intc0, INTREQ0 + 4 * group);
diff --git a/arch/avr32/mach-at32ap/at32ap.c b/arch/avr32/mach-at32ap/pdc.c
index 7c4987f3287a..1040bda4fda7 100644
--- a/arch/avr32/mach-at32ap/at32ap.c
+++ b/arch/avr32/mach-at32ap/pdc.c
@@ -11,14 +11,6 @@
11#include <linux/init.h> 11#include <linux/init.h>
12#include <linux/platform_device.h> 12#include <linux/platform_device.h>
13 13
14#include <asm/arch/init.h>
15
16void __init setup_platform(void)
17{
18 at32_clock_init();
19 at32_portmux_init();
20}
21
22static int __init pdc_probe(struct platform_device *pdev) 14static int __init pdc_probe(struct platform_device *pdev)
23{ 15{
24 struct clk *pclk, *hclk; 16 struct clk *pclk, *hclk;
diff --git a/arch/avr32/mach-at32ap/pio.c b/arch/avr32/mach-at32ap/pio.c
index 38a8fa31c0b5..60da03ba7117 100644
--- a/arch/avr32/mach-at32ap/pio.c
+++ b/arch/avr32/mach-at32ap/pio.c
@@ -318,6 +318,8 @@ static void pio_bank_show(struct seq_file *s, struct gpio_chip *chip)
318 const char *label; 318 const char *label;
319 319
320 label = gpiochip_is_requested(chip, i); 320 label = gpiochip_is_requested(chip, i);
321 if (!label && (imr & mask))
322 label = "[irq]";
321 if (!label) 323 if (!label)
322 continue; 324 continue;
323 325
diff --git a/arch/avr32/mach-at32ap/pio.h b/arch/avr32/mach-at32ap/pio.h
index 7795116a483a..9484dfcc08f2 100644
--- a/arch/avr32/mach-at32ap/pio.h
+++ b/arch/avr32/mach-at32ap/pio.h
@@ -57,7 +57,7 @@
57 57
58/* Bitfields in IFDR */ 58/* Bitfields in IFDR */
59 59
60/* Bitfields in ISFR */ 60/* Bitfields in IFSR */
61 61
62/* Bitfields in SODR */ 62/* Bitfields in SODR */
63 63
diff --git a/arch/avr32/mach-at32ap/pm-at32ap700x.S b/arch/avr32/mach-at32ap/pm-at32ap700x.S
index 949e2485e278..0a53ad314ff4 100644
--- a/arch/avr32/mach-at32ap/pm-at32ap700x.S
+++ b/arch/avr32/mach-at32ap/pm-at32ap700x.S
@@ -12,6 +12,12 @@
12#include <asm/thread_info.h> 12#include <asm/thread_info.h>
13#include <asm/arch/pm.h> 13#include <asm/arch/pm.h>
14 14
15#include "pm.h"
16#include "sdramc.h"
17
18/* Same as 0xfff00000 but fits in a 21 bit signed immediate */
19#define PM_BASE -0x100000
20
15 .section .bss, "wa", @nobits 21 .section .bss, "wa", @nobits
16 .global disable_idle_sleep 22 .global disable_idle_sleep
17 .type disable_idle_sleep, @object 23 .type disable_idle_sleep, @object
@@ -64,3 +70,105 @@ cpu_idle_skip_sleep:
64 unmask_interrupts 70 unmask_interrupts
65 retal r12 71 retal r12
66 .size cpu_idle_skip_sleep, . - cpu_idle_skip_sleep 72 .size cpu_idle_skip_sleep, . - cpu_idle_skip_sleep
73
74#ifdef CONFIG_PM
75 .section .init.text, "ax", @progbits
76
77 .global pm_exception
78 .type pm_exception, @function
79pm_exception:
80 /*
81 * Exceptions are masked when we switch to this handler, so
82 * we'll only get "unrecoverable" exceptions (offset 0.)
83 */
84 sub r12, pc, . - .Lpanic_msg
85 lddpc pc, .Lpanic_addr
86
87 .align 2
88.Lpanic_addr:
89 .long panic
90.Lpanic_msg:
91 .asciz "Unrecoverable exception during suspend\n"
92 .size pm_exception, . - pm_exception
93
94 .global pm_irq0
95 .type pm_irq0, @function
96pm_irq0:
97 /* Disable interrupts and return after the sleep instruction */
98 mfsr r9, SYSREG_RSR_INT0
99 mtsr SYSREG_RAR_INT0, r8
100 sbr r9, SYSREG_GM_OFFSET
101 mtsr SYSREG_RSR_INT0, r9
102 rete
103
104 /*
105 * void cpu_enter_standby(unsigned long sdramc_base)
106 *
107 * Enter PM_SUSPEND_STANDBY mode. At this point, all drivers
108 * are suspended and interrupts are disabled. Interrupts
109 * marked as 'wakeup' event sources may still come along and
110 * get us out of here.
111 *
112 * The SDRAM will be put into self-refresh mode (which does
113 * not require a clock from the CPU), and the CPU will be put
114 * into "frozen" mode (HSB bus stopped). The SDRAM controller
115 * will automatically bring the SDRAM into normal mode on the
116 * first access, and the power manager will automatically
117 * start the HSB and CPU clocks upon a wakeup event.
118 *
119 * This code uses the same "skip sleep" technique as above.
120 * It is very important that we jump directly to
121 * cpu_after_sleep after the sleep instruction since that's
122 * where we'll end up if the interrupt handler decides that we
123 * need to skip the sleep instruction.
124 */
125 .global pm_standby
126 .type pm_standby, @function
127pm_standby:
128 /*
129 * interrupts are already masked at this point, and EVBA
130 * points to pm_exception above.
131 */
132 ld.w r10, r12[SDRAMC_LPR]
133 sub r8, pc, . - 1f /* return address for irq handler */
134 mov r11, SDRAMC_LPR_LPCB_SELF_RFR
135 bfins r10, r11, 0, 2 /* LPCB <- self Refresh */
136 sync 0 /* flush write buffer */
137 st.w r12[SDRAMC_LPR], r11 /* put SDRAM in self-refresh mode */
138 ld.w r11, r12[SDRAMC_LPR]
139 unmask_interrupts
140 sleep CPU_SLEEP_FROZEN
1411: mask_interrupts
142 retal r12
143 .size pm_standby, . - pm_standby
144
145 .global pm_suspend_to_ram
146 .type pm_suspend_to_ram, @function
147pm_suspend_to_ram:
148 /*
149 * interrupts are already masked at this point, and EVBA
150 * points to pm_exception above.
151 */
152 mov r11, 0
153 cache r11[2], 8 /* clean all dcache lines */
154 sync 0 /* flush write buffer */
155 ld.w r10, r12[SDRAMC_LPR]
156 sub r8, pc, . - 1f /* return address for irq handler */
157 mov r11, SDRAMC_LPR_LPCB_SELF_RFR
158 bfins r10, r11, 0, 2 /* LPCB <- self refresh */
159 st.w r12[SDRAMC_LPR], r10 /* put SDRAM in self-refresh mode */
160 ld.w r11, r12[SDRAMC_LPR]
161
162 unmask_interrupts
163 sleep CPU_SLEEP_STOP
1641: mask_interrupts
165
166 retal r12
167 .size pm_suspend_to_ram, . - pm_suspend_to_ram
168
169 .global pm_sram_end
170 .type pm_sram_end, @function
171pm_sram_end:
172 .size pm_sram_end, 0
173
174#endif /* CONFIG_PM */
diff --git a/arch/avr32/mach-at32ap/pm.c b/arch/avr32/mach-at32ap/pm.c
new file mode 100644
index 000000000000..0b764320135d
--- /dev/null
+++ b/arch/avr32/mach-at32ap/pm.c
@@ -0,0 +1,245 @@
1/*
2 * AVR32 AP Power Management
3 *
4 * Copyright (C) 2008 Atmel Corporation
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * version 2 as published by the Free Software Foundation.
9 */
10#include <linux/io.h>
11#include <linux/suspend.h>
12#include <linux/vmalloc.h>
13
14#include <asm/cacheflush.h>
15#include <asm/sysreg.h>
16
17#include <asm/arch/pm.h>
18#include <asm/arch/sram.h>
19
20/* FIXME: This is only valid for AP7000 */
21#define SDRAMC_BASE 0xfff03800
22
23#include "sdramc.h"
24
25#define SRAM_PAGE_FLAGS (SYSREG_BIT(TLBELO_D) | SYSREG_BF(SZ, 1) \
26 | SYSREG_BF(AP, 3) | SYSREG_BIT(G))
27
28
29static unsigned long pm_sram_start;
30static size_t pm_sram_size;
31static struct vm_struct *pm_sram_area;
32
33static void (*avr32_pm_enter_standby)(unsigned long sdramc_base);
34static void (*avr32_pm_enter_str)(unsigned long sdramc_base);
35
36/*
37 * Must be called with interrupts disabled. Exceptions will be masked
38 * on return (i.e. all exceptions will be "unrecoverable".)
39 */
40static void *avr32_pm_map_sram(void)
41{
42 unsigned long vaddr;
43 unsigned long page_addr;
44 u32 tlbehi;
45 u32 mmucr;
46
47 vaddr = (unsigned long)pm_sram_area->addr;
48 page_addr = pm_sram_start & PAGE_MASK;
49
50 /*
51 * Mask exceptions and grab the first TLB entry. We won't be
52 * needing it while sleeping.
53 */
54 asm volatile("ssrf %0" : : "i"(SYSREG_EM_OFFSET) : "memory");
55
56 mmucr = sysreg_read(MMUCR);
57 tlbehi = sysreg_read(TLBEHI);
58 sysreg_write(MMUCR, SYSREG_BFINS(DRP, 0, mmucr));
59
60 tlbehi = SYSREG_BF(ASID, SYSREG_BFEXT(ASID, tlbehi));
61 tlbehi |= vaddr & PAGE_MASK;
62 tlbehi |= SYSREG_BIT(TLBEHI_V);
63
64 sysreg_write(TLBELO, page_addr | SRAM_PAGE_FLAGS);
65 sysreg_write(TLBEHI, tlbehi);
66 __builtin_tlbw();
67
68 return (void *)(vaddr + pm_sram_start - page_addr);
69}
70
71/*
72 * Must be called with interrupts disabled. Exceptions will be
73 * unmasked on return.
74 */
75static void avr32_pm_unmap_sram(void)
76{
77 u32 mmucr;
78 u32 tlbehi;
79 u32 tlbarlo;
80
81 /* Going to update TLB entry at index 0 */
82 mmucr = sysreg_read(MMUCR);
83 tlbehi = sysreg_read(TLBEHI);
84 sysreg_write(MMUCR, SYSREG_BFINS(DRP, 0, mmucr));
85
86 /* Clear the "valid" bit */
87 tlbehi = SYSREG_BF(ASID, SYSREG_BFEXT(ASID, tlbehi));
88 sysreg_write(TLBEHI, tlbehi);
89
90 /* Mark it as "not accessed" */
91 tlbarlo = sysreg_read(TLBARLO);
92 sysreg_write(TLBARLO, tlbarlo | 0x80000000U);
93
94 /* Update the TLB */
95 __builtin_tlbw();
96
97 /* Unmask exceptions */
98 asm volatile("csrf %0" : : "i"(SYSREG_EM_OFFSET) : "memory");
99}
100
101static int avr32_pm_valid_state(suspend_state_t state)
102{
103 switch (state) {
104 case PM_SUSPEND_ON:
105 case PM_SUSPEND_STANDBY:
106 case PM_SUSPEND_MEM:
107 return 1;
108
109 default:
110 return 0;
111 }
112}
113
114static int avr32_pm_enter(suspend_state_t state)
115{
116 u32 lpr_saved;
117 u32 evba_saved;
118 void *sram;
119
120 switch (state) {
121 case PM_SUSPEND_STANDBY:
122 sram = avr32_pm_map_sram();
123
124 /* Switch to in-sram exception handlers */
125 evba_saved = sysreg_read(EVBA);
126 sysreg_write(EVBA, (unsigned long)sram);
127
128 /*
129 * Save the LPR register so that we can re-enable
130 * SDRAM Low Power mode on resume.
131 */
132 lpr_saved = sdramc_readl(LPR);
133 pr_debug("%s: Entering standby...\n", __func__);
134 avr32_pm_enter_standby(SDRAMC_BASE);
135 sdramc_writel(LPR, lpr_saved);
136
137 /* Switch back to regular exception handlers */
138 sysreg_write(EVBA, evba_saved);
139
140 avr32_pm_unmap_sram();
141 break;
142
143 case PM_SUSPEND_MEM:
144 sram = avr32_pm_map_sram();
145
146 /* Switch to in-sram exception handlers */
147 evba_saved = sysreg_read(EVBA);
148 sysreg_write(EVBA, (unsigned long)sram);
149
150 /*
151 * Save the LPR register so that we can re-enable
152 * SDRAM Low Power mode on resume.
153 */
154 lpr_saved = sdramc_readl(LPR);
155 pr_debug("%s: Entering suspend-to-ram...\n", __func__);
156 avr32_pm_enter_str(SDRAMC_BASE);
157 sdramc_writel(LPR, lpr_saved);
158
159 /* Switch back to regular exception handlers */
160 sysreg_write(EVBA, evba_saved);
161
162 avr32_pm_unmap_sram();
163 break;
164
165 case PM_SUSPEND_ON:
166 pr_debug("%s: Entering idle...\n", __func__);
167 cpu_enter_idle();
168 break;
169
170 default:
171 pr_debug("%s: Invalid suspend state %d\n", __func__, state);
172 goto out;
173 }
174
175 pr_debug("%s: wakeup\n", __func__);
176
177out:
178 return 0;
179}
180
181static struct platform_suspend_ops avr32_pm_ops = {
182 .valid = avr32_pm_valid_state,
183 .enter = avr32_pm_enter,
184};
185
186static unsigned long avr32_pm_offset(void *symbol)
187{
188 extern u8 pm_exception[];
189
190 return (unsigned long)symbol - (unsigned long)pm_exception;
191}
192
193static int __init avr32_pm_init(void)
194{
195 extern u8 pm_exception[];
196 extern u8 pm_irq0[];
197 extern u8 pm_standby[];
198 extern u8 pm_suspend_to_ram[];
199 extern u8 pm_sram_end[];
200 void *dst;
201
202 /*
203 * To keep things simple, we depend on not needing more than a
204 * single page.
205 */
206 pm_sram_size = avr32_pm_offset(pm_sram_end);
207 if (pm_sram_size > PAGE_SIZE)
208 goto err;
209
210 pm_sram_start = sram_alloc(pm_sram_size);
211 if (!pm_sram_start)
212 goto err_alloc_sram;
213
214 /* Grab a virtual area we can use later on. */
215 pm_sram_area = get_vm_area(pm_sram_size, VM_IOREMAP);
216 if (!pm_sram_area)
217 goto err_vm_area;
218 pm_sram_area->phys_addr = pm_sram_start;
219
220 local_irq_disable();
221 dst = avr32_pm_map_sram();
222 memcpy(dst, pm_exception, pm_sram_size);
223 flush_dcache_region(dst, pm_sram_size);
224 invalidate_icache_region(dst, pm_sram_size);
225 avr32_pm_unmap_sram();
226 local_irq_enable();
227
228 avr32_pm_enter_standby = dst + avr32_pm_offset(pm_standby);
229 avr32_pm_enter_str = dst + avr32_pm_offset(pm_suspend_to_ram);
230 intc_set_suspend_handler(avr32_pm_offset(pm_irq0));
231
232 suspend_set_ops(&avr32_pm_ops);
233
234 printk("AVR32 AP Power Management enabled\n");
235
236 return 0;
237
238err_vm_area:
239 sram_free(pm_sram_start, pm_sram_size);
240err_alloc_sram:
241err:
242 pr_err("AVR32 Power Management initialization failed\n");
243 return -ENOMEM;
244}
245arch_initcall(avr32_pm_init);
diff --git a/arch/avr32/mach-at32ap/sdramc.h b/arch/avr32/mach-at32ap/sdramc.h
new file mode 100644
index 000000000000..66eeaed49073
--- /dev/null
+++ b/arch/avr32/mach-at32ap/sdramc.h
@@ -0,0 +1,76 @@
1/*
2 * Register definitions for the AT32AP SDRAM Controller
3 *
4 * Copyright (C) 2008 Atmel Corporation
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * version 2 as published by the Free Software Foundation.
9 */
10
11/* Register offsets */
12#define SDRAMC_MR 0x0000
13#define SDRAMC_TR 0x0004
14#define SDRAMC_CR 0x0008
15#define SDRAMC_HSR 0x000c
16#define SDRAMC_LPR 0x0010
17#define SDRAMC_IER 0x0014
18#define SDRAMC_IDR 0x0018
19#define SDRAMC_IMR 0x001c
20#define SDRAMC_ISR 0x0020
21#define SDRAMC_MDR 0x0024
22
23/* MR - Mode Register */
24#define SDRAMC_MR_MODE_NORMAL ( 0 << 0)
25#define SDRAMC_MR_MODE_NOP ( 1 << 0)
26#define SDRAMC_MR_MODE_BANKS_PRECHARGE ( 2 << 0)
27#define SDRAMC_MR_MODE_LOAD_MODE ( 3 << 0)
28#define SDRAMC_MR_MODE_AUTO_REFRESH ( 4 << 0)
29#define SDRAMC_MR_MODE_EXT_LOAD_MODE ( 5 << 0)
30#define SDRAMC_MR_MODE_POWER_DOWN ( 6 << 0)
31
32/* CR - Configuration Register */
33#define SDRAMC_CR_NC_8_BITS ( 0 << 0)
34#define SDRAMC_CR_NC_9_BITS ( 1 << 0)
35#define SDRAMC_CR_NC_10_BITS ( 2 << 0)
36#define SDRAMC_CR_NC_11_BITS ( 3 << 0)
37#define SDRAMC_CR_NR_11_BITS ( 0 << 2)
38#define SDRAMC_CR_NR_12_BITS ( 1 << 2)
39#define SDRAMC_CR_NR_13_BITS ( 2 << 2)
40#define SDRAMC_CR_NB_2_BANKS ( 0 << 4)
41#define SDRAMC_CR_NB_4_BANKS ( 1 << 4)
42#define SDRAMC_CR_CAS(x) ((x) << 5)
43#define SDRAMC_CR_DBW_32_BITS ( 0 << 7)
44#define SDRAMC_CR_DBW_16_BITS ( 1 << 7)
45#define SDRAMC_CR_TWR(x) ((x) << 8)
46#define SDRAMC_CR_TRC(x) ((x) << 12)
47#define SDRAMC_CR_TRP(x) ((x) << 16)
48#define SDRAMC_CR_TRCD(x) ((x) << 20)
49#define SDRAMC_CR_TRAS(x) ((x) << 24)
50#define SDRAMC_CR_TXSR(x) ((x) << 28)
51
52/* HSR - High Speed Register */
53#define SDRAMC_HSR_DA ( 1 << 0)
54
55/* LPR - Low Power Register */
56#define SDRAMC_LPR_LPCB_INHIBIT ( 0 << 0)
57#define SDRAMC_LPR_LPCB_SELF_RFR ( 1 << 0)
58#define SDRAMC_LPR_LPCB_PDOWN ( 2 << 0)
59#define SDRAMC_LPR_LPCB_DEEP_PDOWN ( 3 << 0)
60#define SDRAMC_LPR_PASR(x) ((x) << 4)
61#define SDRAMC_LPR_TCSR(x) ((x) << 8)
62#define SDRAMC_LPR_DS(x) ((x) << 10)
63#define SDRAMC_LPR_TIMEOUT(x) ((x) << 12)
64
65/* IER/IDR/IMR/ISR - Interrupt Enable/Disable/Mask/Status Register */
66#define SDRAMC_ISR_RES ( 1 << 0)
67
68/* MDR - Memory Device Register */
69#define SDRAMC_MDR_MD_SDRAM ( 0 << 0)
70#define SDRAMC_MDR_MD_LOW_PWR_SDRAM ( 1 << 0)
71
72/* Register access macros */
73#define sdramc_readl(reg) \
74 __raw_readl((void __iomem __force *)SDRAMC_BASE + SDRAMC_##reg)
75#define sdramc_writel(reg, value) \
76 __raw_writel(value, (void __iomem __force *)SDRAMC_BASE + SDRAMC_##reg)
diff --git a/arch/avr32/mm/init.c b/arch/avr32/mm/init.c
index 0e64ddc45e37..3f90a87527bb 100644
--- a/arch/avr32/mm/init.c
+++ b/arch/avr32/mm/init.c
@@ -11,6 +11,7 @@
11#include <linux/swap.h> 11#include <linux/swap.h>
12#include <linux/init.h> 12#include <linux/init.h>
13#include <linux/mmzone.h> 13#include <linux/mmzone.h>
14#include <linux/module.h>
14#include <linux/bootmem.h> 15#include <linux/bootmem.h>
15#include <linux/pagemap.h> 16#include <linux/pagemap.h>
16#include <linux/nodemask.h> 17#include <linux/nodemask.h>
@@ -23,11 +24,14 @@
23#include <asm/setup.h> 24#include <asm/setup.h>
24#include <asm/sections.h> 25#include <asm/sections.h>
25 26
27#define __page_aligned __attribute__((section(".data.page_aligned")))
28
26DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); 29DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
27 30
28pgd_t swapper_pg_dir[PTRS_PER_PGD]; 31pgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned;
29 32
30struct page *empty_zero_page; 33struct page *empty_zero_page;
34EXPORT_SYMBOL(empty_zero_page);
31 35
32/* 36/*
33 * Cache of MMU context last used. 37 * Cache of MMU context last used.
@@ -106,19 +110,9 @@ void __init paging_init(void)
106 zero_page = alloc_bootmem_low_pages_node(NODE_DATA(0), 110 zero_page = alloc_bootmem_low_pages_node(NODE_DATA(0),
107 PAGE_SIZE); 111 PAGE_SIZE);
108 112
109 { 113 sysreg_write(PTBR, (unsigned long)swapper_pg_dir);
110 pgd_t *pg_dir; 114 enable_mmu();
111 int i; 115 printk ("CPU: Paging enabled\n");
112
113 pg_dir = swapper_pg_dir;
114 sysreg_write(PTBR, (unsigned long)pg_dir);
115
116 for (i = 0; i < PTRS_PER_PGD; i++)
117 pgd_val(pg_dir[i]) = 0;
118
119 enable_mmu();
120 printk ("CPU: Paging enabled\n");
121 }
122 116
123 for_each_online_node(nid) { 117 for_each_online_node(nid) {
124 pg_data_t *pgdat = NODE_DATA(nid); 118 pg_data_t *pgdat = NODE_DATA(nid);
diff --git a/arch/avr32/mm/tlb.c b/arch/avr32/mm/tlb.c
index cd12edbea9f2..06677be98ffb 100644
--- a/arch/avr32/mm/tlb.c
+++ b/arch/avr32/mm/tlb.c
@@ -11,21 +11,21 @@
11 11
12#include <asm/mmu_context.h> 12#include <asm/mmu_context.h>
13 13
14#define _TLBEHI_I 0x100 14/* TODO: Get the correct number from the CONFIG1 system register */
15#define NR_TLB_ENTRIES 32
15 16
16void show_dtlb_entry(unsigned int index) 17static void show_dtlb_entry(unsigned int index)
17{ 18{
18 unsigned int tlbehi, tlbehi_save, tlbelo, mmucr, mmucr_save; 19 u32 tlbehi, tlbehi_save, tlbelo, mmucr, mmucr_save;
19 unsigned long flags; 20 unsigned long flags;
20 21
21 local_irq_save(flags); 22 local_irq_save(flags);
22 mmucr_save = sysreg_read(MMUCR); 23 mmucr_save = sysreg_read(MMUCR);
23 tlbehi_save = sysreg_read(TLBEHI); 24 tlbehi_save = sysreg_read(TLBEHI);
24 mmucr = mmucr_save & 0x13; 25 mmucr = SYSREG_BFINS(DRP, index, mmucr_save);
25 mmucr |= index << 14;
26 sysreg_write(MMUCR, mmucr); 26 sysreg_write(MMUCR, mmucr);
27 27
28 asm volatile("tlbr" : : : "memory"); 28 __builtin_tlbr();
29 cpu_sync_pipeline(); 29 cpu_sync_pipeline();
30 30
31 tlbehi = sysreg_read(TLBEHI); 31 tlbehi = sysreg_read(TLBEHI);
@@ -33,15 +33,17 @@ void show_dtlb_entry(unsigned int index)
33 33
34 printk("%2u: %c %c %02x %05x %05x %o %o %c %c %c %c\n", 34 printk("%2u: %c %c %02x %05x %05x %o %o %c %c %c %c\n",
35 index, 35 index,
36 (tlbehi & 0x200)?'1':'0', 36 SYSREG_BFEXT(TLBEHI_V, tlbehi) ? '1' : '0',
37 (tlbelo & 0x100)?'1':'0', 37 SYSREG_BFEXT(G, tlbelo) ? '1' : '0',
38 (tlbehi & 0xff), 38 SYSREG_BFEXT(ASID, tlbehi),
39 (tlbehi >> 12), (tlbelo >> 12), 39 SYSREG_BFEXT(VPN, tlbehi) >> 2,
40 (tlbelo >> 4) & 7, (tlbelo >> 2) & 3, 40 SYSREG_BFEXT(PFN, tlbelo) >> 2,
41 (tlbelo & 0x200)?'1':'0', 41 SYSREG_BFEXT(AP, tlbelo),
42 (tlbelo & 0x080)?'1':'0', 42 SYSREG_BFEXT(SZ, tlbelo),
43 (tlbelo & 0x001)?'1':'0', 43 SYSREG_BFEXT(TLBELO_C, tlbelo) ? 'C' : ' ',
44 (tlbelo & 0x002)?'1':'0'); 44 SYSREG_BFEXT(B, tlbelo) ? 'B' : ' ',
45 SYSREG_BFEXT(W, tlbelo) ? 'W' : ' ',
46 SYSREG_BFEXT(TLBELO_D, tlbelo) ? 'D' : ' ');
45 47
46 sysreg_write(MMUCR, mmucr_save); 48 sysreg_write(MMUCR, mmucr_save);
47 sysreg_write(TLBEHI, tlbehi_save); 49 sysreg_write(TLBEHI, tlbehi_save);
@@ -54,29 +56,33 @@ void dump_dtlb(void)
54 unsigned int i; 56 unsigned int i;
55 57
56 printk("ID V G ASID VPN PFN AP SZ C B W D\n"); 58 printk("ID V G ASID VPN PFN AP SZ C B W D\n");
57 for (i = 0; i < 32; i++) 59 for (i = 0; i < NR_TLB_ENTRIES; i++)
58 show_dtlb_entry(i); 60 show_dtlb_entry(i);
59} 61}
60 62
61static unsigned long last_mmucr; 63static void update_dtlb(unsigned long address, pte_t pte)
62
63static inline void set_replacement_pointer(unsigned shift)
64{ 64{
65 unsigned long mmucr, mmucr_save; 65 u32 tlbehi;
66 u32 mmucr;
66 67
67 mmucr = mmucr_save = sysreg_read(MMUCR); 68 /*
69 * We're not changing the ASID here, so no need to flush the
70 * pipeline.
71 */
72 tlbehi = sysreg_read(TLBEHI);
73 tlbehi = SYSREG_BF(ASID, SYSREG_BFEXT(ASID, tlbehi));
74 tlbehi |= address & MMU_VPN_MASK;
75 tlbehi |= SYSREG_BIT(TLBEHI_V);
76 sysreg_write(TLBEHI, tlbehi);
68 77
69 /* Does this mapping already exist? */ 78 /* Does this mapping already exist? */
70 __asm__ __volatile__( 79 __builtin_tlbs();
71 " tlbs\n" 80 mmucr = sysreg_read(MMUCR);
72 " mfsr %0, %1"
73 : "=r"(mmucr)
74 : "i"(SYSREG_MMUCR));
75 81
76 if (mmucr & SYSREG_BIT(MMUCR_N)) { 82 if (mmucr & SYSREG_BIT(MMUCR_N)) {
77 /* Not found -- pick a not-recently-accessed entry */ 83 /* Not found -- pick a not-recently-accessed entry */
78 unsigned long rp; 84 unsigned int rp;
79 unsigned long tlbar = sysreg_read(TLBARLO); 85 u32 tlbar = sysreg_read(TLBARLO);
80 86
81 rp = 32 - fls(tlbar); 87 rp = 32 - fls(tlbar);
82 if (rp == 32) { 88 if (rp == 32) {
@@ -84,30 +90,14 @@ static inline void set_replacement_pointer(unsigned shift)
84 sysreg_write(TLBARLO, -1L); 90 sysreg_write(TLBARLO, -1L);
85 } 91 }
86 92
87 mmucr &= 0x13; 93 mmucr = SYSREG_BFINS(DRP, rp, mmucr);
88 mmucr |= (rp << shift);
89
90 sysreg_write(MMUCR, mmucr); 94 sysreg_write(MMUCR, mmucr);
91 } 95 }
92 96
93 last_mmucr = mmucr;
94}
95
96static void update_dtlb(unsigned long address, pte_t pte, unsigned long asid)
97{
98 unsigned long vpn;
99
100 vpn = (address & MMU_VPN_MASK) | _TLBEHI_VALID | asid;
101 sysreg_write(TLBEHI, vpn);
102 cpu_sync_pipeline();
103
104 set_replacement_pointer(14);
105
106 sysreg_write(TLBELO, pte_val(pte) & _PAGE_FLAGS_HARDWARE_MASK); 97 sysreg_write(TLBELO, pte_val(pte) & _PAGE_FLAGS_HARDWARE_MASK);
107 98
108 /* Let's go */ 99 /* Let's go */
109 asm volatile("nop\n\ttlbw" : : : "memory"); 100 __builtin_tlbw();
110 cpu_sync_pipeline();
111} 101}
112 102
113void update_mmu_cache(struct vm_area_struct *vma, 103void update_mmu_cache(struct vm_area_struct *vma,
@@ -120,39 +110,40 @@ void update_mmu_cache(struct vm_area_struct *vma,
120 return; 110 return;
121 111
122 local_irq_save(flags); 112 local_irq_save(flags);
123 update_dtlb(address, pte, get_asid()); 113 update_dtlb(address, pte);
124 local_irq_restore(flags); 114 local_irq_restore(flags);
125} 115}
126 116
127void __flush_tlb_page(unsigned long asid, unsigned long page) 117static void __flush_tlb_page(unsigned long asid, unsigned long page)
128{ 118{
129 unsigned long mmucr, tlbehi; 119 u32 mmucr, tlbehi;
130 120
131 page |= asid; 121 /*
132 sysreg_write(TLBEHI, page); 122 * Caller is responsible for masking out non-PFN bits in page
133 cpu_sync_pipeline(); 123 * and changing the current ASID if necessary. This means that
134 asm volatile("tlbs"); 124 * we don't need to flush the pipeline after writing TLBEHI.
125 */
126 tlbehi = page | asid;
127 sysreg_write(TLBEHI, tlbehi);
128
129 __builtin_tlbs();
135 mmucr = sysreg_read(MMUCR); 130 mmucr = sysreg_read(MMUCR);
136 131
137 if (!(mmucr & SYSREG_BIT(MMUCR_N))) { 132 if (!(mmucr & SYSREG_BIT(MMUCR_N))) {
138 unsigned long tlbarlo; 133 unsigned int entry;
139 unsigned long entry; 134 u32 tlbarlo;
140 135
141 /* Clear the "valid" bit */ 136 /* Clear the "valid" bit */
142 tlbehi = sysreg_read(TLBEHI);
143 tlbehi &= ~_TLBEHI_VALID;
144 sysreg_write(TLBEHI, tlbehi); 137 sysreg_write(TLBEHI, tlbehi);
145 cpu_sync_pipeline();
146 138
147 /* mark the entry as "not accessed" */ 139 /* mark the entry as "not accessed" */
148 entry = (mmucr >> 14) & 0x3f; 140 entry = SYSREG_BFEXT(DRP, mmucr);
149 tlbarlo = sysreg_read(TLBARLO); 141 tlbarlo = sysreg_read(TLBARLO);
150 tlbarlo |= (0x80000000 >> entry); 142 tlbarlo |= (0x80000000UL >> entry);
151 sysreg_write(TLBARLO, tlbarlo); 143 sysreg_write(TLBARLO, tlbarlo);
152 144
153 /* update the entry with valid bit clear */ 145 /* update the entry with valid bit clear */
154 asm volatile("tlbw"); 146 __builtin_tlbw();
155 cpu_sync_pipeline();
156 } 147 }
157} 148}
158 149
@@ -190,17 +181,22 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
190 181
191 local_irq_save(flags); 182 local_irq_save(flags);
192 size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; 183 size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
184
193 if (size > (MMU_DTLB_ENTRIES / 4)) { /* Too many entries to flush */ 185 if (size > (MMU_DTLB_ENTRIES / 4)) { /* Too many entries to flush */
194 mm->context = NO_CONTEXT; 186 mm->context = NO_CONTEXT;
195 if (mm == current->mm) 187 if (mm == current->mm)
196 activate_context(mm); 188 activate_context(mm);
197 } else { 189 } else {
198 unsigned long asid = mm->context & MMU_CONTEXT_ASID_MASK; 190 unsigned long asid;
199 unsigned long saved_asid = MMU_NO_ASID; 191 unsigned long saved_asid;
192
193 asid = mm->context & MMU_CONTEXT_ASID_MASK;
194 saved_asid = MMU_NO_ASID;
200 195
201 start &= PAGE_MASK; 196 start &= PAGE_MASK;
202 end += (PAGE_SIZE - 1); 197 end += (PAGE_SIZE - 1);
203 end &= PAGE_MASK; 198 end &= PAGE_MASK;
199
204 if (mm != current->mm) { 200 if (mm != current->mm) {
205 saved_asid = get_asid(); 201 saved_asid = get_asid();
206 set_asid(asid); 202 set_asid(asid);
@@ -218,33 +214,34 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
218} 214}
219 215
220/* 216/*
221 * TODO: If this is only called for addresses > TASK_SIZE, we can probably 217 * This function depends on the pages to be flushed having the G
222 * skip the ASID stuff and just use the Global bit... 218 * (global) bit set in their pte. This is true for all
219 * PAGE_KERNEL(_RO) pages.
223 */ 220 */
224void flush_tlb_kernel_range(unsigned long start, unsigned long end) 221void flush_tlb_kernel_range(unsigned long start, unsigned long end)
225{ 222{
226 unsigned long flags; 223 unsigned long flags;
227 int size; 224 int size;
228 225
229 local_irq_save(flags);
230 size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; 226 size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
231 if (size > (MMU_DTLB_ENTRIES / 4)) { /* Too many entries to flush */ 227 if (size > (MMU_DTLB_ENTRIES / 4)) { /* Too many entries to flush */
232 flush_tlb_all(); 228 flush_tlb_all();
233 } else { 229 } else {
234 unsigned long asid = init_mm.context & MMU_CONTEXT_ASID_MASK; 230 unsigned long asid;
235 unsigned long saved_asid = get_asid(); 231
232 local_irq_save(flags);
233 asid = get_asid();
236 234
237 start &= PAGE_MASK; 235 start &= PAGE_MASK;
238 end += (PAGE_SIZE - 1); 236 end += (PAGE_SIZE - 1);
239 end &= PAGE_MASK; 237 end &= PAGE_MASK;
240 set_asid(asid); 238
241 while (start < end) { 239 while (start < end) {
242 __flush_tlb_page(asid, start); 240 __flush_tlb_page(asid, start);
243 start += PAGE_SIZE; 241 start += PAGE_SIZE;
244 } 242 }
245 set_asid(saved_asid); 243 local_irq_restore(flags);
246 } 244 }
247 local_irq_restore(flags);
248} 245}
249 246
250void flush_tlb_mm(struct mm_struct *mm) 247void flush_tlb_mm(struct mm_struct *mm)
@@ -280,7 +277,7 @@ static void *tlb_start(struct seq_file *tlb, loff_t *pos)
280{ 277{
281 static unsigned long tlb_index; 278 static unsigned long tlb_index;
282 279
283 if (*pos >= 32) 280 if (*pos >= NR_TLB_ENTRIES)
284 return NULL; 281 return NULL;
285 282
286 tlb_index = 0; 283 tlb_index = 0;
@@ -291,7 +288,7 @@ static void *tlb_next(struct seq_file *tlb, void *v, loff_t *pos)
291{ 288{
292 unsigned long *index = v; 289 unsigned long *index = v;
293 290
294 if (*index >= 31) 291 if (*index >= NR_TLB_ENTRIES - 1)
295 return NULL; 292 return NULL;
296 293
297 ++*pos; 294 ++*pos;
@@ -313,16 +310,16 @@ static int tlb_show(struct seq_file *tlb, void *v)
313 if (*index == 0) 310 if (*index == 0)
314 seq_puts(tlb, "ID V G ASID VPN PFN AP SZ C B W D\n"); 311 seq_puts(tlb, "ID V G ASID VPN PFN AP SZ C B W D\n");
315 312
316 BUG_ON(*index >= 32); 313 BUG_ON(*index >= NR_TLB_ENTRIES);
317 314
318 local_irq_save(flags); 315 local_irq_save(flags);
319 mmucr_save = sysreg_read(MMUCR); 316 mmucr_save = sysreg_read(MMUCR);
320 tlbehi_save = sysreg_read(TLBEHI); 317 tlbehi_save = sysreg_read(TLBEHI);
321 mmucr = mmucr_save & 0x13; 318 mmucr = SYSREG_BFINS(DRP, *index, mmucr_save);
322 mmucr |= *index << 14;
323 sysreg_write(MMUCR, mmucr); 319 sysreg_write(MMUCR, mmucr);
324 320
325 asm volatile("tlbr" : : : "memory"); 321 /* TLBR might change the ASID */
322 __builtin_tlbr();
326 cpu_sync_pipeline(); 323 cpu_sync_pipeline();
327 324
328 tlbehi = sysreg_read(TLBEHI); 325 tlbehi = sysreg_read(TLBEHI);
@@ -334,16 +331,18 @@ static int tlb_show(struct seq_file *tlb, void *v)
334 local_irq_restore(flags); 331 local_irq_restore(flags);
335 332
336 seq_printf(tlb, "%2lu: %c %c %02x %05x %05x %o %o %c %c %c %c\n", 333 seq_printf(tlb, "%2lu: %c %c %02x %05x %05x %o %o %c %c %c %c\n",
337 *index, 334 *index,
338 (tlbehi & 0x200)?'1':'0', 335 SYSREG_BFEXT(TLBEHI_V, tlbehi) ? '1' : '0',
339 (tlbelo & 0x100)?'1':'0', 336 SYSREG_BFEXT(G, tlbelo) ? '1' : '0',
340 (tlbehi & 0xff), 337 SYSREG_BFEXT(ASID, tlbehi),
341 (tlbehi >> 12), (tlbelo >> 12), 338 SYSREG_BFEXT(VPN, tlbehi) >> 2,
342 (tlbelo >> 4) & 7, (tlbelo >> 2) & 3, 339 SYSREG_BFEXT(PFN, tlbelo) >> 2,
343 (tlbelo & 0x200)?'1':'0', 340 SYSREG_BFEXT(AP, tlbelo),
344 (tlbelo & 0x080)?'1':'0', 341 SYSREG_BFEXT(SZ, tlbelo),
345 (tlbelo & 0x001)?'1':'0', 342 SYSREG_BFEXT(TLBELO_C, tlbelo) ? '1' : '0',
346 (tlbelo & 0x002)?'1':'0'); 343 SYSREG_BFEXT(B, tlbelo) ? '1' : '0',
344 SYSREG_BFEXT(W, tlbelo) ? '1' : '0',
345 SYSREG_BFEXT(TLBELO_D, tlbelo) ? '1' : '0');
347 346
348 return 0; 347 return 0;
349} 348}