提交 9ef9dc69 编写于 作者: L Linus Torvalds

Merge branch 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm

* 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm: (44 commits)
  [ARM] 4822/1: RealView: Change the REALVIEW_MPCORE configuration option
  [ARM] 4821/1: RealView: Remove the platform dependencies from localtimer.c
  [ARM] 4820/1: RealView: Select the timer IRQ at run-time
  [ARM] 4819/1: RealView: Fix entry-macro.S to work with multiple platforms
  [ARM] 4818/1: RealView: Add core-tile detection
  [ARM] 4817/1: RealView: Move the AMBA resource definitions to realview_eb.c
  [ARM] 4816/1: RealView: Move the platform-specific definitions into board-eb.h
  [ARM] 4815/1: RealView: Add clockevents suport for the local timers
  [ARM] 4814/1: RealView: Add broadcasting clockevents support for ARM11MPCore
  [ARM] 4813/1: Add SMP helper functions for clockevents support
  [ARM] 4812/1: RealView: clockevents support for the RealView platforms
  [ARM] 4811/1: RealView: clocksource support for the RealView platforms
  [ARM] 4736/1: Export atags to userspace and allow kexec to use customised atags
  [ARM] 4798/1: pcm027: fix missing header file
  [ARM] 4803/1: pxa: fix building issue of poodle.c caused by patch 4737/1
  [ARM] 4801/1: pxa: fix building issues of missing pxa2xx-regs.h
  [ARM] pxa: introduce sysdev for pxa3xx static memory controller
  [ARM] pxa: add preliminary suspend/resume code for pxa3xx
  [ARM] pxa: introduce sysdev for GPIO register saving/restoring
  [ARM] pxa: introduce sysdev for IRQ register saving/restoring
  ...
......@@ -35,6 +35,11 @@ config GENERIC_CLOCKEVENTS
bool
default n
config GENERIC_CLOCKEVENTS_BROADCAST
bool
depends on GENERIC_CLOCKEVENTS
default y if SMP && !LOCAL_TIMERS
config MMU
bool
default y
......@@ -187,6 +192,8 @@ config ARCH_REALVIEW
bool "ARM Ltd. RealView family"
select ARM_AMBA
select ICST307
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
help
This enables support for ARM Ltd RealView boards.
......@@ -623,7 +630,7 @@ source "kernel/time/Kconfig"
config SMP
bool "Symmetric Multi-Processing (EXPERIMENTAL)"
depends on EXPERIMENTAL && REALVIEW_MPCORE
depends on EXPERIMENTAL && REALVIEW_EB_ARM11MP
help
This enables support for systems with more than one CPU. If you have
a system with only one CPU, like most personal computers, say N. If
......@@ -656,7 +663,7 @@ config HOTPLUG_CPU
config LOCAL_TIMERS
bool "Use local timer interrupts"
depends on SMP && REALVIEW_MPCORE
depends on SMP && REALVIEW_EB_ARM11MP
default y
help
Enable support for local timers on SMP platforms, rather then the
......@@ -912,6 +919,13 @@ config KEXEC
initially work for you. It may help to enable device hotplugging
support.
config ATAGS_PROC
bool "Export atags in procfs"
default n
help
Should the atags used to boot the kernel be exported in an "atags"
file in procfs. Useful with kexec.
endmenu
if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX || ARCH_PXA)
......
......@@ -69,9 +69,7 @@ void __init ioctime_init(void)
static irqreturn_t
ioc_timer_interrupt(int irq, void *dev_id)
{
write_seqlock(&xtime_lock);
timer_tick();
write_sequnlock(&xtime_lock);
return IRQ_HANDLED;
}
......
此差异已折叠。
......@@ -20,6 +20,7 @@ obj-$(CONFIG_PCI) += bios32.o isa.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
obj-$(CONFIG_KPROBES) += kprobes.o kprobes-decode.o
obj-$(CONFIG_ATAGS_PROC) += atags.o
obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o
obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o
......
#include <linux/slab.h>
#include <linux/kexec.h>
#include <linux/proc_fs.h>
#include <asm/setup.h>
#include <asm/types.h>
#include <asm/page.h>
struct buffer {
size_t size;
char *data;
};
static struct buffer tags_buffer;
static int
read_buffer(char* page, char** start, off_t off, int count,
int* eof, void* data)
{
struct buffer *buffer = (struct buffer *)data;
if (off >= buffer->size) {
*eof = 1;
return 0;
}
count = min((int) (buffer->size - off), count);
memcpy(page, &buffer->data[off], count);
return count;
}
static int
create_proc_entries(void)
{
struct proc_dir_entry* tags_entry;
tags_entry = create_proc_read_entry("atags", 0400, &proc_root, read_buffer, &tags_buffer);
if (!tags_entry)
return -ENOMEM;
return 0;
}
static char __initdata atags_copy_buf[KEXEC_BOOT_PARAMS_SIZE];
static char __initdata *atags_copy;
void __init save_atags(const struct tag *tags)
{
atags_copy = atags_copy_buf;
memcpy(atags_copy, tags, KEXEC_BOOT_PARAMS_SIZE);
}
static int __init init_atags_procfs(void)
{
struct tag *tag;
int error;
if (!atags_copy) {
printk(KERN_WARNING "Exporting ATAGs: No saved tags found\n");
return -EIO;
}
for (tag = (struct tag *) atags_copy; tag->hdr.size; tag = tag_next(tag))
;
tags_buffer.size = ((char *) tag - atags_copy) + sizeof(tag->hdr);
tags_buffer.data = kmalloc(tags_buffer.size, GFP_KERNEL);
if (tags_buffer.data == NULL)
return -ENOMEM;
memcpy(tags_buffer.data, atags_copy, tags_buffer.size);
error = create_proc_entries();
if (error) {
printk(KERN_ERR "Exporting ATAGs: not enough memory\n");
kfree(tags_buffer.data);
tags_buffer.size = 0;
tags_buffer.data = NULL;
}
return error;
}
arch_initcall(init_atags_procfs);
#ifdef CONFIG_ATAGS_PROC
extern void save_atags(struct tag *tags);
#else
static inline void save_atags(struct tag *tags) { }
#endif
......@@ -21,6 +21,7 @@ extern void setup_mm_for_reboot(char mode);
extern unsigned long kexec_start_address;
extern unsigned long kexec_indirection_page;
extern unsigned long kexec_mach_type;
extern unsigned long kexec_boot_atags;
/*
* Provide a dummy crash_notes definition while crash dump arrives to arm.
......@@ -62,6 +63,7 @@ void machine_kexec(struct kimage *image)
kexec_start_address = image->start;
kexec_indirection_page = page_list;
kexec_mach_type = machine_arch_type;
kexec_boot_atags = image->start - KEXEC_ARM_ZIMAGE_OFFSET + KEXEC_ARM_ATAGS_OFFSET;
/* copy our kernel relocation code to the control code page */
memcpy(reboot_code_buffer,
......
......@@ -7,23 +7,6 @@
.globl relocate_new_kernel
relocate_new_kernel:
/* Move boot params back to where the kernel expects them */
ldr r0,kexec_boot_params_address
teq r0,#0
beq 8f
ldr r1,kexec_boot_params_copy
mov r6,#KEXEC_BOOT_PARAMS_SIZE/4
7:
ldr r5,[r1],#4
str r5,[r0],#4
subs r6,r6,#1
bne 7b
8:
/* Boot params moved, now go on with the kernel */
ldr r0,kexec_indirection_page
ldr r1,kexec_start_address
......@@ -67,7 +50,7 @@ relocate_new_kernel:
mov lr,r1
mov r0,#0
ldr r1,kexec_mach_type
ldr r2,kexec_boot_params_address
ldr r2,kexec_boot_atags
mov pc,lr
.globl kexec_start_address
......@@ -82,14 +65,9 @@ kexec_indirection_page:
kexec_mach_type:
.long 0x0
/* phy addr where new kernel will expect to find boot params */
.globl kexec_boot_params_address
kexec_boot_params_address:
.long 0x0
/* phy addr where old kernel put a copy of orig boot params */
.globl kexec_boot_params_copy
kexec_boot_params_copy:
/* phy addr of the atags for the new kernel */
.globl kexec_boot_atags
kexec_boot_atags:
.long 0x0
relocate_new_kernel_end:
......
......@@ -24,7 +24,6 @@
#include <linux/interrupt.h>
#include <linux/smp.h>
#include <linux/fs.h>
#include <linux/kexec.h>
#include <asm/cpu.h>
#include <asm/elf.h>
......@@ -39,6 +38,7 @@
#include <asm/mach/time.h>
#include "compat.h"
#include "atags.h"
#ifndef MEM_SIZE
#define MEM_SIZE (16*1024*1024)
......@@ -62,6 +62,7 @@ extern int root_mountflags;
extern void _stext, _text, _etext, __data_start, _edata, _end;
unsigned int processor_id;
EXPORT_SYMBOL(processor_id);
unsigned int __machine_arch_type;
EXPORT_SYMBOL(__machine_arch_type);
......@@ -784,23 +785,6 @@ static int __init customize_machine(void)
}
arch_initcall(customize_machine);
#ifdef CONFIG_KEXEC
/* Physical addr of where the boot params should be for this machine */
extern unsigned long kexec_boot_params_address;
/* Physical addr of the buffer into which the boot params are copied */
extern unsigned long kexec_boot_params_copy;
/* Pointer to the boot params buffer, for manipulation and display */
unsigned long kexec_boot_params;
EXPORT_SYMBOL(kexec_boot_params);
/* The buffer itself - make sure it is sized correctly */
static unsigned long kexec_boot_params_buf[(KEXEC_BOOT_PARAMS_SIZE + 3) / 4];
#endif
void __init setup_arch(char **cmdline_p)
{
struct tag *tags = (struct tag *)&init_tags;
......@@ -819,18 +803,6 @@ void __init setup_arch(char **cmdline_p)
else if (mdesc->boot_params)
tags = phys_to_virt(mdesc->boot_params);
#ifdef CONFIG_KEXEC
kexec_boot_params_copy = virt_to_phys(kexec_boot_params_buf);
kexec_boot_params = (unsigned long)kexec_boot_params_buf;
if (__atags_pointer) {
kexec_boot_params_address = __atags_pointer;
memcpy((void *)kexec_boot_params, tags, KEXEC_BOOT_PARAMS_SIZE);
} else if (mdesc->boot_params) {
kexec_boot_params_address = mdesc->boot_params;
memcpy((void *)kexec_boot_params, tags, KEXEC_BOOT_PARAMS_SIZE);
}
#endif
/*
* If we have the old style parameters, convert them to
* a tag list.
......@@ -846,6 +818,7 @@ void __init setup_arch(char **cmdline_p)
if (tags->hdr.tag == ATAG_CORE) {
if (meminfo.nr_banks != 0)
squash_mem_tags(tags);
save_atags(tags);
parse_tags(tags);
}
......
......@@ -290,6 +290,11 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
local_irq_enable();
local_fiq_enable();
/*
* Setup local timer for this CPU.
*/
local_timer_setup(cpu);
calibrate_delay();
smp_store_cpu_info(cpu);
......@@ -299,11 +304,6 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
*/
cpu_set(cpu, cpu_online_map);
/*
* Setup local timer for this CPU.
*/
local_timer_setup(cpu);
/*
* OK, it's off to the idle thread for us
*/
......@@ -454,6 +454,27 @@ int smp_call_function(void (*func)(void *info), void *info, int retry,
}
EXPORT_SYMBOL_GPL(smp_call_function);
int smp_call_function_single(int cpu, void (*func)(void *info), void *info,
int retry, int wait)
{
/* prevent preemption and reschedule on another processor */
int current_cpu = get_cpu();
int ret = 0;
if (cpu == current_cpu) {
local_irq_disable();
func(info);
local_irq_enable();
} else
ret = smp_call_function_on_cpu(func, info, retry, wait,
cpumask_of_cpu(cpu));
put_cpu();
return ret;
}
EXPORT_SYMBOL_GPL(smp_call_function_single);
void show_ipi_list(struct seq_file *p)
{
unsigned int cpu;
......@@ -481,8 +502,7 @@ void show_local_irqs(struct seq_file *p)
static void ipi_timer(void)
{
irq_enter();
profile_tick(CPU_PROFILING);
update_process_times(user_mode(get_irq_regs()));
local_timer_interrupt();
irq_exit();
}
......@@ -621,6 +641,11 @@ void smp_send_timer(void)
send_ipi_message(mask, IPI_TIMER);
}
void smp_timer_broadcast(cpumask_t mask)
{
send_ipi_message(mask, IPI_TIMER);
}
void smp_send_stop(void)
{
cpumask_t mask = cpu_online_map;
......
......@@ -253,6 +253,36 @@ config AT91_TIMER_HZ
system clock (of at least several MHz), rounding is less of a
problem so it can be safer to use a decimal values like 100.
choice
prompt "Select a UART for early kernel messages"
config AT91_EARLY_DBGU
bool "DBGU"
config AT91_EARLY_USART0
bool "USART0"
config AT91_EARLY_USART1
bool "USART1"
config AT91_EARLY_USART2
bool "USART2"
depends on ! ARCH_AT91X40
config AT91_EARLY_USART3
bool "USART3"
depends on (ARCH_AT91RM9200 || ARCH_AT91SAM9RL || ARCH_AT91SAM9260)
config AT91_EARLY_USART4
bool "USART4"
depends on ARCH_AT91SAM9260
config AT91_EARLY_USART5
bool "USART5"
depends on ARCH_AT91SAM9260
endchoice
endmenu
endif
......@@ -49,8 +49,6 @@ static irqreturn_t at91sam926x_timer_interrupt(int irq, void *dev_id)
volatile long nr_ticks;
if (at91_sys_read(AT91_PIT_SR) & AT91_PIT_PITS) { /* This is a shared interrupt */
write_seqlock(&xtime_lock);
/* Get number to ticks performed before interrupt and clear PIT interrupt */
nr_ticks = PIT_PICNT(at91_sys_read(AT91_PIT_PIVR));
do {
......@@ -58,7 +56,6 @@ static irqreturn_t at91sam926x_timer_interrupt(int irq, void *dev_id)
nr_ticks--;
} while (nr_ticks);
write_sequnlock(&xtime_lock);
return IRQ_HANDLED;
} else
return IRQ_NONE; /* not handled */
......
......@@ -47,6 +47,9 @@ extern void at91_irq_resume(void);
#define AT91RM9200_BGA 4 /* AT91RM9200 BGA package has 4 banks */
struct at91_gpio_bank {
unsigned chipbase; /* bank's first GPIO number */
void __iomem *regbase; /* base of register bank */
struct at91_gpio_bank *next; /* bank sharing same IRQ/clock/... */
unsigned short id; /* peripheral ID */
unsigned long offset; /* offset from system peripheral base */
struct clk *clock; /* associated clock */
......
......@@ -33,12 +33,10 @@ static int gpio_banks;
static inline void __iomem *pin_to_controller(unsigned pin)
{
void __iomem *sys_base = (void __iomem *) AT91_VA_BASE_SYS;
pin -= PIN_BASE;
pin /= 32;
if (likely(pin < gpio_banks))
return sys_base + gpio[pin].offset;
return gpio[pin].regbase;
return NULL;
}
......@@ -294,11 +292,11 @@ void at91_gpio_suspend(void)
int i;
for (i = 0; i < gpio_banks; i++) {
u32 pio = gpio[i].offset;
void __iomem *pio = gpio[i].regbase;
backups[i] = at91_sys_read(pio + PIO_IMR);
at91_sys_write(pio + PIO_IDR, backups[i]);
at91_sys_write(pio + PIO_IER, wakeups[i]);
backups[i] = __raw_readl(pio + PIO_IMR);
__raw_writel(backups[i], pio + PIO_IDR);
__raw_writel(wakeups[i], pio + PIO_IER);
if (!wakeups[i])
clk_disable(gpio[i].clock);
......@@ -315,13 +313,13 @@ void at91_gpio_resume(void)
int i;
for (i = 0; i < gpio_banks; i++) {
u32 pio = gpio[i].offset;
void __iomem *pio = gpio[i].regbase;
if (!wakeups[i])
clk_enable(gpio[i].clock);
at91_sys_write(pio + PIO_IDR, wakeups[i]);
at91_sys_write(pio + PIO_IER, backups[i]);
__raw_writel(wakeups[i], pio + PIO_IDR);
__raw_writel(backups[i], pio + PIO_IER);
}
}
......@@ -361,7 +359,13 @@ static void gpio_irq_unmask(unsigned pin)
static int gpio_irq_type(unsigned pin, unsigned type)
{
return (type == IRQT_BOTHEDGE) ? 0 : -EINVAL;
switch (type) {
case IRQ_TYPE_NONE:
case IRQ_TYPE_EDGE_BOTH:
return 0;
default:
return -EINVAL;
}
}
static struct irq_chip gpio_irqchip = {
......@@ -376,20 +380,30 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
{
unsigned pin;
struct irq_desc *gpio;
struct at91_gpio_bank *bank;
void __iomem *pio;
u32 isr;
pio = get_irq_chip_data(irq);
bank = get_irq_chip_data(irq);
pio = bank->regbase;
/* temporarily mask (level sensitive) parent IRQ */
desc->chip->ack(irq);
for (;;) {
/* reading ISR acks the pending (edge triggered) GPIO interrupt */
/* Reading ISR acks pending (edge triggered) GPIO interrupts.
* When there none are pending, we're finished unless we need
* to process multiple banks (like ID_PIOCDE on sam9263).
*/
isr = __raw_readl(pio + PIO_ISR) & __raw_readl(pio + PIO_IMR);
if (!isr)
break;
if (!isr) {
if (!bank->next)
break;
bank = bank->next;
pio = bank->regbase;
continue;
}
pin = (unsigned) get_irq_data(irq);
pin = bank->chipbase;
gpio = &irq_desc[pin];
while (isr) {
......@@ -481,24 +495,21 @@ postcore_initcall(at91_gpio_debugfs_init);
*/
void __init at91_gpio_irq_setup(void)
{
unsigned pioc, pin;
unsigned pioc, pin;
struct at91_gpio_bank *this, *prev;
for (pioc = 0, pin = PIN_BASE;
pioc < gpio_banks;
pioc++) {
void __iomem *controller;
unsigned id = gpio[pioc].id;
for (pioc = 0, pin = PIN_BASE, this = gpio, prev = NULL;
pioc++ < gpio_banks;
prev = this, this++) {
unsigned id = this->id;
unsigned i;
clk_enable(gpio[pioc].clock); /* enable PIO controller's clock */
controller = (void __iomem *) AT91_VA_BASE_SYS + gpio[pioc].offset;
__raw_writel(~0, controller + PIO_IDR);
/* enable PIO controller's clock */
clk_enable(this->clock);
set_irq_data(id, (void *) pin);
set_irq_chip_data(id, controller);
__raw_writel(~0, this->regbase + PIO_IDR);
for (i = 0; i < 32; i++, pin++) {
for (i = 0, pin = this->chipbase; i < 32; i++, pin++) {
/*
* Can use the "simple" and not "edge" handler since it's
* shorter, and the AIC handles interrupts sanely.
......@@ -508,6 +519,14 @@ void __init at91_gpio_irq_setup(void)
set_irq_flags(pin, IRQF_VALID);
}
/* The toplevel handler handles one bank of GPIOs, except
* AT91SAM9263_ID_PIOCDE handles three... PIOC is first in
* the list, so we only set up that handler.
*/
if (prev && prev->next == this)
continue;
set_irq_chip_data(id, this);
set_irq_chained_handler(id, gpio_irq_handler);
}
pr_info("AT91: %d gpio irqs in %d banks\n", pin - PIN_BASE, gpio_banks);
......@@ -518,8 +537,20 @@ void __init at91_gpio_irq_setup(void)
*/
void __init at91_gpio_init(struct at91_gpio_bank *data, int nr_banks)
{
unsigned i;
struct at91_gpio_bank *last;
BUG_ON(nr_banks > MAX_GPIO_BANKS);
gpio = data;
gpio_banks = nr_banks;
for (i = 0, last = NULL; i < nr_banks; i++, last = data, data++) {
data->chipbase = PIN_BASE + i * 32;
data->regbase = data->offset + (void __iomem *)AT91_VA_BASE_SYS;
/* AT91SAM9263_ID_PIOCDE groups PIOC, PIOD, PIOE */
if (last && last->id == data->id)
last->next = data;
}
}
......@@ -189,6 +189,20 @@ config IXP4XX_INDIRECT_PCI
need to use the indirect method instead. If you don't know
what you need, leave this option unselected.
config IXP4XX_QMGR
tristate "IXP4xx Queue Manager support"
help
This driver supports IXP4xx built-in hardware queue manager
and is automatically selected by Ethernet and HSS drivers.
config IXP4XX_NPE
tristate "IXP4xx Network Processor Engine support"
select HOTPLUG
select FW_LOADER
help
This driver supports IXP4xx built-in network coprocessors
and is automatically selected by Ethernet and HSS drivers.
endmenu
endif
......@@ -23,10 +23,12 @@ obj-$(CONFIG_MACH_AVILA) += avila-setup.o
obj-$(CONFIG_MACH_IXDPG425) += coyote-setup.o
obj-$(CONFIG_ARCH_ADI_COYOTE) += coyote-setup.o
obj-$(CONFIG_MACH_GTWX5715) += gtwx5715-setup.o
obj-$(CONFIG_MACH_NSLU2) += nslu2-setup.o nslu2-power.o
obj-$(CONFIG_MACH_NAS100D) += nas100d-setup.o nas100d-power.o
obj-$(CONFIG_MACH_DSMG600) += dsmg600-setup.o dsmg600-power.o
obj-$(CONFIG_MACH_NSLU2) += nslu2-setup.o
obj-$(CONFIG_MACH_NAS100D) += nas100d-setup.o
obj-$(CONFIG_MACH_DSMG600) += dsmg600-setup.o
obj-$(CONFIG_MACH_GATEWAY7001) += gateway7001-setup.o
obj-$(CONFIG_MACH_WG302V2) += wg302v2-setup.o
obj-$(CONFIG_PCI) += $(obj-pci-$(CONFIG_PCI)) common-pci.o
obj-$(CONFIG_IXP4XX_QMGR) += ixp4xx_qmgr.o
obj-$(CONFIG_IXP4XX_NPE) += ixp4xx_npe.o
/*
* arch/arm/mach-ixp4xx/dsmg600-power.c
*
* DSM-G600 Power/Reset driver
* Author: Michael Westerhof <mwester@dls.net>
*
* Based on nslu2-power.c
* Copyright (C) 2005 Tower Technologies
* Author: Alessandro Zummo <a.zummo@towertech.it>
*
* which was based on nslu2-io.c
* Copyright (C) 2004 Karen Spearel
*
* Maintainers: http://www.nslu2-linux.org/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/module.h>
#include <linux/reboot.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/jiffies.h>
#include <linux/timer.h>
#include <asm/mach-types.h>
extern void ctrl_alt_del(void);
/* This is used to make sure the power-button pusher is serious. The button
* must be held until the value of this counter reaches zero.
*/
static volatile int power_button_countdown;
/* Must hold the button down for at least this many counts to be processed */
#define PBUTTON_HOLDDOWN_COUNT 4 /* 2 secs */
static void dsmg600_power_handler(unsigned long data);
static DEFINE_TIMER(dsmg600_power_timer, dsmg600_power_handler, 0, 0);
static void dsmg600_power_handler(unsigned long data)
{
/* This routine is called twice per second to check the
* state of the power button.
*/
if (*IXP4XX_GPIO_GPINR & DSMG600_PB_BM) {
/* IO Pin is 1 (button pushed) */
if (power_button_countdown == 0) {
/* Signal init to do the ctrlaltdel action, this will bypass
* init if it hasn't started and do a kernel_restart.
*/
ctrl_alt_del();
/* Change the state of the power LED to "blink" */
gpio_line_set(DSMG600_LED_PWR_GPIO, IXP4XX_GPIO_LOW);
}
power_button_countdown--;
} else {
power_button_countdown = PBUTTON_HOLDDOWN_COUNT;
}
mod_timer(&dsmg600_power_timer, jiffies + msecs_to_jiffies(500));
}
static irqreturn_t dsmg600_reset_handler(int irq, void *dev_id)
{
/* This is the paper-clip reset, it shuts the machine down directly. */
machine_power_off();
return IRQ_HANDLED;
}
static int __init dsmg600_power_init(void)
{
if (!(machine_is_dsmg600()))
return 0;
if (request_irq(DSMG600_RB_IRQ, &dsmg600_reset_handler,
IRQF_DISABLED | IRQF_TRIGGER_LOW, "DSM-G600 reset button",
NULL) < 0) {
printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
DSMG600_RB_IRQ);
return -EIO;
}
/* The power button on the D-Link DSM-G600 is on GPIO 15, but
* it cannot handle interrupts on that GPIO line. So we'll
* have to poll it with a kernel timer.
*/
/* Make sure that the power button GPIO is set up as an input */
gpio_line_config(DSMG600_PB_GPIO, IXP4XX_GPIO_IN);
/* Set the initial value for the power button IRQ handler */
power_button_countdown = PBUTTON_HOLDDOWN_COUNT;
mod_timer(&dsmg600_power_timer, jiffies + msecs_to_jiffies(500));
return 0;
}
static void __exit dsmg600_power_exit(void)
{
if (!(machine_is_dsmg600()))
return;
del_timer_sync(&dsmg600_power_timer);
free_irq(DSMG600_RB_IRQ, NULL);
}
module_init(dsmg600_power_init);
module_exit(dsmg600_power_exit);
MODULE_AUTHOR("Michael Westerhof <mwester@dls.net>");
MODULE_DESCRIPTION("DSM-G600 Power/Reset driver");
MODULE_LICENSE("GPL");
/*
* DSM-G600 board-setup
*
* Copyright (C) 2008 Rod Whitby <rod@whitby.id.au>
* Copyright (C) 2006 Tower Technologies
* Author: Alessandro Zummo <a.zummo@towertech.it>
*
* based ixdp425-setup.c:
* based on ixdp425-setup.c:
* Copyright (C) 2003-2004 MontaVista Software, Inc.
* based on nslu2-power.c:
* Copyright (C) 2005 Tower Technologies
* based on nslu2-io.c:
* Copyright (C) 2004 Karen Spearel
*
* Author: Alessandro Zummo <a.zummo@towertech.it>
* Author: Michael Westerhof <mwester@dls.net>
* Author: Rod Whitby <rod@whitby.id.au>
* Maintainers: http://www.nslu2-linux.org/
*/
#include <linux/kernel.h>
#include <linux/irq.h>
#include <linux/jiffies.h>
#include <linux/timer.h>
#include <linux/serial.h>
#include <linux/serial_8250.h>
#include <linux/leds.h>
#include <linux/reboot.h>
#include <linux/i2c.h>
#include <linux/i2c-gpio.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
#include <asm/mach/time.h>
#include <asm/gpio.h>
static struct flash_platform_data dsmg600_flash_data = {
.map_name = "cfi_probe",
......@@ -51,29 +63,34 @@ static struct platform_device dsmg600_i2c_gpio = {
},
};
#ifdef CONFIG_LEDS_CLASS
static struct resource dsmg600_led_resources[] = {
static struct i2c_board_info __initdata dsmg600_i2c_board_info [] = {
{
I2C_BOARD_INFO("rtc-pcf8563", 0x51),
},
};
static struct gpio_led dsmg600_led_pins[] = {
{
.name = "power",
.start = DSMG600_LED_PWR_GPIO,
.end = DSMG600_LED_PWR_GPIO,
.flags = IXP4XX_GPIO_HIGH,
.name = "power",
.gpio = DSMG600_LED_PWR_GPIO,
},
{
.name = "wlan",
.start = DSMG600_LED_WLAN_GPIO,
.end = DSMG600_LED_WLAN_GPIO,
.flags = IXP4XX_GPIO_LOW,
.name = "wlan",
.gpio = DSMG600_LED_WLAN_GPIO,
.active_low = true,
},
};
static struct gpio_led_platform_data dsmg600_led_data = {
.num_leds = ARRAY_SIZE(dsmg600_led_pins),
.leds = dsmg600_led_pins,
};
static struct platform_device dsmg600_leds = {
.name = "IXP4XX-GPIO-LED",
.id = -1,
.num_resources = ARRAY_SIZE(dsmg600_led_resources),
.resource = dsmg600_led_resources,
.name = "leds-gpio",
.id = -1,
.dev.platform_data = &dsmg600_led_data,
};
#endif
static struct resource dsmg600_uart_resources[] = {
{
......@@ -121,6 +138,7 @@ static struct platform_device dsmg600_uart = {
static struct platform_device *dsmg600_devices[] __initdata = {
&dsmg600_i2c_gpio,
&dsmg600_flash,
&dsmg600_leds,
};
static void dsmg600_power_off(void)
......@@ -132,6 +150,57 @@ static void dsmg600_power_off(void)
gpio_line_set(DSMG600_PO_GPIO, IXP4XX_GPIO_HIGH);
}
/* This is used to make sure the power-button pusher is serious. The button
* must be held until the value of this counter reaches zero.
*/
static int power_button_countdown;
/* Must hold the button down for at least this many counts to be processed */
#define PBUTTON_HOLDDOWN_COUNT 4 /* 2 secs */
static void dsmg600_power_handler(unsigned long data);
static DEFINE_TIMER(dsmg600_power_timer, dsmg600_power_handler, 0, 0);
static void dsmg600_power_handler(unsigned long data)
{
/* This routine is called twice per second to check the
* state of the power button.
*/
if (gpio_get_value(DSMG600_PB_GPIO)) {
/* IO Pin is 1 (button pushed) */
if (power_button_countdown > 0)
power_button_countdown--;
} else {
/* Done on button release, to allow for auto-power-on mods. */
if (power_button_countdown == 0) {
/* Signal init to do the ctrlaltdel action,
* this will bypass init if it hasn't started
* and do a kernel_restart.
*/
ctrl_alt_del();
/* Change the state of the power LED to "blink" */
gpio_line_set(DSMG600_LED_PWR_GPIO, IXP4XX_GPIO_LOW);
} else {
power_button_countdown = PBUTTON_HOLDDOWN_COUNT;
}
}
mod_timer(&dsmg600_power_timer, jiffies + msecs_to_jiffies(500));
}
static irqreturn_t dsmg600_reset_handler(int irq, void *dev_id)
{
/* This is the paper-clip reset, it shuts the machine down directly. */
machine_power_off();
return IRQ_HANDLED;
}
static void __init dsmg600_timer_init(void)
{
/* The xtal on this machine is non-standard. */
......@@ -156,7 +225,8 @@ static void __init dsmg600_init(void)
dsmg600_flash_resource.end =
IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1;
pm_power_off = dsmg600_power_off;
i2c_register_board_info(0, dsmg600_i2c_board_info,
ARRAY_SIZE(dsmg600_i2c_board_info));
/* The UART is required on the DSM-G600 (Redboot cannot use the
* NIC) -- do it here so that it does *not* get removed if
......@@ -166,10 +236,28 @@ static void __init dsmg600_init(void)
platform_add_devices(dsmg600_devices, ARRAY_SIZE(dsmg600_devices));
#ifdef CONFIG_LEDS_CLASS
/* We don't care whether or not this works. */
(void)platform_device_register(&dsmg600_leds);
#endif
pm_power_off = dsmg600_power_off;
if (request_irq(gpio_to_irq(DSMG600_RB_GPIO), &dsmg600_reset_handler,
IRQF_DISABLED | IRQF_TRIGGER_LOW,
"DSM-G600 reset button", NULL) < 0) {
printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
gpio_to_irq(DSMG600_RB_GPIO));
}
/* The power button on the D-Link DSM-G600 is on GPIO 15, but
* it cannot handle interrupts on that GPIO line. So we'll
* have to poll it with a kernel timer.
*/
/* Make sure that the power button GPIO is set up as an input */
gpio_line_config(DSMG600_PB_GPIO, IXP4XX_GPIO_IN);
/* Set the initial value for the power button IRQ handler */
power_button_countdown = PBUTTON_HOLDDOWN_COUNT;
mod_timer(&dsmg600_power_timer, jiffies + msecs_to_jiffies(500));
}
MACHINE_START(DSMG600, "D-Link DSM-G600 RevA")
......
......@@ -177,6 +177,31 @@ static struct platform_device ixdp425_uart = {
.resource = ixdp425_uart_resources
};
/* Built-in 10/100 Ethernet MAC interfaces */
static struct eth_plat_info ixdp425_plat_eth[] = {
{
.phy = 0,
.rxq = 3,
.txreadyq = 20,
}, {
.phy = 1,
.rxq = 4,
.txreadyq = 21,
}
};
static struct platform_device ixdp425_eth[] = {
{
.name = "ixp4xx_eth",
.id = IXP4XX_ETH_NPEB,
.dev.platform_data = ixdp425_plat_eth,
}, {
.name = "ixp4xx_eth",
.id = IXP4XX_ETH_NPEC,
.dev.platform_data = ixdp425_plat_eth + 1,
}
};
static struct platform_device *ixdp425_devices[] __initdata = {
&ixdp425_i2c_gpio,
&ixdp425_flash,
......@@ -184,7 +209,9 @@ static struct platform_device *ixdp425_devices[] __initdata = {
defined(CONFIG_MTD_NAND_PLATFORM_MODULE)
&ixdp425_flash_nand,
#endif
&ixdp425_uart
&ixdp425_uart,
&ixdp425_eth[0],
&ixdp425_eth[1],
};
static void __init ixdp425_init(void)
......
此差异已折叠。
/*
* Intel IXP4xx Queue Manager driver for Linux
*
* Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License
* as published by the Free Software Foundation.
*/
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/arch/qmgr.h>
#define DEBUG 0
struct qmgr_regs __iomem *qmgr_regs;
static struct resource *mem_res;
static spinlock_t qmgr_lock;
static u32 used_sram_bitmap[4]; /* 128 16-dword pages */
static void (*irq_handlers[HALF_QUEUES])(void *pdev);
static void *irq_pdevs[HALF_QUEUES];
void qmgr_set_irq(unsigned int queue, int src,
void (*handler)(void *pdev), void *pdev)
{
u32 __iomem *reg = &qmgr_regs->irqsrc[queue / 8]; /* 8 queues / u32 */
int bit = (queue % 8) * 4; /* 3 bits + 1 reserved bit per queue */
unsigned long flags;
src &= 7;
spin_lock_irqsave(&qmgr_lock, flags);
__raw_writel((__raw_readl(reg) & ~(7 << bit)) | (src << bit), reg);
irq_handlers[queue] = handler;
irq_pdevs[queue] = pdev;
spin_unlock_irqrestore(&qmgr_lock, flags);
}
static irqreturn_t qmgr_irq1(int irq, void *pdev)
{
int i;
u32 val = __raw_readl(&qmgr_regs->irqstat[0]);
__raw_writel(val, &qmgr_regs->irqstat[0]); /* ACK */
for (i = 0; i < HALF_QUEUES; i++)
if (val & (1 << i))
irq_handlers[i](irq_pdevs[i]);
return val ? IRQ_HANDLED : 0;
}
void qmgr_enable_irq(unsigned int queue)
{
unsigned long flags;
spin_lock_irqsave(&qmgr_lock, flags);
__raw_writel(__raw_readl(&qmgr_regs->irqen[0]) | (1 << queue),
&qmgr_regs->irqen[0]);
spin_unlock_irqrestore(&qmgr_lock, flags);
}
void qmgr_disable_irq(unsigned int queue)
{
unsigned long flags;
spin_lock_irqsave(&qmgr_lock, flags);
__raw_writel(__raw_readl(&qmgr_regs->irqen[0]) & ~(1 << queue),
&qmgr_regs->irqen[0]);
spin_unlock_irqrestore(&qmgr_lock, flags);
}
static inline void shift_mask(u32 *mask)
{
mask[3] = mask[3] << 1 | mask[2] >> 31;
mask[2] = mask[2] << 1 | mask[1] >> 31;
mask[1] = mask[1] << 1 | mask[0] >> 31;
mask[0] <<= 1;
}
int qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
unsigned int nearly_empty_watermark,
unsigned int nearly_full_watermark)
{
u32 cfg, addr = 0, mask[4]; /* in 16-dwords */
int err;
if (queue >= HALF_QUEUES)
return -ERANGE;
if ((nearly_empty_watermark | nearly_full_watermark) & ~7)
return -EINVAL;
switch (len) {
case 16:
cfg = 0 << 24;
mask[0] = 0x1;
break;
case 32:
cfg = 1 << 24;
mask[0] = 0x3;
break;
case 64:
cfg = 2 << 24;
mask[0] = 0xF;
break;
case 128:
cfg = 3 << 24;
mask[0] = 0xFF;
break;
default:
return -EINVAL;
}
cfg |= nearly_empty_watermark << 26;
cfg |= nearly_full_watermark << 29;
len /= 16; /* in 16-dwords: 1, 2, 4 or 8 */
mask[1] = mask[2] = mask[3] = 0;
if (!try_module_get(THIS_MODULE))
return -ENODEV;
spin_lock_irq(&qmgr_lock);
if (__raw_readl(&qmgr_regs->sram[queue])) {
err = -EBUSY;
goto err;
}
while (1) {
if (!(used_sram_bitmap[0] & mask[0]) &&
!(used_sram_bitmap[1] & mask[1]) &&
!(used_sram_bitmap[2] & mask[2]) &&
!(used_sram_bitmap[3] & mask[3]))
break; /* found free space */
addr++;
shift_mask(mask);
if (addr + len > ARRAY_SIZE(qmgr_regs->sram)) {
printk(KERN_ERR "qmgr: no free SRAM space for"
" queue %i\n", queue);
err = -ENOMEM;
goto err;
}
}
used_sram_bitmap[0] |= mask[0];
used_sram_bitmap[1] |= mask[1];
used_sram_bitmap[2] |= mask[2];
used_sram_bitmap[3] |= mask[3];
__raw_writel(cfg | (addr << 14), &qmgr_regs->sram[queue]);
spin_unlock_irq(&qmgr_lock);
#if DEBUG
printk(KERN_DEBUG "qmgr: requested queue %i, addr = 0x%02X\n",
queue, addr);
#endif
return 0;
err:
spin_unlock_irq(&qmgr_lock);
module_put(THIS_MODULE);
return err;
}
void qmgr_release_queue(unsigned int queue)
{
u32 cfg, addr, mask[4];
BUG_ON(queue >= HALF_QUEUES); /* not in valid range */
spin_lock_irq(&qmgr_lock);
cfg = __raw_readl(&qmgr_regs->sram[queue]);
addr = (cfg >> 14) & 0xFF;
BUG_ON(!addr); /* not requested */
switch ((cfg >> 24) & 3) {
case 0: mask[0] = 0x1; break;
case 1: mask[0] = 0x3; break;
case 2: mask[0] = 0xF; break;
case 3: mask[0] = 0xFF; break;
}
while (addr--)
shift_mask(mask);
__raw_writel(0, &qmgr_regs->sram[queue]);
used_sram_bitmap[0] &= ~mask[0];
used_sram_bitmap[1] &= ~mask[1];
used_sram_bitmap[2] &= ~mask[2];
used_sram_bitmap[3] &= ~mask[3];
irq_handlers[queue] = NULL; /* catch IRQ bugs */
spin_unlock_irq(&qmgr_lock);
module_put(THIS_MODULE);
#if DEBUG
printk(KERN_DEBUG "qmgr: released queue %i\n", queue);
#endif
}
static int qmgr_init(void)
{
int i, err;
mem_res = request_mem_region(IXP4XX_QMGR_BASE_PHYS,
IXP4XX_QMGR_REGION_SIZE,
"IXP4xx Queue Manager");
if (mem_res == NULL)
return -EBUSY;
qmgr_regs = ioremap(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE);
if (qmgr_regs == NULL) {
err = -ENOMEM;
goto error_map;
}
/* reset qmgr registers */
for (i = 0; i < 4; i++) {
__raw_writel(0x33333333, &qmgr_regs->stat1[i]);
__raw_writel(0, &qmgr_regs->irqsrc[i]);
}
for (i = 0; i < 2; i++) {
__raw_writel(0, &qmgr_regs->stat2[i]);
__raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[i]); /* clear */
__raw_writel(0, &qmgr_regs->irqen[i]);
}
for (i = 0; i < QUEUES; i++)
__raw_writel(0, &qmgr_regs->sram[i]);
err = request_irq(IRQ_IXP4XX_QM1, qmgr_irq1, 0,
"IXP4xx Queue Manager", NULL);
if (err) {
printk(KERN_ERR "qmgr: failed to request IRQ%i\n",
IRQ_IXP4XX_QM1);
goto error_irq;
}
used_sram_bitmap[0] = 0xF; /* 4 first pages reserved for config */
spin_lock_init(&qmgr_lock);
printk(KERN_INFO "IXP4xx Queue Manager initialized.\n");
return 0;
error_irq:
iounmap(qmgr_regs);
error_map:
release_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE);
return err;
}
static void qmgr_remove(void)
{
free_irq(IRQ_IXP4XX_QM1, NULL);
synchronize_irq(IRQ_IXP4XX_QM1);
iounmap(qmgr_regs);
release_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE);
}
module_init(qmgr_init);
module_exit(qmgr_remove);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Krzysztof Halasa");
EXPORT_SYMBOL(qmgr_regs);
EXPORT_SYMBOL(qmgr_set_irq);
EXPORT_SYMBOL(qmgr_enable_irq);
EXPORT_SYMBOL(qmgr_disable_irq);
EXPORT_SYMBOL(qmgr_request_queue);
EXPORT_SYMBOL(qmgr_release_queue);
/*
* arch/arm/mach-ixp4xx/nas100d-power.c
*
* NAS 100d Power/Reset driver
*
* Copyright (C) 2005 Tower Technologies
*
* based on nas100d-io.c
* Copyright (C) 2004 Karen Spearel
*
* Author: Alessandro Zummo <a.zummo@towertech.it>
* Maintainers: http://www.nslu2-linux.org/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/reboot.h>
#include <asm/mach-types.h>
static irqreturn_t nas100d_reset_handler(int irq, void *dev_id)
{
/* Signal init to do the ctrlaltdel action, this will bypass init if
* it hasn't started and do a kernel_restart.
*/
ctrl_alt_del();
return IRQ_HANDLED;
}
static int __init nas100d_power_init(void)
{
if (!(machine_is_nas100d()))
return 0;
set_irq_type(NAS100D_RB_IRQ, IRQT_LOW);
if (request_irq(NAS100D_RB_IRQ, &nas100d_reset_handler,
IRQF_DISABLED, "NAS100D reset button", NULL) < 0) {
printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
NAS100D_RB_IRQ);
return -EIO;
}
return 0;
}
static void __exit nas100d_power_exit(void)
{
if (!(machine_is_nas100d()))
return;
free_irq(NAS100D_RB_IRQ, NULL);
}
module_init(nas100d_power_init);
module_exit(nas100d_power_exit);
MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
MODULE_DESCRIPTION("NAS100D Power/Reset driver");
MODULE_LICENSE("GPL");
......@@ -3,8 +3,14 @@
*
* NAS 100d board-setup
*
* based ixdp425-setup.c:
* Copyright (C) 2008 Rod Whitby <rod@whitby.id.au>
*
* based on ixdp425-setup.c:
* Copyright (C) 2003-2004 MontaVista Software, Inc.
* based on nas100d-power.c:
* Copyright (C) 2005 Tower Technologies
* based on nas100d-io.c
* Copyright (C) 2004 Karen Spearel
*
* Author: Alessandro Zummo <a.zummo@towertech.it>
* Author: Rod Whitby <rod@whitby.id.au>
......@@ -12,15 +18,22 @@
*
*/
#include <linux/kernel.h>
#include <linux/if_ether.h>
#include <linux/irq.h>
#include <linux/jiffies.h>
#include <linux/timer.h>
#include <linux/serial.h>
#include <linux/serial_8250.h>
#include <linux/leds.h>
#include <linux/reboot.h>
#include <linux/i2c.h>
#include <linux/i2c-gpio.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
#include <asm/io.h>
#include <asm/gpio.h>
static struct flash_platform_data nas100d_flash_data = {
.map_name = "cfi_probe",
......@@ -39,35 +52,40 @@ static struct platform_device nas100d_flash = {
.resource = &nas100d_flash_resource,
};
#ifdef CONFIG_LEDS_IXP4XX
static struct resource nas100d_led_resources[] = {
static struct i2c_board_info __initdata nas100d_i2c_board_info [] = {
{
I2C_BOARD_INFO("rtc-pcf8563", 0x51),
},
};
static struct gpio_led nas100d_led_pins[] = {
{
.name = "wlan", /* green led */
.start = 0,
.end = 0,
.flags = IXP4XX_GPIO_LOW,
.gpio = NAS100D_LED_WLAN_GPIO,
.active_low = true,
},
{
.name = "ready", /* blue power led (off is flashing!) */
.start = 15,
.end = 15,
.flags = IXP4XX_GPIO_LOW,
.name = "power", /* blue power led (off=flashing) */
.gpio = NAS100D_LED_PWR_GPIO,
.active_low = true,
},
{
.name = "disk", /* yellow led */
.start = 3,
.end = 3,
.flags = IXP4XX_GPIO_LOW,
.gpio = NAS100D_LED_DISK_GPIO,
.active_low = true,
},
};
static struct gpio_led_platform_data nas100d_led_data = {
.num_leds = ARRAY_SIZE(nas100d_led_pins),
.leds = nas100d_led_pins,
};
static struct platform_device nas100d_leds = {
.name = "IXP4XX-GPIO-LED",
.name = "leds-gpio",
.id = -1,
.num_resources = ARRAY_SIZE(nas100d_led_resources),
.resource = nas100d_led_resources,
.dev.platform_data = &nas100d_led_data,
};
#endif
static struct i2c_gpio_platform_data nas100d_i2c_gpio_data = {
.sda_pin = NAS100D_SDA_PIN,
......@@ -125,12 +143,28 @@ static struct platform_device nas100d_uart = {
.resource = nas100d_uart_resources,
};
/* Built-in 10/100 Ethernet MAC interfaces */
static struct eth_plat_info nas100d_plat_eth[] = {
{
.phy = 0,
.rxq = 3,
.txreadyq = 20,
}
};
static struct platform_device nas100d_eth[] = {
{
.name = "ixp4xx_eth",
.id = IXP4XX_ETH_NPEB,
.dev.platform_data = nas100d_plat_eth,
}
};
static struct platform_device *nas100d_devices[] __initdata = {
&nas100d_i2c_gpio,
&nas100d_flash,
#ifdef CONFIG_LEDS_IXP4XX
&nas100d_leds,
#endif
&nas100d_eth[0],
};
static void nas100d_power_off(void)
......@@ -144,8 +178,63 @@ static void nas100d_power_off(void)
gpio_line_set(NAS100D_PO_GPIO, IXP4XX_GPIO_HIGH);
}
/* This is used to make sure the power-button pusher is serious. The button
* must be held until the value of this counter reaches zero.
*/
static int power_button_countdown;
/* Must hold the button down for at least this many counts to be processed */
#define PBUTTON_HOLDDOWN_COUNT 4 /* 2 secs */
static void nas100d_power_handler(unsigned long data);
static DEFINE_TIMER(nas100d_power_timer, nas100d_power_handler, 0, 0);
static void nas100d_power_handler(unsigned long data)
{
/* This routine is called twice per second to check the
* state of the power button.
*/
if (gpio_get_value(NAS100D_PB_GPIO)) {
/* IO Pin is 1 (button pushed) */
if (power_button_countdown > 0)
power_button_countdown--;
} else {
/* Done on button release, to allow for auto-power-on mods. */
if (power_button_countdown == 0) {
/* Signal init to do the ctrlaltdel action,
* this will bypass init if it hasn't started
* and do a kernel_restart.
*/
ctrl_alt_del();
/* Change the state of the power LED to "blink" */
gpio_line_set(NAS100D_LED_PWR_GPIO, IXP4XX_GPIO_LOW);
} else {
power_button_countdown = PBUTTON_HOLDDOWN_COUNT;
}
}
mod_timer(&nas100d_power_timer, jiffies + msecs_to_jiffies(500));
}
static irqreturn_t nas100d_reset_handler(int irq, void *dev_id)
{
/* This is the paper-clip reset, it shuts the machine down directly. */
machine_power_off();
return IRQ_HANDLED;
}
static void __init nas100d_init(void)
{
DECLARE_MAC_BUF(mac_buf);
uint8_t __iomem *f;
int i;
ixp4xx_sys_init();
/* gpio 14 and 15 are _not_ clocks */
......@@ -155,7 +244,8 @@ static void __init nas100d_init(void)
nas100d_flash_resource.end =
IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1;
pm_power_off = nas100d_power_off;
i2c_register_board_info(0, nas100d_i2c_board_info,
ARRAY_SIZE(nas100d_i2c_board_info));
/*
* This is only useful on a modified machine, but it is valuable
......@@ -165,6 +255,48 @@ static void __init nas100d_init(void)
(void)platform_device_register(&nas100d_uart);
platform_add_devices(nas100d_devices, ARRAY_SIZE(nas100d_devices));
pm_power_off = nas100d_power_off;
if (request_irq(gpio_to_irq(NAS100D_RB_GPIO), &nas100d_reset_handler,
IRQF_DISABLED | IRQF_TRIGGER_LOW,
"NAS100D reset button", NULL) < 0) {
printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
gpio_to_irq(NAS100D_RB_GPIO));
}
/* The power button on the Iomega NAS100d is on GPIO 14, but
* it cannot handle interrupts on that GPIO line. So we'll
* have to poll it with a kernel timer.
*/
/* Make sure that the power button GPIO is set up as an input */
gpio_line_config(NAS100D_PB_GPIO, IXP4XX_GPIO_IN);
/* Set the initial value for the power button IRQ handler */
power_button_countdown = PBUTTON_HOLDDOWN_COUNT;
mod_timer(&nas100d_power_timer, jiffies + msecs_to_jiffies(500));
/*
* Map in a portion of the flash and read the MAC address.
* Since it is stored in BE in the flash itself, we need to
* byteswap it if we're in LE mode.
*/
f = ioremap(IXP4XX_EXP_BUS_BASE(0), 0x1000000);
if (f) {
for (i = 0; i < 6; i++)
#ifdef __ARMEB__
nas100d_plat_eth[0].hwaddr[i] = readb(f + 0xFC0FD8 + i);
#else
nas100d_plat_eth[0].hwaddr[i] = readb(f + 0xFC0FD8 + (i^3));
#endif
iounmap(f);
}
printk(KERN_INFO "NAS100D: Using MAC address %s for port 0\n",
print_mac(mac_buf, nas100d_plat_eth[0].hwaddr));
}
MACHINE_START(NAS100D, "Iomega NAS 100d")
......
/*
* arch/arm/mach-ixp4xx/nslu2-power.c
*
* NSLU2 Power/Reset driver
*
* Copyright (C) 2005 Tower Technologies
*
* based on nslu2-io.c
* Copyright (C) 2004 Karen Spearel
*
* Author: Alessandro Zummo <a.zummo@towertech.it>
* Maintainers: http://www.nslu2-linux.org/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/module.h>
#include <linux/reboot.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <asm/mach-types.h>
static irqreturn_t nslu2_power_handler(int irq, void *dev_id)
{
/* Signal init to do the ctrlaltdel action, this will bypass init if
* it hasn't started and do a kernel_restart.
*/
ctrl_alt_del();
return IRQ_HANDLED;
}
static irqreturn_t nslu2_reset_handler(int irq, void *dev_id)
{
/* This is the paper-clip reset, it shuts the machine down directly.
*/
machine_power_off();
return IRQ_HANDLED;
}
static int __init nslu2_power_init(void)
{
if (!(machine_is_nslu2()))
return 0;
*IXP4XX_GPIO_GPISR = 0x20400000; /* read the 2 irqs to clr */
set_irq_type(NSLU2_RB_IRQ, IRQT_LOW);
set_irq_type(NSLU2_PB_IRQ, IRQT_HIGH);
if (request_irq(NSLU2_RB_IRQ, &nslu2_reset_handler,
IRQF_DISABLED, "NSLU2 reset button", NULL) < 0) {
printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
NSLU2_RB_IRQ);
return -EIO;
}
if (request_irq(NSLU2_PB_IRQ, &nslu2_power_handler,
IRQF_DISABLED, "NSLU2 power button", NULL) < 0) {
printk(KERN_DEBUG "Power Button IRQ %d not available\n",
NSLU2_PB_IRQ);
return -EIO;
}
return 0;
}
static void __exit nslu2_power_exit(void)
{
if (!(machine_is_nslu2()))
return;
free_irq(NSLU2_RB_IRQ, NULL);
free_irq(NSLU2_PB_IRQ, NULL);
}
module_init(nslu2_power_init);
module_exit(nslu2_power_exit);
MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
MODULE_DESCRIPTION("NSLU2 Power/Reset driver");
MODULE_LICENSE("GPL");
......@@ -3,27 +3,35 @@
*
* NSLU2 board-setup
*
* based ixdp425-setup.c:
* Copyright (C) 2008 Rod Whitby <rod@whitby.id.au>
*
* based on ixdp425-setup.c:
* Copyright (C) 2003-2004 MontaVista Software, Inc.
* based on nslu2-power.c:
* Copyright (C) 2005 Tower Technologies
*
* Author: Mark Rakes <mrakes at mac.com>
* Author: Rod Whitby <rod@whitby.id.au>
* Author: Alessandro Zummo <a.zummo@towertech.it>
* Maintainers: http://www.nslu2-linux.org/
*
* Fixed missing init_time in MACHINE_START kas11 10/22/04
* Changed to conform to new style __init ixdp425 kas11 10/22/04
*/
#include <linux/kernel.h>
#include <linux/if_ether.h>
#include <linux/irq.h>
#include <linux/serial.h>
#include <linux/serial_8250.h>
#include <linux/leds.h>
#include <linux/reboot.h>
#include <linux/i2c.h>
#include <linux/i2c-gpio.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
#include <asm/mach/time.h>
#include <asm/io.h>
#include <asm/gpio.h>
static struct flash_platform_data nslu2_flash_data = {
.map_name = "cfi_probe",
......@@ -47,41 +55,43 @@ static struct i2c_gpio_platform_data nslu2_i2c_gpio_data = {
.scl_pin = NSLU2_SCL_PIN,
};
#ifdef CONFIG_LEDS_IXP4XX
static struct resource nslu2_led_resources[] = {
static struct i2c_board_info __initdata nslu2_i2c_board_info [] = {
{
I2C_BOARD_INFO("rtc-x1205", 0x6f),
},
};
static struct gpio_led nslu2_led_pins[] = {
{
.name = "ready", /* green led */
.start = NSLU2_LED_GRN_GPIO,
.end = NSLU2_LED_GRN_GPIO,
.flags = IXP4XX_GPIO_HIGH,
.gpio = NSLU2_LED_GRN_GPIO,
},
{
.name = "status", /* red led */
.start = NSLU2_LED_RED_GPIO,
.end = NSLU2_LED_RED_GPIO,
.flags = IXP4XX_GPIO_HIGH,
.gpio = NSLU2_LED_RED_GPIO,
},
{
.name = "disk-1",
.start = NSLU2_LED_DISK1_GPIO,
.end = NSLU2_LED_DISK1_GPIO,
.flags = IXP4XX_GPIO_LOW,
.gpio = NSLU2_LED_DISK1_GPIO,
.active_low = true,
},
{
.name = "disk-2",
.start = NSLU2_LED_DISK2_GPIO,
.end = NSLU2_LED_DISK2_GPIO,
.flags = IXP4XX_GPIO_LOW,
.gpio = NSLU2_LED_DISK2_GPIO,
.active_low = true,
},
};
static struct gpio_led_platform_data nslu2_led_data = {
.num_leds = ARRAY_SIZE(nslu2_led_pins),
.leds = nslu2_led_pins,
};
static struct platform_device nslu2_leds = {
.name = "IXP4XX-GPIO-LED",
.name = "leds-gpio",
.id = -1,
.num_resources = ARRAY_SIZE(nslu2_led_resources),
.resource = nslu2_led_resources,
.dev.platform_data = &nslu2_led_data,
};
#endif
static struct platform_device nslu2_i2c_gpio = {
.name = "i2c-gpio",
......@@ -140,13 +150,29 @@ static struct platform_device nslu2_uart = {
.resource = nslu2_uart_resources,
};
/* Built-in 10/100 Ethernet MAC interfaces */
static struct eth_plat_info nslu2_plat_eth[] = {
{
.phy = 1,
.rxq = 3,
.txreadyq = 20,
}
};
static struct platform_device nslu2_eth[] = {
{
.name = "ixp4xx_eth",
.id = IXP4XX_ETH_NPEB,
.dev.platform_data = nslu2_plat_eth,
}
};
static struct platform_device *nslu2_devices[] __initdata = {
&nslu2_i2c_gpio,
&nslu2_flash,
&nslu2_beeper,
#ifdef CONFIG_LEDS_IXP4XX
&nslu2_leds,
#endif
&nslu2_eth[0],
};
static void nslu2_power_off(void)
......@@ -160,6 +186,25 @@ static void nslu2_power_off(void)
gpio_line_set(NSLU2_PO_GPIO, IXP4XX_GPIO_HIGH);
}
static irqreturn_t nslu2_power_handler(int irq, void *dev_id)
{
/* Signal init to do the ctrlaltdel action, this will bypass init if
* it hasn't started and do a kernel_restart.
*/
ctrl_alt_del();
return IRQ_HANDLED;
}
static irqreturn_t nslu2_reset_handler(int irq, void *dev_id)
{
/* This is the paper-clip reset, it shuts the machine down directly.
*/
machine_power_off();
return IRQ_HANDLED;
}
static void __init nslu2_timer_init(void)
{
/* The xtal on this machine is non-standard. */
......@@ -175,13 +220,18 @@ static struct sys_timer nslu2_timer = {
static void __init nslu2_init(void)
{
DECLARE_MAC_BUF(mac_buf);
uint8_t __iomem *f;
int i;
ixp4xx_sys_init();
nslu2_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
nslu2_flash_resource.end =
IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1;
pm_power_off = nslu2_power_off;
i2c_register_board_info(0, nslu2_i2c_board_info,
ARRAY_SIZE(nslu2_i2c_board_info));
/*
* This is only useful on a modified machine, but it is valuable
......@@ -191,6 +241,43 @@ static void __init nslu2_init(void)
(void)platform_device_register(&nslu2_uart);
platform_add_devices(nslu2_devices, ARRAY_SIZE(nslu2_devices));
pm_power_off = nslu2_power_off;
if (request_irq(gpio_to_irq(NSLU2_RB_GPIO), &nslu2_reset_handler,
IRQF_DISABLED | IRQF_TRIGGER_LOW,
"NSLU2 reset button", NULL) < 0) {
printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
gpio_to_irq(NSLU2_RB_GPIO));
}
if (request_irq(gpio_to_irq(NSLU2_PB_GPIO), &nslu2_power_handler,
IRQF_DISABLED | IRQF_TRIGGER_HIGH,
"NSLU2 power button", NULL) < 0) {
printk(KERN_DEBUG "Power Button IRQ %d not available\n",
gpio_to_irq(NSLU2_PB_GPIO));
}
/*
* Map in a portion of the flash and read the MAC address.
* Since it is stored in BE in the flash itself, we need to
* byteswap it if we're in LE mode.
*/
f = ioremap(IXP4XX_EXP_BUS_BASE(0), 0x40000);
if (f) {
for (i = 0; i < 6; i++)
#ifdef __ARMEB__
nslu2_plat_eth[0].hwaddr[i] = readb(f + 0x3FFB0 + i);
#else
nslu2_plat_eth[0].hwaddr[i] = readb(f + 0x3FFB0 + (i^3));
#endif
iounmap(f);
}
printk(KERN_INFO "NSLU2: Using MAC address %s for port 0\n",
print_mac(mac_buf, nslu2_plat_eth[0].hwaddr));
}
MACHINE_START(NSLU2, "Linksys NSLU2")
......
......@@ -6,7 +6,7 @@
obj-y += clock.o devices.o generic.o irq.o dma.o time.o
obj-$(CONFIG_PXA25x) += pxa25x.o
obj-$(CONFIG_PXA27x) += pxa27x.o
obj-$(CONFIG_PXA3xx) += pxa3xx.o mfp.o
obj-$(CONFIG_PXA3xx) += pxa3xx.o mfp.o smemc.o
obj-$(CONFIG_CPU_PXA300) += pxa300.o
obj-$(CONFIG_CPU_PXA320) += pxa320.o
......
......@@ -29,6 +29,7 @@
#include <asm/mach/map.h>
#include <asm/arch/pxa-regs.h>
#include <asm/arch/pxa2xx-regs.h>
#include <asm/arch/pxafb.h>
#include <asm/arch/ohci.h>
#include <asm/arch/mmc.h>
......
......@@ -10,6 +10,7 @@
#include <asm/arch/mmc.h>
#include <asm/arch/irda.h>
#include <asm/arch/i2c.h>
#include <asm/arch/ohci.h>
#include "devices.h"
......
......@@ -23,6 +23,7 @@
#include <linux/ioport.h>
#include <linux/pm.h>
#include <linux/string.h>
#include <linux/sysdev.h>
#include <asm/hardware.h>
#include <asm/irq.h>
......@@ -226,3 +227,59 @@ void __init pxa_map_io(void)
iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc));
get_clk_frequency_khz(1);
}
#ifdef CONFIG_PM
static unsigned long saved_gplr[4];
static unsigned long saved_gpdr[4];
static unsigned long saved_grer[4];
static unsigned long saved_gfer[4];
static int pxa_gpio_suspend(struct sys_device *dev, pm_message_t state)
{
int i, gpio;
for (gpio = 0, i = 0; gpio < pxa_last_gpio; gpio += 32, i++) {
saved_gplr[i] = GPLR(gpio);
saved_gpdr[i] = GPDR(gpio);
saved_grer[i] = GRER(gpio);
saved_gfer[i] = GFER(gpio);
/* Clear GPIO transition detect bits */
GEDR(gpio) = GEDR(gpio);
}
return 0;
}
static int pxa_gpio_resume(struct sys_device *dev)
{
int i, gpio;
for (gpio = 0, i = 0; gpio < pxa_last_gpio; gpio += 32, i++) {
/* restore level with set/clear */
GPSR(gpio) = saved_gplr[i];
GPCR(gpio) = ~saved_gplr[i];
GRER(gpio) = saved_grer[i];
GFER(gpio) = saved_gfer[i];
GPDR(gpio) = saved_gpdr[i];
}
return 0;
}
#else
#define pxa_gpio_suspend NULL
#define pxa_gpio_resume NULL
#endif
struct sysdev_class pxa_gpio_sysclass = {
.name = "gpio",
.suspend = pxa_gpio_suspend,
.resume = pxa_gpio_resume,
};
static int __init pxa_gpio_init(void)
{
return sysdev_class_register(&pxa_gpio_sysclass);
}
core_initcall(pxa_gpio_init);
......@@ -52,3 +52,6 @@ extern unsigned pxa3xx_get_memclk_frequency_10khz(void);
#define pxa3xx_get_clk_frequency_khz(x) (0)
#define pxa3xx_get_memclk_frequency_10khz() (0)
#endif
extern struct sysdev_class pxa_irq_sysclass;
extern struct sysdev_class pxa_gpio_sysclass;
......@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/sysdev.h>
#include <asm/hardware.h>
#include <asm/irq.h>
......@@ -321,3 +322,64 @@ void __init pxa_init_irq_set_wake(int (*set_wake)(unsigned int, unsigned int))
pxa_low_gpio_chip.set_wake = set_wake;
pxa_muxed_gpio_chip.set_wake = set_wake;
}
#ifdef CONFIG_PM
static unsigned long saved_icmr[2];
static int pxa_irq_suspend(struct sys_device *dev, pm_message_t state)
{
switch (dev->id) {
case 0:
saved_icmr[0] = ICMR;
ICMR = 0;
break;
#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
case 1:
saved_icmr[1] = ICMR2;
ICMR2 = 0;
break;
#endif
default:
return -EINVAL;
}
return 0;
}
static int pxa_irq_resume(struct sys_device *dev)
{
switch (dev->id) {
case 0:
ICMR = saved_icmr[0];
ICLR = 0;
ICCR = 1;
break;
#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
case 1:
ICMR2 = saved_icmr[1];
ICLR2 = 0;
break;
#endif
default:
return -EINVAL;
}
return 0;
}
#else
#define pxa_irq_suspend NULL
#define pxa_irq_resume NULL
#endif
struct sysdev_class pxa_irq_sysclass = {
.name = "irq",
.suspend = pxa_irq_suspend,
.resume = pxa_irq_resume,
};
static int __init pxa_irq_init(void)
{
return sysdev_class_register(&pxa_irq_sysclass);
}
core_initcall(pxa_irq_init);
......@@ -22,6 +22,7 @@
#include <asm/hardware.h>
#include <asm/arch/mfp.h>
#include <asm/arch/mfp-pxa3xx.h>
#include <asm/arch/pxa3xx-regs.h>
/* mfp_spin_lock is used to ensure that MFP register configuration
* (most likely a read-modify-write operation) is atomic, and that
......@@ -223,11 +224,19 @@ static int pxa3xx_mfp_resume(struct sys_device *d)
struct pxa3xx_mfp_pin *p = &mfp_table[pin];
__mfp_config_run(p);
}
/* clear RDH bit when MFP settings are restored
*
* NOTE: the last 3 bits DxS are write-1-to-clear so carefully
* preserve them here in case they will be referenced later
*/
ASCR &= ~(ASCR_RDH | ASCR_D1S | ASCR_D2S | ASCR_D3S);
return 0;
}
static struct sysdev_class mfp_sysclass = {
set_kset_name("mfp"),
.name = "mfp",
.suspend = pxa3xx_mfp_suspend,
.resume = pxa3xx_mfp_resume,
};
......
......@@ -29,6 +29,7 @@
#include <asm/mach/arch.h>
#include <asm/arch/hardware.h>
#include <asm/arch/pxa-regs.h>
#include <asm/arch/pxa2xx-regs.h>
#include <asm/arch/pxa2xx_spi.h>
#include <asm/arch/pcm027.h>
#include "generic.h"
......
......@@ -164,7 +164,7 @@ static struct resource poodlets_resources[] = {
},
};
static unsigned long poodle_get_hsync_len(void)
static unsigned long poodle_get_hsync_invperiod(void)
{
return 0;
}
......@@ -174,9 +174,9 @@ static void poodle_null_hsync(void)
}
static struct corgits_machinfo poodle_ts_machinfo = {
.get_hsync_len = poodle_get_hsync_len,
.put_hsync = poodle_null_hsync,
.wait_hsync = poodle_null_hsync,
.get_hsync_invperiod = poodle_get_hsync_invperiod,
.put_hsync = poodle_null_hsync,
.wait_hsync = poodle_null_hsync,
};
static struct platform_device poodle_ts_device = {
......
......@@ -21,6 +21,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/suspend.h>
#include <linux/sysdev.h>
#include <asm/hardware.h>
#include <asm/arch/irqs.h>
......@@ -141,11 +142,6 @@ static struct clk pxa25x_clks[] = {
#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x
#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x]
#define RESTORE_GPLEVEL(n) do { \
GPSR##n = sleep_save[SLEEP_SAVE_GPLR##n]; \
GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \
} while (0)
/*
* List of global PXA peripheral registers to preserve.
* More ones like CP and general purpose register values are preserved
......@@ -153,10 +149,6 @@ static struct clk pxa25x_clks[] = {
*/
enum { SLEEP_SAVE_START = 0,
SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2,
SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2,
SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2,
SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2,
SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2,
SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U,
......@@ -165,7 +157,6 @@ enum { SLEEP_SAVE_START = 0,
SLEEP_SAVE_PSTR,
SLEEP_SAVE_ICMR,
SLEEP_SAVE_CKEN,
SLEEP_SAVE_SIZE
......@@ -174,17 +165,12 @@ enum { SLEEP_SAVE_START = 0,
static void pxa25x_cpu_pm_save(unsigned long *sleep_save)
{
SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2);
SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2);
SAVE(GRER0); SAVE(GRER1); SAVE(GRER2);
SAVE(GFER0); SAVE(GFER1); SAVE(GFER2);
SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2);
SAVE(GAFR0_L); SAVE(GAFR0_U);
SAVE(GAFR1_L); SAVE(GAFR1_U);
SAVE(GAFR2_L); SAVE(GAFR2_U);
SAVE(ICMR); ICMR = 0;
SAVE(CKEN);
SAVE(PSTR);
......@@ -198,22 +184,14 @@ static void pxa25x_cpu_pm_restore(unsigned long *sleep_save)
PSPR = 0;
/* restore registers */
RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1); RESTORE_GPLEVEL(2);
RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2);
RESTORE(GAFR0_L); RESTORE(GAFR0_U);
RESTORE(GAFR1_L); RESTORE(GAFR1_U);
RESTORE(GAFR2_L); RESTORE(GAFR2_U);
RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2);
RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2);
RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2);
PSSR = PSSR_RDH | PSSR_PH;
RESTORE(CKEN);
ICLR = 0;
ICCR = 1;
RESTORE(ICMR);
RESTORE(PSTR);
}
......@@ -304,9 +282,17 @@ static struct platform_device *pxa25x_devices[] __initdata = {
&pxa25x_device_assp,
};
static struct sys_device pxa25x_sysdev[] = {
{
.cls = &pxa_irq_sysclass,
}, {
.cls = &pxa_gpio_sysclass,
},
};
static int __init pxa25x_init(void)
{
int ret = 0;
int i, ret = 0;
/* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */
if (cpu_is_pxa25x())
......@@ -320,9 +306,18 @@ static int __init pxa25x_init(void)
pxa25x_init_pm();
for (i = 0; i < ARRAY_SIZE(pxa25x_sysdev); i++) {
ret = sysdev_register(&pxa25x_sysdev[i]);
if (ret)
pr_err("failed to register sysdev[%d]\n", i);
}
ret = platform_add_devices(pxa25x_devices,
ARRAY_SIZE(pxa25x_devices));
if (ret)
return ret;
}
/* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */
if (cpu_is_pxa25x())
ret = platform_device_register(&pxa_device_hwuart);
......
......@@ -16,6 +16,7 @@
#include <linux/init.h>
#include <linux/suspend.h>
#include <linux/platform_device.h>
#include <linux/sysdev.h>
#include <asm/hardware.h>
#include <asm/irq.h>
......@@ -171,11 +172,6 @@ static struct clk pxa27x_clks[] = {
#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x
#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x]
#define RESTORE_GPLEVEL(n) do { \
GPSR##n = sleep_save[SLEEP_SAVE_GPLR##n]; \
GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \
} while (0)
/*
* List of global PXA peripheral registers to preserve.
* More ones like CP and general purpose register values are preserved
......@@ -183,10 +179,6 @@ static struct clk pxa27x_clks[] = {
*/
enum { SLEEP_SAVE_START = 0,
SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2, SLEEP_SAVE_GPLR3,
SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2, SLEEP_SAVE_GPDR3,
SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2, SLEEP_SAVE_GRER3,
SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2, SLEEP_SAVE_GFER3,
SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2, SLEEP_SAVE_PGSR3,
SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U,
......@@ -196,7 +188,6 @@ enum { SLEEP_SAVE_START = 0,
SLEEP_SAVE_PSTR,
SLEEP_SAVE_ICMR,
SLEEP_SAVE_CKEN,
SLEEP_SAVE_MDREFR,
......@@ -208,10 +199,6 @@ enum { SLEEP_SAVE_START = 0,
void pxa27x_cpu_pm_save(unsigned long *sleep_save)
{
SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2); SAVE(GPLR3);
SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2); SAVE(GPDR3);
SAVE(GRER0); SAVE(GRER1); SAVE(GRER2); SAVE(GRER3);
SAVE(GFER0); SAVE(GFER1); SAVE(GFER2); SAVE(GFER3);
SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2); SAVE(PGSR3);
SAVE(GAFR0_L); SAVE(GAFR0_U);
......@@ -223,12 +210,8 @@ void pxa27x_cpu_pm_save(unsigned long *sleep_save)
SAVE(PWER); SAVE(PCFR); SAVE(PRER);
SAVE(PFER); SAVE(PKWR);
SAVE(ICMR); ICMR = 0;
SAVE(CKEN);
SAVE(PSTR);
/* Clear GPIO transition detect bits */
GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2; GEDR3 = GEDR3;
}
void pxa27x_cpu_pm_restore(unsigned long *sleep_save)
......@@ -237,15 +220,10 @@ void pxa27x_cpu_pm_restore(unsigned long *sleep_save)
PSPR = 0;
/* restore registers */
RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1);
RESTORE_GPLEVEL(2); RESTORE_GPLEVEL(3);
RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2); RESTORE(GPDR3);
RESTORE(GAFR0_L); RESTORE(GAFR0_U);
RESTORE(GAFR1_L); RESTORE(GAFR1_U);
RESTORE(GAFR2_L); RESTORE(GAFR2_U);
RESTORE(GAFR3_L); RESTORE(GAFR3_U);
RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2); RESTORE(GRER3);
RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2); RESTORE(GFER3);
RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2); RESTORE(PGSR3);
RESTORE(MDREFR);
......@@ -256,9 +234,6 @@ void pxa27x_cpu_pm_restore(unsigned long *sleep_save)
RESTORE(CKEN);
ICLR = 0;
ICCR = 1;
RESTORE(ICMR);
RESTORE(PSTR);
}
......@@ -409,9 +384,22 @@ static struct platform_device *devices[] __initdata = {
&pxa27x_device_ssp3,
};
static struct sys_device pxa27x_sysdev[] = {
{
.id = 0,
.cls = &pxa_irq_sysclass,
}, {
.id = 1,
.cls = &pxa_irq_sysclass,
}, {
.cls = &pxa_gpio_sysclass,
},
};
static int __init pxa27x_init(void)
{
int ret = 0;
int i, ret = 0;
if (cpu_is_pxa27x()) {
clks_register(pxa27x_clks, ARRAY_SIZE(pxa27x_clks));
......@@ -420,8 +408,15 @@ static int __init pxa27x_init(void)
pxa27x_init_pm();
for (i = 0; i < ARRAY_SIZE(pxa27x_sysdev); i++) {
ret = sysdev_register(&pxa27x_sysdev[i]);
if (ret)
pr_err("failed to register sysdev[%d]\n", i);
}
ret = platform_add_devices(devices, ARRAY_SIZE(devices));
}
return ret;
}
......
......@@ -20,6 +20,7 @@
#include <linux/platform_device.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/sysdev.h>
#include <asm/hardware.h>
#include <asm/arch/pxa3xx-regs.h>
......@@ -39,6 +40,7 @@
#define RO_CLK 60000000
#define ACCR_D0CS (1 << 26)
#define ACCR_PCCE (1 << 11)
/* crystal frequency to static memory controller multiplier (SMCFS) */
static unsigned char smcfs_mult[8] = { 6, 0, 8, 0, 0, 16, };
......@@ -203,7 +205,6 @@ static struct clk pxa3xx_clks[] = {
};
#ifdef CONFIG_PM
#define SLEEP_SAVE_SIZE 4
#define ISRAM_START 0x5c000000
#define ISRAM_SIZE SZ_256K
......@@ -211,25 +212,29 @@ static struct clk pxa3xx_clks[] = {
static void __iomem *sram;
static unsigned long wakeup_src;
static void pxa3xx_cpu_pm_save(unsigned long *sleep_save)
{
pr_debug("PM: CKENA=%08x CKENB=%08x\n", CKENA, CKENB);
#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x
#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x]
if (CKENA & (1 << CKEN_USBH)) {
printk(KERN_ERR "PM: USB host clock not stopped?\n");
CKENA &= ~(1 << CKEN_USBH);
}
// CKENA |= 1 << (CKEN_ISC & 31);
enum { SLEEP_SAVE_START = 0,
SLEEP_SAVE_CKENA,
SLEEP_SAVE_CKENB,
SLEEP_SAVE_ACCR,
/*
* Low power modes require the HSIO2 clock to be enabled.
*/
CKENB |= 1 << (CKEN_HSIO2 & 31);
SLEEP_SAVE_SIZE,
};
static void pxa3xx_cpu_pm_save(unsigned long *sleep_save)
{
SAVE(CKENA);
SAVE(CKENB);
SAVE(ACCR);
}
static void pxa3xx_cpu_pm_restore(unsigned long *sleep_save)
{
CKENB &= ~(1 << (CKEN_HSIO2 & 31));
RESTORE(ACCR);
RESTORE(CKENA);
RESTORE(CKENB);
}
/*
......@@ -265,6 +270,46 @@ static void pxa3xx_cpu_standby(unsigned int pwrmode)
printk("PM: AD2D0SR=%08x ASCR=%08x\n", AD2D0SR, ASCR);
}
/*
* NOTE: currently, the OBM (OEM Boot Module) binary comes along with
* PXA3xx development kits assumes that the resuming process continues
* with the address stored within the first 4 bytes of SDRAM. The PSPR
* register is used privately by BootROM and OBM, and _must_ be set to
* 0x5c014000 for the moment.
*/
static void pxa3xx_cpu_pm_suspend(void)
{
volatile unsigned long *p = (volatile void *)0xc0000000;
unsigned long saved_data = *p;
extern void pxa3xx_cpu_suspend(void);
extern void pxa3xx_cpu_resume(void);
/* resuming from D2 requires the HSIO2/BOOT/TPM clocks enabled */
CKENA |= (1 << CKEN_BOOT) | (1 << CKEN_TPM);
CKENB |= 1 << (CKEN_HSIO2 & 0x1f);
/* clear and setup wakeup source */
AD3SR = ~0;
AD3ER = wakeup_src;
ASCR = ASCR;
ARSR = ARSR;
PCFR |= (1u << 13); /* L1_DIS */
PCFR &= ~((1u << 12) | (1u << 1)); /* L0_EN | SL_ROD */
PSPR = 0x5c014000;
/* overwrite with the resume address */
*p = virt_to_phys(pxa3xx_cpu_resume);
pxa3xx_cpu_suspend();
*p = saved_data;
AD3ER = 0;
}
static void pxa3xx_cpu_pm_enter(suspend_state_t state)
{
/*
......@@ -279,6 +324,7 @@ static void pxa3xx_cpu_pm_enter(suspend_state_t state)
break;
case PM_SUSPEND_MEM:
pxa3xx_cpu_pm_suspend();
break;
}
}
......@@ -452,9 +498,21 @@ static struct platform_device *devices[] __initdata = {
&pxa3xx_device_ssp4,
};
static struct sys_device pxa3xx_sysdev[] = {
{
.id = 0,
.cls = &pxa_irq_sysclass,
}, {
.id = 1,
.cls = &pxa_irq_sysclass,
}, {
.cls = &pxa_gpio_sysclass,
},
};
static int __init pxa3xx_init(void)
{
int ret = 0;
int i, ret = 0;
if (cpu_is_pxa3xx()) {
clks_register(pxa3xx_clks, ARRAY_SIZE(pxa3xx_clks));
......@@ -464,9 +522,16 @@ static int __init pxa3xx_init(void)
pxa3xx_init_pm();
return platform_add_devices(devices, ARRAY_SIZE(devices));
for (i = 0; i < ARRAY_SIZE(pxa3xx_sysdev); i++) {
ret = sysdev_register(&pxa3xx_sysdev[i]);
if (ret)
pr_err("failed to register sysdev[%d]\n", i);
}
ret = platform_add_devices(devices, ARRAY_SIZE(devices));
}
return 0;
return ret;
}
subsys_initcall(pxa3xx_init);
......@@ -50,6 +50,108 @@ pxa_cpu_save_sp:
str r0, [r1]
ldr pc, [sp], #4
#ifdef CONFIG_PXA3xx
/*
* pxa3xx_cpu_suspend() - forces CPU into sleep state (S2D3C4)
*
* NOTE: unfortunately, pxa_cpu_save_cp can not be reused here since
* the auxiliary control register address is different between pxa3xx
* and pxa{25x,27x}
*/
ENTRY(pxa3xx_cpu_suspend)
#ifndef CONFIG_IWMMXT
mra r2, r3, acc0
#endif
stmfd sp!, {r2 - r12, lr} @ save registers on stack
mrc p14, 0, r3, c6, c0, 0 @ clock configuration, for turbo mode
mrc p15, 0, r4, c15, c1, 0 @ CP access reg
mrc p15, 0, r5, c13, c0, 0 @ PID
mrc p15, 0, r6, c3, c0, 0 @ domain ID
mrc p15, 0, r7, c2, c0, 0 @ translation table base addr
mrc p15, 0, r8, c1, c0, 1 @ auxiliary control reg
mrc p15, 0, r9, c1, c0, 0 @ control reg
bic r3, r3, #2 @ clear frequency change bit
@ store them plus current virtual stack ptr on stack
mov r10, sp
stmfd sp!, {r3 - r10}
@ store physical address of stack pointer
mov r0, sp
bl sleep_phys_sp
ldr r1, =sleep_save_sp
str r0, [r1]
@ clean data cache
bl xsc3_flush_kern_cache_all
mov r0, #0x06 @ S2D3C4 mode
mcr p14, 0, r0, c7, c0, 0 @ enter sleep
20: b 20b @ waiting for sleep
.data
.align 5
/*
* pxa3xx_cpu_resume
*/
ENTRY(pxa3xx_cpu_resume)
mov r0, #PSR_I_BIT | PSR_F_BIT | SVC_MODE @ set SVC, irqs off
msr cpsr_c, r0
ldr r0, sleep_save_sp @ stack phys addr
ldmfd r0, {r3 - r9, sp} @ CP regs + virt stack ptr
mov r1, #0
mcr p15, 0, r1, c7, c7, 0 @ invalidate I & D caches, BTB
mcr p15, 0, r1, c7, c10, 4 @ drain write (&fill) buffer
mcr p15, 0, r1, c7, c5, 4 @ flush prefetch buffer
mcr p15, 0, r1, c8, c7, 0 @ invalidate I & D TLBs
mcr p14, 0, r3, c6, c0, 0 @ clock configuration, turbo mode.
mcr p15, 0, r4, c15, c1, 0 @ CP access reg
mcr p15, 0, r5, c13, c0, 0 @ PID
mcr p15, 0, r6, c3, c0, 0 @ domain ID
mcr p15, 0, r7, c2, c0, 0 @ translation table base addr
mcr p15, 0, r8, c1, c0, 1 @ auxiliary control reg
@ temporarily map resume_turn_on_mmu into the page table,
@ otherwise prefetch abort occurs after MMU is turned on
mov r1, r7
bic r1, r1, #0x00ff
bic r1, r1, #0x3f00
ldr r2, =0x542e
adr r3, resume_turn_on_mmu
mov r3, r3, lsr #20
orr r4, r2, r3, lsl #20
ldr r5, [r1, r3, lsl #2]
str r4, [r1, r3, lsl #2]
@ Mapping page table address in the page table
mov r6, r1, lsr #20
orr r7, r2, r6, lsl #20
ldr r8, [r1, r6, lsl #2]
str r7, [r1, r6, lsl #2]
ldr r2, =pxa3xx_resume_after_mmu @ absolute virtual address
b resume_turn_on_mmu @ cache align execution
.text
pxa3xx_resume_after_mmu:
/* restore the temporary mapping */
str r5, [r1, r3, lsl #2]
str r8, [r1, r6, lsl #2]
b resume_after_mmu
#endif /* CONFIG_PXA3xx */
#ifdef CONFIG_PXA27x
/*
* pxa27x_cpu_suspend()
......
此差异已折叠。
......@@ -36,6 +36,7 @@
#include <asm/mach/irq.h>
#include <asm/arch/pxa-regs.h>
#include <asm/arch/pxa2xx-regs.h>
#include <asm/arch/irda.h>
#include <asm/arch/mmc.h>
#include <asm/arch/ohci.h>
......
......@@ -29,6 +29,7 @@
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/arch/pxa-regs.h>
#include <asm/arch/pxa2xx-regs.h>
#include <asm/arch/irda.h>
#include <asm/arch/mmc.h>
#include <asm/arch/udc.h>
......
此差异已折叠。
......@@ -4,6 +4,5 @@
obj-y := core.o clock.o
obj-$(CONFIG_MACH_REALVIEW_EB) += realview_eb.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o localtimer.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -23,7 +23,6 @@
#define __ASM_ARCH_HARDWARE_H
#include <asm/sizes.h>
#include <asm/arch/platform.h>
/* macro to get at IO space when running virtually */
#define IO_ADDRESS(x) ((((x) & 0x0effffff) | (((x) >> 4) & 0x0f000000)) + 0xf0000000)
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册