add idl4k kernel firmware version 1.13.0.105

This commit is contained in:
Jaroslav Kysela
2015-03-26 17:22:37 +01:00
parent 5194d2792e
commit e9070cdc77
31064 changed files with 12769984 additions and 0 deletions

View File

@@ -0,0 +1,41 @@
choice
prompt "PMC-Sierra MSP SOC type"
depends on PMC_MSP
config PMC_MSP4200_EVAL
bool "PMC-Sierra MSP4200 Eval Board"
select CEVT_R4K
select CSRC_R4K
select IRQ_MSP_SLP
select HW_HAS_PCI
config PMC_MSP4200_GW
bool "PMC-Sierra MSP4200 VoIP Gateway"
select CEVT_R4K
select CSRC_R4K
select IRQ_MSP_SLP
select HW_HAS_PCI
config PMC_MSP7120_EVAL
bool "PMC-Sierra MSP7120 Eval Board"
select SYS_SUPPORTS_MULTITHREADING
select IRQ_MSP_CIC
select HW_HAS_PCI
config PMC_MSP7120_GW
bool "PMC-Sierra MSP7120 Residential Gateway"
select SYS_SUPPORTS_MULTITHREADING
select IRQ_MSP_CIC
select HW_HAS_PCI
config PMC_MSP7120_FPGA
bool "PMC-Sierra MSP7120 FPGA"
select SYS_SUPPORTS_MULTITHREADING
select IRQ_MSP_CIC
select HW_HAS_PCI
endchoice
config HYPERTRANSPORT
bool "Hypertransport Support for PMC-Sierra Yosemite"
depends on PMC_YOSEMITE

View File

@@ -0,0 +1,12 @@
#
# 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_HAVE_GPIO_LIB) += gpio.o gpio_extended.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

View File

@@ -0,0 +1,216 @@
/*
* Generic PMC MSP71xx GPIO handling. These base gpio are controlled by two
* types of registers. The data register sets the output level when in output
* mode and when in input mode will contain the value at the input. The config
* register sets the various modes for each gpio.
*
* 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.
*
* @author Patrick Glass <patrickglass@gmail.com>
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#define MSP71XX_CFG_OFFSET(gpio) (4 * (gpio))
#define CONF_MASK 0x0F
#define MSP71XX_GPIO_INPUT 0x01
#define MSP71XX_GPIO_OUTPUT 0x08
#define MSP71XX_GPIO_BASE 0x0B8400000L
#define to_msp71xx_gpio_chip(c) container_of(c, struct msp71xx_gpio_chip, chip)
static spinlock_t gpio_lock;
/*
* struct msp71xx_gpio_chip - container for gpio chip and registers
* @chip: chip structure for the specified gpio bank
* @data_reg: register for reading and writing the gpio pin value
* @config_reg: register to set the mode for the gpio pin bank
* @out_drive_reg: register to set the output drive mode for the gpio pin bank
*/
struct msp71xx_gpio_chip {
struct gpio_chip chip;
void __iomem *data_reg;
void __iomem *config_reg;
void __iomem *out_drive_reg;
};
/*
* msp71xx_gpio_get() - return the chip's gpio value
* @chip: chip structure which controls the specified gpio
* @offset: gpio whose value will be returned
*
* It will return 0 if gpio value is low and other if high.
*/
static int msp71xx_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct msp71xx_gpio_chip *msp_chip = to_msp71xx_gpio_chip(chip);
return __raw_readl(msp_chip->data_reg) & (1 << offset);
}
/*
* msp71xx_gpio_set() - set the output value for the gpio
* @chip: chip structure who controls the specified gpio
* @offset: gpio whose value will be assigned
* @value: logic level to assign to the gpio initially
*
* This will set the gpio bit specified to the desired value. It will set the
* gpio pin low if value is 0 otherwise it will be high.
*/
static void msp71xx_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
struct msp71xx_gpio_chip *msp_chip = to_msp71xx_gpio_chip(chip);
unsigned long flags;
u32 data;
spin_lock_irqsave(&gpio_lock, flags);
data = __raw_readl(msp_chip->data_reg);
if (value)
data |= (1 << offset);
else
data &= ~(1 << offset);
__raw_writel(data, msp_chip->data_reg);
spin_unlock_irqrestore(&gpio_lock, flags);
}
/*
* msp71xx_set_gpio_mode() - declare the mode for a gpio
* @chip: chip structure which controls the specified gpio
* @offset: gpio whose value will be assigned
* @mode: desired configuration for the gpio (see datasheet)
*
* It will set the gpio pin config to the @mode value passed in.
*/
static int msp71xx_set_gpio_mode(struct gpio_chip *chip,
unsigned offset, int mode)
{
struct msp71xx_gpio_chip *msp_chip = to_msp71xx_gpio_chip(chip);
const unsigned bit_offset = MSP71XX_CFG_OFFSET(offset);
unsigned long flags;
u32 cfg;
spin_lock_irqsave(&gpio_lock, flags);
cfg = __raw_readl(msp_chip->config_reg);
cfg &= ~(CONF_MASK << bit_offset);
cfg |= (mode << bit_offset);
__raw_writel(cfg, msp_chip->config_reg);
spin_unlock_irqrestore(&gpio_lock, flags);
return 0;
}
/*
* msp71xx_direction_output() - declare the direction mode for a gpio
* @chip: chip structure which controls the specified gpio
* @offset: gpio whose value will be assigned
* @value: logic level to assign to the gpio initially
*
* This call will set the mode for the @gpio to output. It will set the
* gpio pin low if value is 0 otherwise it will be high.
*/
static int msp71xx_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
msp71xx_gpio_set(chip, offset, value);
return msp71xx_set_gpio_mode(chip, offset, MSP71XX_GPIO_OUTPUT);
}
/*
* msp71xx_direction_input() - declare the direction mode for a gpio
* @chip: chip structure which controls the specified gpio
* @offset: gpio whose to which the value will be assigned
*
* This call will set the mode for the @gpio to input.
*/
static int msp71xx_direction_input(struct gpio_chip *chip, unsigned offset)
{
return msp71xx_set_gpio_mode(chip, offset, MSP71XX_GPIO_INPUT);
}
/*
* msp71xx_set_output_drive() - declare the output drive for the gpio line
* @gpio: gpio pin whose output drive you wish to modify
* @value: zero for active drain 1 for open drain drive
*
* This call will set the output drive mode for the @gpio to output.
*/
int msp71xx_set_output_drive(unsigned gpio, int value)
{
unsigned long flags;
u32 data;
if (gpio > 15 || gpio < 0)
return -EINVAL;
spin_lock_irqsave(&gpio_lock, flags);
data = __raw_readl((void __iomem *)(MSP71XX_GPIO_BASE + 0x190));
if (value)
data |= (1 << gpio);
else
data &= ~(1 << gpio);
__raw_writel(data, (void __iomem *)(MSP71XX_GPIO_BASE + 0x190));
spin_unlock_irqrestore(&gpio_lock, flags);
return 0;
}
EXPORT_SYMBOL(msp71xx_set_output_drive);
#define MSP71XX_GPIO_BANK(name, dr, cr, base_gpio, num_gpio) \
{ \
.chip = { \
.label = name, \
.direction_input = msp71xx_direction_input, \
.direction_output = msp71xx_direction_output, \
.get = msp71xx_gpio_get, \
.set = msp71xx_gpio_set, \
.base = base_gpio, \
.ngpio = num_gpio \
}, \
.data_reg = (void __iomem *)(MSP71XX_GPIO_BASE + dr), \
.config_reg = (void __iomem *)(MSP71XX_GPIO_BASE + cr), \
.out_drive_reg = (void __iomem *)(MSP71XX_GPIO_BASE + 0x190), \
}
/*
* struct msp71xx_gpio_banks[] - container array of gpio banks
* @chip: chip structure for the specified gpio bank
* @data_reg: register for reading and writing the gpio pin value
* @config_reg: register to set the mode for the gpio pin bank
*
* This array structure defines the gpio banks for the PMC MIPS Processor.
* We specify the bank name, the data register, the config register, base
* starting gpio number, and the number of gpios exposed by the bank.
*/
static struct msp71xx_gpio_chip msp71xx_gpio_banks[] = {
MSP71XX_GPIO_BANK("GPIO_1_0", 0x170, 0x180, 0, 2),
MSP71XX_GPIO_BANK("GPIO_5_2", 0x174, 0x184, 2, 4),
MSP71XX_GPIO_BANK("GPIO_9_6", 0x178, 0x188, 6, 4),
MSP71XX_GPIO_BANK("GPIO_15_10", 0x17C, 0x18C, 10, 6),
};
void __init msp71xx_init_gpio(void)
{
int i;
spin_lock_init(&gpio_lock);
for (i = 0; i < ARRAY_SIZE(msp71xx_gpio_banks); i++)
gpiochip_add(&msp71xx_gpio_banks[i].chip);
}

View File

@@ -0,0 +1,146 @@
/*
* Generic PMC MSP71xx EXTENDED (EXD) GPIO handling. The extended gpio is
* a set of hardware registers that have no need for explicit locking as
* it is handled by unique method of writing individual set/clr bits.
*
* 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.
*
* @author Patrick Glass <patrickglass@gmail.com>
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/io.h>
#define MSP71XX_DATA_OFFSET(gpio) (2 * (gpio))
#define MSP71XX_READ_OFFSET(gpio) (MSP71XX_DATA_OFFSET(gpio) + 1)
#define MSP71XX_CFG_OUT_OFFSET(gpio) (MSP71XX_DATA_OFFSET(gpio) + 16)
#define MSP71XX_CFG_IN_OFFSET(gpio) (MSP71XX_CFG_OUT_OFFSET(gpio) + 1)
#define MSP71XX_EXD_GPIO_BASE 0x0BC000000L
#define to_msp71xx_exd_gpio_chip(c) \
container_of(c, struct msp71xx_exd_gpio_chip, chip)
/*
* struct msp71xx_exd_gpio_chip - container for gpio chip and registers
* @chip: chip structure for the specified gpio bank
* @reg: register for control and data of gpio pin
*/
struct msp71xx_exd_gpio_chip {
struct gpio_chip chip;
void __iomem *reg;
};
/*
* msp71xx_exd_gpio_get() - return the chip's gpio value
* @chip: chip structure which controls the specified gpio
* @offset: gpio whose value will be returned
*
* It will return 0 if gpio value is low and other if high.
*/
static int msp71xx_exd_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct msp71xx_exd_gpio_chip *msp71xx_chip =
to_msp71xx_exd_gpio_chip(chip);
const unsigned bit = MSP71XX_READ_OFFSET(offset);
return __raw_readl(msp71xx_chip->reg) & (1 << bit);
}
/*
* msp71xx_exd_gpio_set() - set the output value for the gpio
* @chip: chip structure who controls the specified gpio
* @offset: gpio whose value will be assigned
* @value: logic level to assign to the gpio initially
*
* This will set the gpio bit specified to the desired value. It will set the
* gpio pin low if value is 0 otherwise it will be high.
*/
static void msp71xx_exd_gpio_set(struct gpio_chip *chip,
unsigned offset, int value)
{
struct msp71xx_exd_gpio_chip *msp71xx_chip =
to_msp71xx_exd_gpio_chip(chip);
const unsigned bit = MSP71XX_DATA_OFFSET(offset);
__raw_writel(1 << (bit + (value ? 1 : 0)), msp71xx_chip->reg);
}
/*
* msp71xx_exd_direction_output() - declare the direction mode for a gpio
* @chip: chip structure which controls the specified gpio
* @offset: gpio whose value will be assigned
* @value: logic level to assign to the gpio initially
*
* This call will set the mode for the @gpio to output. It will set the
* gpio pin low if value is 0 otherwise it will be high.
*/
static int msp71xx_exd_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
struct msp71xx_exd_gpio_chip *msp71xx_chip =
to_msp71xx_exd_gpio_chip(chip);
msp71xx_exd_gpio_set(chip, offset, value);
__raw_writel(1 << MSP71XX_CFG_OUT_OFFSET(offset), msp71xx_chip->reg);
return 0;
}
/*
* msp71xx_exd_direction_input() - declare the direction mode for a gpio
* @chip: chip structure which controls the specified gpio
* @offset: gpio whose to which the value will be assigned
*
* This call will set the mode for the @gpio to input.
*/
static int msp71xx_exd_direction_input(struct gpio_chip *chip, unsigned offset)
{
struct msp71xx_exd_gpio_chip *msp71xx_chip =
to_msp71xx_exd_gpio_chip(chip);
__raw_writel(1 << MSP71XX_CFG_IN_OFFSET(offset), msp71xx_chip->reg);
return 0;
}
#define MSP71XX_EXD_GPIO_BANK(name, exd_reg, base_gpio, num_gpio) \
{ \
.chip = { \
.label = name, \
.direction_input = msp71xx_exd_direction_input, \
.direction_output = msp71xx_exd_direction_output, \
.get = msp71xx_exd_gpio_get, \
.set = msp71xx_exd_gpio_set, \
.base = base_gpio, \
.ngpio = num_gpio, \
}, \
.reg = (void __iomem *)(MSP71XX_EXD_GPIO_BASE + exd_reg), \
}
/*
* struct msp71xx_exd_gpio_banks[] - container array of gpio banks
* @chip: chip structure for the specified gpio bank
* @reg: register for reading and writing the gpio pin value
*
* This array structure defines the extended gpio banks for the
* PMC MIPS Processor. We specify the bank name, the data/config
* register,the base starting gpio number, and the number of
* gpios exposed by the bank of gpios.
*/
static struct msp71xx_exd_gpio_chip msp71xx_exd_gpio_banks[] = {
MSP71XX_EXD_GPIO_BANK("GPIO_23_16", 0x188, 16, 8),
MSP71XX_EXD_GPIO_BANK("GPIO_27_24", 0x18C, 24, 4),
};
void __init msp71xx_init_gpio_extended(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(msp71xx_exd_gpio_banks); i++)
gpiochip_add(&msp71xx_exd_gpio_banks[i].chip);
}

View File

@@ -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);

View File

@@ -0,0 +1,176 @@
/*
* 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 (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, IRQF_DISABLED,
hirq->name, 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);

View File

@@ -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
}

View File

@@ -0,0 +1,134 @@
/*
* This file define the irq handler for MSP SLM subsystem interrupts.
*
* Copyright 2005-2007 PMC-Sierra, Inc, derived from irq_cpu.c
* Author: Andrew Hughes, Andrew_Hughes@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.
*/
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/bitops.h>
#include <asm/system.h>
#include <msp_cic_int.h>
#include <msp_regs.h>
/*
* NOTE: We are only enabling support for VPE0 right now.
*/
static inline void unmask_msp_cic_irq(unsigned int irq)
{
/* check for PER interrupt range */
if (irq < MSP_PER_INTBASE)
*CIC_VPE0_MSK_REG |= (1 << (irq - MSP_CIC_INTBASE));
else
*PER_INT_MSK_REG |= (1 << (irq - MSP_PER_INTBASE));
}
static inline void mask_msp_cic_irq(unsigned int irq)
{
/* check for PER interrupt range */
if (irq < MSP_PER_INTBASE)
*CIC_VPE0_MSK_REG &= ~(1 << (irq - MSP_CIC_INTBASE));
else
*PER_INT_MSK_REG &= ~(1 << (irq - MSP_PER_INTBASE));
}
/*
* While we ack the interrupt interrupts are disabled and thus we don't need
* to deal with concurrency issues. Same for msp_cic_irq_end.
*/
static inline void ack_msp_cic_irq(unsigned int irq)
{
mask_msp_cic_irq(irq);
/*
* only really necessary for 18, 16-14 and sometimes 3:0 (since
* these can be edge sensitive) but it doesn't hurt for the others.
*/
/* check for PER interrupt range */
if (irq < MSP_PER_INTBASE)
*CIC_STS_REG = (1 << (irq - MSP_CIC_INTBASE));
else
*PER_INT_STS_REG = (1 << (irq - MSP_PER_INTBASE));
}
static struct irq_chip msp_cic_irq_controller = {
.name = "MSP_CIC",
.ack = ack_msp_cic_irq,
.mask = ack_msp_cic_irq,
.mask_ack = ack_msp_cic_irq,
.unmask = unmask_msp_cic_irq,
};
void __init msp_cic_irq_init(void)
{
int i;
/* Mask/clear interrupts. */
*CIC_VPE0_MSK_REG = 0x00000000;
*PER_INT_MSK_REG = 0x00000000;
*CIC_STS_REG = 0xFFFFFFFF;
*PER_INT_STS_REG = 0xFFFFFFFF;
#if defined(CONFIG_PMC_MSP7120_GW) || \
defined(CONFIG_PMC_MSP7120_EVAL)
/*
* The MSP7120 RG and EVBD boards use IRQ[6:4] for PCI.
* These inputs map to EXT_INT_POL[6:4] inside the CIC.
* They are to be active low, level sensitive.
*/
*CIC_EXT_CFG_REG &= 0xFFFF8F8F;
#endif
/* initialize all the IRQ descriptors */
for (i = MSP_CIC_INTBASE; i < MSP_PER_INTBASE + 32; i++)
set_irq_chip_and_handler(i, &msp_cic_irq_controller,
handle_level_irq);
}
void msp_cic_irq_dispatch(void)
{
u32 pending;
int intbase;
intbase = MSP_CIC_INTBASE;
pending = *CIC_STS_REG & *CIC_VPE0_MSK_REG;
/* check for PER interrupt */
if (pending == (1 << (MSP_INT_PER - MSP_CIC_INTBASE))) {
intbase = MSP_PER_INTBASE;
pending = *PER_INT_STS_REG & *PER_INT_MSK_REG;
}
/* check for spurious interrupt */
if (pending == 0x00000000) {
printk(KERN_ERR
"Spurious %s interrupt? status %08x, mask %08x\n",
(intbase == MSP_CIC_INTBASE) ? "CIC" : "PER",
(intbase == MSP_CIC_INTBASE) ?
*CIC_STS_REG : *PER_INT_STS_REG,
(intbase == MSP_CIC_INTBASE) ?
*CIC_VPE0_MSK_REG : *PER_INT_MSK_REG);
return;
}
/* check for the timer and dispatch it first */
if ((intbase == MSP_CIC_INTBASE) &&
(pending & (1 << (MSP_INT_VPE0_TIMER - MSP_CIC_INTBASE))))
do_IRQ(MSP_INT_VPE0_TIMER);
else
do_IRQ(ffs(pending) + intbase - 1);
}

View File

@@ -0,0 +1,101 @@
/*
* This file define the irq handler for MSP SLM subsystem interrupts.
*
* Copyright 2005-2006 PMC-Sierra, Inc, derived from irq_cpu.c
* Author: Andrew Hughes, Andrew_Hughes@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.
*/
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/bitops.h>
#include <asm/mipsregs.h>
#include <asm/system.h>
#include <msp_slp_int.h>
#include <msp_regs.h>
static inline void unmask_msp_slp_irq(unsigned int irq)
{
/* check for PER interrupt range */
if (irq < MSP_PER_INTBASE)
*SLP_INT_MSK_REG |= (1 << (irq - MSP_SLP_INTBASE));
else
*PER_INT_MSK_REG |= (1 << (irq - MSP_PER_INTBASE));
}
static inline void mask_msp_slp_irq(unsigned int irq)
{
/* check for PER interrupt range */
if (irq < MSP_PER_INTBASE)
*SLP_INT_MSK_REG &= ~(1 << (irq - MSP_SLP_INTBASE));
else
*PER_INT_MSK_REG &= ~(1 << (irq - MSP_PER_INTBASE));
}
/*
* While we ack the interrupt interrupts are disabled and thus we don't need
* to deal with concurrency issues. Same for msp_slp_irq_end.
*/
static inline void ack_msp_slp_irq(unsigned int irq)
{
/* check for PER interrupt range */
if (irq < MSP_PER_INTBASE)
*SLP_INT_STS_REG = (1 << (irq - MSP_SLP_INTBASE));
else
*PER_INT_STS_REG = (1 << (irq - MSP_PER_INTBASE));
}
static struct irq_chip msp_slp_irq_controller = {
.name = "MSP_SLP",
.ack = ack_msp_slp_irq,
.mask = mask_msp_slp_irq,
.unmask = unmask_msp_slp_irq,
};
void __init msp_slp_irq_init(void)
{
int i;
/* Mask/clear interrupts. */
*SLP_INT_MSK_REG = 0x00000000;
*PER_INT_MSK_REG = 0x00000000;
*SLP_INT_STS_REG = 0xFFFFFFFF;
*PER_INT_STS_REG = 0xFFFFFFFF;
/* initialize all the IRQ descriptors */
for (i = MSP_SLP_INTBASE; i < MSP_PER_INTBASE + 32; i++)
set_irq_chip_and_handler(i, &msp_slp_irq_controller,
handle_level_irq);
}
void msp_slp_irq_dispatch(void)
{
u32 pending;
int intbase;
intbase = MSP_SLP_INTBASE;
pending = *SLP_INT_STS_REG & *SLP_INT_MSK_REG;
/* check for PER interrupt */
if (pending == (1 << (MSP_INT_PER - MSP_SLP_INTBASE))) {
intbase = MSP_PER_INTBASE;
pending = *PER_INT_STS_REG & *PER_INT_MSK_REG;
}
/* check for spurious interrupt */
if (pending == 0x00000000) {
printk(KERN_ERR "Spurious %s interrupt?\n",
(intbase == MSP_SLP_INTBASE) ? "SLP" : "PER");
return;
}
/* dispatch the irq */
do_IRQ(ffs(pending) + intbase - 1);
}

View File

@@ -0,0 +1,50 @@
/*
* The setup file for PCI related hardware on PMC-Sierra MSP processors.
*
* Copyright 2005-2006 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/init.h>
#include <msp_prom.h>
#include <msp_regs.h>
extern void msp_pci_init(void);
static int __init msp_pci_setup(void)
{
#if 0 /* Linux 2.6 initialization code to be completed */
if (getdeviceid() & DEV_ID_SINGLE_PC) {
/* If single card mode */
slmRegs *sreg = (slmRegs *) SREG_BASE;
sreg->single_pc_enable = SINGLE_PCCARD;
}
#endif
msp_pci_init();
return 0;
}
subsys_initcall(msp_pci_setup);

View File

@@ -0,0 +1,508 @@
/*
* BRIEF MODULE DESCRIPTION
* PROM library initialisation code, assuming a version of
* pmon is the boot code.
*
* Copyright 2000,2001 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
* This file was derived from Carsten Langgaard's
* arch/mips/mips-boards/xx files.
*
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
*
* 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/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/interrupt.h>
#include <linux/mm.h>
#include <asm/addrspace.h>
#include <asm/bootinfo.h>
#include <asm-generic/sections.h>
#include <asm/page.h>
#include <msp_prom.h>
#include <msp_regs.h>
/* global PROM environment variables and pointers */
int prom_argc;
char **prom_argv, **prom_envp;
int *prom_vec;
/* debug flag */
int init_debug = 1;
/* memory blocks */
struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS];
/* default feature sets */
static char msp_default_features[] =
#if defined(CONFIG_PMC_MSP4200_EVAL) \
|| defined(CONFIG_PMC_MSP4200_GW)
"ERER";
#elif defined(CONFIG_PMC_MSP7120_EVAL) \
|| defined(CONFIG_PMC_MSP7120_GW)
"EMEMSP";
#elif defined(CONFIG_PMC_MSP7120_FPGA)
"EMEM";
#endif
/* conversion functions */
static inline unsigned char str2hexnum(unsigned char c)
{
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
return 0; /* foo */
}
static inline int str2eaddr(unsigned char *ea, unsigned char *str)
{
int index = 0;
unsigned char num = 0;
while (*str != '\0') {
if ((*str == '.') || (*str == ':')) {
ea[index++] = num;
num = 0;
str++;
} else {
num = num << 4;
num |= str2hexnum(*str++);
}
}
if (index == 5) {
ea[index++] = num;
return 0;
} else
return -1;
}
EXPORT_SYMBOL(str2eaddr);
static inline unsigned long str2hex(unsigned char *str)
{
int value = 0;
while (*str) {
value = value << 4;
value |= str2hexnum(*str++);
}
return value;
}
/* function to query the system information */
const char *get_system_type(void)
{
#if defined(CONFIG_PMC_MSP4200_EVAL)
return "PMC-Sierra MSP4200 Eval Board";
#elif defined(CONFIG_PMC_MSP4200_GW)
return "PMC-Sierra MSP4200 VoIP Gateway";
#elif defined(CONFIG_PMC_MSP7120_EVAL)
return "PMC-Sierra MSP7120 Eval Board";
#elif defined(CONFIG_PMC_MSP7120_GW)
return "PMC-Sierra MSP7120 Residential Gateway";
#elif defined(CONFIG_PMC_MSP7120_FPGA)
return "PMC-Sierra MSP7120 FPGA";
#else
#error "What is the type of *your* MSP?"
#endif
}
int get_ethernet_addr(char *ethaddr_name, char *ethernet_addr)
{
char *ethaddr_str;
ethaddr_str = prom_getenv(ethaddr_name);
if (!ethaddr_str) {
printk(KERN_WARNING "%s not set in boot prom\n", ethaddr_name);
return -1;
}
if (str2eaddr(ethernet_addr, ethaddr_str) == -1) {
printk(KERN_WARNING "%s badly formatted-<%s>\n",
ethaddr_name, ethaddr_str);
return -1;
}
if (init_debug > 1) {
int i;
printk(KERN_DEBUG "get_ethernet_addr: for %s ", ethaddr_name);
for (i = 0; i < 5; i++)
printk(KERN_DEBUG "%02x:",
(unsigned char)*(ethernet_addr+i));
printk(KERN_DEBUG "%02x\n", *(ethernet_addr+i));
}
return 0;
}
EXPORT_SYMBOL(get_ethernet_addr);
static char *get_features(void)
{
char *feature = prom_getenv(FEATURES);
if (feature == NULL) {
/* default features based on MACHINE_TYPE */
feature = msp_default_features;
}
return feature;
}
static char test_feature(char c)
{
char *feature = get_features();
while (*feature) {
if (*feature++ == c)
return *feature;
feature++;
}
return FEATURE_NOEXIST;
}
unsigned long get_deviceid(void)
{
char *deviceid = prom_getenv(DEVICEID);
if (deviceid == NULL)
return *DEV_ID_REG;
else
return str2hex(deviceid);
}
char identify_pci(void)
{
return test_feature(PCI_KEY);
}
EXPORT_SYMBOL(identify_pci);
char identify_pcimux(void)
{
return test_feature(PCIMUX_KEY);
}
char identify_sec(void)
{
return test_feature(SEC_KEY);
}
EXPORT_SYMBOL(identify_sec);
char identify_spad(void)
{
return test_feature(SPAD_KEY);
}
EXPORT_SYMBOL(identify_spad);
char identify_tdm(void)
{
return test_feature(TDM_KEY);
}
EXPORT_SYMBOL(identify_tdm);
char identify_zsp(void)
{
return test_feature(ZSP_KEY);
}
EXPORT_SYMBOL(identify_zsp);
static char identify_enetfeature(char key, unsigned long interface_num)
{
char *feature = get_features();
while (*feature) {
if (*feature++ == key && interface_num-- == 0)
return *feature;
feature++;
}
return FEATURE_NOEXIST;
}
char identify_enet(unsigned long interface_num)
{
return identify_enetfeature(ENET_KEY, interface_num);
}
EXPORT_SYMBOL(identify_enet);
char identify_enetTxD(unsigned long interface_num)
{
return identify_enetfeature(ENETTXD_KEY, interface_num);
}
EXPORT_SYMBOL(identify_enetTxD);
unsigned long identify_family(void)
{
unsigned long deviceid;
deviceid = get_deviceid();
return deviceid & CPU_DEVID_FAMILY;
}
EXPORT_SYMBOL(identify_family);
unsigned long identify_revision(void)
{
unsigned long deviceid;
deviceid = get_deviceid();
return deviceid & CPU_DEVID_REVISION;
}
EXPORT_SYMBOL(identify_revision);
/* PROM environment functions */
char *prom_getenv(char *env_name)
{
/*
* Return a pointer to the given environment variable. prom_envp
* points to a null terminated array of pointers to variables.
* Environment variables are stored in the form of "memsize=64"
*/
char **var = prom_envp;
int i = strlen(env_name);
while (*var) {
if (strncmp(env_name, *var, i) == 0) {
return (*var + strlen(env_name) + 1);
}
var++;
}
return NULL;
}
/* PROM commandline functions */
char *prom_getcmdline(void)
{
return &(arcs_cmdline[0]);
}
EXPORT_SYMBOL(prom_getcmdline);
void __init prom_init_cmdline(void)
{
char *cp;
int actr;
actr = 1; /* Always ignore argv[0] */
cp = &(arcs_cmdline[0]);
while (actr < prom_argc) {
strcpy(cp, prom_argv[actr]);
cp += strlen(prom_argv[actr]);
*cp++ = ' ';
actr++;
}
if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
--cp;
*cp = '\0';
}
/* memory allocation functions */
static int __init prom_memtype_classify(unsigned int type)
{
switch (type) {
case yamon_free:
return BOOT_MEM_RAM;
case yamon_prom:
return BOOT_MEM_ROM_DATA;
default:
return BOOT_MEM_RESERVED;
}
}
void __init prom_meminit(void)
{
struct prom_pmemblock *p;
p = prom_getmdesc();
while (p->size) {
long type;
unsigned long base, size;
type = prom_memtype_classify(p->type);
base = p->base;
size = p->size;
add_memory_region(base, size, type);
p++;
}
}
void __init prom_free_prom_memory(void)
{
int argc;
char **argv;
char **envp;
char *ptr;
int len = 0;
int i;
unsigned long addr;
/*
* preserve environment variables and command line from pmon/bbload
* first preserve the command line
*/
for (argc = 0; argc < prom_argc; argc++) {
len += sizeof(char *); /* length of pointer */
len += strlen(prom_argv[argc]) + 1; /* length of string */
}
len += sizeof(char *); /* plus length of null pointer */
argv = kmalloc(len, GFP_KERNEL);
ptr = (char *) &argv[prom_argc + 1]; /* strings follow array */
for (argc = 0; argc < prom_argc; argc++) {
argv[argc] = ptr;
strcpy(ptr, prom_argv[argc]);
ptr += strlen(prom_argv[argc]) + 1;
}
argv[prom_argc] = NULL; /* end array with null pointer */
prom_argv = argv;
/* next preserve the environment variables */
len = 0;
i = 0;
for (envp = prom_envp; *envp != NULL; envp++) {
i++; /* count number of environment variables */
len += sizeof(char *); /* length of pointer */
len += strlen(*envp) + 1; /* length of string */
}
len += sizeof(char *); /* plus length of null pointer */
envp = kmalloc(len, GFP_KERNEL);
ptr = (char *) &envp[i+1];
for (argc = 0; argc < i; argc++) {
envp[argc] = ptr;
strcpy(ptr, prom_envp[argc]);
ptr += strlen(prom_envp[argc]) + 1;
}
envp[i] = NULL; /* end array with null pointer */
prom_envp = envp;
for (i = 0; i < boot_mem_map.nr_map; i++) {
if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA)
continue;
addr = boot_mem_map.map[i].addr;
free_init_pages("prom memory",
addr, addr + boot_mem_map.map[i].size);
}
}
struct prom_pmemblock *__init prom_getmdesc(void)
{
static char memsz_env[] __initdata = "memsize";
static char heaptop_env[] __initdata = "heaptop";
char *str;
unsigned int memsize;
unsigned int heaptop;
int i;
str = prom_getenv(memsz_env);
if (!str) {
ppfinit("memsize not set in boot prom, "
"set to default (32Mb)\n");
memsize = 0x02000000;
} else {
memsize = simple_strtol(str, NULL, 0);
if (memsize == 0) {
/* if memsize is a bad size, use reasonable default */
memsize = 0x02000000;
}
/* convert to physical address (removing caching bits, etc) */
memsize = CPHYSADDR(memsize);
}
str = prom_getenv(heaptop_env);
if (!str) {
heaptop = CPHYSADDR((u32)&_text);
ppfinit("heaptop not set in boot prom, "
"set to default 0x%08x\n", heaptop);
} else {
heaptop = simple_strtol(str, NULL, 16);
if (heaptop == 0) {
/* heaptop conversion bad, might have 0xValue */
heaptop = simple_strtol(str, NULL, 0);
if (heaptop == 0) {
/* heaptop still bad, use reasonable default */
heaptop = CPHYSADDR((u32)&_text);
}
}
/* convert to physical address (removing caching bits, etc) */
heaptop = CPHYSADDR((u32)heaptop);
}
/* the base region */
i = 0;
mdesc[i].type = BOOT_MEM_RESERVED;
mdesc[i].base = 0x00000000;
mdesc[i].size = PAGE_ALIGN(0x300 + 0x80);
/* jtag interrupt vector + sizeof vector */
/* PMON data */
if (heaptop > mdesc[i].base + mdesc[i].size) {
i++; /* 1 */
mdesc[i].type = BOOT_MEM_ROM_DATA;
mdesc[i].base = mdesc[i-1].base + mdesc[i-1].size;
mdesc[i].size = heaptop - mdesc[i].base;
}
/* end of PMON data to start of kernel -- probably zero .. */
if (heaptop != CPHYSADDR((u32)_text)) {
i++; /* 2 */
mdesc[i].type = BOOT_MEM_RAM;
mdesc[i].base = heaptop;
mdesc[i].size = CPHYSADDR((u32)_text) - mdesc[i].base;
}
/* kernel proper */
i++; /* 3 */
mdesc[i].type = BOOT_MEM_RESERVED;
mdesc[i].base = CPHYSADDR((u32)_text);
mdesc[i].size = CPHYSADDR(PAGE_ALIGN((u32)_end)) - mdesc[i].base;
/* Remainder of RAM -- under memsize */
i++; /* 5 */
mdesc[i].type = yamon_free;
mdesc[i].base = mdesc[i-1].base + mdesc[i-1].size;
mdesc[i].size = memsize - mdesc[i].base;
return &mdesc[0];
}

View File

@@ -0,0 +1,93 @@
/*
* The setup file for serial related hardware on PMC-Sierra MSP processors.
*
* Copyright 2005 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/serial.h>
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
#include <asm/bootinfo.h>
#include <asm/io.h>
#include <asm/processor.h>
#include <asm/serial.h>
#include <linux/serial_8250.h>
#include <msp_prom.h>
#include <msp_int.h>
#include <msp_regs.h>
void __init msp_serial_setup(void)
{
char *s;
char *endp;
struct uart_port up;
unsigned int uartclk;
memset(&up, 0, sizeof(up));
/* Check if clock was specified in environment */
s = prom_getenv("uartfreqhz");
if(!(s && *s && (uartclk = simple_strtoul(s, &endp, 10)) && *endp == 0))
uartclk = MSP_BASE_BAUD;
ppfinit("UART clock set to %d\n", uartclk);
/* Initialize first serial port */
up.mapbase = MSP_UART0_BASE;
up.membase = ioremap_nocache(up.mapbase, MSP_UART_REG_LEN);
up.irq = MSP_INT_UART0;
up.uartclk = uartclk;
up.regshift = 2;
up.iotype = UPIO_DWAPB; /* UPIO_MEM like */
up.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
up.type = PORT_16550A;
up.line = 0;
up.private_data = (void*)UART0_STATUS_REG;
if (early_serial_setup(&up))
printk(KERN_ERR "Early serial init of port 0 failed\n");
/* Initialize the second serial port, if one exists */
switch (mips_machtype) {
case MACH_MSP4200_EVAL:
case MACH_MSP4200_GW:
case MACH_MSP4200_FPGA:
case MACH_MSP7120_EVAL:
case MACH_MSP7120_GW:
case MACH_MSP7120_FPGA:
/* Enable UART1 on MSP4200 and MSP7120 */
*GPIO_CFG2_REG = 0x00002299;
break;
default:
return; /* No second serial port, good-bye. */
}
up.mapbase = MSP_UART1_BASE;
up.membase = ioremap_nocache(up.mapbase, MSP_UART_REG_LEN);
up.irq = MSP_INT_UART1;
up.line = 1;
up.private_data = (void*)UART1_STATUS_REG;
if (early_serial_setup(&up))
printk(KERN_ERR "Early serial init of port 1 failed\n");
}

View File

@@ -0,0 +1,236 @@
/*
* The generic setup file for PMC-Sierra MSP processors
*
* Copyright 2005-2007 PMC-Sierra, Inc,
* Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
*
* 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.
*/
#include <asm/bootinfo.h>
#include <asm/cacheflush.h>
#include <asm/r4kcache.h>
#include <asm/reboot.h>
#include <asm/time.h>
#include <msp_prom.h>
#include <msp_regs.h>
#if defined(CONFIG_PMC_MSP7120_GW)
#include <msp_regops.h>
#define MSP_BOARD_RESET_GPIO 9
#endif
extern void msp_serial_setup(void);
extern void pmctwiled_setup(void);
#if defined(CONFIG_PMC_MSP7120_EVAL) || \
defined(CONFIG_PMC_MSP7120_GW) || \
defined(CONFIG_PMC_MSP7120_FPGA)
/*
* Performs the reset for MSP7120-based boards
*/
void msp7120_reset(void)
{
void *start, *end, *iptr;
register int i;
/* Diasble all interrupts */
local_irq_disable();
#ifdef CONFIG_SYS_SUPPORTS_MULTITHREADING
dvpe();
#endif
/* Cache the reset code of this function */
__asm__ __volatile__ (
" .set push \n"
" .set mips3 \n"
" la %0,startpoint \n"
" la %1,endpoint \n"
" .set pop \n"
: "=r" (start), "=r" (end)
:
);
for (iptr = (void *)((unsigned int)start & ~(L1_CACHE_BYTES - 1));
iptr < end; iptr += L1_CACHE_BYTES)
cache_op(Fill, iptr);
__asm__ __volatile__ (
"startpoint: \n"
);
/* Put the DDRC into self-refresh mode */
DDRC_INDIRECT_WRITE(DDRC_CTL(10), 0xb, 1 << 16);
/*
* IMPORTANT!
* DO NOT do anything from here on out that might even
* think about fetching from RAM - i.e., don't call any
* non-inlined functions, and be VERY sure that any inline
* functions you do call do NOT access any sort of RAM
* anywhere!
*/
/* Wait a bit for the DDRC to settle */
for (i = 0; i < 100000000; i++);
#if defined(CONFIG_PMC_MSP7120_GW)
/*
* Set GPIO 9 HI, (tied to board reset logic)
* GPIO 9 is the 4th GPIO of register 3
*
* NOTE: We cannot use the higher-level msp_gpio_mode()/out()
* as GPIO char driver may not be enabled and it would look up
* data inRAM!
*/
set_value_reg32(GPIO_CFG3_REG, 0xf000, 0x8000);
set_reg32(GPIO_DATA3_REG, 8);
/*
* In case GPIO9 doesn't reset the board (jumper configurable!)
* fallback to device reset below.
*/
#endif
/* Set bit 1 of the MSP7120 reset register */
*RST_SET_REG = 0x00000001;
__asm__ __volatile__ (
"endpoint: \n"
);
}
#endif
void msp_restart(char *command)
{
printk(KERN_WARNING "Now rebooting .......\n");
#if defined(CONFIG_PMC_MSP7120_EVAL) || \
defined(CONFIG_PMC_MSP7120_GW) || \
defined(CONFIG_PMC_MSP7120_FPGA)
msp7120_reset();
#else
/* No chip-specific reset code, just jump to the ROM reset vector */
set_c0_status(ST0_BEV | ST0_ERL);
change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
flush_cache_all();
write_c0_wired(0);
__asm__ __volatile__("jr\t%0"::"r"(0xbfc00000));
#endif
}
void msp_halt(void)
{
printk(KERN_WARNING "\n** You can safely turn off the power\n");
while (1)
/* If possible call official function to get CPU WARs */
if (cpu_wait)
(*cpu_wait)();
else
__asm__(".set\tmips3\n\t" "wait\n\t" ".set\tmips0");
}
void msp_power_off(void)
{
msp_halt();
}
void __init plat_mem_setup(void)
{
_machine_restart = msp_restart;
_machine_halt = msp_halt;
pm_power_off = msp_power_off;
}
void __init prom_init(void)
{
unsigned long family;
unsigned long revision;
prom_argc = fw_arg0;
prom_argv = (char **)fw_arg1;
prom_envp = (char **)fw_arg2;
/*
* Someday we can use this with PMON2000 to get a
* platform call prom routines for output etc. without
* having to use grody hacks. For now it's unused.
*
* struct callvectors *cv = (struct callvectors *) fw_arg3;
*/
family = identify_family();
revision = identify_revision();
switch (family) {
case FAMILY_FPGA:
if (FPGA_IS_MSP4200(revision)) {
/* Old-style revision ID */
mips_machtype = MACH_MSP4200_FPGA;
} else {
mips_machtype = MACH_MSP_OTHER;
}
break;
case FAMILY_MSP4200:
#if defined(CONFIG_PMC_MSP4200_EVAL)
mips_machtype = MACH_MSP4200_EVAL;
#elif defined(CONFIG_PMC_MSP4200_GW)
mips_machtype = MACH_MSP4200_GW;
#else
mips_machtype = MACH_MSP_OTHER;
#endif
break;
case FAMILY_MSP4200_FPGA:
mips_machtype = MACH_MSP4200_FPGA;
break;
case FAMILY_MSP7100:
#if defined(CONFIG_PMC_MSP7120_EVAL)
mips_machtype = MACH_MSP7120_EVAL;
#elif defined(CONFIG_PMC_MSP7120_GW)
mips_machtype = MACH_MSP7120_GW;
#else
mips_machtype = MACH_MSP_OTHER;
#endif
break;
case FAMILY_MSP7100_FPGA:
mips_machtype = MACH_MSP7120_FPGA;
break;
default:
/* we don't recognize the machine */
mips_machtype = MACH_UNKNOWN;
panic("***Bogosity factor five***, exiting\n");
break;
}
prom_init_cmdline();
prom_meminit();
/*
* Sub-system setup follows.
* Setup functions can either be called here or using the
* subsys_initcall mechanism (i.e. see msp_pci_setup). The
* order in which they are called can be changed by using the
* link order in arch/mips/pmc-sierra/msp71xx/Makefile.
*
* NOTE: Please keep sub-system specific initialization code
* in separate specific files.
*/
msp_serial_setup();
#ifdef CONFIG_PMCTWILED
/*
* Setup LED states before the subsys_initcall loads other
* dependant drivers/modules.
*/
pmctwiled_setup();
#endif
}

View File

@@ -0,0 +1,87 @@
/*
* Setting up the clock on MSP SOCs. No RTC typically.
*
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
*
* ########################################################################
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* 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.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
* ########################################################################
*/
#include <linux/init.h>
#include <linux/kernel_stat.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/module.h>
#include <linux/ptrace.h>
#include <asm/mipsregs.h>
#include <asm/time.h>
#include <msp_prom.h>
#include <msp_int.h>
#include <msp_regs.h>
void __init plat_time_init(void)
{
char *endp, *s;
unsigned long cpu_rate = 0;
if (cpu_rate == 0) {
s = prom_getenv("clkfreqhz");
cpu_rate = simple_strtoul(s, &endp, 10);
if (endp != NULL && *endp != 0) {
printk(KERN_ERR
"Clock rate in Hz parse error: %s\n", s);
cpu_rate = 0;
}
}
if (cpu_rate == 0) {
s = prom_getenv("clkfreq");
cpu_rate = 1000 * simple_strtoul(s, &endp, 10);
if (endp != NULL && *endp != 0) {
printk(KERN_ERR
"Clock rate in MHz parse error: %s\n", s);
cpu_rate = 0;
}
}
if (cpu_rate == 0) {
#if defined(CONFIG_PMC_MSP7120_EVAL) \
|| defined(CONFIG_PMC_MSP7120_GW)
cpu_rate = 400000000;
#elif defined(CONFIG_PMC_MSP7120_FPGA)
cpu_rate = 25000000;
#else
cpu_rate = 150000000;
#endif
printk(KERN_ERR
"Failed to determine CPU clock rate, "
"assuming %ld hz ...\n", cpu_rate);
}
printk(KERN_WARNING "Clock rate set to %ld\n", cpu_rate);
/* timer frequency is 1/2 clock rate */
mips_hpt_frequency = cpu_rate/2;
}
unsigned int __init get_c0_compare_int(void)
{
return MSP_INT_VPE0_TIMER;
}

View File

@@ -0,0 +1,150 @@
/*
* The setup file for USB related hardware on PMC-Sierra MSP processors.
*
* Copyright 2006-2007 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/dma-mapping.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <asm/mipsregs.h>
#include <msp_regs.h>
#include <msp_int.h>
#include <msp_prom.h>
#if defined(CONFIG_USB_EHCI_HCD)
static struct resource msp_usbhost_resources [] = {
[0] = {
.start = MSP_USB_BASE_START,
.end = MSP_USB_BASE_END,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = MSP_INT_USB,
.end = MSP_INT_USB,
.flags = IORESOURCE_IRQ,
},
};
static u64 msp_usbhost_dma_mask = DMA_BIT_MASK(32);
static struct platform_device msp_usbhost_device = {
.name = "pmcmsp-ehci",
.id = 0,
.dev = {
.dma_mask = &msp_usbhost_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
.num_resources = ARRAY_SIZE(msp_usbhost_resources),
.resource = msp_usbhost_resources,
};
#endif /* CONFIG_USB_EHCI_HCD */
#if defined(CONFIG_USB_GADGET)
static struct resource msp_usbdev_resources [] = {
[0] = {
.start = MSP_USB_BASE,
.end = MSP_USB_BASE_END,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = MSP_INT_USB,
.end = MSP_INT_USB,
.flags = IORESOURCE_IRQ,
},
};
static u64 msp_usbdev_dma_mask = DMA_BIT_MASK(32);
static struct platform_device msp_usbdev_device = {
.name = "msp71xx_udc",
.id = 0,
.dev = {
.dma_mask = &msp_usbdev_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
.num_resources = ARRAY_SIZE(msp_usbdev_resources),
.resource = msp_usbdev_resources,
};
#endif /* CONFIG_USB_GADGET */
#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_GADGET)
static struct platform_device *msp_devs[1];
#endif
static int __init msp_usb_setup(void)
{
#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_GADGET)
char *strp;
char envstr[32];
unsigned int val = 0;
int result = 0;
/*
* construct environment name usbmode
* set usbmode <host/device> as pmon environment var
*/
snprintf((char *)&envstr[0], sizeof(envstr), "usbmode");
#if defined(CONFIG_USB_EHCI_HCD)
/* default to host mode */
val = 1;
#endif
/* get environment string */
strp = prom_getenv((char *)&envstr[0]);
if (strp) {
if (!strcmp(strp, "device"))
val = 0;
}
if (val) {
#if defined(CONFIG_USB_EHCI_HCD)
/* get host mode device */
msp_devs[0] = &msp_usbhost_device;
ppfinit("platform add USB HOST done %s.\n",
msp_devs[0]->name);
result = platform_add_devices(msp_devs, ARRAY_SIZE(msp_devs));
#endif /* CONFIG_USB_EHCI_HCD */
}
#if defined(CONFIG_USB_GADGET)
else {
/* get device mode structure */
msp_devs[0] = &msp_usbdev_device;
ppfinit("platform add USB DEVICE done %s.\n",
msp_devs[0]->name);
result = platform_add_devices(msp_devs, ARRAY_SIZE(msp_devs));
}
#endif /* CONFIG_USB_GADGET */
#endif /* CONFIG_USB_EHCI_HCD || CONFIG_USB_GADGET */
return result;
}
subsys_initcall(msp_usb_setup);

View File

@@ -0,0 +1,9 @@
#
# Makefile for the PMC-Sierra Titan
#
obj-y += irq.o prom.o py-console.o setup.o
obj-$(CONFIG_SMP) += smp.o
EXTRA_CFLAGS += -Werror

View File

@@ -0,0 +1,169 @@
/*
* Copyright (C) 2003 PMC-Sierra Inc.
* Author: Manish Lachwani (lachwani@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.
*/
/*
* Description:
*
* This code reads the ATMEL 24CXX EEPROM. The PMC-Sierra Yosemite board uses the ATMEL
* 24C32/24C64 which uses two byte addressing as compared to 24C16. Note that this program
* uses the serial port like /dev/ttyS0, to communicate with the EEPROM. Hence, you are
* expected to have a connectivity from the EEPROM to the serial port. This program does
* __not__ communicate using the I2C protocol
*/
#include "atmel_read_eeprom.h"
static void delay(int delay)
{
while (delay--);
}
static void send_bit(unsigned char bit)
{
scl_lo;
delay(TXX);
if (bit)
sda_hi;
else
sda_lo;
delay(TXX);
scl_hi;
delay(TXX);
}
static void send_ack(void)
{
send_bit(0);
}
static void send_byte(unsigned char byte)
{
int i = 0;
for (i = 7; i >= 0; i--)
send_bit((byte >> i) & 0x01);
}
static void send_start(void)
{
sda_hi;
delay(TXX);
scl_hi;
delay(TXX);
sda_lo;
delay(TXX);
}
static void send_stop(void)
{
sda_lo;
delay(TXX);
scl_hi;
delay(TXX);
sda_hi;
delay(TXX);
}
static void do_idle(void)
{
sda_hi;
scl_hi;
vcc_off;
}
static int recv_bit(void)
{
int status;
scl_lo;
delay(TXX);
sda_hi;
delay(TXX);
scl_hi;
delay(TXX);
return 1;
}
static unsigned char recv_byte(void) {
int i;
unsigned char byte=0;
for (i=7;i>=0;i--)
byte |= (recv_bit() << i);
return byte;
}
static int recv_ack(void)
{
unsigned int ack;
ack = (unsigned int)recv_bit();
scl_lo;
if (ack) {
do_idle();
printk(KERN_ERR "Error reading the Atmel 24C32/24C64 EEPROM \n");
return -1;
}
return ack;
}
/*
* This function does the actual read of the EEPROM. It needs the buffer into which the
* read data is copied, the size of the EEPROM being read and the buffer size
*/
int read_eeprom(char *buffer, int eeprom_size, int size)
{
int i = 0, err;
send_start();
send_byte(W_HEADER);
recv_ack();
/* EEPROM with size of more than 2K need two byte addressing */
if (eeprom_size > 2048) {
send_byte(0x00);
recv_ack();
}
send_start();
send_byte(R_HEADER);
err = recv_ack();
if (err == -1)
return err;
for (i = 0; i < size; i++) {
*buffer++ = recv_byte();
send_ack();
}
/* Note : We should do some check if the buffer contains correct information */
send_stop();
}

View File

@@ -0,0 +1,68 @@
/*
* arch/mips/pmc-sierra/yosemite/atmel_read_eeprom.c
*
* Copyright (C) 2003 PMC-Sierra Inc.
* Author: Manish Lachwani (lachwani@pmc-sierra.com)
* Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
*
* 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.
*/
/*
* Header file for atmel_read_eeprom.c
*/
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <asm/pci.h>
#include <asm/io.h>
#include <linux/init.h>
#include <asm/termios.h>
#include <asm/ioctls.h>
#include <linux/ioctl.h>
#include <linux/fcntl.h>
#define DEFAULT_PORT "/dev/ttyS0" /* Port to open */
#define TXX 0 /* Dummy loop for spinning */
#define BLOCK_SEL 0x00
#define SLAVE_ADDR 0xa0
#define READ_BIT 0x01
#define WRITE_BIT 0x00
#define R_HEADER SLAVE_ADDR + BLOCK_SEL + READ_BIT
#define W_HEADER SLAVE_ADDR + BLOCK_SEL + WRITE_BIT
/*
* Clock, Voltages and Data
*/
#define vcc_off (ioctl(fd, TIOCSBRK, 0))
#define vcc_on (ioctl(fd, TIOCCBRK, 0))
#define sda_hi (ioctl(fd, TIOCMBIS, &dtr))
#define sda_lo (ioctl(fd, TIOCMBIC, &dtr))
#define scl_lo (ioctl(fd, TIOCMBIC, &rts))
#define scl_hi (ioctl(fd, TIOCMBIS, &rts))
const char rts = TIOCM_RTS;
const char dtr = TIOCM_DTR;
int fd;

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2003 PMC-Sierra
* Author: Manish Lachwani (lachwani@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/types.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/pci.h>
/*
* HT Bus fixup for the Titan
* XXX IRQ values need to change based on the board layout
*/
void __init titan_ht_pcibios_fixup_bus(struct pci_bus *bus)
{
struct pci_bus *current_bus = bus;
struct pci_dev *devices;
struct list_head *devices_link;
list_for_each(devices_link, &(current_bus->devices)) {
devices = pci_dev_b(devices_link);
if (devices == NULL)
continue;
}
/*
* PLX and SPKT related changes go here
*/
}

View File

@@ -0,0 +1,416 @@
/*
* Copyright 2003 PMC-Sierra
* Author: Manish Lachwani (lachwani@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/types.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <asm/pci.h>
#include <asm/io.h>
#include <linux/init.h>
#include <asm/titan_dep.h>
#ifdef CONFIG_HYPERTRANSPORT
/*
* This function check if the Hypertransport Link Initialization completed. If
* it did, then proceed further with scanning bus #2
*/
static __inline__ int check_titan_htlink(void)
{
u32 val;
val = *(volatile uint32_t *)(RM9000x2_HTLINK_REG);
if (val & 0x00000020)
/* HT Link Initialization completed */
return 1;
else
return 0;
}
static int titan_ht_config_read_dword(struct pci_dev *device,
int offset, u32* val)
{
int dev, bus, func;
uint32_t address_reg, data_reg;
uint32_t address;
bus = device->bus->number;
dev = PCI_SLOT(device->devfn);
func = PCI_FUNC(device->devfn);
/* XXX Need to change the Bus # */
if (bus > 2)
address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |
0x80000000 | 0x1;
else
address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;
address_reg = RM9000x2_OCD_HTCFGA;
data_reg = RM9000x2_OCD_HTCFGD;
RM9K_WRITE(address_reg, address);
RM9K_READ(data_reg, val);
return PCIBIOS_SUCCESSFUL;
}
static int titan_ht_config_read_word(struct pci_dev *device,
int offset, u16* val)
{
int dev, bus, func;
uint32_t address_reg, data_reg;
uint32_t address;
bus = device->bus->number;
dev = PCI_SLOT(device->devfn);
func = PCI_FUNC(device->devfn);
/* XXX Need to change the Bus # */
if (bus > 2)
address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |
0x80000000 | 0x1;
else
address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;
address_reg = RM9000x2_OCD_HTCFGA;
data_reg = RM9000x2_OCD_HTCFGD;
if ((offset & 0x3) == 0)
offset = 0x2;
else
offset = 0x0;
RM9K_WRITE(address_reg, address);
RM9K_READ_16(data_reg + offset, val);
return PCIBIOS_SUCCESSFUL;
}
u32 longswap(unsigned long l)
{
unsigned char b1, b2, b3, b4;
b1 = l&255;
b2 = (l>>8)&255;
b3 = (l>>16)&255;
b4 = (l>>24)&255;
return ((b1<<24) + (b2<<16) + (b3<<8) + b4);
}
static int titan_ht_config_read_byte(struct pci_dev *device,
int offset, u8* val)
{
int dev, bus, func;
uint32_t address_reg, data_reg;
uint32_t address;
int offset1;
bus = device->bus->number;
dev = PCI_SLOT(device->devfn);
func = PCI_FUNC(device->devfn);
/* XXX Need to change the Bus # */
if (bus > 2)
address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |
0x80000000 | 0x1;
else
address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;
address_reg = RM9000x2_OCD_HTCFGA;
data_reg = RM9000x2_OCD_HTCFGD;
RM9K_WRITE(address_reg, address);
if ((offset & 0x3) == 0) {
offset1 = 0x3;
}
if ((offset & 0x3) == 1) {
offset1 = 0x2;
}
if ((offset & 0x3) == 2) {
offset1 = 0x1;
}
if ((offset & 0x3) == 3) {
offset1 = 0x0;
}
RM9K_READ_8(data_reg + offset1, val);
return PCIBIOS_SUCCESSFUL;
}
static int titan_ht_config_write_dword(struct pci_dev *device,
int offset, u8 val)
{
int dev, bus, func;
uint32_t address_reg, data_reg;
uint32_t address;
bus = device->bus->number;
dev = PCI_SLOT(device->devfn);
func = PCI_FUNC(device->devfn);
/* XXX Need to change the Bus # */
if (bus > 2)
address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |
0x80000000 | 0x1;
else
address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;
address_reg = RM9000x2_OCD_HTCFGA;
data_reg = RM9000x2_OCD_HTCFGD;
RM9K_WRITE(address_reg, address);
RM9K_WRITE(data_reg, val);
return PCIBIOS_SUCCESSFUL;
}
static int titan_ht_config_write_word(struct pci_dev *device,
int offset, u8 val)
{
int dev, bus, func;
uint32_t address_reg, data_reg;
uint32_t address;
bus = device->bus->number;
dev = PCI_SLOT(device->devfn);
func = PCI_FUNC(device->devfn);
/* XXX Need to change the Bus # */
if (bus > 2)
address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |
0x80000000 | 0x1;
else
address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;
address_reg = RM9000x2_OCD_HTCFGA;
data_reg = RM9000x2_OCD_HTCFGD;
if ((offset & 0x3) == 0)
offset = 0x2;
else
offset = 0x0;
RM9K_WRITE(address_reg, address);
RM9K_WRITE_16(data_reg + offset, val);
return PCIBIOS_SUCCESSFUL;
}
static int titan_ht_config_write_byte(struct pci_dev *device,
int offset, u8 val)
{
int dev, bus, func;
uint32_t address_reg, data_reg;
uint32_t address;
int offset1;
bus = device->bus->number;
dev = PCI_SLOT(device->devfn);
func = PCI_FUNC(device->devfn);
/* XXX Need to change the Bus # */
if (bus > 2)
address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |
0x80000000 | 0x1;
else
address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;
address_reg = RM9000x2_OCD_HTCFGA;
data_reg = RM9000x2_OCD_HTCFGD;
RM9K_WRITE(address_reg, address);
if ((offset & 0x3) == 0) {
offset1 = 0x3;
}
if ((offset & 0x3) == 1) {
offset1 = 0x2;
}
if ((offset & 0x3) == 2) {
offset1 = 0x1;
}
if ((offset & 0x3) == 3) {
offset1 = 0x0;
}
RM9K_WRITE_8(data_reg + offset1, val);
return PCIBIOS_SUCCESSFUL;
}
static void titan_pcibios_set_master(struct pci_dev *dev)
{
u16 cmd;
int bus = dev->bus->number;
if (check_titan_htlink())
titan_ht_config_read_word(dev, PCI_COMMAND, &cmd);
cmd |= PCI_COMMAND_MASTER;
if (check_titan_htlink())
titan_ht_config_write_word(dev, PCI_COMMAND, cmd);
}
int pcibios_enable_resources(struct pci_dev *dev)
{
u16 cmd, old_cmd;
u8 tmp1;
int idx;
struct resource *r;
int bus = dev->bus->number;
if (check_titan_htlink())
titan_ht_config_read_word(dev, PCI_COMMAND, &cmd);
old_cmd = cmd;
for (idx = 0; idx < 6; idx++) {
r = &dev->resource[idx];
if (!r->start && r->end) {
printk(KERN_ERR
"PCI: Device %s not available because of "
"resource collisions\n", pci_name(dev));
return -EINVAL;
}
if (r->flags & IORESOURCE_IO)
cmd |= PCI_COMMAND_IO;
if (r->flags & IORESOURCE_MEM)
cmd |= PCI_COMMAND_MEMORY;
}
if (cmd != old_cmd) {
if (check_titan_htlink())
titan_ht_config_write_word(dev, PCI_COMMAND, cmd);
}
if (check_titan_htlink())
titan_ht_config_read_byte(dev, PCI_CACHE_LINE_SIZE, &tmp1);
if (tmp1 != 8) {
printk(KERN_WARNING "PCI setting cache line size to 8 from "
"%d\n", tmp1);
}
if (check_titan_htlink())
titan_ht_config_write_byte(dev, PCI_CACHE_LINE_SIZE, 8);
if (check_titan_htlink())
titan_ht_config_read_byte(dev, PCI_LATENCY_TIMER, &tmp1);
if (tmp1 < 32 || tmp1 == 0xff) {
printk(KERN_WARNING "PCI setting latency timer to 32 from %d\n",
tmp1);
}
if (check_titan_htlink())
titan_ht_config_write_byte(dev, PCI_LATENCY_TIMER, 32);
return 0;
}
int pcibios_enable_device(struct pci_dev *dev, int mask)
{
return pcibios_enable_resources(dev);
}
void pcibios_align_resource(void *data, struct resource *res,
resource_size_t size, resource_size_t align)
{
struct pci_dev *dev = data;
if (res->flags & IORESOURCE_IO) {
resource_size_t start = res->start;
/* We need to avoid collisions with `mirrored' VGA ports
and other strange ISA hardware, so we always want the
addresses kilobyte aligned. */
if (size > 0x100) {
printk(KERN_ERR "PCI: I/O Region %s/%d too large"
" (%ld bytes)\n", pci_name(dev),
dev->resource - res, size);
}
start = (start + 1024 - 1) & ~(1024 - 1);
res->start = start;
}
}
struct pci_ops titan_pci_ops = {
titan_ht_config_read_byte,
titan_ht_config_read_word,
titan_ht_config_read_dword,
titan_ht_config_write_byte,
titan_ht_config_write_word,
titan_ht_config_write_dword
};
void __init pcibios_fixup_bus(struct pci_bus *c)
{
titan_ht_pcibios_fixup_bus(c);
}
void __init pcibios_init(void)
{
/* Reset PCI I/O and PCI MEM values */
/* XXX Need to add the proper values here */
ioport_resource.start = 0xe0000000;
ioport_resource.end = 0xe0000000 + 0x20000000 - 1;
iomem_resource.start = 0xc0000000;
iomem_resource.end = 0xc0000000 + 0x20000000 - 1;
/* XXX Need to add bus values */
pci_scan_bus(2, &titan_pci_ops, NULL);
pci_scan_bus(3, &titan_pci_ops, NULL);
}
/*
* for parsing "pci=" kernel boot arguments.
*/
char *pcibios_setup(char *str)
{
printk(KERN_INFO "rr: pcibios_setup\n");
/* Nothing to do for now. */
return str;
}
unsigned __init int pcibios_assign_all_busses(void)
{
/* We want to use the PCI bus detection done by PMON */
return 0;
}
#endif /* CONFIG_HYPERTRANSPORT */

View File

@@ -0,0 +1,158 @@
/*
* Copyright (C) 2003 PMC-Sierra Inc.
* Author: Manish Lachwani (lachwani@pmc-sierra.com)
*
* Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org)
*
* 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.
*
* Second level Interrupt handlers for the PMC-Sierra Titan/Yosemite board
*/
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/kernel_stat.h>
#include <linux/module.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/irq.h>
#include <linux/timex.h>
#include <linux/slab.h>
#include <linux/random.h>
#include <linux/bitops.h>
#include <asm/bootinfo.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/irq_cpu.h>
#include <asm/mipsregs.h>
#include <asm/system.h>
#include <asm/titan_dep.h>
/* Hypertransport specific */
#define IRQ_ACK_BITS 0x00000000 /* Ack bits */
#define HYPERTRANSPORT_INTA 0x78 /* INTA# */
#define HYPERTRANSPORT_INTB 0x79 /* INTB# */
#define HYPERTRANSPORT_INTC 0x7a /* INTC# */
#define HYPERTRANSPORT_INTD 0x7b /* INTD# */
extern void titan_mailbox_irq(void);
#ifdef CONFIG_HYPERTRANSPORT
/*
* Handle hypertransport & SMP interrupts. The interrupt lines are scarce.
* For interprocessor interrupts, the best thing to do is to use the INTMSG
* register. We use the same external interrupt line, i.e. INTB3 and monitor
* another status bit
*/
static void ll_ht_smp_irq_handler(int irq)
{
u32 status = OCD_READ(RM9000x2_OCD_INTP0STATUS4);
/* Ack all the bits that correspond to the interrupt sources */
if (status != 0)
OCD_WRITE(RM9000x2_OCD_INTP0STATUS4, IRQ_ACK_BITS);
status = OCD_READ(RM9000x2_OCD_INTP1STATUS4);
if (status != 0)
OCD_WRITE(RM9000x2_OCD_INTP1STATUS4, IRQ_ACK_BITS);
#ifdef CONFIG_HT_LEVEL_TRIGGER
/*
* Level Trigger Mode only. Send the HT EOI message back to the source.
*/
switch (status) {
case 0x1000000:
OCD_WRITE(RM9000x2_OCD_HTEOI, HYPERTRANSPORT_INTA);
break;
case 0x2000000:
OCD_WRITE(RM9000x2_OCD_HTEOI, HYPERTRANSPORT_INTB);
break;
case 0x4000000:
OCD_WRITE(RM9000x2_OCD_HTEOI, HYPERTRANSPORT_INTC);
break;
case 0x8000000:
OCD_WRITE(RM9000x2_OCD_HTEOI, HYPERTRANSPORT_INTD);
break;
case 0x0000001:
/* PLX */
OCD_WRITE(RM9000x2_OCD_HTEOI, 0x20);
OCD_WRITE(IRQ_CLEAR_REG, IRQ_ACK_BITS);
break;
case 0xf000000:
OCD_WRITE(RM9000x2_OCD_HTEOI, HYPERTRANSPORT_INTA);
OCD_WRITE(RM9000x2_OCD_HTEOI, HYPERTRANSPORT_INTB);
OCD_WRITE(RM9000x2_OCD_HTEOI, HYPERTRANSPORT_INTC);
OCD_WRITE(RM9000x2_OCD_HTEOI, HYPERTRANSPORT_INTD);
break;
}
#endif /* CONFIG_HT_LEVEL_TRIGGER */
do_IRQ(irq);
}
#endif
asmlinkage void plat_irq_dispatch(void)
{
unsigned int cause = read_c0_cause();
unsigned int status = read_c0_status();
unsigned int pending = cause & status;
if (pending & STATUSF_IP7) {
do_IRQ(7);
} else if (pending & STATUSF_IP2) {
#ifdef CONFIG_HYPERTRANSPORT
ll_ht_smp_irq_handler(2);
#else
do_IRQ(2);
#endif
} else if (pending & STATUSF_IP3) {
do_IRQ(3);
} else if (pending & STATUSF_IP4) {
do_IRQ(4);
} else if (pending & STATUSF_IP5) {
#ifdef CONFIG_SMP
titan_mailbox_irq();
#else
do_IRQ(5);
#endif
} else if (pending & STATUSF_IP6) {
do_IRQ(4);
}
}
/*
* Initialize the next level interrupt handler
*/
void __init arch_init_irq(void)
{
clear_c0_status(ST0_IM);
mips_cpu_irq_init();
rm7k_cpu_irq_init();
rm9k_cpu_irq_init();
#ifdef CONFIG_GDB_CONSOLE
register_gdb_console();
#endif
}

View File

@@ -0,0 +1,143 @@
/*
* 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.
*
* Copyright (C) 2003, 2004 PMC-Sierra Inc.
* Author: Manish Lachwani (lachwani@pmc-sierra.com)
* Copyright (C) 2004 Ralf Baechle
*/
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/smp.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
#include <asm/reboot.h>
#include <asm/smp-ops.h>
#include <asm/system.h>
#include <asm/bootinfo.h>
#include <asm/pmon.h>
#ifdef CONFIG_SMP
extern void prom_grab_secondary(void);
#else
#define prom_grab_secondary() do { } while (0)
#endif
#include "setup.h"
struct callvectors *debug_vectors;
extern unsigned long yosemite_base;
extern unsigned long cpu_clock_freq;
const char *get_system_type(void)
{
return "PMC-Sierra Yosemite";
}
static void prom_cpu0_exit(void *arg)
{
void *nvram = (void *) YOSEMITE_RTC_BASE;
/* Ask the NVRAM/RTC/watchdog chip to assert reset in 1/16 second */
writeb(0x84, nvram + 0xff7);
/* wait for the watchdog to go off */
mdelay(100 + (1000 / 16));
/* if the watchdog fails for some reason, let people know */
printk(KERN_NOTICE "Watchdog reset failed\n");
}
/*
* Reset the NVRAM over the local bus
*/
static void prom_exit(void)
{
#ifdef CONFIG_SMP
if (smp_processor_id())
/* CPU 1 */
smp_call_function(prom_cpu0_exit, NULL, 1);
#endif
prom_cpu0_exit(NULL);
}
/*
* Halt the system
*/
static void prom_halt(void)
{
printk(KERN_NOTICE "\n** You can safely turn off the power\n");
while (1)
__asm__(".set\tmips3\n\t" "wait\n\t" ".set\tmips0");
}
extern struct plat_smp_ops yos_smp_ops;
/*
* Init routine which accepts the variables from PMON
*/
void __init prom_init(void)
{
int argc = fw_arg0;
char **arg = (char **) fw_arg1;
char **env = (char **) fw_arg2;
struct callvectors *cv = (struct callvectors *) fw_arg3;
int i = 0;
/* Callbacks for halt, restart */
_machine_restart = (void (*)(char *)) prom_exit;
_machine_halt = prom_halt;
pm_power_off = prom_halt;
debug_vectors = cv;
arcs_cmdline[0] = '\0';
/* Get the boot parameters */
for (i = 1; i < argc; i++) {
if (strlen(arcs_cmdline) + strlen(arg[i] + 1) >=
sizeof(arcs_cmdline))
break;
strcat(arcs_cmdline, arg[i]);
strcat(arcs_cmdline, " ");
}
#ifdef CONFIG_SERIAL_8250_CONSOLE
if ((strstr(arcs_cmdline, "console=ttyS")) == NULL)
strcat(arcs_cmdline, "console=ttyS0,115200");
#endif
while (*env) {
if (strncmp("ocd_base", *env, strlen("ocd_base")) == 0)
yosemite_base =
simple_strtol(*env + strlen("ocd_base="), NULL,
16);
if (strncmp("cpuclock", *env, strlen("cpuclock")) == 0)
cpu_clock_freq =
simple_strtol(*env + strlen("cpuclock="), NULL,
10);
env++;
}
prom_grab_secondary();
register_smp_ops(&yos_smp_ops);
}
void __init prom_free_prom_memory(void)
{
}
void __init prom_fixup_mem_map(unsigned long start, unsigned long end)
{
}

View File

@@ -0,0 +1,109 @@
/*
* 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.
*
* Copyright (C) 2001, 2002, 2004 Ralf Baechle
*/
#include <linux/init.h>
#include <linux/console.h>
#include <linux/kdev_t.h>
#include <linux/major.h>
#include <linux/termios.h>
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <asm/serial.h>
#include <asm/io.h>
/* SUPERIO uart register map */
struct yo_uartregs {
union {
volatile u8 rbr; /* read only, DLAB == 0 */
volatile u8 thr; /* write only, DLAB == 0 */
volatile u8 dll; /* DLAB == 1 */
} u1;
union {
volatile u8 ier; /* DLAB == 0 */
volatile u8 dlm; /* DLAB == 1 */
} u2;
union {
volatile u8 iir; /* read only */
volatile u8 fcr; /* write only */
} u3;
volatile u8 iu_lcr;
volatile u8 iu_mcr;
volatile u8 iu_lsr;
volatile u8 iu_msr;
volatile u8 iu_scr;
} yo_uregs_t;
#define iu_rbr u1.rbr
#define iu_thr u1.thr
#define iu_dll u1.dll
#define iu_ier u2.ier
#define iu_dlm u2.dlm
#define iu_iir u3.iir
#define iu_fcr u3.fcr
#define ssnop() __asm__ __volatile__("sll $0, $0, 1\n");
#define ssnop_4() do { ssnop(); ssnop(); ssnop(); ssnop(); } while (0)
#define IO_BASE_64 0x9000000000000000ULL
static unsigned char readb_outer_space(unsigned long long phys)
{
unsigned long long vaddr = IO_BASE_64 | phys;
unsigned char res;
unsigned int sr;
sr = read_c0_status();
write_c0_status((sr | ST0_KX) & ~ ST0_IE);
ssnop_4();
__asm__ __volatile__ (
" .set mips3 \n"
" ld %0, %1 \n"
" lbu %0, (%0) \n"
" .set mips0 \n"
: "=r" (res)
: "m" (vaddr));
write_c0_status(sr);
ssnop_4();
return res;
}
static void writeb_outer_space(unsigned long long phys, unsigned char c)
{
unsigned long long vaddr = IO_BASE_64 | phys;
unsigned long tmp;
unsigned int sr;
sr = read_c0_status();
write_c0_status((sr | ST0_KX) & ~ ST0_IE);
ssnop_4();
__asm__ __volatile__ (
" .set mips3 \n"
" ld %0, %1 \n"
" sb %2, (%0) \n"
" .set mips0 \n"
: "=&r" (tmp)
: "m" (vaddr), "r" (c));
write_c0_status(sr);
ssnop_4();
}
void prom_putchar(char c)
{
unsigned long lsr = 0xfd000008ULL + offsetof(struct yo_uartregs, iu_lsr);
unsigned long thr = 0xfd000008ULL + offsetof(struct yo_uartregs, iu_thr);
while ((readb_outer_space(lsr) & 0x20) == 0);
writeb_outer_space(thr, c);
}

View File

@@ -0,0 +1,223 @@
/*
* Copyright (C) 2003 PMC-Sierra Inc.
* Author: Manish Lachwani (lachwani@pmc-sierra.com)
*
* Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
*
* 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/bcd.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/bootmem.h>
#include <linux/swap.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
#include <linux/termios.h>
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/serial_8250.h>
#include <asm/time.h>
#include <asm/bootinfo.h>
#include <asm/page.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/processor.h>
#include <asm/reboot.h>
#include <asm/serial.h>
#include <asm/titan_dep.h>
#include <asm/m48t37.h>
#include "setup.h"
unsigned char titan_ge_mac_addr_base[6] = {
// 0x00, 0x03, 0xcc, 0x1d, 0x22, 0x00
0x00, 0xe0, 0x04, 0x00, 0x00, 0x21
};
unsigned long cpu_clock_freq;
unsigned long yosemite_base;
static struct m48t37_rtc *m48t37_base;
void __init bus_error_init(void)
{
/* Do nothing */
}
void read_persistent_clock(struct timespec *ts)
{
unsigned int year, month, day, hour, min, sec;
unsigned long flags;
spin_lock_irqsave(&rtc_lock, flags);
/* Stop the update to the time */
m48t37_base->control = 0x40;
year = bcd2bin(m48t37_base->year);
year += bcd2bin(m48t37_base->century) * 100;
month = bcd2bin(m48t37_base->month);
day = bcd2bin(m48t37_base->date);
hour = bcd2bin(m48t37_base->hour);
min = bcd2bin(m48t37_base->min);
sec = bcd2bin(m48t37_base->sec);
/* Start the update to the time again */
m48t37_base->control = 0x00;
spin_unlock_irqrestore(&rtc_lock, flags);
ts->tv_sec = mktime(year, month, day, hour, min, sec);
ts->tv_nsec = 0;
}
int rtc_mips_set_time(unsigned long tim)
{
struct rtc_time tm;
unsigned long flags;
/*
* Convert to a more useful format -- note months count from 0
* and years from 1900
*/
rtc_time_to_tm(tim, &tm);
tm.tm_year += 1900;
tm.tm_mon += 1;
spin_lock_irqsave(&rtc_lock, flags);
/* enable writing */
m48t37_base->control = 0x80;
/* year */
m48t37_base->year = bin2bcd(tm.tm_year % 100);
m48t37_base->century = bin2bcd(tm.tm_year / 100);
/* month */
m48t37_base->month = bin2bcd(tm.tm_mon);
/* day */
m48t37_base->date = bin2bcd(tm.tm_mday);
/* hour/min/sec */
m48t37_base->hour = bin2bcd(tm.tm_hour);
m48t37_base->min = bin2bcd(tm.tm_min);
m48t37_base->sec = bin2bcd(tm.tm_sec);
/* day of week -- not really used, but let's keep it up-to-date */
m48t37_base->day = bin2bcd(tm.tm_wday + 1);
/* disable writing */
m48t37_base->control = 0x00;
spin_unlock_irqrestore(&rtc_lock, flags);
return 0;
}
void __init plat_time_init(void)
{
mips_hpt_frequency = cpu_clock_freq / 2;
mips_hpt_frequency = 33000000 * 3 * 5;
}
unsigned long ocd_base;
EXPORT_SYMBOL(ocd_base);
/*
* Common setup before any secondaries are started
*/
#define TITAN_UART_CLK 3686400
#define TITAN_SERIAL_BASE_BAUD (TITAN_UART_CLK / 16)
#define TITAN_SERIAL_IRQ 4
#define TITAN_SERIAL_BASE 0xfd000008UL
static void __init py_map_ocd(void)
{
ocd_base = (unsigned long) ioremap(OCD_BASE, OCD_SIZE);
if (!ocd_base)
panic("Mapping OCD failed - game over. Your score is 0.");
/* Kludge for PMON bug ... */
OCD_WRITE(0x0710, 0x0ffff029);
}
static void __init py_uart_setup(void)
{
#ifdef CONFIG_SERIAL_8250
struct uart_port up;
/*
* Register to interrupt zero because we share the interrupt with
* the serial driver which we don't properly support yet.
*/
memset(&up, 0, sizeof(up));
up.membase = (unsigned char *) ioremap(TITAN_SERIAL_BASE, 8);
up.irq = TITAN_SERIAL_IRQ;
up.uartclk = TITAN_UART_CLK;
up.regshift = 0;
up.iotype = UPIO_MEM;
up.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
up.line = 0;
if (early_serial_setup(&up))
printk(KERN_ERR "Early serial init of port 0 failed\n");
#endif /* CONFIG_SERIAL_8250 */
}
static void __init py_rtc_setup(void)
{
m48t37_base = ioremap(YOSEMITE_RTC_BASE, YOSEMITE_RTC_SIZE);
if (!m48t37_base)
printk(KERN_ERR "Mapping the RTC failed\n");
}
/* Not only time init but that's what the hook it's called through is named */
static void __init py_late_time_init(void)
{
py_map_ocd();
py_uart_setup();
py_rtc_setup();
}
void __init plat_mem_setup(void)
{
late_time_init = py_late_time_init;
/* Add memory regions */
add_memory_region(0x00000000, 0x10000000, BOOT_MEM_RAM);
#if 0 /* XXX Crash ... */
OCD_WRITE(RM9000x2_OCD_HTSC,
OCD_READ(RM9000x2_OCD_HTSC) | HYPERTRANSPORT_ENABLE);
/* Set the BAR. Shifted mode */
OCD_WRITE(RM9000x2_OCD_HTBAR0, HYPERTRANSPORT_BAR0_ADDR);
OCD_WRITE(RM9000x2_OCD_HTMASK0, HYPERTRANSPORT_SIZE0);
#endif
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2003, 04 PMC-Sierra
* Author: Manish Lachwani (lachwani@pmc-sierra.com)
* Copyright 2004 Ralf Baechle <ralf@linux-mips.org>
*
* Board specific definititions for the PMC-Sierra Yosemite
*
* 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.
*/
#ifndef __SETUP_H__
#define __SETUP_H__
/* M48T37 RTC + NVRAM */
#define YOSEMITE_RTC_BASE 0xfc800000
#define YOSEMITE_RTC_SIZE 0x00800000
#define HYPERTRANSPORT_BAR0_ADDR 0x00000006
#define HYPERTRANSPORT_SIZE0 0x0fffffff
#define HYPERTRANSPORT_BAR0_ATTR 0x00002000
#define HYPERTRANSPORT_ENABLE 0x6
/*
* EEPROM Size
*/
#define TITAN_ATMEL_24C32_SIZE 32768
#define TITAN_ATMEL_24C64_SIZE 65536
#endif /* __SETUP_H__ */

View File

@@ -0,0 +1,181 @@
#include <linux/linkage.h>
#include <linux/sched.h>
#include <linux/smp.h>
#include <asm/pmon.h>
#include <asm/titan_dep.h>
#include <asm/time.h>
#define LAUNCHSTACK_SIZE 256
static __cpuinitdata DEFINE_SPINLOCK(launch_lock);
static unsigned long secondary_sp __cpuinitdata;
static unsigned long secondary_gp __cpuinitdata;
static unsigned char launchstack[LAUNCHSTACK_SIZE] __initdata
__attribute__((aligned(2 * sizeof(long))));
static void __init prom_smp_bootstrap(void)
{
local_irq_disable();
while (spin_is_locked(&launch_lock));
__asm__ __volatile__(
" move $sp, %0 \n"
" move $gp, %1 \n"
" j smp_bootstrap \n"
:
: "r" (secondary_sp), "r" (secondary_gp));
}
/*
* PMON is a fragile beast. It'll blow up once the mappings it's littering
* right into the middle of KSEG3 are blown away so we have to grab the slave
* core early and keep it in a waiting loop.
*/
void __init prom_grab_secondary(void)
{
spin_lock(&launch_lock);
pmon_cpustart(1, &prom_smp_bootstrap,
launchstack + LAUNCHSTACK_SIZE, 0);
}
void titan_mailbox_irq(void)
{
int cpu = smp_processor_id();
unsigned long status;
switch (cpu) {
case 0:
status = OCD_READ(RM9000x2_OCD_INTP0STATUS3);
OCD_WRITE(RM9000x2_OCD_INTP0CLEAR3, status);
if (status & 0x2)
smp_call_function_interrupt();
break;
case 1:
status = OCD_READ(RM9000x2_OCD_INTP1STATUS3);
OCD_WRITE(RM9000x2_OCD_INTP1CLEAR3, status);
if (status & 0x2)
smp_call_function_interrupt();
break;
}
}
/*
* Send inter-processor interrupt
*/
static void yos_send_ipi_single(int cpu, unsigned int action)
{
/*
* Generate an INTMSG so that it can be sent over to the
* destination CPU. The INTMSG will put the STATUS bits
* based on the action desired. An alternative strategy
* is to write to the Interrupt Set register, read the
* Interrupt Status register and clear the Interrupt
* Clear register. The latter is preffered.
*/
switch (action) {
case SMP_RESCHEDULE_YOURSELF:
if (cpu == 1)
OCD_WRITE(RM9000x2_OCD_INTP1SET3, 4);
else
OCD_WRITE(RM9000x2_OCD_INTP0SET3, 4);
break;
case SMP_CALL_FUNCTION:
if (cpu == 1)
OCD_WRITE(RM9000x2_OCD_INTP1SET3, 2);
else
OCD_WRITE(RM9000x2_OCD_INTP0SET3, 2);
break;
}
}
static void yos_send_ipi_mask(const struct cpumask *mask, unsigned int action)
{
unsigned int i;
for_each_cpu(i, mask)
yos_send_ipi_single(i, action);
}
/*
* After we've done initial boot, this function is called to allow the
* board code to clean up state, if needed
*/
static void __cpuinit yos_init_secondary(void)
{
set_c0_status(ST0_CO | ST0_IE | ST0_IM);
}
static void __cpuinit yos_smp_finish(void)
{
}
/* Hook for after all CPUs are online */
static void yos_cpus_done(void)
{
}
/*
* Firmware CPU startup hook
* Complicated by PMON's weird interface which tries to minimic the UNIX fork.
* It launches the next * available CPU and copies some information on the
* stack so the first thing we do is throw away that stuff and load useful
* values into the registers ...
*/
static void __cpuinit yos_boot_secondary(int cpu, struct task_struct *idle)
{
unsigned long gp = (unsigned long) task_thread_info(idle);
unsigned long sp = __KSTK_TOS(idle);
secondary_sp = sp;
secondary_gp = gp;
spin_unlock(&launch_lock);
}
/*
* Detect available CPUs, populate cpu_possible_map before smp_init
*
* We don't want to start the secondary CPU yet nor do we have a nice probing
* feature in PMON so we just assume presence of the secondary core.
*/
static void __init yos_smp_setup(void)
{
int i;
cpus_clear(cpu_possible_map);
for (i = 0; i < 2; i++) {
cpu_set(i, cpu_possible_map);
__cpu_number_map[i] = i;
__cpu_logical_map[i] = i;
}
}
static void __init yos_prepare_cpus(unsigned int max_cpus)
{
/*
* Be paranoid. Enable the IPI only if we're really about to go SMP.
*/
if (cpus_weight(cpu_possible_map))
set_c0_status(STATUSF_IP5);
}
struct plat_smp_ops yos_smp_ops = {
.send_ipi_single = yos_send_ipi_single,
.send_ipi_mask = yos_send_ipi_mask,
.init_secondary = yos_init_secondary,
.smp_finish = yos_smp_finish,
.cpus_done = yos_cpus_done,
.boot_secondary = yos_boot_secondary,
.smp_setup = yos_smp_setup,
.prepare_cpus = yos_prepare_cpus,
};