Skip to content

Commit

Permalink
[MIPS] PMC MSP71xx core platform
Browse files Browse the repository at this point in the history
Patch to add core platform support for the PMC-Sierra MSP71xx devices.

Signed-off-by: Marc St-Jean <Marc_St-Jean@pmc-sierra.com>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
  • Loading branch information
Marc St-Jean authored and Ralf Baechle committed Jul 10, 2007
1 parent a4b156d commit 35832e2
Show file tree
Hide file tree
Showing 16 changed files with 3,083 additions and 0 deletions.
11 changes: 11 additions & 0 deletions arch/mips/pmc-sierra/msp71xx/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#
# Makefile for the PMC-Sierra MSP SOCs
#
obj-y += msp_prom.o msp_setup.o msp_irq.o \
msp_time.o msp_serial.o msp_elb.o
obj-$(CONFIG_PMC_MSP7120_GW) += msp_hwbutton.o
obj-$(CONFIG_IRQ_MSP_SLP) += msp_irq_slp.o
obj-$(CONFIG_IRQ_MSP_CIC) += msp_irq_cic.o
obj-$(CONFIG_PCI) += msp_pci.o
obj-$(CONFIG_MSPETH) += msp_eth.o
obj-$(CONFIG_USB_MSP71XX) += msp_usb.o
46 changes: 46 additions & 0 deletions arch/mips/pmc-sierra/msp71xx/msp_elb.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Sets up the proper Chip Select configuration registers. It is assumed that
* PMON sets up the ADDR and MASK registers properly.
*
* Copyright 2005-2006 PMC-Sierra, Inc.
* Author: Marc St-Jean, Marc_St-Jean@pmc-sierra.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <linux/kernel.h>
#include <linux/init.h>
#include <msp_regs.h>

static int __init msp_elb_setup(void)
{
#if defined(CONFIG_PMC_MSP7120_GW) \
|| defined(CONFIG_PMC_MSP7120_EVAL)
/*
* Force all CNFG to be identical and equal to CS0,
* according to OPS doc
*/
*CS1_CNFG_REG = *CS2_CNFG_REG = *CS3_CNFG_REG = *CS0_CNFG_REG;
#endif
return 0;
}

subsys_initcall(msp_elb_setup);
179 changes: 179 additions & 0 deletions arch/mips/pmc-sierra/msp71xx/msp_hwbutton.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
/*
* Sets up interrupt handlers for various hardware switches which are
* connected to interrupt lines.
*
* Copyright 2005-2207 PMC-Sierra, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>

#include <msp_int.h>
#include <msp_regs.h>
#include <msp_regops.h>
#ifdef CONFIG_PMCTWILED
#include <msp_led_macros.h>
#endif

/* For hwbutton_interrupt->initial_state */
#define HWBUTTON_HI 0x1
#define HWBUTTON_LO 0x2

/*
* This struct describes a hardware button
*/
struct hwbutton_interrupt {
char *name; /* Name of button */
int irq; /* Actual LINUX IRQ */
int eirq; /* Extended IRQ number (0-7) */
int initial_state; /* The "normal" state of the switch */
void (*handle_hi)(void *); /* Handler: switch input has gone HI */
void (*handle_lo)(void *); /* Handler: switch input has gone LO */
void *data; /* Optional data to pass to handler */
};

#ifdef CONFIG_PMC_MSP7120_GW
extern void msp_restart(char *);

static void softreset_push(void *data)
{
printk(KERN_WARNING "SOFTRESET switch was pushed\n");

/*
* In the future you could move this to the release handler,
* timing the difference between the 'push' and 'release', and only
* doing this ungraceful restart if the button has been down for
* a certain amount of time; otherwise doing a graceful restart.
*/

msp_restart(NULL);
}

static void softreset_release(void *data)
{
printk(KERN_WARNING "SOFTRESET switch was released\n");

/* Do nothing */
}

static void standby_on(void *data)
{
printk(KERN_WARNING "STANDBY switch was set to ON (not implemented)\n");

/* TODO: Put board in standby mode */
#ifdef CONFIG_PMCTWILED
msp_led_turn_off(MSP_LED_PWRSTANDBY_GREEN);
msp_led_turn_on(MSP_LED_PWRSTANDBY_RED);
#endif
}

static void standby_off(void *data)
{
printk(KERN_WARNING
"STANDBY switch was set to OFF (not implemented)\n");

/* TODO: Take out of standby mode */
#ifdef CONFIG_PMCTWILED
msp_led_turn_on(MSP_LED_PWRSTANDBY_GREEN);
msp_led_turn_off(MSP_LED_PWRSTANDBY_RED);
#endif
}

static struct hwbutton_interrupt softreset_sw = {
.name = "Softreset button",
.irq = MSP_INT_EXT0,
.eirq = 0,
.initial_state = HWBUTTON_HI,
.handle_hi = softreset_release,
.handle_lo = softreset_push,
.data = NULL,
};

static struct hwbutton_interrupt standby_sw = {
.name = "Standby switch",
.irq = MSP_INT_EXT1,
.eirq = 1,
.initial_state = HWBUTTON_HI,
.handle_hi = standby_off,
.handle_lo = standby_on,
.data = NULL,
};
#endif /* CONFIG_PMC_MSP7120_GW */

static irqreturn_t hwbutton_handler(int irq, void *data)
{
struct hwbutton_interrupt *hirq = data;
unsigned long cic_ext = *CIC_EXT_CFG_REG;

if (irq != hirq->irq)
return IRQ_NONE;

if (CIC_EXT_IS_ACTIVE_HI(cic_ext, hirq->eirq)) {
/* Interrupt: pin is now HI */
CIC_EXT_SET_ACTIVE_LO(cic_ext, hirq->eirq);
hirq->handle_hi(hirq->data);
} else {
/* Interrupt: pin is now LO */
CIC_EXT_SET_ACTIVE_HI(cic_ext, hirq->eirq);
hirq->handle_lo(hirq->data);
}

/*
* Invert the POLARITY of this level interrupt to ack the interrupt
* Thus next state change will invoke the opposite message
*/
*CIC_EXT_CFG_REG = cic_ext;

return IRQ_HANDLED;
}

static int msp_hwbutton_register(struct hwbutton_interrupt *hirq)
{
unsigned long cic_ext;

if (hirq->handle_hi == NULL || hirq->handle_lo == NULL)
return -EINVAL;

cic_ext = *CIC_EXT_CFG_REG;
CIC_EXT_SET_TRIGGER_LEVEL(cic_ext, hirq->eirq);
if (hirq->initial_state == HWBUTTON_HI)
CIC_EXT_SET_ACTIVE_LO(cic_ext, hirq->eirq);
else
CIC_EXT_SET_ACTIVE_HI(cic_ext, hirq->eirq);
*CIC_EXT_CFG_REG = cic_ext;

return request_irq(hirq->irq, hwbutton_handler, SA_INTERRUPT,
hirq->name, (void *)hirq);
}

static int __init msp_hwbutton_setup(void)
{
#ifdef CONFIG_PMC_MSP7120_GW
msp_hwbutton_register(&softreset_sw);
msp_hwbutton_register(&standby_sw);
#endif
return 0;
}

subsys_initcall(msp_hwbutton_setup);
124 changes: 124 additions & 0 deletions arch/mips/pmc-sierra/msp71xx/msp_irq.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
* IRQ vector handles
*
* Copyright (C) 1995, 1996, 1997, 2003 by Ralf Baechle
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/ptrace.h>
#include <linux/time.h>

#include <asm/irq_cpu.h>

#include <msp_int.h>

extern void msp_int_handle(void);

/* SLP bases systems */
extern void msp_slp_irq_init(void);
extern void msp_slp_irq_dispatch(void);

/* CIC based systems */
extern void msp_cic_irq_init(void);
extern void msp_cic_irq_dispatch(void);

/*
* The PMC-Sierra MSP interrupts are arranged in a 3 level cascaded
* hierarchical system. The first level are the direct MIPS interrupts
* and are assigned the interrupt range 0-7. The second level is the SLM
* interrupt controller and is assigned the range 8-39. The third level
* comprises the Peripherial block, the PCI block, the PCI MSI block and
* the SLP. The PCI interrupts and the SLP errors are handled by the
* relevant subsystems so the core interrupt code needs only concern
* itself with the Peripheral block. These are assigned interrupts in
* the range 40-71.
*/

asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
u32 pending;

pending = read_c0_status() & read_c0_cause();

/*
* jump to the correct interrupt routine
* These are arranged in priority order and the timer
* comes first!
*/

#ifdef CONFIG_IRQ_MSP_CIC /* break out the CIC stuff for now */
if (pending & C_IRQ4) /* do the peripherals first, that's the timer */
msp_cic_irq_dispatch();

else if (pending & C_IRQ0)
do_IRQ(MSP_INT_MAC0);

else if (pending & C_IRQ1)
do_IRQ(MSP_INT_MAC1);

else if (pending & C_IRQ2)
do_IRQ(MSP_INT_USB);

else if (pending & C_IRQ3)
do_IRQ(MSP_INT_SAR);

else if (pending & C_IRQ5)
do_IRQ(MSP_INT_SEC);

#else
if (pending & C_IRQ5)
do_IRQ(MSP_INT_TIMER);

else if (pending & C_IRQ0)
do_IRQ(MSP_INT_MAC0);

else if (pending & C_IRQ1)
do_IRQ(MSP_INT_MAC1);

else if (pending & C_IRQ3)
do_IRQ(MSP_INT_VE);

else if (pending & C_IRQ4)
msp_slp_irq_dispatch();
#endif

else if (pending & C_SW0) /* do software after hardware */
do_IRQ(MSP_INT_SW0);

else if (pending & C_SW1)
do_IRQ(MSP_INT_SW1);
}

static struct irqaction cascade_msp = {
.handler = no_action,
.name = "MSP cascade"
};


void __init arch_init_irq(void)
{
/* initialize the 1st-level CPU based interrupt controller */
mips_cpu_irq_init();

#ifdef CONFIG_IRQ_MSP_CIC
msp_cic_irq_init();

/* setup the cascaded interrupts */
setup_irq(MSP_INT_CIC, &cascade_msp);
setup_irq(MSP_INT_PER, &cascade_msp);
#else
/* setup the 2nd-level SLP register based interrupt controller */
msp_slp_irq_init();

/* setup the cascaded SLP/PER interrupts */
setup_irq(MSP_INT_SLP, &cascade_msp);
setup_irq(MSP_INT_PER, &cascade_msp);
#endif
}
Loading

0 comments on commit 35832e2

Please sign in to comment.