Skip to content

Commit

Permalink
[ARM] 4318/2: DSM-G600 Board Support
Browse files Browse the repository at this point in the history
This patch adds support for the D-Link DSM-G600 Rev A.
This is an ARM XScale IXP4xx system relatively similar to
the NSLU2 and NAS-100D already supported by mainline. An
important difference is Gigabit Ethernet support using
the Via Velocity chipset.

This patch is the combined work of Michael Westerhof and
Alessandro Zummo, with contributions from Michael-Luke
Jones. This version addresses review comments from rmk
and Deepak Saxena.

Signed-off-by: Michael-Luke Jones <mlj28@cam.ac.uk>
Signed-off-by: Alessandro Zummo <a.zummo@towertech.it>
Signed-off-by: Michael Westerhof <mwester@dls.net>
Signed-off-by: Deepak Saxena <dsaxena@plexity.net>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
Michael-Luke Jones authored and Russell King committed May 5, 2007
1 parent 53b2e01 commit 28bd3a0
Show file tree
Hide file tree
Showing 8 changed files with 453 additions and 0 deletions.
9 changes: 9 additions & 0 deletions arch/arm/mach-ixp4xx/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,15 @@ config MACH_NAS100D
NAS 100d device. For more information on this platform,
see http://www.nslu2-linux.org/wiki/NAS100d/HomePage

config MACH_DSMG600
bool
prompt "D-Link DSM-G600 RevA"
select PCI
help
Say 'Y' here if you want your kernel to support D-Link's
DSM-G600 RevA device. For more information on this platform,
see http://www.nslu2-linux.org/wiki/DSMG600/HomePage

#
# Avila and IXDP share the same source for now. Will change in future
#
Expand Down
2 changes: 2 additions & 0 deletions arch/arm/mach-ixp4xx/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ obj-pci-$(CONFIG_ARCH_ADI_COYOTE) += coyote-pci.o
obj-pci-$(CONFIG_MACH_GTWX5715) += gtwx5715-pci.o
obj-pci-$(CONFIG_MACH_NSLU2) += nslu2-pci.o
obj-pci-$(CONFIG_MACH_NAS100D) += nas100d-pci.o
obj-pci-$(CONFIG_MACH_DSMG600) += dsmg600-pci.o

obj-y += common.o

Expand All @@ -22,5 +23,6 @@ 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_PCI) += $(obj-pci-$(CONFIG_PCI)) common-pci.o
74 changes: 74 additions & 0 deletions arch/arm/mach-ixp4xx/dsmg600-pci.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* DSM-G600 board-level PCI initialization
*
* Copyright (C) 2006 Tower Technologies
* Author: Alessandro Zummo <a.zummo@towertech.it>
*
* based on ixdp425-pci.c:
* Copyright (C) 2002 Intel Corporation.
* Copyright (C) 2003-2004 MontaVista Software, Inc.
*
* Maintainer: 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/pci.h>
#include <linux/init.h>
#include <linux/irq.h>

#include <asm/mach/pci.h>
#include <asm/mach-types.h>

void __init dsmg600_pci_preinit(void)
{
set_irq_type(IRQ_DSMG600_PCI_INTA, IRQT_LOW);
set_irq_type(IRQ_DSMG600_PCI_INTB, IRQT_LOW);
set_irq_type(IRQ_DSMG600_PCI_INTC, IRQT_LOW);
set_irq_type(IRQ_DSMG600_PCI_INTD, IRQT_LOW);
set_irq_type(IRQ_DSMG600_PCI_INTE, IRQT_LOW);
set_irq_type(IRQ_DSMG600_PCI_INTF, IRQT_LOW);

ixp4xx_pci_preinit();
}

static int __init dsmg600_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
static int pci_irq_table[DSMG600_PCI_MAX_DEV][DSMG600_PCI_IRQ_LINES] =
{
{ IRQ_DSMG600_PCI_INTE, -1, -1 },
{ IRQ_DSMG600_PCI_INTA, -1, -1 },
{ IRQ_DSMG600_PCI_INTB, IRQ_DSMG600_PCI_INTC, IRQ_DSMG600_PCI_INTD },
{ IRQ_DSMG600_PCI_INTF, -1, -1 },
};

int irq = -1;

if (slot >= 1 && slot <= DSMG600_PCI_MAX_DEV &&
pin >= 1 && pin <= DSMG600_PCI_IRQ_LINES)
irq = pci_irq_table[slot-1][pin-1];

return irq;
}

struct hw_pci __initdata dsmg600_pci = {
.nr_controllers = 1,
.preinit = dsmg600_pci_preinit,
.swizzle = pci_std_swizzle,
.setup = ixp4xx_setup,
.scan = ixp4xx_scan_bus,
.map_irq = dsmg600_map_irq,
};

int __init dsmg600_pci_init(void)
{
if (machine_is_dsmg600())
pci_common_init(&dsmg600_pci);

return 0;
}

subsys_initcall(dsmg600_pci_init);
125 changes: 125 additions & 0 deletions arch/arm/mach-ixp4xx/dsmg600-power.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* 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");
Loading

0 comments on commit 28bd3a0

Please sign in to comment.