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 ...
This commit is contained in:
commit
6c118e43dc
36 changed files with 1093 additions and 280 deletions
|
@ -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"
|
||||
|
|
|
@ -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>
|
||||
|
@ -25,6 +27,13 @@
|
|||
#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);
|
||||
|
|
|
@ -28,6 +28,12 @@
|
|||
|
||||
#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, ð_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
|
||||
|
|
|
@ -27,6 +27,13 @@
|
|||
|
||||
#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,
|
||||
|
|
|
@ -29,6 +29,13 @@
|
|||
|
||||
#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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,6 +1371,9 @@ at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
|
|||
switch (id) {
|
||||
case 0:
|
||||
pdev = &atmel_lcdfb0_device;
|
||||
|
||||
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 */
|
||||
|
@ -1322,6 +1405,43 @@ at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
|
|||
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);
|
||||
|
|
|
@ -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
|
||||
|
@ -12,6 +12,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/sysdev.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
|
@ -20,6 +21,11 @@
|
|||
struct intc {
|
||||
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 @@ void __init init_IRQ(void)
|
|||
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);
|
||||
|
|
|
@ -11,14 +11,6 @@
|
|||
#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;
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
|
||||
/* Bitfields in IFDR */
|
||||
|
||||
/* Bitfields in ISFR */
|
||||
/* Bitfields in IFSR */
|
||||
|
||||
/* Bitfields in SODR */
|
||||
|
||||
|
|
|
@ -12,6 +12,12 @@
|
|||
#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 */
|
||||
|
|
245
arch/avr32/mach-at32ap/pm.c
Normal file
245
arch/avr32/mach-at32ap/pm.c
Normal file
|
@ -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);
|
76
arch/avr32/mach-at32ap/sdramc.h
Normal file
76
arch/avr32/mach-at32ap/sdramc.h
Normal file
|
@ -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)
|
|
@ -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>
|
||||
|
@ -23,11 +24,14 @@
|
|||
#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;
|
||||
|
||||
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);
|
||||
|
|
|
@ -11,21 +11,21 @@
|
|||
|
||||
#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,34 +214,35 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -335,15 +332,17 @@ static int tlb_show(struct seq_file *tlb, void *v)
|
|||
|
||||
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');
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -13,10 +13,6 @@
|
|||
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__ */
|
||||
|
|
|
@ -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 */
|
||||
|
|
30
include/asm-avr32/arch-at32ap/sram.h
Normal file
30
include/asm-avr32/arch-at32ap/sram.h
Normal file
|
@ -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 */
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -5,4 +5,6 @@
|
|||
|
||||
#define PCI_DMA_BUS_IS_PHYS (1)
|
||||
|
||||
#include <asm-generic/pci-dma-compat.h>
|
||||
|
||||
#endif /* __ASM_AVR32_PCI_H__ */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,16 +300,13 @@ 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_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))
|
||||
|
||||
/* to find an entry in a kernel page-table-directory */
|
||||
#define pgd_offset_k(address) pgd_offset(&init_mm, address)
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue