Commit d249e539 authored by Paul Mundt's avatar Paul Mundt Committed by Linus Torvalds

[PATCH] Move SH board-specific code around

This patch moves the old board-specific SH code
parent 47050253
#
# Makefile for ADX boards
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
obj-y := mach.o setup.o io.o irq.o irq_maskreq.o
......@@ -173,6 +173,7 @@ void adx_iounmap(void *addr)
EXPORT_SYMBOL(adx_iounmap);
#ifdef CONFIG_IDE
#include <linux/vmalloc.h>
extern void *cf_io_base;
......@@ -190,3 +191,5 @@ unsigned long adx_isa_port2addr(unsigned long offset)
return offset + 0xb0000000; /* IOBUS (AREA 4)*/
}
#endif
/*
* linux/arch/sh/boards/adx/irq.c
*
* Copyright (C) 2001 A&D Co., Ltd.
*
* I/O routine and setup routines for A&D ADX Board
*
* 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 <asm/irq.h>
void init_adx_IRQ(void)
{
int i;
/* printk("init_adx_IRQ()\n");*/
/* setup irq_mask_register */
irq_mask_register = (unsigned short *)0xa6000008;
/* cover all external interrupt area by maskreg_irq_type
* (Actually, irq15 doesn't exist)
*/
for (i = 0; i < 16; i++) {
make_maskreg_irq(i);
disable_irq(i);
}
}
......@@ -65,11 +65,11 @@ static void disable_maskreg_irq(unsigned int irq)
unsigned short val, mask = 0x01 << irq;
/* Set "irq"th bit */
save_and_cli(flags);
local_irq_save(flags);
val = ctrl_inw((unsigned long)irq_mask_register);
val |= mask;
ctrl_outw(val, (unsigned long)irq_mask_register);
restore_flags(flags);
local_irq_restore(flags);
}
}
......@@ -80,11 +80,11 @@ static void enable_maskreg_irq(unsigned int irq)
unsigned short val, mask = ~(0x01 << irq);
/* Clear "irq"th bit */
save_and_cli(flags);
local_irq_save(flags);
val = ctrl_inw((unsigned long)irq_mask_register);
val &= mask;
ctrl_outw(val, (unsigned long)irq_mask_register);
restore_flags(flags);
local_irq_restore(flags);
}
}
......
......@@ -15,9 +15,8 @@
#include <asm/machvec.h>
#include <asm/rtc.h>
#include <asm/machvec_init.h>
#include <asm/io_adx.h>
#include <asm/adx/io.h>
extern void setup_adx(void);
extern void init_adx_IRQ(void);
/*
......@@ -25,49 +24,43 @@ extern void init_adx_IRQ(void);
*/
struct sh_machine_vector mv_adx __initmv = {
.mv_name = "A&D_ADX",
mv_nr_irqs: 48,
.mv_nr_irqs = 48,
mv_inb: adx_inb,
mv_inw: adx_inw,
mv_inl: adx_inl,
mv_outb: adx_outb,
mv_outw: adx_outw,
mv_outl: adx_outl,
.mv_inb = adx_inb,
.mv_inw = adx_inw,
.mv_inl = adx_inl,
.mv_outb = adx_outb,
.mv_outw = adx_outw,
.mv_outl = adx_outl,
mv_inb_p: adx_inb_p,
mv_inw_p: adx_inw,
mv_inl_p: adx_inl,
mv_outb_p: adx_outb_p,
mv_outw_p: adx_outw,
mv_outl_p: adx_outl,
.mv_inb_p = adx_inb_p,
.mv_inw_p = adx_inw,
.mv_inl_p = adx_inl,
.mv_outb_p = adx_outb_p,
.mv_outw_p = adx_outw,
.mv_outl_p = adx_outl,
mv_insb: adx_insb,
mv_insw: adx_insw,
mv_insl: adx_insl,
mv_outsb: adx_outsb,
mv_outsw: adx_outsw,
mv_outsl: adx_outsl,
.mv_insb = adx_insb,
.mv_insw = adx_insw,
.mv_insl = adx_insl,
.mv_outsb = adx_outsb,
.mv_outsw = adx_outsw,
.mv_outsl = adx_outsl,
mv_readb: adx_readb,
mv_readw: adx_readw,
mv_readl: adx_readl,
mv_writeb: adx_writeb,
mv_writew: adx_writew,
mv_writel: adx_writel,
.mv_readb = adx_readb,
.mv_readw = adx_readw,
.mv_readl = adx_readl,
.mv_writeb = adx_writeb,
.mv_writew = adx_writew,
.mv_writel = adx_writel,
mv_ioremap: adx_ioremap,
mv_iounmap: adx_iounmap,
.mv_ioremap = adx_ioremap,
.mv_iounmap = adx_iounmap,
mv_isa_port2addr: adx_isa_port2addr,
.mv_isa_port2addr = adx_isa_port2addr,
mv_init_irq: init_adx_IRQ,
.mv_init_arch = setup_adx,
.mv_init_irq = init_adx_IRQ,
.mv_rtc_gettimeofday = sh_rtc_gettimeofday,
.mv_rtc_settimeofday = sh_rtc_settimeofday,
.mv_hw_adx = 1,
mv_hw_adx: 1,
};
ALIAS_MV(adx)
/*
* linux/arch/sh/kernel/setup_adx.c
* linux/arch/sh/board/adx/setup.c
*
* Copyright (C) 2001 A&D Co., Ltd.
*
......@@ -11,30 +11,14 @@
*
*/
#include <asm/io.h>
#include <asm/machvec.h>
#include <asm/irq.h>
#include <linux/module.h>
void setup_adx(void)
const char *get_system_type(void)
{
/* nothing to do just yet */
/* printk("setup_adx()\n");*/
return "A&D ADX";
}
void init_adx_IRQ(void)
void platform_setup(void)
{
int i;
/* printk("init_adx_IRQ()\n");*/
/* setup irq_mask_register */
irq_mask_register = (unsigned short *)0xa6000008;
/* cover all external interrupt area by maskreg_irq_type
* (Actually, irq15 doesn't exist)
*/
for (i = 0; i < 16; i++) {
make_maskreg_irq(i);
disable_irq(i);
}
}
#
# Makefile for the BigSur specific parts of the kernel
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
obj-y := mach.o setup.o io.o irq.o led.o
obj-$(CONFIG_PCI) += pci.o
......@@ -19,7 +19,7 @@
#include <linux/module.h>
#include <asm/machvec.h>
#include <asm/io.h>
#include <asm/bigsur.h>
#include <asm/bigsur/bigsur.h>
//#define BIGSUR_DEBUG 2
#undef BIGSUR_DEBUG
......
/*
*
* By Dustin McIntire (dustin@sensoria.com) (c)2001
*
* Setup and IRQ handling code for the HD64465 companion chip.
* by Greg Banks <gbanks@pocketpenguins.com>
* Copyright (c) 2000 PocketPenguins Inc
*
* Derived from setup_hd64465.c which bore the message:
* Greg Banks <gbanks@pocketpenguins.com>
* Copyright (c) 2000 PocketPenguins Inc and
* Copyright (C) 2000 YAEGASHI Takeshi
* and setup_cqreek.c which bore message:
* Copyright (C) 2000 Niibe Yutaka
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* IRQ functions for a Hitachi Big Sur Evaluation Board.
*
*/
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/param.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/bitops.h>
#include <asm/bigsur/io.h>
#include <asm/hd64465/hd64465.h>
#include <asm/bigsur/bigsur.h>
//#define BIGSUR_DEBUG 3
#undef BIGSUR_DEBUG
#ifdef BIGSUR_DEBUG
#define DPRINTK(args...) printk(args)
#define DIPRINTK(n, args...) if (BIGSUR_DEBUG>(n)) printk(args)
#else
#define DPRINTK(args...)
#define DIPRINTK(n, args...)
#endif /* BIGSUR_DEBUG */
#ifdef CONFIG_HD64465
extern int hd64465_irq_demux(int irq);
#endif /* CONFIG_HD64465 */
/*===========================================================*/
// Big Sur CPLD IRQ Routines
/*===========================================================*/
/* Level 1 IRQ routines */
static void disable_bigsur_l1irq(unsigned int irq)
{
unsigned long flags;
unsigned char mask;
unsigned int mask_port = ((irq - BIGSUR_IRQ_LOW)/8) ? BIGSUR_IRLMR1 : BIGSUR_IRLMR0;
unsigned char bit = (1 << ((irq - MGATE_IRQ_LOW)%8) );
if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
DPRINTK("Disable L1 IRQ %d\n", irq);
DIPRINTK(2,"disable_bigsur_l1irq: IMR=0x%08x mask=0x%x\n",
mask_port, bit);
local_irq_save(flags);
/* Disable IRQ - set mask bit */
mask = inb(mask_port) | bit;
outb(mask, mask_port);
local_irq_restore(flags);
return;
}
DPRINTK("disable_bigsur_l1irq: Invalid IRQ %d\n", irq);
}
static void enable_bigsur_l1irq(unsigned int irq)
{
unsigned long flags;
unsigned char mask;
unsigned int mask_port = ((irq - BIGSUR_IRQ_LOW)/8) ? BIGSUR_IRLMR1 : BIGSUR_IRLMR0;
unsigned char bit = (1 << ((irq - MGATE_IRQ_LOW)%8) );
if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
DPRINTK("Enable L1 IRQ %d\n", irq);
DIPRINTK(2,"enable_bigsur_l1irq: IMR=0x%08x mask=0x%x\n",
mask_port, bit);
local_irq_save(flags);
/* Enable L1 IRQ - clear mask bit */
mask = inb(mask_port) & ~bit;
outb(mask, mask_port);
local_irq_restore(flags);
return;
}
DPRINTK("enable_bigsur_l1irq: Invalid IRQ %d\n", irq);
}
/* Level 2 irq masks and registers for L2 decoding */
/* Level2 bitmasks for each level 1 IRQ */
const u32 bigsur_l2irq_mask[] =
{0x40,0x80,0x08,0x01,0x01,0x3C,0x3E,0xFF,0x40,0x80,0x06,0x03};
/* Level2 to ISR[n] map for each level 1 IRQ */
const u32 bigsur_l2irq_reg[] =
{ 2, 2, 3, 3, 1, 2, 1, 0, 1, 1, 3, 2};
/* Level2 to Level 1 IRQ map */
const u32 bigsur_l2_l1_map[] =
{7,7,7,7,7,7,7,7, 4,6,6,6,6,6,8,9, 11,11,5,5,5,5,0,1, 3,10,10,2,-1,-1,-1,-1};
/* IRQ inactive level (high or low) */
const u32 bigsur_l2_inactv_state[] = {0x00, 0xBE, 0xFC, 0xF7};
/* CPLD external status and mask registers base and offsets */
static const u32 isr_base = BIGSUR_IRQ0;
static const u32 isr_offset = BIGSUR_IRQ0 - BIGSUR_IRQ1;
static const u32 imr_base = BIGSUR_IMR0;
static const u32 imr_offset = BIGSUR_IMR0 - BIGSUR_IMR1;
#define REG_NUM(irq) ((irq-BIGSUR_2NDLVL_IRQ_LOW)/8 )
/* Level 2 IRQ routines */
static void disable_bigsur_l2irq(unsigned int irq)
{
unsigned long flags;
unsigned char mask;
unsigned char bit = 1 << ((irq-BIGSUR_2NDLVL_IRQ_LOW)%8);
unsigned int mask_port = imr_base - REG_NUM(irq)*imr_offset;
if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
DPRINTK("Disable L2 IRQ %d\n", irq);
DIPRINTK(2,"disable_bigsur_l2irq: IMR=0x%08x mask=0x%x\n",
mask_port, bit);
local_irq_save(flags);
/* Disable L2 IRQ - set mask bit */
mask = inb(mask_port) | bit;
outb(mask, mask_port);
local_irq_restore(flags);
return;
}
DPRINTK("disable_bigsur_l2irq: Invalid IRQ %d\n", irq);
}
static void enable_bigsur_l2irq(unsigned int irq)
{
unsigned long flags;
unsigned char mask;
unsigned char bit = 1 << ((irq-BIGSUR_2NDLVL_IRQ_LOW)%8);
unsigned int mask_port = imr_base - REG_NUM(irq)*imr_offset;
if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
DPRINTK("Enable L2 IRQ %d\n", irq);
DIPRINTK(2,"enable_bigsur_l2irq: IMR=0x%08x mask=0x%x\n",
mask_port, bit);
local_irq_save(flags);
/* Enable L2 IRQ - clear mask bit */
mask = inb(mask_port) & ~bit;
outb(mask, mask_port);
local_irq_restore(flags);
return;
}
DPRINTK("enable_bigsur_l2irq: Invalid IRQ %d\n", irq);
}
static void mask_and_ack_bigsur(unsigned int irq)
{
DPRINTK("mask_and_ack_bigsur IRQ %d\n", irq);
if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH)
disable_bigsur_l1irq(irq);
else
disable_bigsur_l2irq(irq);
}
static void end_bigsur_irq(unsigned int irq)
{
DPRINTK("end_bigsur_irq IRQ %d\n", irq);
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH)
enable_bigsur_l1irq(irq);
else
enable_bigsur_l2irq(irq);
}
}
static unsigned int startup_bigsur_irq(unsigned int irq)
{
u8 mask;
u32 reg;
DPRINTK("startup_bigsur_irq IRQ %d\n", irq);
if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
/* Enable the L1 IRQ */
enable_bigsur_l1irq(irq);
/* Enable all L2 IRQs in this L1 IRQ */
mask = ~(bigsur_l2irq_mask[irq-BIGSUR_IRQ_LOW]);
reg = imr_base - bigsur_l2irq_reg[irq-BIGSUR_IRQ_LOW] * imr_offset;
mask &= inb(reg);
outb(mask,reg);
DIPRINTK(2,"startup_bigsur_irq: IMR=0x%08x mask=0x%x\n",reg,inb(reg));
}
else {
/* Enable the L2 IRQ - clear mask bit */
enable_bigsur_l2irq(irq);
/* Enable the L1 bit masking this L2 IRQ */
enable_bigsur_l1irq(bigsur_l2_l1_map[irq-BIGSUR_2NDLVL_IRQ_LOW]);
DIPRINTK(2,"startup_bigsur_irq: L1=%d L2=%d\n",
bigsur_l2_l1_map[irq-BIGSUR_2NDLVL_IRQ_LOW],irq);
}
return 0;
}
static void shutdown_bigsur_irq(unsigned int irq)
{
DPRINTK("shutdown_bigsur_irq IRQ %d\n", irq);
if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH)
disable_bigsur_l1irq(irq);
else
disable_bigsur_l2irq(irq);
}
/* Define the IRQ structures for the L1 and L2 IRQ types */
static struct hw_interrupt_type bigsur_l1irq_type = {
"BigSur-CPLD-Level1-IRQ",
startup_bigsur_irq,
shutdown_bigsur_irq,
enable_bigsur_l1irq,
disable_bigsur_l1irq,
mask_and_ack_bigsur,
end_bigsur_irq
};
static struct hw_interrupt_type bigsur_l2irq_type = {
"BigSur-CPLD-Level2-IRQ",
startup_bigsur_irq,
shutdown_bigsur_irq,
enable_bigsur_l2irq,
disable_bigsur_l2irq,
mask_and_ack_bigsur,
end_bigsur_irq
};
static void make_bigsur_l1isr(unsigned int irq) {
/* sanity check first */
if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
/* save the handler in the main description table */
irq_desc[irq].handler = &bigsur_l1irq_type;
irq_desc[irq].status = IRQ_DISABLED;
irq_desc[irq].action = 0;
irq_desc[irq].depth = 1;
disable_bigsur_l1irq(irq);
return;
}
DPRINTK("make_bigsur_l1isr: bad irq, %d\n", irq);
return;
}
static void make_bigsur_l2isr(unsigned int irq) {
/* sanity check first */
if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
/* save the handler in the main description table */
irq_desc[irq].handler = &bigsur_l2irq_type;
irq_desc[irq].status = IRQ_DISABLED;
irq_desc[irq].action = 0;
irq_desc[irq].depth = 1;
disable_bigsur_l2irq(irq);
return;
}
DPRINTK("make_bigsur_l2isr: bad irq, %d\n", irq);
return;
}
/* The IRQ's will be decoded as follows:
* If a level 2 handler exists and there is an unmasked active
* IRQ, the 2nd level handler will be called.
* If a level 2 handler does not exist for the active IRQ
* the 1st level handler will be called.
*/
int bigsur_irq_demux(int irq)
{
int dmux_irq = irq;
u8 mask, actv_irqs;
u32 reg_num;
DIPRINTK(3,"bigsur_irq_demux, irq=%d\n", irq);
/* decode the 1st level IRQ */
if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
/* Get corresponding L2 ISR bitmask and ISR number */
mask = bigsur_l2irq_mask[irq-BIGSUR_IRQ_LOW];
reg_num = bigsur_l2irq_reg[irq-BIGSUR_IRQ_LOW];
/* find the active IRQ's (XOR with inactive level)*/
actv_irqs = inb(isr_base-reg_num*isr_offset) ^
bigsur_l2_inactv_state[reg_num];
/* decode active IRQ's */
actv_irqs = actv_irqs & mask & ~(inb(imr_base-reg_num*imr_offset));
/* if NEZ then we have an active L2 IRQ */
if(actv_irqs) dmux_irq = ffz(~actv_irqs) + reg_num*8+BIGSUR_2NDLVL_IRQ_LOW;
/* if no 2nd level IRQ action, but has 1st level, use 1st level handler */
if(!irq_desc[dmux_irq].action && irq_desc[irq].action)
dmux_irq = irq;
DIPRINTK(1,"bigsur_irq_demux: irq=%d dmux_irq=%d mask=0x%04x reg=%d\n",
irq, dmux_irq, mask, reg_num);
}
#ifdef CONFIG_HD64465
dmux_irq = hd64465_irq_demux(dmux_irq);
#endif /* CONFIG_HD64465 */
DIPRINTK(3,"bigsur_irq_demux, demux_irq=%d\n", dmux_irq);
return dmux_irq;
}
/*===========================================================*/
// Big Sur Init Routines
/*===========================================================*/
void __init init_bigsur_IRQ(void)
{
int i;
if (!MACH_BIGSUR) return;
/* Create ISR's for Big Sur CPLD IRQ's */
/*==============================================================*/
for(i=BIGSUR_IRQ_LOW;i<BIGSUR_IRQ_HIGH;i++)
make_bigsur_l1isr(i);
printk(KERN_INFO "Big Sur CPLD L1 interrupts %d to %d.\n",
BIGSUR_IRQ_LOW,BIGSUR_IRQ_HIGH);
for(i=BIGSUR_2NDLVL_IRQ_LOW;i<BIGSUR_2NDLVL_IRQ_HIGH;i++)
make_bigsur_l2isr(i);
printk(KERN_INFO "Big Sur CPLD L2 interrupts %d to %d.\n",
BIGSUR_2NDLVL_IRQ_LOW,BIGSUR_2NDLVL_IRQ_HIGH);
}
......@@ -13,7 +13,7 @@
#include <linux/config.h>
#include <asm/io.h>
#include <asm/bigsur.h>
#include <asm/bigsur/bigsur.h>
static void mach_led(int position, int value)
{
......
......@@ -18,60 +18,55 @@
#include <asm/rtc.h>
#include <asm/machvec_init.h>
#include <asm/io.h>
#include <asm/io_bigsur.h>
#include <asm/bigsur/io.h>
#include <asm/irq.h>
/*
* The Machine Vector
*/
extern void heartbeat_bigsur(void);
extern void setup_bigsur(void);
extern void init_bigsur_IRQ(void);
struct sh_machine_vector mv_bigsur __initmv = {
.mv_name = "Big Sur",
.mv_nr_irqs = NR_IRQS, // Defined in <asm/irq.h>
.mv_inb = bigsur_inb,
.mv_inw = bigsur_inw,
.mv_inl = bigsur_inl,
.mv_outb = bigsur_outb,
.mv_outw = bigsur_outw,
.mv_outl = bigsur_outl,
mv_nr_irqs: NR_IRQS, // Defined in <asm/irq.h>
mv_inb: bigsur_inb,
mv_inw: bigsur_inw,
mv_inl: bigsur_inl,
mv_outb: bigsur_outb,
mv_outw: bigsur_outw,
mv_outl: bigsur_outl,
.mv_inb_p = bigsur_inb_p,
.mv_inw_p = bigsur_inw,
.mv_inl_p = bigsur_inl,
.mv_outb_p = bigsur_outb_p,
.mv_outw_p = bigsur_outw,
.mv_outl_p = bigsur_outl,
mv_inb_p: bigsur_inb_p,
mv_inw_p: bigsur_inw,
mv_inl_p: bigsur_inl,
mv_outb_p: bigsur_outb_p,
mv_outw_p: bigsur_outw,
mv_outl_p: bigsur_outl,
.mv_insb = bigsur_insb,
.mv_insw = bigsur_insw,
.mv_insl = bigsur_insl,
.mv_outsb = bigsur_outsb,
.mv_outsw = bigsur_outsw,
.mv_outsl = bigsur_outsl,
mv_insb: bigsur_insb,
mv_insw: bigsur_insw,
mv_insl: bigsur_insl,
mv_outsb: bigsur_outsb,
mv_outsw: bigsur_outsw,
mv_outsl: bigsur_outsl,
.mv_readb = generic_readb,
.mv_readw = generic_readw,
.mv_readl = generic_readl,
.mv_writeb = generic_writeb,
.mv_writew = generic_writew,
.mv_writel = generic_writel,
mv_readb: generic_readb,
mv_readw: generic_readw,
mv_readl: generic_readl,
mv_writeb: generic_writeb,
mv_writew: generic_writew,
mv_writel: generic_writel,
.mv_ioremap = generic_ioremap,
.mv_iounmap = generic_iounmap,
mv_ioremap: generic_ioremap,
mv_iounmap: generic_iounmap,
.mv_isa_port2addr = bigsur_isa_port2addr,
.mv_irq_demux = bigsur_irq_demux,
mv_isa_port2addr: bigsur_isa_port2addr,
mv_irq_demux: bigsur_irq_demux,
.mv_init_arch = setup_bigsur,
.mv_init_irq = init_bigsur_IRQ,
mv_init_irq: init_bigsur_IRQ,
#ifdef CONFIG_HEARTBEAT
.mv_heartbeat = heartbeat_bigsur,
mv_heartbeat: heartbeat_bigsur,
#endif
.mv_rtc_gettimeofday = sh_rtc_gettimeofday,
.mv_rtc_settimeofday = sh_rtc_settimeofday,
};
ALIAS_MV(bigsur)
......@@ -18,7 +18,7 @@
#include <asm/io.h>
#include <asm/pci-sh7751.h>
#include <asm/bigsur.h>
#include <asm/bigsur/bigsur.h>
#define PCI_REG(reg) (SH7751_PCIREG_BASE+reg)
......
/*
*
* By Dustin McIntire (dustin@sensoria.com) (c)2001
*
* Setup and IRQ handling code for the HD64465 companion chip.
* by Greg Banks <gbanks@pocketpenguins.com>
* Copyright (c) 2000 PocketPenguins Inc
*
* Derived from setup_hd64465.c which bore the message:
* Greg Banks <gbanks@pocketpenguins.com>
* Copyright (c) 2000 PocketPenguins Inc and
* Copyright (C) 2000 YAEGASHI Takeshi
* and setup_cqreek.c which bore message:
* Copyright (C) 2000 Niibe Yutaka
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* Setup functions for a Hitachi Big Sur Evaluation Board.
*
*/
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/param.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/bitops.h>
#include <asm/bigsur/io.h>
#include <asm/hd64465/hd64465.h>
#include <asm/bigsur/bigsur.h>
//#define BIGSUR_DEBUG 3
#undef BIGSUR_DEBUG
#ifdef BIGSUR_DEBUG
#define DPRINTK(args...) printk(args)
#define DIPRINTK(n, args...) if (BIGSUR_DEBUG>(n)) printk(args)
#else
#define DPRINTK(args...)
#define DIPRINTK(n, args...)
#endif /* BIGSUR_DEBUG */
/*===========================================================*/
// Big Sur Init Routines
/*===========================================================*/
const char *get_system_type(void)
{
return "Big Sur";
}
int __init platform_setup(void)
{
static int done = 0; /* run this only once */
if (!MACH_BIGSUR || done) return 0;
done = 1;
/* Mask all 2nd level IRQ's */
outb(-1,BIGSUR_IMR0);
outb(-1,BIGSUR_IMR1);
outb(-1,BIGSUR_IMR2);
outb(-1,BIGSUR_IMR3);
/* Mask 1st level interrupts */
outb(-1,BIGSUR_IRLMR0);
outb(-1,BIGSUR_IRLMR1);
#if defined (CONFIG_HD64465) && defined (CONFIG_SERIAL)
/* remap IO ports for first ISA serial port to HD64465 UART */
bigsur_port_map(0x3f8, 8, CONFIG_HD64465_IOBASE + 0x8000, 1);
#endif /* CONFIG_HD64465 && CONFIG_SERIAL */
/* TODO: setup IDE registers */
bigsur_port_map(BIGSUR_IDECTL_IOPORT, 2, BIGSUR_ICTL, 8);
/* Setup the Ethernet port to BIGSUR_ETHER_IOPORT */
bigsur_port_map(BIGSUR_ETHER_IOPORT, 16, BIGSUR_ETHR+BIGSUR_ETHER_IOPORT, 0);
/* set page to 1 */
outw(1, BIGSUR_ETHR+0xe);
/* set the IO port to BIGSUR_ETHER_IOPORT */
outw(BIGSUR_ETHER_IOPORT<<3, BIGSUR_ETHR+0x2);
return 0;
}
module_init(setup_bigsur);
#
# Makefile for the CAT-68701 specific parts of the kernel
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
obj-y := mach.o setup.o io.o irq.o
/*
* linux/arch/sh/kernel/io_cat68701.c
* linux/arch/sh/boards/cat68701/io.c
*
* Copyright (C) 2000 Niibe Yutaka
* 2001 Yutaro Ebihara
*
* I/O routine and setup routines for A-ONE Corp CAT-68701 SH7708 Board
* I/O routines for A-ONE Corp CAT-68701 SH7708 Board
*
* 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
......@@ -205,45 +205,3 @@ unsigned long cat68701_isa_port2addr(unsigned long offset)
return offset + 0xb4000000; /* other I/O (EREA 5)*/
}
int cat68701_irq_demux(int irq)
{
if(irq==13) return 14;
if(irq==7) return 10;
return irq;
}
/*-------------------------------------------------------*/
void setup_cat68701(){
/* dummy read erea5 (CS8900A) */
}
void init_cat68701_IRQ(){
make_imask_irq(10);
make_imask_irq(14);
}
#ifdef CONFIG_HEARTBEAT
#include <linux/sched.h>
void heartbeat_cat68701()
{
static unsigned int cnt = 0, period = 0 , bit = 0;
cnt += 1;
if (cnt < period) {
return;
}
cnt = 0;
/* Go through the points (roughly!):
* f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110
*/
period = 110 - ( (300<<FSHIFT)/
((avenrun[0]/5) + (3<<FSHIFT)) );
if(bit){ bit=0; }else{ bit=1; }
outw(bit<<15,0x3fe);
}
#endif /* CONFIG_HEARTBEAT */
/*
* linux/arch/sh/boards/cat68701/irq.c
*
* Copyright (C) 2000 Niibe Yutaka
* 2001 Yutaro Ebihara
*
* Setup routines for A-ONE Corp CAT-68701 SH7708 Board
*
* 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 <asm/irq.h>
int cat68701_irq_demux(int irq)
{
if(irq==13) return 14;
if(irq==7) return 10;
return irq;
}
void init_cat68701_IRQ()
{
make_imask_irq(10);
make_imask_irq(14);
}
/*
* linux/arch/sh/kernel/mach_cat68701.c
* linux/arch/sh/boards/cat68701/mach.c
*
* Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
* 2001 Yutaro Ebihara (ebihara@si-linux.com)
......@@ -16,57 +16,51 @@
#include <asm/machvec.h>
#include <asm/rtc.h>
#include <asm/machvec_init.h>
#include <asm/io_cat68701.h>
#include <asm/cat68701/io.h>
/*
* The Machine Vector
*/
struct sh_machine_vector mv_cat68701 __initmv = {
.mv_name = "CAT-68701",
.mv_nr_irqs = 32,
.mv_inb = cat68701_inb,
.mv_inw = cat68701_inw,
.mv_inl = cat68701_inl,
.mv_outb = cat68701_outb,
.mv_outw = cat68701_outw,
.mv_outl = cat68701_outl,
mv_nr_irqs: 32,
mv_inb: cat68701_inb,
mv_inw: cat68701_inw,
mv_inl: cat68701_inl,
mv_outb: cat68701_outb,
mv_outw: cat68701_outw,
mv_outl: cat68701_outl,
.mv_inb_p = cat68701_inb_p,
.mv_inw_p = cat68701_inw,
.mv_inl_p = cat68701_inl,
.mv_outb_p = cat68701_outb_p,
.mv_outw_p = cat68701_outw,
.mv_outl_p = cat68701_outl,
mv_inb_p: cat68701_inb_p,
mv_inw_p: cat68701_inw,
mv_inl_p: cat68701_inl,
mv_outb_p: cat68701_outb_p,
mv_outw_p: cat68701_outw,
mv_outl_p: cat68701_outl,
.mv_insb = cat68701_insb,
.mv_insw = cat68701_insw,
.mv_insl = cat68701_insl,
.mv_outsb = cat68701_outsb,
.mv_outsw = cat68701_outsw,
.mv_outsl = cat68701_outsl,
mv_insb: cat68701_insb,
mv_insw: cat68701_insw,
mv_insl: cat68701_insl,
mv_outsb: cat68701_outsb,
mv_outsw: cat68701_outsw,
mv_outsl: cat68701_outsl,
.mv_readb = cat68701_readb,
.mv_readw = cat68701_readw,
.mv_readl = cat68701_readl,
.mv_writeb = cat68701_writeb,
.mv_writew = cat68701_writew,
.mv_writel = cat68701_writel,
mv_readb: cat68701_readb,
mv_readw: cat68701_readw,
mv_readl: cat68701_readl,
mv_writeb: cat68701_writeb,
mv_writew: cat68701_writew,
mv_writel: cat68701_writel,
.mv_ioremap = cat68701_ioremap,
.mv_iounmap = cat68701_iounmap,
mv_ioremap: cat68701_ioremap,
mv_iounmap: cat68701_iounmap,
.mv_isa_port2addr = cat68701_isa_port2addr,
.mv_irq_demux = cat68701_irq_demux,
mv_isa_port2addr: cat68701_isa_port2addr,
mv_irq_demux: cat68701_irq_demux,
.mv_init_arch = setup_cat68701,
.mv_init_irq = init_cat68701_IRQ,
mv_init_irq: init_cat68701_IRQ,
#ifdef CONFIG_HEARTBEAT
.mv_heartbeat = heartbeat_cat68701,
mv_heartbeat: heartbeat_cat68701,
#endif
.mv_rtc_gettimeofday = sh_rtc_gettimeofday,
.mv_rtc_settimeofday = sh_rtc_settimeofday,
};
ALIAS_MV(cat68701)
/*
* linux/arch/sh/boards/cat68701/setup.c
*
* Copyright (C) 2000 Niibe Yutaka
* 2001 Yutaro Ebihara
*
* Setup routines for A-ONE Corp CAT-68701 SH7708 Board
*
* 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 <asm/io.h>
#include <asm/machvec.h>
#include <linux/config.h>
#include <linux/module.h>
const char *get_system_type(void)
{
return "CAT-68701";
}
void platform_setup()
{
/* dummy read erea5 (CS8900A) */
}
#ifdef CONFIG_HEARTBEAT
#include <linux/sched.h>
void heartbeat_cat68701()
{
static unsigned int cnt = 0, period = 0 , bit = 0;
cnt += 1;
if (cnt < period) {
return;
}
cnt = 0;
/* Go through the points (roughly!):
* f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110
*/
period = 110 - ( (300<<FSHIFT)/
((avenrun[0]/5) + (3<<FSHIFT)) );
if(bit){ bit=0; }else{ bit=1; }
outw(bit<<15,0x3fe);
}
#endif /* CONFIG_HEARTBEAT */
#
# Makefile for the CqREEK specific parts of the kernel
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
obj-y := mach.o setup.o io.o irq.o
#define IDE_OFFSET 0xA4000000UL
#define ISA_OFFSET 0xA4A00000UL
unsigned long cqreek_port2addr(unsigned long port)
{
if (0x0000<=port && port<=0x0040)
return IDE_OFFSET + port;
if ((0x01f0<=port && port<=0x01f7) || port == 0x03f6)
return IDE_OFFSET + port;
return ISA_OFFSET + port;
}
/* $Id: setup_cqreek.c,v 1.9 2001/07/30 12:43:28 gniibe Exp $
/* $Id: irq.c,v 1.1.2.4 2002/11/04 20:33:56 lethal Exp $
*
* arch/sh/kernel/setup_cqreek.c
* arch/sh/boards/cqreek/irq.c
*
* Copyright (C) 2000 Niibe Yutaka
*
......@@ -8,11 +8,10 @@
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/init.h>
#include <asm/cqreek/cqreek.h>
#include <asm/io.h>
#include <asm/io_generic.h>
#include <asm/irq.h>
......@@ -20,31 +19,6 @@
#include <asm/machvec_init.h>
#include <asm/rtc.h>
#define BRIDGE_FEATURE 0x0002
#define BRIDGE_IDE_CTRL 0x0018
#define BRIDGE_IDE_INTR_LVL 0x001A
#define BRIDGE_IDE_INTR_MASK 0x001C
#define BRIDGE_IDE_INTR_STAT 0x001E
#define BRIDGE_ISA_CTRL 0x0028
#define BRIDGE_ISA_INTR_LVL 0x002A
#define BRIDGE_ISA_INTR_MASK 0x002C
#define BRIDGE_ISA_INTR_STAT 0x002E
#define IDE_OFFSET 0xA4000000UL
#define ISA_OFFSET 0xA4A00000UL
static unsigned long cqreek_port2addr(unsigned long port)
{
if (0x0000<=port && port<=0x0040)
return IDE_OFFSET + port;
if ((0x01f0<=port && port<=0x01f7) || port == 0x03f6)
return IDE_OFFSET + port;
return ISA_OFFSET + port;
}
struct cqreek_irq_data {
unsigned short mask_port; /* Port of Interrupt Mask Register */
unsigned short stat_port; /* Port of Interrupt Status Register */
......@@ -59,11 +33,11 @@ static void disable_cqreek_irq(unsigned int irq)
unsigned short mask_port = cqreek_irq_data[irq].mask_port;
unsigned short bit = cqreek_irq_data[irq].bit;
save_and_cli(flags);
local_irq_save(flags);
/* Disable IRQ */
mask = inw(mask_port) & ~bit;
outw_p(mask, mask_port);
restore_flags(flags);
local_irq_restore(flags);
}
static void enable_cqreek_irq(unsigned int irq)
......@@ -73,11 +47,11 @@ static void enable_cqreek_irq(unsigned int irq)
unsigned short mask_port = cqreek_irq_data[irq].mask_port;
unsigned short bit = cqreek_irq_data[irq].bit;
save_and_cli(flags);
local_irq_save(flags);
/* Enable IRQ */
mask = inw(mask_port) | bit;
outw_p(mask, mask_port);
restore_flags(flags);
local_irq_restore(flags);
}
static void mask_and_ack_cqreek(unsigned int irq)
......@@ -118,13 +92,13 @@ static struct hw_interrupt_type cqreek_irq_type = {
end_cqreek_irq
};
static int has_ide, has_isa;
int cqreek_has_ide, cqreek_has_isa;
/* XXX: This is just for test for my NE2000 ISA board
What we really need is virtualized IRQ and demultiplexer like HP600 port */
void __init init_cqreek_IRQ(void)
{
if (has_ide) {
if (cqreek_has_ide) {
cqreek_irq_data[14].mask_port = BRIDGE_IDE_INTR_MASK;
cqreek_irq_data[14].stat_port = BRIDGE_IDE_INTR_STAT;
cqreek_irq_data[14].bit = 1;
......@@ -137,7 +111,7 @@ void __init init_cqreek_IRQ(void)
disable_cqreek_irq(14);
}
if (has_isa) {
if (cqreek_has_isa) {
cqreek_irq_data[10].mask_port = BRIDGE_ISA_INTR_MASK;
cqreek_irq_data[10].stat_port = BRIDGE_ISA_INTR_STAT;
cqreek_irq_data[10].bit = (1 << 10);
......@@ -152,101 +126,3 @@ void __init init_cqreek_IRQ(void)
}
}
/*
* Initialize the board
*/
void __init setup_cqreek(void)
{
int i;
/* udelay is not available at setup time yet... */
#define DELAY() do {for (i=0; i<10000; i++) ctrl_inw(0xa0000000);} while(0)
if ((inw (BRIDGE_FEATURE) & 1)) { /* We have IDE interface */
outw_p(0, BRIDGE_IDE_INTR_LVL);
outw_p(0, BRIDGE_IDE_INTR_MASK);
outw_p(0, BRIDGE_IDE_CTRL);
DELAY();
outw_p(0x8000, BRIDGE_IDE_CTRL);
DELAY();
outw_p(0xffff, BRIDGE_IDE_INTR_STAT); /* Clear interrupt status */
outw_p(0x0f-14, BRIDGE_IDE_INTR_LVL); /* Use 14 IPR */
outw_p(1, BRIDGE_IDE_INTR_MASK); /* Enable interrupt */
has_ide=1;
}
if ((inw (BRIDGE_FEATURE) & 2)) { /* We have ISA interface */
outw_p(0, BRIDGE_ISA_INTR_LVL);
outw_p(0, BRIDGE_ISA_INTR_MASK);
outw_p(0, BRIDGE_ISA_CTRL);
DELAY();
outw_p(0x8000, BRIDGE_ISA_CTRL);
DELAY();
outw_p(0xffff, BRIDGE_ISA_INTR_STAT); /* Clear interrupt status */
outw_p(0x0f-10, BRIDGE_ISA_INTR_LVL); /* Use 10 IPR */
outw_p(0xfff8, BRIDGE_ISA_INTR_MASK); /* Enable interrupt */
has_isa=1;
}
printk(KERN_INFO "CqREEK Setup (IDE=%d, ISA=%d)...done\n", has_ide, has_isa);
}
/*
* The Machine Vector
*/
struct sh_machine_vector mv_cqreek __initmv = {
.mv_name = "CqREEK",
#if defined(__SH4__)
.mv_nr_irqs = 48,
#elif defined(CONFIG_CPU_SUBTYPE_SH7708)
.mv_nr_irqs = 32,
#elif defined(CONFIG_CPU_SUBTYPE_SH7709)
.mv_nr_irqs = 61,
#endif
.mv_inb = generic_inb,
.mv_inw = generic_inw,
.mv_inl = generic_inl,
.mv_outb = generic_outb,
.mv_outw = generic_outw,
.mv_outl = generic_outl,
.mv_inb_p = generic_inb_p,
.mv_inw_p = generic_inw_p,
.mv_inl_p = generic_inl_p,
.mv_outb_p = generic_outb_p,
.mv_outw_p = generic_outw_p,
.mv_outl_p = generic_outl_p,
.mv_insb = generic_insb,
.mv_insw = generic_insw,
.mv_insl = generic_insl,
.mv_outsb = generic_outsb,
.mv_outsw = generic_outsw,
.mv_outsl = generic_outsl,
.mv_readb = generic_readb,
.mv_readw = generic_readw,
.mv_readl = generic_readl,
.mv_writeb = generic_writeb,
.mv_writew = generic_writew,
.mv_writel = generic_writel,
.mv_init_arch = setup_cqreek,
.mv_init_irq = init_cqreek_IRQ,
.mv_isa_port2addr = cqreek_port2addr,
.mv_ioremap = generic_ioremap,
.mv_iounmap = generic_iounmap,
.mv_rtc_gettimeofday = sh_rtc_gettimeofday,
.mv_rtc_settimeofday = sh_rtc_settimeofday,
};
ALIAS_MV(cqreek)
/* $Id: mach.c,v 1.1.2.4.2.1 2003/01/10 17:26:32 lethal Exp $
*
* arch/sh/kernel/setup_cqreek.c
*
* Copyright (C) 2000 Niibe Yutaka
*
* CqREEK IDE/ISA Bridge Support.
*
*/
#include <asm/rtc.h>
#include <asm/io.h>
#include <asm/io_generic.h>
#include <asm/machvec.h>
#include <asm/machvec_init.h>
#include <asm/cqreek/cqreek.h>
/*
* The Machine Vector
*/
struct sh_machine_vector mv_cqreek __initmv = {
#if defined(CONFIG_CPU_SH4)
mv_nr_irqs: 48,
#elif defined(CONFIG_CPU_SUBTYPE_SH7708)
mv_nr_irqs: 32,
#elif defined(CONFIG_CPU_SUBTYPE_SH7709)
mv_nr_irqs: 61,
#endif
mv_inb: generic_inb,
mv_inw: generic_inw,
mv_inl: generic_inl,
mv_outb: generic_outb,
mv_outw: generic_outw,
mv_outl: generic_outl,
mv_inb_p: generic_inb_p,
mv_inw_p: generic_inw_p,
mv_inl_p: generic_inl_p,
mv_outb_p: generic_outb_p,
mv_outw_p: generic_outw_p,
mv_outl_p: generic_outl_p,
mv_insb: generic_insb,
mv_insw: generic_insw,
mv_insl: generic_insl,
mv_outsb: generic_outsb,
mv_outsw: generic_outsw,
mv_outsl: generic_outsl,
mv_readb: generic_readb,
mv_readw: generic_readw,
mv_readl: generic_readl,
mv_writeb: generic_writeb,
mv_writew: generic_writew,
mv_writel: generic_writel,
mv_init_irq: init_cqreek_IRQ,
mv_isa_port2addr: cqreek_port2addr,
mv_ioremap: generic_ioremap,
mv_iounmap: generic_iounmap,
};
ALIAS_MV(cqreek)
/* $Id: setup.c,v 1.1.2.5 2002/03/02 21:57:07 lethal Exp $
*
* arch/sh/kernel/setup_cqreek.c
*
* Copyright (C) 2000 Niibe Yutaka
*
* CqREEK IDE/ISA Bridge Support.
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <asm/cqreek/cqreek.h>
#include <asm/io.h>
#include <asm/io_generic.h>
#include <asm/irq.h>
#include <asm/rtc.h>
const char *get_system_type(void)
{
return "CqREEK";
}
/*
* Initialize the board
*/
void __init platform_setup(void)
{
int i;
/* udelay is not available at setup time yet... */
#define DELAY() do {for (i=0; i<10000; i++) ctrl_inw(0xa0000000);} while(0)
if ((inw (BRIDGE_FEATURE) & 1)) { /* We have IDE interface */
outw_p(0, BRIDGE_IDE_INTR_LVL);
outw_p(0, BRIDGE_IDE_INTR_MASK);
outw_p(0, BRIDGE_IDE_CTRL);
DELAY();
outw_p(0x8000, BRIDGE_IDE_CTRL);
DELAY();
outw_p(0xffff, BRIDGE_IDE_INTR_STAT); /* Clear interrupt status */
outw_p(0x0f-14, BRIDGE_IDE_INTR_LVL); /* Use 14 IPR */
outw_p(1, BRIDGE_IDE_INTR_MASK); /* Enable interrupt */
cqreek_has_ide=1;
}
if ((inw (BRIDGE_FEATURE) & 2)) { /* We have ISA interface */
outw_p(0, BRIDGE_ISA_INTR_LVL);
outw_p(0, BRIDGE_ISA_INTR_MASK);
outw_p(0, BRIDGE_ISA_CTRL);
DELAY();
outw_p(0x8000, BRIDGE_ISA_CTRL);
DELAY();
outw_p(0xffff, BRIDGE_ISA_INTR_STAT); /* Clear interrupt status */
outw_p(0x0f-10, BRIDGE_ISA_INTR_LVL); /* Use 10 IPR */
outw_p(0xfff8, BRIDGE_ISA_INTR_MASK); /* Enable interrupt */
cqreek_has_isa=1;
}
printk(KERN_INFO "CqREEK Setup (IDE=%d, ISA=%d)...done\n", cqreek_has_ide, cqreek_has_isa);
}
#
# Makefile for the DataMyte Industrial Digital Assistant(tm) specific parts
# of the kernel
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
obj-y := mach.o
......@@ -22,7 +22,7 @@
#include <asm/machvec_init.h>
#include <asm/io.h>
#include <asm/hd64465.h>
#include <asm/hd64465/hd64465.h>
#include <asm/irq.h>
/*
......@@ -30,44 +30,44 @@
*/
struct sh_machine_vector mv_dmida __initmv = {
.mv_name = "DMIDA",
mv_name: "DMIDA",
.mv_nr_irqs = HD64465_IRQ_BASE+HD64465_IRQ_NUM,
mv_nr_irqs: HD64465_IRQ_BASE+HD64465_IRQ_NUM,
.mv_inb = hd64465_inb,
.mv_inw = hd64465_inw,
.mv_inl = hd64465_inl,
.mv_outb = hd64465_outb,
.mv_outw = hd64465_outw,
.mv_outl = hd64465_outl,
mv_inb: hd64465_inb,
mv_inw: hd64465_inw,
mv_inl: hd64465_inl,
mv_outb: hd64465_outb,
mv_outw: hd64465_outw,
mv_outl: hd64465_outl,
.mv_inb_p = hd64465_inb_p,
.mv_inw_p = hd64465_inw,
.mv_inl_p = hd64465_inl,
.mv_outb_p = hd64465_outb_p,
.mv_outw_p = hd64465_outw,
.mv_outl_p = hd64465_outl,
mv_inb_p: hd64465_inb_p,
mv_inw_p: hd64465_inw,
mv_inl_p: hd64465_inl,
mv_outb_p: hd64465_outb_p,
mv_outw_p: hd64465_outw,
mv_outl_p: hd64465_outl,
.mv_insb = hd64465_insb,
.mv_insw = hd64465_insw,
.mv_insl = hd64465_insl,
.mv_outsb = hd64465_outsb,
.mv_outsw = hd64465_outsw,
.mv_outsl = hd64465_outsl,
mv_insb: hd64465_insb,
mv_insw: hd64465_insw,
mv_insl: hd64465_insl,
mv_outsb: hd64465_outsb,
mv_outsw: hd64465_outsw,
mv_outsl: hd64465_outsl,
.mv_readb = generic_readb,
.mv_readw = generic_readw,
.mv_readl = generic_readl,
.mv_writeb = generic_writeb,
.mv_writew = generic_writew,
.mv_writel = generic_writel,
mv_readb: generic_readb,
mv_readw: generic_readw,
mv_readl: generic_readl,
mv_writeb: generic_writeb,
mv_writew: generic_writew,
mv_writel: generic_writel,
.mv_irq_demux = hd64465_irq_demux,
mv_irq_demux: hd64465_irq_demux,
.mv_rtc_gettimeofday = sh_rtc_gettimeofday,
.mv_rtc_settimeofday = sh_rtc_settimeofday,
mv_rtc_gettimeofday: sh_rtc_gettimeofday,
mv_rtc_settimeofday: sh_rtc_settimeofday,
.mv_hw_hd64465 = 1,
mv_hw_hd64465: 1,
};
ALIAS_MV(dmida)
#
# Makefile for the Sega Dreamcast specific parts of the kernel
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
obj-y := mach.o setup.o io.o irq.o rtc.o
obj-$(CONFIG_PCI) += pci.o
/*
* $Id: io_dc.c,v 1.2 2001/05/24 00:13:47 gniibe Exp $
* $Id: io.c,v 1.1.2.1 2002/01/19 23:54:19 mrbrown Exp $
* I/O routines for SEGA Dreamcast
*/
......
/* arch/sh/kernel/setup_dc.c
/*
* arch/sh/boards/dreamcast/irq.c
*
* Hardware support for the Sega Dreamcast.
* Holly IRQ support for the Sega Dreamcast.
*
* Copyright (c) 2001 M. R. Brown <mrbrown@linuxdc.org>
* Copyright (c) 2001, 2002 M. R. Brown <mrbrown@0xd6.org>
*
* This file is part of the LinuxDC project (www.linuxdc.org)
*
* Released under the terms of the GNU GPL v2.0.
*
* This file originally bore the message (with enclosed-$):
* Id: setup_dc.c,v 1.5 2001/05/24 05:09:16 mrbrown Exp
* SEGA Dreamcast support
* Released under the terms of the GNU GPL v2.0
*/
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/param.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/dc_sysasic.h>
int __init gapspci_init(void);
#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
#include <asm/dreamcast/sysasic.h>
/* Dreamcast System ASIC Hardware Events -
The Dreamcast's System ASIC (located on the PowerVR2 chip) is responsible
for receiving hardware events from system peripherals and triggering an
SH7750 IRQ. Hardware events can trigger IRQs 13, 11, or 9 depending on
which bits are set in the Event Mask Registers (EMRs). When a hardware
event is triggered, it's corresponding bit in the Event Status Registers
(ESRs) is set, and that bit should be rewritten to the ESR to acknowledge
that event.
The Dreamcast's System ASIC (a.k.a. Holly) is responsible for receiving
hardware events from system peripherals and triggering an SH7750 IRQ.
Hardware events can trigger IRQs 13, 11, or 9 depending on which bits are
set in the Event Mask Registers (EMRs). When a hardware event is
triggered, it's corresponding bit in the Event Status Registers (ESRs)
is set, and that bit should be rewritten to the ESR to acknowledge that
event.
There are three 32-bit ESRs located at 0xa05f8900 - 0xa05f6908. Event
types can be found in include/asm-sh/dc_sysasic.h. There are three groups
......@@ -70,66 +57,66 @@ int __init gapspci_init(void);
/* Disable the hardware event by masking its bit in its EMR */
static inline void disable_systemasic_irq(unsigned int irq)
{
unsigned long flags;
__u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
__u32 mask;
save_and_cli(flags);
mask = inl(emr);
mask &= ~(1 << EVENT_BIT(irq));
outl(mask, emr);
restore_flags(flags);
unsigned long flags;
__u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
__u32 mask;
local_irq_save(flags);
mask = inl(emr);
mask &= ~(1 << EVENT_BIT(irq));
outl(mask, emr);
local_irq_restore(flags);
}
/* Enable the hardware event by setting its bit in its EMR */
static inline void enable_systemasic_irq(unsigned int irq)
{
unsigned long flags;
__u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
__u32 mask;
save_and_cli(flags);
mask = inl(emr);
mask |= (1 << EVENT_BIT(irq));
outl(mask, emr);
restore_flags(flags);
unsigned long flags;
__u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
__u32 mask;
local_irq_save(flags);
mask = inl(emr);
mask |= (1 << EVENT_BIT(irq));
outl(mask, emr);
local_irq_restore(flags);
}
/* Acknowledge a hardware event by writing its bit back to its ESR */
static void ack_systemasic_irq(unsigned int irq)
{
__u32 esr = ESR_BASE + (LEVEL(irq) << 2);
disable_systemasic_irq(irq);
outl((1 << EVENT_BIT(irq)), esr);
__u32 esr = ESR_BASE + (LEVEL(irq) << 2);
disable_systemasic_irq(irq);
outl((1 << EVENT_BIT(irq)), esr);
}
/* After a IRQ has been ack'd and responded to, it needs to be renabled */
static void end_systemasic_irq(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
enable_systemasic_irq(irq);
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
enable_systemasic_irq(irq);
}
static unsigned int startup_systemasic_irq(unsigned int irq)
{
enable_systemasic_irq(irq);
enable_systemasic_irq(irq);
return 0;
return 0;
}
static void shutdown_systemasic_irq(unsigned int irq)
{
disable_systemasic_irq(irq);
disable_systemasic_irq(irq);
}
static struct hw_interrupt_type systemasic_int = {
.typename = "System ASIC",
.startup = startup_systemasic_irq,
.shutdown = shutdown_systemasic_irq,
.enable = enable_systemasic_irq,
.disable = disable_systemasic_irq,
.ack = ack_systemasic_irq,
.end = end_systemasic_irq,
struct hw_interrupt_type systemasic_int = {
typename: "System ASIC",
startup: startup_systemasic_irq,
shutdown: shutdown_systemasic_irq,
enable: enable_systemasic_irq,
disable: disable_systemasic_irq,
ack: ack_systemasic_irq,
end: end_systemasic_irq,
};
/*
......@@ -137,77 +124,37 @@ static struct hw_interrupt_type systemasic_int = {
*/
int systemasic_irq_demux(int irq)
{
__u32 emr, esr, status, level;
__u32 j, bit;
switch (irq) {
case 13:
level = 0;
break;
case 11:
level = 1;
break;
case 9:
level = 2;
break;
default:
return irq;
}
emr = EMR_BASE + (level << 4) + (level << 2);
esr = ESR_BASE + (level << 2);
/* Mask the ESR to filter any spurious, unwanted interrtupts */
status = inl(esr);
status &= inl(emr);
/* Now scan and find the first set bit as the event to map */
for (bit = 1, j = 0; j < 32; bit <<= 1, j++) {
if (status & bit) {
irq = HW_EVENT_IRQ_BASE + j + (level << 5);
return irq;
}
}
/* Not reached */
return irq;
}
int __init setup_dreamcast(void)
{
int i;
/* Mask all hardware events */
/* XXX */
/* Acknowledge any previous events */
/* XXX */
/* Assign all virtual IRQs to the System ASIC int. handler */
for (i = HW_EVENT_IRQ_BASE; i < HW_EVENT_IRQ_MAX; i++)
irq_desc[i].handler = &systemasic_int;
#ifdef CONFIG_PCI
gapspci_init();
#endif
printk(KERN_INFO "SEGA Dreamcast support.\n");
#if 0
printk(KERN_INFO "BCR1: 0x%08x\n", ctrl_inl(0xff800000));
printk(KERN_INFO "BCR2: 0x%08x\n", ctrl_inw(0xff800004));
printk(KERN_INFO "WCR1: 0x%08x\n", ctrl_inl(0xff800008));
printk(KERN_INFO "WCR2: 0x%08x\n", ctrl_inl(0xff80000c));
printk(KERN_INFO "WCR3: 0x%08x\n", ctrl_inl(0xff800010));
printk(KERN_INFO "MCR: 0x%08x\n", ctrl_inl(0xff800014));
printk(KERN_INFO "PCR: 0x%08x\n", ctrl_inw(0xff800018));
/*
* BCR1: 0xa3020008
* BCR2: 0x0001
* WCR1: 0x01110111
* WCR2: 0x618066d8
* WCR3: 0x07777777
* MCR: 0xc00a0e24
* PCR: 0x0000
*/
#endif
return 0;
__u32 emr, esr, status, level;
__u32 j, bit;
switch (irq) {
case 13:
level = 0;
break;
case 11:
level = 1;
break;
case 9:
level = 2;
break;
default:
return irq;
}
emr = EMR_BASE + (level << 4) + (level << 2);
esr = ESR_BASE + (level << 2);
/* Mask the ESR to filter any spurious, unwanted interrtupts */
status = inl(esr);
status &= inl(emr);
/* Now scan and find the first set bit as the event to map */
for (bit = 1, j = 0; j < 32; bit <<= 1, j++) {
if (status & bit) {
irq = HW_EVENT_IRQ_BASE + j + (level << 5);
return irq;
}
}
/* Not reached */
return irq;
}
/*
* $Id: mach.c,v 1.1.2.5 2002/03/01 11:22:17 lethal Exp $
* SEGA Dreamcast machine vector
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/time.h>
#include <asm/machvec.h>
#include <asm/machvec_init.h>
#include <asm/io_generic.h>
#include <asm/dreamcast/io.h>
#include <asm/irq.h>
void __init dreamcast_pcibios_init(void);
/*
* The Machine Vector
*/
struct sh_machine_vector mv_dreamcast __initmv = {
mv_nr_irqs: NR_IRQS,
mv_inb: generic_inb,
mv_inw: generic_inw,
mv_inl: generic_inl,
mv_outb: generic_outb,
mv_outw: generic_outw,
mv_outl: generic_outl,
mv_inb_p: generic_inb_p,
mv_inw_p: generic_inw,
mv_inl_p: generic_inl,
mv_outb_p: generic_outb_p,
mv_outw_p: generic_outw,
mv_outl_p: generic_outl,
mv_insb: generic_insb,
mv_insw: generic_insw,
mv_insl: generic_insl,
mv_outsb: generic_outsb,
mv_outsw: generic_outsw,
mv_outsl: generic_outsl,
mv_readb: generic_readb,
mv_readw: generic_readw,
mv_readl: generic_readl,
mv_writeb: generic_writeb,
mv_writew: generic_writew,
mv_writel: generic_writel,
mv_ioremap: generic_ioremap,
mv_iounmap: generic_iounmap,
mv_isa_port2addr: dreamcast_isa_port2addr,
mv_irq_demux: systemasic_irq_demux,
mv_hw_dreamcast: 1,
};
ALIAS_MV(dreamcast)
/*
$ $Id: pci-dc.c,v 1.5 2001/08/24 12:38:19 dwmw2 Exp $
$ $Id: pci.c,v 1.1.2.4.2.1 2003/03/31 14:33:18 lethal Exp $
* Dreamcast PCI: Supports SEGA Broadband Adaptor only.
*/
......@@ -14,7 +14,7 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/dc_sysasic.h>
#include <asm/dreamcast/sysasic.h>
#define GAPSPCI_REGS 0x01001400
#define GAPSPCI_DMA_BASE 0x01840000
......@@ -25,7 +25,26 @@
static int gapspci_dma_used;
static struct pci_bus *pci_root_bus;
/* XXX: Uh... */
static struct resource gapspci_io_resource = {
"GAPSPCI IO",
0x01001600,
0x010016ff,
IORESOURCE_IO
};
static struct resource gapspci_mem_resource = {
"GAPSPCI mem",
0x01840000,
0x01847fff,
IORESOURCE_MEM
};
static struct pci_ops gapspci_pci_ops;
struct pci_channel board_pci_channels[] = {
{&gapspci_pci_ops, &gapspci_io_resource, &gapspci_mem_resource, 0, 1},
{NULL, NULL, NULL, 0, 0},
};
struct pci_fixup pcibios_fixups[] = {
{0, 0, 0, NULL}
......@@ -39,23 +58,23 @@ static int gapspci_read(struct pci_bus *bus, unsigned int devfn, int where, int
case 1:
if (BBA_SELECTED(bus, devfn))
*val = (u8)inb(GAPSPCI_BBA_CONFIG+where);
else
else
*val = (u8)0xff;
break;
case 2:
if (BBA_SELECTED(bus, devfn))
*val = (u16)inw(GAPSPCI_BBA_CONFIG+where);
else
else
*val = (u16)0xffff;
break;
case 4:
if (BBA_SELECTED(bus, devfn))
*val = inl(GAPSPCI_BBA_CONFIG+where);
else
*val = 0xffffffff;
*val = inl(GAPSPCI_BBA_CONFIG+where);
else
*val = 0xffffffff;
break;
}
return PCIBIOS_SUCCESSFUL;
return PCIBIOS_SUCCESSFUL;
}
static int gapspci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val)
......@@ -72,14 +91,14 @@ static int gapspci_write(struct pci_bus *bus, unsigned int devfn, int where, int
break;
case 4:
if (BBA_SELECTED(bus, devfn))
outl(val, GAPSPCI_BBA_CONFIG+where);
outl(val, GAPSPCI_BBA_CONFIG+where);
break;
}
}
return PCIBIOS_SUCCESSFUL;
return PCIBIOS_SUCCESSFUL;
}
static struct pci_ops pci_config_ops = {
static struct pci_ops gapspci_pci_ops = {
.read = gapspci_read,
.write = gapspci_write,
};
......@@ -122,7 +141,7 @@ void __init pcibios_fixup_bus(struct pci_bus *bus)
dev = pci_dev_b(ln);
if (!BBA_SELECTED(bus, dev->devfn)) continue;
printk("PCI: MMIO fixup to %s\n", dev->name);
printk("PCI: MMIO fixup to %s\n", dev->dev.name);
dev->resource[1].start=0x01001700;
dev->resource[1].end=0x010017ff;
}
......@@ -140,22 +159,13 @@ static int __init map_dc_irq(struct pci_dev *dev, u8 slot, u8 pin)
return GAPSPCI_IRQ;
}
void __init pcibios_fixup(void) { /* Do nothing. */ }
void __init pcibios_init(void)
void __init pcibios_fixup_irqs(void)
{
pci_root_bus = pci_scan_bus(0, &pci_config_ops, NULL);
/* pci_assign_unassigned_resources(); */
pci_fixup_irqs(no_swizzle, map_dc_irq);
}
/* Haven't done anything here as yet */
char * __init pcibios_setup(char *str)
{
return str;
}
int __init gapspci_init(void)
{
int i;
......@@ -196,3 +206,9 @@ int __init gapspci_init(void)
return 0;
}
/* Haven't done anything here as yet */
char * __devinit pcibios_setup(char *str)
{
return str;
}
......@@ -2,7 +2,8 @@
*
* Dreamcast AICA RTC routines.
*
* Copyright (c) 2001 M. R. Brown <mrbrown@0xd6.org>
* Copyright (c) 2001, 2002 M. R. Brown <mrbrown@0xd6.org>
* Copyright (c) 2002 Paul Mundt <lethal@chaoticdreams.org>
*
* Released under the terms of the GNU GPL v2.0.
*
......@@ -12,6 +13,9 @@
#include <asm/io.h>
extern void (*rtc_get_time)(struct timespec *);
extern int (*rtc_set_time)(const time_t);
/* The AICA RTC has an Epoch of 1/1/1950, so we must subtract 20 years (in
seconds to get the standard Unix Epoch when getting the time, and add 20
years when setting the time. */
......@@ -28,7 +32,7 @@
*
* Grabs the current RTC seconds counter and adjusts it to the Unix Epoch.
*/
void aica_rtc_gettimeofday(struct timeval *tv) {
void aica_rtc_gettimeofday(struct timespec *ts) {
unsigned long val1, val2;
do {
......@@ -39,10 +43,10 @@ void aica_rtc_gettimeofday(struct timeval *tv) {
(ctrl_inl(AICA_RTC_SECS_L) & 0xffff);
} while (val1 != val2);
tv->tv_sec = val1 - TWENTY_YEARS;
ts->tv_sec = val1 - TWENTY_YEARS;
/* Can't get microseconds with just a seconds counter. */
tv->tv_usec = 0;
/* Can't get nanoseconds with just a seconds counter. */
ts->tv_nsec = 0;
}
/**
......@@ -51,13 +55,13 @@ void aica_rtc_gettimeofday(struct timeval *tv) {
*
* Adjusts the given @tv to the AICA Epoch and sets the RTC seconds counter.
*/
int aica_rtc_settimeofday(const struct timeval *tv) {
int aica_rtc_settimeofday(const time_t secs) {
unsigned long val1, val2;
unsigned long secs = tv->tv_sec + TWENTY_YEARS;
unsigned long adj = secs + TWENTY_YEARS;
do {
ctrl_outl((secs & 0xffff0000) >> 16, AICA_RTC_SECS_H);
ctrl_outl((secs & 0xffff), AICA_RTC_SECS_L);
ctrl_outl((adj & 0xffff0000) >> 16, AICA_RTC_SECS_H);
ctrl_outl((adj & 0xffff), AICA_RTC_SECS_L);
val1 = ((ctrl_inl(AICA_RTC_SECS_H) & 0xffff) << 16) |
(ctrl_inl(AICA_RTC_SECS_L) & 0xffff);
......@@ -68,3 +72,10 @@ int aica_rtc_settimeofday(const struct timeval *tv) {
return 0;
}
void aica_time_init(void)
{
rtc_get_time = aica_rtc_gettimeofday;
rtc_set_time = aica_rtc_settimeofday;
}
/* arch/sh/kernel/setup_dc.c
*
* Hardware support for the Sega Dreamcast.
*
* Copyright (c) 2001, 2002 M. R. Brown <mrbrown@linuxdc.org>
* Copyright (c) 2002 Paul Mundt <lethal@chaoticdreams.org>
*
* This file is part of the LinuxDC project (www.linuxdc.org)
*
* Released under the terms of the GNU GPL v2.0.
*
* This file originally bore the message (with enclosed-$):
* Id: setup_dc.c,v 1.5 2001/05/24 05:09:16 mrbrown Exp
* SEGA Dreamcast support
*/
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/param.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/dreamcast/sysasic.h>
extern struct hw_interrupt_type systemasic_int;
/* XXX: Move this into it's proper header. */
extern void (*board_time_init)(void);
extern void aica_time_init(void);
const char *get_system_type(void)
{
return "Sega Dreamcast";
}
#ifdef CONFIG_PCI
extern int gapspci_init(void);
#endif
int __init platform_setup(void)
{
int i;
/* Mask all hardware events */
/* XXX */
/* Acknowledge any previous events */
/* XXX */
/* Assign all virtual IRQs to the System ASIC int. handler */
for (i = HW_EVENT_IRQ_BASE; i < HW_EVENT_IRQ_MAX; i++)
irq_desc[i].handler = &systemasic_int;
board_time_init = aica_time_init;
#ifdef CONFIG_PCI
if (gapspci_init() < 0)
printk(KERN_WARNING "GAPSPCI was not detected.\n");
#endif
return 0;
}
#
# Makefile for the EC3104 specific parts of the kernel
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
obj-y := mach.o setup.o io.o irq.o
......@@ -18,7 +18,7 @@
#include <linux/types.h>
#include <asm/io.h>
#include <asm/page.h>
#include <asm/ec3104.h>
#include <asm/ec3104/ec3104.h>
/*
* EC3104 has a real ISA bus which we redirect low port accesses to (the
......
/*
* linux/arch/sh/kernel/setup_ec3104.c
* EC3104 companion chip support
* linux/arch/sh/boards/ec3104/irq.c
* EC3104 companion chip support
*
* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
*
*/
/* EC3104 note:
* This code was written without any documentation about the EC3104 chip. While
* I hope I got most of the basic functionality right, the register names I use
* are most likely completely different from those in the chip documentation.
*
* If you have any further information about the EC3104, please tell me
* (prumpf@tux.org).
*/
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/param.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/types.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/ec3104.h>
#include <asm/ec3104/ec3104.h>
/* This is for debugging mostly; here's the table that I intend to keep
* in here:
*
* index function base addr power interrupt bit
* 0 power b0ec0000 --- 00000001 (unused)
* 1 irqs b0ec1000 --- 00000002 (unused)
* 2 ?? b0ec2000 b0ec0008 00000004
* 3 PS2 (1) b0ec3000 b0ec000c 00000008
* 4 PS2 (2) b0ec4000 b0ec0010 00000010
* 5 ?? b0ec5000 b0ec0014 00000020
* 6 I2C b0ec6000 b0ec0018 00000040
* 7 serial (1) b0ec7000 b0ec001c 00000080
* 8 serial (2) b0ec8000 b0ec0020 00000100
* 9 serial (3) b0ec9000 b0ec0024 00000200
* 10 serial (4) b0eca000 b0ec0028 00000400
* 12 GPIO (1) b0ecc000 b0ec0030
* 13 GPIO (2) b0ecc000 b0ec0030
* 16 pcmcia (1) b0ed0000 b0ec0040 00010000
* 17 pcmcia (2) b0ed1000 b0ec0044 00020000
* index function base addr power interrupt bit
* 0 power b0ec0000 --- 00000001 (unused)
* 1 irqs b0ec1000 --- 00000002 (unused)
* 2 ?? b0ec2000 b0ec0008 00000004
* 3 PS2 (1) b0ec3000 b0ec000c 00000008
* 4 PS2 (2) b0ec4000 b0ec0010 00000010
* 5 ?? b0ec5000 b0ec0014 00000020
* 6 I2C b0ec6000 b0ec0018 00000040
* 7 serial (1) b0ec7000 b0ec001c 00000080
* 8 serial (2) b0ec8000 b0ec0020 00000100
* 9 serial (3) b0ec9000 b0ec0024 00000200
* 10 serial (4) b0eca000 b0ec0028 00000400
* 12 GPIO (1) b0ecc000 b0ec0030
* 13 GPIO (2) b0ecc000 b0ec0030
* 16 pcmcia (1) b0ed0000 b0ec0040 00010000
* 17 pcmcia (2) b0ed1000 b0ec0044 00020000
*/
/* I used the register names from another interrupt controller I worked with,
......@@ -69,174 +53,144 @@
static char *ec3104_name(unsigned index)
{
switch(index) {
case 0:
return "power management";
case 1:
return "interrupts";
case 3:
return "PS2 (1)";
case 4:
return "PS2 (2)";
case 5:
return "I2C (1)";
case 6:
return "I2C (2)";
case 7:
return "serial (1)";
case 8:
return "serial (2)";
case 9:
return "serial (3)";
case 10:
return "serial (4)";
case 16:
return "pcmcia (1)";
case 17:
return "pcmcia (2)";
default: {
static char buf[32];
sprintf(buf, "unknown (%d)", index);
return buf;
}
}
switch(index) {
case 0:
return "power management";
case 1:
return "interrupts";
case 3:
return "PS2 (1)";
case 4:
return "PS2 (2)";
case 5:
return "I2C (1)";
case 6:
return "I2C (2)";
case 7:
return "serial (1)";
case 8:
return "serial (2)";
case 9:
return "serial (3)";
case 10:
return "serial (4)";
case 16:
return "pcmcia (1)";
case 17:
return "pcmcia (2)";
default: {
static char buf[32];
sprintf(buf, "unknown (%d)", index);
return buf;
}
}
}
int get_pending_interrupts(char *buf)
{
u32 ipr;
u32 bit;
char *p = buf;
u32 ipr;
u32 bit;
char *p = buf;
p += sprintf(p, "pending: (");
ipr = ctrl_inl(EC3104_IPR);
for (bit = 1; bit < 32; bit++)
if (!(ipr & (1<<bit)))
p += sprintf(p, "%s ", ec3104_name(bit));
p += sprintf(p, ")\n");
ipr = ctrl_inl(EC3104_IPR);
for (bit = 1; bit < 32; bit++)
if (!(ipr & (1<<bit)))
p += sprintf(p, "%s ", ec3104_name(bit));
p += sprintf(p, ")\n");
return p - buf;
return p - buf;
}
static inline u32 ec3104_irq2mask(unsigned int irq)
{
return (1 << (irq - EC3104_IRQBASE));
return (1 << (irq - EC3104_IRQBASE));
}
static inline void mask_ec3104_irq(unsigned int irq)
{
u32 mask;
u32 mask;
mask = ctrl_readl(EC3104_IMR);
mask = ctrl_readl(EC3104_IMR);
mask |= ec3104_irq2mask(irq);
mask |= ec3104_irq2mask(irq);
ctrl_writel(mask, EC3104_IMR);
ctrl_writel(mask, EC3104_IMR);
}
static inline void unmask_ec3104_irq(unsigned int irq)
{
u32 mask;
u32 mask;
mask = ctrl_readl(EC3104_IMR);
mask = ctrl_readl(EC3104_IMR);
mask &= ~ec3104_irq2mask(irq);
ctrl_writel(mask, EC3104_IMR);
mask &= ~ec3104_irq2mask(irq);
ctrl_writel(mask, EC3104_IMR);
}
static void disable_ec3104_irq(unsigned int irq)
{
mask_ec3104_irq(irq);
mask_ec3104_irq(irq);
}
static void enable_ec3104_irq(unsigned int irq)
{
unmask_ec3104_irq(irq);
unmask_ec3104_irq(irq);
}
static void mask_and_ack_ec3104_irq(unsigned int irq)
{
mask_ec3104_irq(irq);
mask_ec3104_irq(irq);
}
static void end_ec3104_irq(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
unmask_ec3104_irq(irq);
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
unmask_ec3104_irq(irq);
}
static unsigned int startup_ec3104_irq(unsigned int irq)
{
unmask_ec3104_irq(irq);
unmask_ec3104_irq(irq);
return 0;
return 0;
}
static void shutdown_ec3104_irq(unsigned int irq)
{
mask_ec3104_irq(irq);
mask_ec3104_irq(irq);
}
static struct hw_interrupt_type ec3104_int = {
.typename = "EC3104",
.enable = enable_ec3104_irq,
.disable = disable_ec3104_irq,
.ack = mask_and_ack_ec3104_irq,
.end = end_ec3104_irq,
.startup = startup_ec3104_irq,
.shutdown = shutdown_ec3104_irq,
typename: "EC3104",
enable: enable_ec3104_irq,
disable: disable_ec3104_irq,
ack: mask_and_ack_ec3104_irq,
end: end_ec3104_irq,
startup: startup_ec3104_irq,
shutdown: shutdown_ec3104_irq,
};
/* Yuck. the _demux API is ugly */
int ec3104_irq_demux(int irq)
{
if (irq == EC3104_IRQ) {
unsigned int mask;
if (irq == EC3104_IRQ) {
unsigned int mask;
mask = ctrl_readl(EC3104_IRR);
mask = ctrl_readl(EC3104_IRR);
if (mask == 0xffffffff)
return EC3104_IRQ;
else
return EC3104_IRQBASE + ffz(mask);
}
if (mask == 0xffffffff)
return EC3104_IRQ;
else
return EC3104_IRQBASE + ffz(mask);
}
return irq;
return irq;
}
int __init setup_ec3104(void)
{
char str[8];
int i;
if (!MACH_EC3104)
printk("!MACH_EC3104\n");
if (0)
return 0;
for (i=0; i<8; i++)
str[i] = ctrl_readb(EC3104_BASE + i);
for (i = EC3104_IRQBASE; i < EC3104_IRQBASE + 32; i++)
irq_desc[i].handler = &ec3104_int;
printk("initializing EC3104 \"%.8s\" at %08x, IRQ %d, IRQ base %d\n",
str, EC3104_BASE, EC3104_IRQ, EC3104_IRQBASE);
/* mask all interrupts. this should have been done by the boot
* loader for us but we want to be sure ... */
ctrl_writel(0xffffffff, EC3104_IMR);
return 0;
}
module_init(setup_ec3104);
......@@ -28,42 +28,42 @@
*/
struct sh_machine_vector mv_ec3104 __initmv = {
.mv_name = "EC3104",
mv_name: "EC3104",
.mv_nr_irqs = 96,
mv_nr_irqs: 96,
.mv_inb = ec3104_inb,
.mv_inw = ec3104_inw,
.mv_inl = ec3104_inl,
.mv_outb = ec3104_outb,
.mv_outw = ec3104_outw,
.mv_outl = ec3104_outl,
mv_inb: ec3104_inb,
mv_inw: ec3104_inw,
mv_inl: ec3104_inl,
mv_outb: ec3104_outb,
mv_outw: ec3104_outw,
mv_outl: ec3104_outl,
.mv_inb_p = generic_inb_p,
.mv_inw_p = generic_inw,
.mv_inl_p = generic_inl,
.mv_outb_p = generic_outb_p,
.mv_outw_p = generic_outw,
.mv_outl_p = generic_outl,
mv_inb_p: generic_inb_p,
mv_inw_p: generic_inw,
mv_inl_p: generic_inl,
mv_outb_p: generic_outb_p,
mv_outw_p: generic_outw,
mv_outl_p: generic_outl,
.mv_insb = generic_insb,
.mv_insw = generic_insw,
.mv_insl = generic_insl,
.mv_outsb = generic_outsb,
.mv_outsw = generic_outsw,
.mv_outsl = generic_outsl,
mv_insb: generic_insb,
mv_insw: generic_insw,
mv_insl: generic_insl,
mv_outsb: generic_outsb,
mv_outsw: generic_outsw,
mv_outsl: generic_outsl,
.mv_readb = generic_readb,
.mv_readw = generic_readw,
.mv_readl = generic_readl,
.mv_writeb = generic_writeb,
.mv_writew = generic_writew,
.mv_writel = generic_writel,
mv_readb: generic_readb,
mv_readw: generic_readw,
mv_readl: generic_readl,
mv_writeb: generic_writeb,
mv_writew: generic_writew,
mv_writel: generic_writel,
.mv_irq_demux = ec3104_irq_demux,
mv_irq_demux: ec3104_irq_demux,
.mv_rtc_gettimeofday = sh_rtc_gettimeofday,
.mv_rtc_settimeofday = sh_rtc_settimeofday,
mv_rtc_gettimeofday: sh_rtc_gettimeofday,
mv_rtc_settimeofday: sh_rtc_settimeofday,
};
ALIAS_MV(ec3104)
/*
* linux/arch/sh/boards/ec3104/setup.c
* EC3104 companion chip support
*
* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
*
*/
/* EC3104 note:
* This code was written without any documentation about the EC3104 chip. While
* I hope I got most of the basic functionality right, the register names I use
* are most likely completely different from those in the chip documentation.
*
* If you have any further information about the EC3104, please tell me
* (prumpf@tux.org).
*/
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/param.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/types.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/ec3104/ec3104.h>
int __init setup_ec3104(void)
{
char str[8];
int i;
if (!MACH_EC3104)
printk("!MACH_EC3104\n");
if (0)
return 0;
for (i=0; i<8; i++)
str[i] = ctrl_readb(EC3104_BASE + i);
for (i = EC3104_IRQBASE; i < EC3104_IRQBASE + 32; i++)
irq_desc[i].handler = &ec3104_int;
printk("initializing EC3104 \"%.8s\" at %08x, IRQ %d, IRQ base %d\n",
str, EC3104_BASE, EC3104_IRQ, EC3104_IRQBASE);
/* mask all interrupts. this should have been done by the boot
* loader for us but we want to be sure ... */
ctrl_writel(0xffffffff, EC3104_IMR);
return 0;
}
module_init(setup_ec3104);
#
# Makefile for STMicroelectronics board specific parts of the kernel
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
obj-y := irq.o setup.o mach.o led.o
obj-$(CONFIG_PCI) += pcidma.o
......@@ -15,8 +15,7 @@
#include <asm/system.h>
#include <asm/io.h>
#include "harp.h"
#include <asm/harp/harp.h>
#define NUM_EXTERNAL_IRQS 16
......@@ -68,14 +67,14 @@ static void disable_harp_irq(unsigned int irq)
pri -= 8;
}
save_and_cli(flags);
local_irq_save(flags);
mask = ctrl_inl(maskReg);
mask &= (~(1 << pri));
#if defined(INVERT_INTMASK_WRITES)
mask ^= 0xff;
#endif
ctrl_outl(mask, maskReg);
restore_flags(flags);
local_irq_restore(flags);
}
static void enable_harp_irq(unsigned int irq)
......@@ -97,7 +96,7 @@ static void enable_harp_irq(unsigned int irq)
pri -= 8;
}
save_and_cli(flags);
local_irq_save(flags);
mask = ctrl_inl(maskReg);
......@@ -108,7 +107,7 @@ static void enable_harp_irq(unsigned int irq)
#endif
ctrl_outl(mask, maskReg);
restore_flags(flags);
local_irq_restore(flags);
}
/* This functions sets the desired irq handler to be an overdrive type */
......
......@@ -11,7 +11,7 @@
#include <linux/config.h>
#include <asm/io.h>
#include "harp.h"
#include <asm/harp/harp.h>
/* Harp: Flash LD10 (front pannel) connected to EPLD (IC8) */
/* Overdrive: Flash LD1 (front panel) connected to EPLD (IC4) */
......
......@@ -14,8 +14,8 @@
#include <asm/machvec.h>
#include <asm/rtc.h>
#include <asm/machvec_init.h>
#include <asm/io_hd64465.h>
#include <asm/hd64465.h>
#include <asm/hd64465.h/io.h>
#include <asm/hd64465/hd64465.h>
void setup_harp(void);
void init_harp_irq(void);
......@@ -26,52 +26,47 @@ void heartbeat_harp(void);
*/
struct sh_machine_vector mv_harp __initmv = {
.mv_name = "STB1 Harp",
mv_nr_irqs: 89 + HD64465_IRQ_NUM,
.mv_nr_irqs = 89 + HD64465_IRQ_NUM,
mv_inb: hd64465_inb,
mv_inw: hd64465_inw,
mv_inl: hd64465_inl,
mv_outb: hd64465_outb,
mv_outw: hd64465_outw,
mv_outl: hd64465_outl,
.mv_inb = hd64465_inb,
.mv_inw = hd64465_inw,
.mv_inl = hd64465_inl,
.mv_outb = hd64465_outb,
.mv_outw = hd64465_outw,
.mv_outl = hd64465_outl,
mv_inb_p: hd64465_inb_p,
mv_inw_p: hd64465_inw,
mv_inl_p: hd64465_inl,
mv_outb_p: hd64465_outb_p,
mv_outw_p: hd64465_outw,
mv_outl_p: hd64465_outl,
.mv_inb_p = hd64465_inb_p,
.mv_inw_p = hd64465_inw,
.mv_inl_p = hd64465_inl,
.mv_outb_p = hd64465_outb_p,
.mv_outw_p = hd64465_outw,
.mv_outl_p = hd64465_outl,
mv_insb: hd64465_insb,
mv_insw: hd64465_insw,
mv_insl: hd64465_insl,
mv_outsb: hd64465_outsb,
mv_outsw: hd64465_outsw,
mv_outsl: hd64465_outsl,
.mv_insb = hd64465_insb,
.mv_insw = hd64465_insw,
.mv_insl = hd64465_insl,
.mv_outsb = hd64465_outsb,
.mv_outsw = hd64465_outsw,
.mv_outsl = hd64465_outsl,
mv_readb: generic_readb,
mv_readw: generic_readw,
mv_readl: generic_readl,
mv_writeb: generic_writeb,
mv_writew: generic_writew,
mv_writel: generic_writel,
.mv_readb = generic_readb,
.mv_readw = generic_readw,
.mv_readl = generic_readl,
.mv_writeb = generic_writeb,
.mv_writew = generic_writew,
.mv_writel = generic_writel,
.mv_ioremap = generic_ioremap,
.mv_iounmap = generic_iounmap,
mv_ioremap: generic_ioremap,
mv_iounmap: generic_iounmap,
.mv_isa_port2addr = hd64465_isa_port2addr,
mv_isa_port2addr: hd64465_isa_port2addr,
.mv_init_arch = setup_harp,
#ifdef CONFIG_PCI
.mv_init_irq = init_harp_irq,
mv_init_irq: init_harp_irq,
#endif
#ifdef CONFIG_HEARTBEAT
.mv_heartbeat = heartbeat_harp,
mv_heartbeat: heartbeat_harp,
#endif
.mv_rtc_gettimeofday = sh_rtc_gettimeofday,
.mv_rtc_settimeofday = sh_rtc_settimeofday,
};
ALIAS_MV(harp)
......@@ -24,7 +24,7 @@ void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
ret = (void *) __get_free_pages(gfp, get_order(size));
if (ret != NULL) {
/* Is it necessary to do the memset? */
/* Is it neccessary to do the memset? */
memset(ret, 0, size);
*dma_handle = virt_to_bus(ret);
}
......
......@@ -13,11 +13,17 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/io.h>
#include "harp.h"
#include <asm/harp/harp.h>
const char *get_system_type(void)
{
return "STB1 Harp";
}
/*
* Initialize the board
*/
int __init setup_harp(void)
int __init platform_setup(void)
{
#ifdef CONFIG_SH_STB1_HARP
unsigned long ic8_version, ic36_version;
......
#
# Makefile for the HP620 specific parts of the kernel
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
obj-y := mach.o
/*
* linux/arch/sh/boards/hp6xx/hp620/mach.c
*
* Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* Machine vector for the HP620
*/
#include <linux/init.h>
#include <asm/machvec.h>
#include <asm/rtc.h>
#include <asm/machvec_init.h>
#include <asm/io.h>
#include <asm/hd64461/hd64461.h>
#include <asm/irq.h>
/*
* The Machine Vector
*/
struct sh_machine_vector mv_hp620 __initmv = {
mv_name: "hp620",
mv_nr_irqs: HD64461_IRQBASE+HD64461_IRQ_NUM,
mv_inb: hd64461_inb,
mv_inw: hd64461_inw,
mv_inl: hd64461_inl,
mv_outb: hd64461_outb,
mv_outw: hd64461_outw,
mv_outl: hd64461_outl,
mv_inb_p: hd64461_inb_p,
mv_inw_p: hd64461_inw,
mv_inl_p: hd64461_inl,
mv_outb_p: hd64461_outb_p,
mv_outw_p: hd64461_outw,
mv_outl_p: hd64461_outl,
mv_insb: hd64461_insb,
mv_insw: hd64461_insw,
mv_insl: hd64461_insl,
mv_outsb: hd64461_outsb,
mv_outsw: hd64461_outsw,
mv_outsl: hd64461_outsl,
mv_readb: generic_readb,
mv_readw: generic_readw,
mv_readl: generic_readl,
mv_writeb: generic_writeb,
mv_writew: generic_writew,
mv_writel: generic_writel,
mv_irq_demux: hd64461_irq_demux,
mv_rtc_gettimeofday: sh_rtc_gettimeofday,
mv_rtc_settimeofday: sh_rtc_settimeofday,
mv_hw_hp600: 1,
mv_hw_hp620: 1,
mv_hw_hd64461: 1,
};
ALIAS_MV(hp620)
#
# Makefile for the HP680 specific parts of the kernel
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
obj-y := mach.o
/*
* linux/arch/sh/boards/hp6xx/hp680/mach.c
*
* Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* Machine vector for the HP680
*/
#include <linux/init.h>
#include <asm/machvec.h>
#include <asm/rtc.h>
#include <asm/machvec_init.h>
#include <asm/io.h>
#include <asm/hd64461/hd64461.h>
#include <asm/irq.h>
struct sh_machine_vector mv_hp680 __initmv = {
mv_name: "hp680",
mv_nr_irqs: HD64461_IRQBASE+HD64461_IRQ_NUM,
mv_inb: hd64461_inb,
mv_inw: hd64461_inw,
mv_inl: hd64461_inl,
mv_outb: hd64461_outb,
mv_outw: hd64461_outw,
mv_outl: hd64461_outl,
mv_inb_p: hd64461_inb_p,
mv_inw_p: hd64461_inw,
mv_inl_p: hd64461_inl,
mv_outb_p: hd64461_outb_p,
mv_outw_p: hd64461_outw,
mv_outl_p: hd64461_outl,
mv_insb: hd64461_insb,
mv_insw: hd64461_insw,
mv_insl: hd64461_insl,
mv_outsb: hd64461_outsb,
mv_outsw: hd64461_outsw,
mv_outsl: hd64461_outsl,
mv_readb: generic_readb,
mv_readw: generic_readw,
mv_readl: generic_readl,
mv_writeb: generic_writeb,
mv_writew: generic_writew,
mv_writel: generic_writel,
mv_irq_demux: hd64461_irq_demux,
mv_rtc_gettimeofday: sh_rtc_gettimeofday,
mv_rtc_settimeofday: sh_rtc_settimeofday,
mv_hw_hp600: 1,
mv_hw_hp680: 1,
mv_hw_hd64461: 1,
};
ALIAS_MV(hp680)
#
# Makefile for the HP690 specific parts of the kernel
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
obj-y := mach.o
/*
* linux/arch/sh/boards/hp6xx/hp690/mach.c
*
* Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* Machine vector for the HP690
*/
#include <linux/init.h>
#include <asm/machvec.h>
#include <asm/rtc.h>
#include <asm/machvec_init.h>
#include <asm/io.h>
#include <asm/hd64461/hd64461.h>
#include <asm/irq.h>
struct sh_machine_vector mv_hp690 __initmv = {
mv_name: "hp690",
mv_nr_irqs: HD64461_IRQBASE+HD64461_IRQ_NUM,
mv_inb: hd64461_inb,
mv_inw: hd64461_inw,
mv_inl: hd64461_inl,
mv_outb: hd64461_outb,
mv_outw: hd64461_outw,
mv_outl: hd64461_outl,
mv_inb_p: hd64461_inb_p,
mv_inw_p: hd64461_inw,
mv_inl_p: hd64461_inl,
mv_outb_p: hd64461_outb_p,
mv_outw_p: hd64461_outw,
mv_outl_p: hd64461_outl,
mv_insb: hd64461_insb,
mv_insw: hd64461_insw,
mv_insl: hd64461_insl,
mv_outsb: hd64461_outsb,
mv_outsw: hd64461_outsw,
mv_outsl: hd64461_outsl,
mv_readb: generic_readb,
mv_readw: generic_readw,
mv_readl: generic_readl,
mv_writeb: generic_writeb,
mv_writew: generic_writew,
mv_writel: generic_writel,
mv_irq_demux: hd64461_irq_demux,
mv_rtc_gettimeofday: sh_rtc_gettimeofday,
mv_rtc_settimeofday: sh_rtc_settimeofday,
mv_hw_hp600: 1,
mv_hw_hp690: 1,
mv_hw_hd64461: 1,
};
ALIAS_MV(hp690)
#
# Makefile for the STMicroelectronics Overdrive specific parts of the kernel
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
obj-y := mach.o setup.o io.o irq.o led.o time.o
obj-$(CONFIG_PCI) += fpga.o galileo.o pcidma.o
/*
* Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* This file handles programming up the Altera Flex10K that interfaces to
* the Galileo, and does the PS/2 keyboard and mouse
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <asm/overdriver/gt64111.h>
#include <asm/overdrive/overdrive.h>
#include <asm/overdrive/fpga.h>
#define FPGA_NotConfigHigh() (*FPGA_ControlReg) = (*FPGA_ControlReg) | ENABLE_FPGA_BIT
#define FPGA_NotConfigLow() (*FPGA_ControlReg) = (*FPGA_ControlReg) & RESET_FPGA_MASK
/* I need to find out what (if any) the real delay factor here is */
/* The delay is definately not critical */
#define long_delay() {int i;for(i=0;i<10000;i++);}
#define short_delay() {int i;for(i=0;i<100;i++);}
static void __init program_overdrive_fpga(const unsigned char *fpgacode,
int size)
{
int timeout = 0;
int i, j;
unsigned char b;
static volatile unsigned char *FPGA_ControlReg =
(volatile unsigned char *) (OVERDRIVE_CTRL);
static volatile unsigned char *FPGA_ProgramReg =
(volatile unsigned char *) (FPGA_DCLK_ADDRESS);
printk("FPGA: Commencing FPGA Programming\n");
/* The PCI reset but MUST be low when programming the FPGA !!! */
b = (*FPGA_ControlReg) & RESET_PCI_MASK;
(*FPGA_ControlReg) = b;
/* Prepare FPGA to program */
FPGA_NotConfigHigh();
long_delay();
FPGA_NotConfigLow();
short_delay();
while ((*FPGA_ProgramReg & FPGA_NOT_STATUS) != 0) {
printk("FPGA: Waiting for NotStatus to go Low ... \n");
}
FPGA_NotConfigHigh();
/* Wait for FPGA "ready to be programmed" signal */
printk("FPGA: Waiting for NotStatus to go high (FPGA ready)... \n");
for (timeout = 0;
(((*FPGA_ProgramReg & FPGA_NOT_STATUS) == 0)
&& (timeout < FPGA_TIMEOUT)); timeout++);
/* Check if timeout condition occured - i.e. an error */
if (timeout == FPGA_TIMEOUT) {
printk
("FPGA: Failed to program - Timeout waiting for notSTATUS to go high\n");
return;
}
printk("FPGA: Copying data to FPGA ... %d bytes\n", size);
/* Copy array to FPGA - bit at a time */
for (i = 0; i < size; i++) {
volatile unsigned w = 0;
for (j = 0; j < 8; j++) {
*FPGA_ProgramReg = (fpgacode[i] >> j) & 0x01;
short_delay();
}
if ((i & 0x3ff) == 0) {
printk(".");
}
}
/* Waiting for CONFDONE to go high - means the program is complete */
for (timeout = 0;
(((*FPGA_ProgramReg & FPGA_CONFDONE) == 0)
&& (timeout < FPGA_TIMEOUT)); timeout++) {
*FPGA_ProgramReg = 0x0;
long_delay();
}
if (timeout == FPGA_TIMEOUT) {
printk
("FPGA: Failed to program - Timeout waiting for CONFDONE to go high\n");
return;
} else { /* Clock another 10 times - gets the device into a working state */
for (i = 0; i < 10; i++) {
*FPGA_ProgramReg = 0x0;
short_delay();
}
}
printk("FPGA: Programming complete\n");
}
static const unsigned char __init fpgacode[] = {
#include "./overdrive.ttf" /* Code from maxplus2 compiler */
, 0, 0
};
int __init init_overdrive_fpga(void)
{
program_overdrive_fpga(fpgacode, sizeof(fpgacode));
return 0;
}
/*
* Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* This file contains the PCI routines required for the Galileo GT6411
* PCI bridge as used on the Orion and Overdrive boards.
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/types.h>
#include <linux/ioport.h>
#include <asm/overdrive/overdrive.h>
#include <asm/overdrive/gt64111.h>
/* After boot, we shift the Galileo registers so that they appear
* in BANK6, along with IO space. This means we can have one contingous
* lump of PCI address space without these registers appearing in the
* middle of them
*/
#define GT64111_BASE_ADDRESS 0xbb000000
#define GT64111_IO_BASE_ADDRESS 0x1000
/* The GT64111 registers appear at this address to the SH4 after reset */
#define RESET_GT64111_BASE_ADDRESS 0xb4000000
/* Macros used to access the Galileo registers */
#define RESET_GT64111_REG(x) (RESET_GT64111_BASE_ADDRESS+x)
#define GT64111_REG(x) (GT64111_BASE_ADDRESS+x)
#define RESET_GT_WRITE(x,v) writel((v),RESET_GT64111_REG(x))
#define RESET_GT_READ(x) readl(RESET_GT64111_REG(x))
#define GT_WRITE(x,v) writel((v),GT64111_REG(x))
#define GT_WRITE_BYTE(x,v) writeb((v),GT64111_REG(x))
#define GT_WRITE_SHORT(x,v) writew((v),GT64111_REG(x))
#define GT_READ(x) readl(GT64111_REG(x))
#define GT_READ_BYTE(x) readb(GT64111_REG(x))
#define GT_READ_SHORT(x) readw(GT64111_REG(x))
/* Where the various SH banks start at */
#define SH_BANK4_ADR 0xb0000000
#define SH_BANK5_ADR 0xb4000000
#define SH_BANK6_ADR 0xb8000000
/* Masks out everything but lines 28,27,26 */
#define BANK_SELECT_MASK 0x1c000000
#define SH4_TO_BANK(x) ( (x) & BANK_SELECT_MASK)
/*
* Masks used for address conversaion. Bank 6 is used for IO and
* has all the address bits zeroed by the FPGA. Special case this
*/
#define MEMORY_BANK_MASK 0x1fffffff
#define IO_BANK_MASK 0x03ffffff
/* Mark bank 6 as the bank used for IO. You can change this in the FPGA code
* if you want
*/
#define IO_BANK_ADR PCI_GTIO_BASE
/* Will select the correct mask to apply depending on the SH$ address */
#define SELECT_BANK_MASK(x) \
( (SH4_TO_BANK(x)==SH4_TO_BANK(IO_BANK_ADR)) ? IO_BANK_MASK : MEMORY_BANK_MASK)
/* Converts between PCI space and P2 region */
#define SH4_TO_PCI(x) ((x)&SELECT_BANK_MASK(x))
/* Various macros for figuring out what to stick in the Galileo registers.
* You *really* don't want to figure this stuff out by hand, you always get
* it wrong
*/
#define GT_MEM_LO_ADR(x) ((((unsigned)((x)&SELECT_BANK_MASK(x)))>>21)&0x7ff)
#define GT_MEM_HI_ADR(x) ((((unsigned)((x)&SELECT_BANK_MASK(x)))>>21)&0x7f)
#define GT_MEM_SUB_ADR(x) ((((unsigned)((x)&SELECT_BANK_MASK(x)))>>20)&0xff)
#define PROGRAM_HI_LO(block,a,s) \
GT_WRITE(block##_LO_DEC_ADR,GT_MEM_LO_ADR(a));\
GT_WRITE(block##_HI_DEC_ADR,GT_MEM_HI_ADR(a+s-1))
#define PROGRAM_SUB_HI_LO(block,a,s) \
GT_WRITE(block##_LO_DEC_ADR,GT_MEM_SUB_ADR(a));\
GT_WRITE(block##_HI_DEC_ADR,GT_MEM_SUB_ADR(a+s-1))
/* We need to set the size, and the offset register */
#define GT_BAR_MASK(x) ((x)&~0xfff)
/* Macro to set up the BAR in the Galileo. Essentially used for the DRAM */
#define PROGRAM_GT_BAR(block,a,s) \
GT_WRITE(PCI_##block##_BANK_SIZE,GT_BAR_MASK((s-1)));\
write_config_to_galileo(PCI_CONFIG_##block##_BASE_ADR,\
GT_BAR_MASK(a))
#define DISABLE_GT_BAR(block) \
GT_WRITE(PCI_##block##_BANK_SIZE,0),\
GT_CONFIG_WRITE(PCI_CONFIG_##block##_BASE_ADR,\
0x80000000)
/* Macros to disable things we are not going to use */
#define DISABLE_DECODE(x) GT_WRITE(x##_LO_DEC_ADR,0x7ff);\
GT_WRITE(x##_HI_DEC_ADR,0x00)
#define DISABLE_SUB_DECODE(x) GT_WRITE(x##_LO_DEC_ADR,0xff);\
GT_WRITE(x##_HI_DEC_ADR,0x00)
static void __init reset_pci(void)
{
/* Set RESET_PCI bit high */
writeb(readb(OVERDRIVE_CTRL) | ENABLE_PCI_BIT, OVERDRIVE_CTRL);
udelay(250);
/* Set RESET_PCI bit low */
writeb(readb(OVERDRIVE_CTRL) & RESET_PCI_MASK, OVERDRIVE_CTRL);
udelay(250);
writeb(readb(OVERDRIVE_CTRL) | ENABLE_PCI_BIT, OVERDRIVE_CTRL);
udelay(250);
}
static int write_config_to_galileo(int where, u32 val);
#define GT_CONFIG_WRITE(where,val) write_config_to_galileo(where,val)
#define ENABLE_PCI_DRAM
#ifdef TEST_DRAM
/* Test function to check out if the PCI DRAM is working OK */
static int /* __init */ test_dram(unsigned *base, unsigned size)
{
unsigned *p = base;
unsigned *end = (unsigned *) (((unsigned) base) + size);
unsigned w;
for (p = base; p < end; p++) {
*p = 0xffffffff;
if (*p != 0xffffffff) {
printk("AAARGH -write failed!!! at %p is %x\n", p,
*p);
return 0;
}
*p = 0x0;
if (*p != 0x0) {
printk("AAARGH -write failed!!!\n");
return 0;
}
}
for (p = base; p < end; p++) {
*p = (unsigned) p;
if (*p != (unsigned) p) {
printk("Failed at 0x%p, actually is 0x%x\n", p,
*p);
return 0;
}
}
for (p = base; p < end; p++) {
w = ((unsigned) p & 0xffff0000);
*p = w | (w >> 16);
}
for (p = base; p < end; p++) {
w = ((unsigned) p & 0xffff0000);
w |= (w >> 16);
if (*p != w) {
printk
("Failed at 0x%p, should be 0x%x actually is 0x%x\n",
p, w, *p);
return 0;
}
}
return 1;
}
#endif
/* Function to set up and initialise the galileo. This sets up the BARS,
* maps the DRAM into the address space etc,etc
*/
int __init galileo_init(void)
{
reset_pci();
/* Now shift the galileo regs into this block */
RESET_GT_WRITE(INTERNAL_SPACE_DEC,
GT_MEM_LO_ADR(GT64111_BASE_ADDRESS));
/* Should have a sanity check here, that you can read back at the new
* address what you just wrote
*/
/* Disable decode for all regions */
DISABLE_DECODE(RAS10);
DISABLE_DECODE(RAS32);
DISABLE_DECODE(CS20);
DISABLE_DECODE(CS3);
DISABLE_DECODE(PCI_IO);
DISABLE_DECODE(PCI_MEM0);
DISABLE_DECODE(PCI_MEM1);
/* Disable all BARS */
GT_WRITE(BAR_ENABLE_ADR, 0x1ff);
DISABLE_GT_BAR(RAS10);
DISABLE_GT_BAR(RAS32);
DISABLE_GT_BAR(CS20);
DISABLE_GT_BAR(CS3);
/* Tell the BAR where the IO registers now are */
GT_CONFIG_WRITE(PCI_CONFIG_INT_REG_IO_ADR,GT_BAR_MASK(
(GT64111_IO_BASE_ADDRESS &
IO_BANK_MASK)));
/* set up a 112 Mb decode */
PROGRAM_HI_LO(PCI_MEM0, SH_BANK4_ADR, 112 * 1024 * 1024);
/* Set up a 32 MB io space decode */
PROGRAM_HI_LO(PCI_IO, IO_BANK_ADR, 32 * 1024 * 1024);
#ifdef ENABLE_PCI_DRAM
/* Program up the DRAM configuration - there is DRAM only in bank 0 */
/* Now set up the DRAM decode */
PROGRAM_HI_LO(RAS10, PCI_DRAM_BASE, PCI_DRAM_SIZE);
/* And the sub decode */
PROGRAM_SUB_HI_LO(RAS0, PCI_DRAM_BASE, PCI_DRAM_SIZE);
DISABLE_SUB_DECODE(RAS1);
/* Set refresh rate */
GT_WRITE(DRAM_BANK0_PARMS, 0x3f);
GT_WRITE(DRAM_CFG, 0x100);
/* we have to lob off the top bits rememeber!! */
PROGRAM_GT_BAR(RAS10, SH4_TO_PCI(PCI_DRAM_BASE), PCI_DRAM_SIZE);
#endif
/* We are only interested in decoding RAS10 and the Galileo's internal
* registers (as IO) on the PCI bus
*/
#ifdef ENABLE_PCI_DRAM
GT_WRITE(BAR_ENABLE_ADR, (~((1 << 8) | (1 << 3))) & 0x1ff);
#else
GT_WRITE(BAR_ENABLE_ADR, (~(1 << 3)) & 0x1ff);
#endif
/* Change the class code to host bridge, it actually powers up
* as a memory controller
*/
GT_CONFIG_WRITE(8, 0x06000011);
/* Allow the galileo to master the PCI bus */
GT_CONFIG_WRITE(PCI_COMMAND,
PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
PCI_COMMAND_IO);
#if 0
printk("Testing PCI DRAM - ");
if(test_dram(PCI_DRAM_BASE,PCI_DRAM_SIZE)) {
printk("Passed\n");
}else {
printk("FAILED\n");
}
#endif
return 0;
}
#define SET_CONFIG_BITS(bus,devfn,where)\
((1<<31) | ((bus) << 16) | ((devfn) << 8) | ((where) & ~3))
#define CONFIG_CMD(dev, where) SET_CONFIG_BITS((dev)->bus->number,(dev)->devfn,where)
/* This write to the galileo config registers, unlike the functions below, can
* be used before the PCI subsystem has started up
*/
static int __init write_config_to_galileo(int where, u32 val)
{
GT_WRITE(PCI_CFG_ADR, SET_CONFIG_BITS(0, 0, where));
GT_WRITE(PCI_CFG_DATA, val);
return 0;
}
/* We exclude the galileo and slot 31, the galileo because I don't know how to stop
* the setup code shagging up the setup I have done on it, and 31 because the whole
* thing locks up if you try to access that slot (which doesn't exist of course anyway
*/
#define EXCLUDED_DEV(dev) ((dev->bus->number==0) && ((PCI_SLOT(dev->devfn)==0) || (PCI_SLOT(dev->devfn) == 31)))
static int galileo_read_config_byte(struct pci_dev *dev, int where,
u8 * val)
{
/* I suspect this doesn't work because this drives a special cycle ? */
if (EXCLUDED_DEV(dev)) {
*val = 0xff;
return PCIBIOS_SUCCESSFUL;
}
/* Start the config cycle */
GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
/* Read back the result */
*val = GT_READ_BYTE(PCI_CFG_DATA + (where & 3));
return PCIBIOS_SUCCESSFUL;
}
static int galileo_read_config_word(struct pci_dev *dev, int where,
u16 * val)
{
if (EXCLUDED_DEV(dev)) {
*val = 0xffff;
return PCIBIOS_SUCCESSFUL;
}
GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
*val = GT_READ_SHORT(PCI_CFG_DATA + (where & 2));
return PCIBIOS_SUCCESSFUL;
}
static int galileo_read_config_dword(struct pci_dev *dev, int where,
u32 * val)
{
if (EXCLUDED_DEV(dev)) {
*val = 0xffffffff;
return PCIBIOS_SUCCESSFUL;
}
GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
*val = GT_READ(PCI_CFG_DATA);
return PCIBIOS_SUCCESSFUL;
}
static int galileo_write_config_byte(struct pci_dev *dev, int where,
u8 val)
{
GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
GT_WRITE_BYTE(PCI_CFG_DATA + (where & 3), val);
return PCIBIOS_SUCCESSFUL;
}
static int galileo_write_config_word(struct pci_dev *dev, int where,
u16 val)
{
GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
GT_WRITE_SHORT(PCI_CFG_DATA + (where & 2), val);
return PCIBIOS_SUCCESSFUL;
}
static int galileo_write_config_dword(struct pci_dev *dev, int where,
u32 val)
{
GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
GT_WRITE(PCI_CFG_DATA, val);
return PCIBIOS_SUCCESSFUL;
}
static struct pci_ops pci_config_ops = {
galileo_read_config_byte,
galileo_read_config_word,
galileo_read_config_dword,
galileo_write_config_byte,
galileo_write_config_word,
galileo_write_config_dword
};
/* Everything hangs off this */
static struct pci_bus *pci_root_bus;
static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin)
{
return PCI_SLOT(dev->devfn);
}
static int __init map_od_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
/* Slot 1: Galileo
* Slot 2: PCI Slot 1
* Slot 3: PCI Slot 2
* Slot 4: ESS
*/
switch (slot) {
case 2:
return OVERDRIVE_PCI_IRQ1;
case 3:
/* Note this assumes you have a hacked card in slot 2 */
return OVERDRIVE_PCI_IRQ2;
case 4:
return OVERDRIVE_ESS_IRQ;
default:
/* printk("PCI: Unexpected IRQ mapping request for slot %d\n", slot); */
return -1;
}
}
void __init
pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *ranges)
{
ranges->io_start -= bus->resource[0]->start;
ranges->io_end -= bus->resource[0]->start;
ranges->mem_start -= bus->resource[1]->start;
ranges->mem_end -= bus->resource[1]->start;
}
static void __init pci_fixup_ide_bases(struct pci_dev *d)
{
int i;
/*
* PCI IDE controllers use non-standard I/O port decoding, respect it.
*/
if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
return;
printk("PCI: IDE base address fixup for %s\n", d->slot_name);
for(i=0; i<4; i++) {
struct resource *r = &d->resource[i];
if ((r->start & ~0x80) == 0x374) {
r->start |= 2;
r->end = r->start;
}
}
}
/* Add future fixups here... */
struct pci_fixup pcibios_fixups[] = {
{ PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases },
{ 0 }
};
void __init pcibios_init(void)
{
static struct resource galio,galmem;
/* Allocate the registers used by the Galileo */
galio.flags = IORESOURCE_IO;
galio.name = "Galileo GT64011";
galmem.flags = IORESOURCE_MEM|IORESOURCE_PREFETCH;
galmem.name = "Galileo GT64011 DRAM";
allocate_resource(&ioport_resource, &galio, 256,
GT64111_IO_BASE_ADDRESS,GT64111_IO_BASE_ADDRESS+256, 256, NULL, NULL);
allocate_resource(&iomem_resource, &galmem,PCI_DRAM_SIZE,
PHYSADDR(PCI_DRAM_BASE), PHYSADDR(PCI_DRAM_BASE)+PCI_DRAM_SIZE,
PCI_DRAM_SIZE, NULL, NULL);
/* ok, do the scan man */
pci_root_bus = pci_scan_bus(0, &pci_config_ops, NULL);
pci_assign_unassigned_resources();
pci_fixup_irqs(no_swizzle, map_od_irq);
#ifdef TEST_DRAM
printk("Testing PCI DRAM - ");
if(test_dram(PCI_DRAM_BASE,PCI_DRAM_SIZE)) {
printk("Passed\n");
}else {
printk("FAILED\n");
}
#endif
}
char * __init pcibios_setup(char *str)
{
return str;
}
int pcibios_enable_device(struct pci_dev *dev)
{
u16 cmd, old_cmd;
int idx;
struct resource *r;
pci_read_config_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",
dev->slot_name);
return -EINVAL;
}
if (r->flags & IORESOURCE_IO)
cmd |= PCI_COMMAND_IO;
if (r->flags & IORESOURCE_MEM)
cmd |= PCI_COMMAND_MEMORY;
}
if (cmd != old_cmd) {
printk("PCI: enabling device %s (%04x -> %04x)\n",
dev->slot_name, old_cmd, cmd);
pci_write_config_word(dev, PCI_COMMAND, cmd);
}
return 0;
}
/* We should do some optimisation work here I think. Ok for now though */
void __init pcibios_fixup_bus(struct pci_bus *bus)
{
}
void pcibios_align_resource(void *data, struct resource *res,
unsigned long size)
{
}
void __init pcibios_update_resource(struct pci_dev *dev, struct resource *root,
struct resource *res, int resource)
{
unsigned long where, size;
u32 reg;
printk("PCI: Assigning %3s %08lx to %s\n",
res->flags & IORESOURCE_IO ? "IO" : "MEM",
res->start, dev->name);
where = PCI_BASE_ADDRESS_0 + resource * 4;
size = res->end - res->start;
pci_read_config_dword(dev, where, &reg);
reg = (reg & size) | (((u32) (res->start - root->start)) & ~size);
pci_write_config_dword(dev, where, reg);
}
void __init pcibios_update_irq(struct pci_dev *dev, int irq)
{
printk("PCI: Assigning IRQ %02d to %s\n", irq, dev->name);
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
}
/*
* If we set up a device for bus mastering, we need to check the latency
* timer as certain crappy BIOSes forget to set it properly.
*/
unsigned int pcibios_max_latency = 255;
void pcibios_set_master(struct pci_dev *dev)
{
u8 lat;
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
if (lat < 16)
lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
else if (lat > pcibios_max_latency)
lat = pcibios_max_latency;
else
return;
printk("PCI: Setting latency timer of device %s to %d\n", dev->slot_name, lat);
pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
}
/*
* Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* This file contains the I/O routines for use on the overdrive board
*
*/
#include <linux/config.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <asm/processor.h>
#include <asm/io.h>
#include <asm/addrspace.h>
#include <asm/overdrive/overdrive.h>
/*
* readX/writeX() are used to access memory mapped devices. On some
* architectures the memory mapped IO stuff needs to be accessed
* differently. On the SuperH architecture, we just read/write the
* memory location directly.
*/
#define dprintk(x...)
/* Translates an IO address to where it is mapped in memory */
#define io_addr(x) (((unsigned)(x))|PCI_GTIO_BASE)
unsigned char od_inb(unsigned long port)
{
dprintk("od_inb(%x)\n", port);
return readb(io_addr(port)) & 0xff;
}
unsigned short od_inw(unsigned long port)
{
dprintk("od_inw(%x)\n", port);
return readw(io_addr(port)) & 0xffff;
}
unsigned int od_inl(unsigned long port)
{
dprintk("od_inl(%x)\n", port);
return readl(io_addr(port));
}
void od_outb(unsigned char value, unsigned long port)
{
dprintk("od_outb(%x, %x)\n", value, port);
writeb(value, io_addr(port));
}
void od_outw(unsigned short value, unsigned long port)
{
dprintk("od_outw(%x, %x)\n", value, port);
writew(value, io_addr(port));
}
void od_outl(unsigned int value, unsigned long port)
{
dprintk("od_outl(%x, %x)\n", value, port);
writel(value, io_addr(port));
}
/* This is horrible at the moment - needs more work to do something sensible */
#define IO_DELAY() udelay(10)
#define OUT_DELAY(x,type) \
void od_out##x##_p(unsigned type value,unsigned long port){out##x(value,port);IO_DELAY();}
#define IN_DELAY(x,type) \
unsigned type od_in##x##_p(unsigned long port) {unsigned type tmp=in##x(port);IO_DELAY();return tmp;}
OUT_DELAY(b,char)
OUT_DELAY(w,short)
OUT_DELAY(l,int)
IN_DELAY(b,char)
IN_DELAY(w,short)
IN_DELAY(l,int)
/* Now for the string version of these functions */
void od_outsb(unsigned long port, const void *addr, unsigned long count)
{
int i;
unsigned char *p = (unsigned char *) addr;
for (i = 0; i < count; i++, p++) {
outb(*p, port);
}
}
void od_insb(unsigned long port, void *addr, unsigned long count)
{
int i;
unsigned char *p = (unsigned char *) addr;
for (i = 0; i < count; i++, p++) {
*p = inb(port);
}
}
/* For the 16 and 32 bit string functions, we have to worry about alignment.
* The SH does not do unaligned accesses, so we have to read as bytes and
* then write as a word or dword.
* This can be optimised a lot more, especially in the case where the data
* is aligned
*/
void od_outsw(unsigned long port, const void *addr, unsigned long count)
{
int i;
unsigned short tmp;
unsigned char *p = (unsigned char *) addr;
for (i = 0; i < count; i++, p += 2) {
tmp = (*p) | ((*(p + 1)) << 8);
outw(tmp, port);
}
}
void od_insw(unsigned long port, void *addr, unsigned long count)
{
int i;
unsigned short tmp;
unsigned char *p = (unsigned char *) addr;
for (i = 0; i < count; i++, p += 2) {
tmp = inw(port);
p[0] = tmp & 0xff;
p[1] = (tmp >> 8) & 0xff;
}
}
void od_outsl(unsigned long port, const void *addr, unsigned long count)
{
int i;
unsigned tmp;
unsigned char *p = (unsigned char *) addr;
for (i = 0; i < count; i++, p += 4) {
tmp = (*p) | ((*(p + 1)) << 8) | ((*(p + 2)) << 16) |
((*(p + 3)) << 24);
outl(tmp, port);
}
}
void od_insl(unsigned long port, void *addr, unsigned long count)
{
int i;
unsigned tmp;
unsigned char *p = (unsigned char *) addr;
for (i = 0; i < count; i++, p += 4) {
tmp = inl(port);
p[0] = tmp & 0xff;
p[1] = (tmp >> 8) & 0xff;
p[2] = (tmp >> 16) & 0xff;
p[3] = (tmp >> 24) & 0xff;
}
}
/*
* Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* Looks after interrupts on the overdrive board.
*
* Bases on the IPR irq system
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/overdrive/overdrive.h>
struct od_data {
int overdrive_irq;
int irq_mask;
};
#define NUM_EXTERNAL_IRQS 16
#define EXTERNAL_IRQ_NOT_IN_USE (-1)
#define EXTERNAL_IRQ_NOT_ASSIGNED (-1)
/*
* This table is used to determine what to program into the FPGA's CT register
* for the specified Linux IRQ.
*
* The irq_mask gives the interrupt number from the PCI board (PCI_Int(6:0))
* but is one greater than that because the because the FPGA treats 0
* as disabled, a value of 1 asserts PCI_Int0, and so on.
*
* The overdrive_irq specifies which of the eight interrupt sources generates
* that interrupt, and but is multiplied by four to give the bit offset into
* the CT register.
*
* The seven interrupts levels (SH4 IRL's) we have available here is hardwired
* by the EPLD. The assignments here of which PCI interrupt generates each
* level is arbitary.
*/
static struct od_data od_data_table[NUM_EXTERNAL_IRQS] = {
/* overdrive_irq , irq_mask */
{EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 0 */
{EXTERNAL_IRQ_NOT_ASSIGNED, 7}, /* 1 */
{EXTERNAL_IRQ_NOT_ASSIGNED, 6}, /* 2 */
{EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 3 */
{EXTERNAL_IRQ_NOT_ASSIGNED, 5}, /* 4 */
{EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 5 */
{EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 6 */
{EXTERNAL_IRQ_NOT_ASSIGNED, 4}, /* 7 */
{EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 8 */
{EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 9 */
{EXTERNAL_IRQ_NOT_ASSIGNED, 3}, /* 10 */
{EXTERNAL_IRQ_NOT_ASSIGNED, 2}, /* 11 */
{EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 12 */
{EXTERNAL_IRQ_NOT_ASSIGNED, 1}, /* 13 */
{EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 14 */
{EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE} /* 15 */
};
static void set_od_data(int overdrive_irq, int irq)
{
if (irq >= NUM_EXTERNAL_IRQS || irq < 0)
return;
od_data_table[irq].overdrive_irq = overdrive_irq << 2;
}
static void enable_od_irq(unsigned int irq);
void disable_od_irq(unsigned int irq);
/* shutdown is same as "disable" */
#define shutdown_od_irq disable_od_irq
static void mask_and_ack_od(unsigned int);
static void end_od_irq(unsigned int irq);
static unsigned int startup_od_irq(unsigned int irq)
{
enable_od_irq(irq);
return 0; /* never anything pending */
}
static struct hw_interrupt_type od_irq_type = {
"Overdrive-IRQ",
startup_od_irq,
shutdown_od_irq,
enable_od_irq,
disable_od_irq,
mask_and_ack_od,
end_od_irq
};
static void disable_od_irq(unsigned int irq)
{
unsigned val, flags;
int overdrive_irq;
unsigned mask;
/* Not a valid interrupt */
if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
return;
/* Is is necessary to use a cli here? Would a spinlock not be
* mroe efficient?
*/
local_irq_save(flags);
overdrive_irq = od_data_table[irq].overdrive_irq;
if (overdrive_irq != EXTERNAL_IRQ_NOT_ASSIGNED) {
mask = ~(0x7 << overdrive_irq);
val = ctrl_inl(OVERDRIVE_INT_CT);
val &= mask;
ctrl_outl(val, OVERDRIVE_INT_CT);
}
local_irq_restore(flags);
}
static void enable_od_irq(unsigned int irq)
{
unsigned val, flags;
int overdrive_irq;
unsigned mask;
/* Not a valid interrupt */
if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
return;
/* Set priority in OD back to original value */
local_irq_save(flags);
/* This one is not in use currently */
overdrive_irq = od_data_table[irq].overdrive_irq;
if (overdrive_irq != EXTERNAL_IRQ_NOT_ASSIGNED) {
val = ctrl_inl(OVERDRIVE_INT_CT);
mask = ~(0x7 << overdrive_irq);
val &= mask;
mask = od_data_table[irq].irq_mask << overdrive_irq;
val |= mask;
ctrl_outl(val, OVERDRIVE_INT_CT);
}
local_irq_restore(flags);
}
/* this functions sets the desired irq handler to be an overdrive type */
static void __init make_od_irq(unsigned int irq)
{
disable_irq_nosync(irq);
irq_desc[irq].handler = &od_irq_type;
disable_od_irq(irq);
}
static void mask_and_ack_od(unsigned int irq)
{
disable_od_irq(irq);
}
static void end_od_irq(unsigned int irq)
{
enable_od_irq(irq);
}
void __init init_overdrive_irq(void)
{
int i;
/* Disable all interrupts */
ctrl_outl(0, OVERDRIVE_INT_CT);
/* Update interrupt pin mode to use encoded interrupts */
i = ctrl_inw(INTC_ICR);
i &= ~INTC_ICR_IRLM;
ctrl_outw(i, INTC_ICR);
for (i = 0; i < NUM_EXTERNAL_IRQS; i++) {
if (od_data_table[i].irq_mask != EXTERNAL_IRQ_NOT_IN_USE) {
make_od_irq(i);
} else if (i != 15) { // Cannot use imask on level 15
make_imask_irq(i);
}
}
/* Set up the interrupts */
set_od_data(OVERDRIVE_PCI_INTA, OVERDRIVE_PCI_IRQ1);
set_od_data(OVERDRIVE_PCI_INTB, OVERDRIVE_PCI_IRQ2);
set_od_data(OVERDRIVE_AUDIO_INT, OVERDRIVE_ESS_IRQ);
}
/*
* linux/arch/sh/overdrive/led.c
*
* Copyright (C) 1999 Stuart Menefy <stuart.menefy@st.com>
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* This file contains an Overdrive specific LED feature.
*/
#include <linux/config.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/overdrive/overdrive.h>
static void mach_led(int position, int value)
{
unsigned long flags;
unsigned long reg;
local_irq_save(flags);
reg = readl(OVERDRIVE_CTRL);
if (value) {
reg |= (1<<3);
} else {
reg &= ~(1<<3);
}
writel(reg, OVERDRIVE_CTRL);
local_irq_restore(flags);
}
#ifdef CONFIG_HEARTBEAT
#include <linux/sched.h>
/* acts like an actual heart beat -- ie thump-thump-pause... */
void heartbeat_od(void)
{
static unsigned cnt = 0, period = 0, dist = 0;
if (cnt == 0 || cnt == dist)
mach_led( -1, 1);
else if (cnt == 7 || cnt == dist+7)
mach_led( -1, 0);
if (++cnt > period) {
cnt = 0;
/* The hyperbolic function below modifies the heartbeat period
* length in dependency of the current (5min) load. It goes
* through the points f(0)=126, f(1)=86, f(5)=51,
* f(inf)->30. */
period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
dist = period / 4;
}
}
#endif /* CONFIG_HEARTBEAT */
/*
* linux/arch/sh/overdrive/mach.c
*
* Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* Machine vector for the STMicroelectronics Overdrive
*/
#include <linux/init.h>
#include <asm/machvec.h>
#include <asm/rtc.h>
#include <asm/machvec_init.h>
#include <asm/io_unknown.h>
#include <asm/io_generic.h>
#include <asm/overdrive/io.h>
void heartbeat_od(void);
void init_overdrive_irq(void);
void galileo_pcibios_init(void);
/*
* The Machine Vector
*/
struct sh_machine_vector mv_od __initmv = {
mv_nr_irqs: 48,
mv_inb: od_inb,
mv_inw: od_inw,
mv_inl: od_inl,
mv_outb: od_outb,
mv_outw: od_outw,
mv_outl: od_outl,
mv_inb_p: od_inb_p,
mv_inw_p: od_inw_p,
mv_inl_p: od_inl_p,
mv_outb_p: od_outb_p,
mv_outw_p: od_outw_p,
mv_outl_p: od_outl_p,
mv_insb: od_insb,
mv_insw: od_insw,
mv_insl: od_insl,
mv_outsb: od_outsb,
mv_outsw: od_outsw,
mv_outsl: od_outsl,
mv_readb: generic_readb,
mv_readw: generic_readw,
mv_readl: generic_readl,
mv_writeb: generic_writeb,
mv_writew: generic_writew,
mv_writel: generic_writel,
mv_ioremap: generic_ioremap,
mv_iounmap: generic_iounmap,
mv_isa_port2addr: generic_isa_port2addr,
#ifdef CONFIG_PCI
mv_init_irq: init_overdrive_irq,
#endif
#ifdef CONFIG_HEARTBEAT
mv_heartbeat: heartbeat_od,
#endif
};
ALIAS_MV(od)
/*
* Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* Dynamic DMA mapping support.
*
* On the overdrive, we can only DMA from memory behind the PCI bus!
* this means that all DMA'able memory must come from there.
* this restriction will not apply to later boards.
*/
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/pci.h>
#include <asm/io.h>
void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
dma_addr_t * dma_handle)
{
void *ret;
int gfp = GFP_ATOMIC;
printk("BUG: pci_alloc_consistent() called - not yet supported\n");
/* We ALWAYS need DMA memory on the overdrive hardware,
* due to it's extreme wierdness
* Need to flush the cache here as well, since the memory
* can still be seen through the cache!
*/
gfp |= GFP_DMA;
ret = (void *) __get_free_pages(gfp, get_order(size));
if (ret != NULL) {
memset(ret, 0, size);
*dma_handle = virt_to_bus(ret);
}
return ret;
}
void pci_free_consistent(struct pci_dev *hwdev, size_t size,
void *vaddr, dma_addr_t dma_handle)
{
free_pages((unsigned long) vaddr, get_order(size));
}
/*
* arch/sh/overdrive/setup.c
*
* Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* STMicroelectronics Overdrive Support.
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/overdrive/overdrive.h>
#include <asm/overdrive/fpga.h>
extern void od_time_init(void);
const char *get_system_type(void)
{
return "SH7750 Overdrive";
}
/*
* Initialize the board
*/
int __init platform_setup(void)
{
#ifdef CONFIG_PCI
init_overdrive_fpga();
galileo_init();
#endif
board_time_init = od_time_init;
/* Enable RS232 receive buffers */
writel(0x1e, OVERDRIVE_CTRL);
}
/*
* arch/sh/boards/overdrive/time.c
*
* Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
* Copyright (C) 2002 Paul Mundt (lethal@chaoticdreams.org)
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* STMicroelectronics Overdrive Support.
*/
void od_time_init(void)
{
struct frqcr_data {
unsigned short frqcr;
struct {
unsigned char multiplier;
unsigned char divisor;
} factor[3];
};
static struct frqcr_data st40_frqcr_table[] = {
{ 0x000, {{1,1}, {1,1}, {1,2}}},
{ 0x002, {{1,1}, {1,1}, {1,4}}},
{ 0x004, {{1,1}, {1,1}, {1,8}}},
{ 0x008, {{1,1}, {1,2}, {1,2}}},
{ 0x00A, {{1,1}, {1,2}, {1,4}}},
{ 0x00C, {{1,1}, {1,2}, {1,8}}},
{ 0x011, {{1,1}, {2,3}, {1,6}}},
{ 0x013, {{1,1}, {2,3}, {1,3}}},
{ 0x01A, {{1,1}, {1,2}, {1,4}}},
{ 0x01C, {{1,1}, {1,2}, {1,8}}},
{ 0x023, {{1,1}, {2,3}, {1,3}}},
{ 0x02C, {{1,1}, {1,2}, {1,8}}},
{ 0x048, {{1,2}, {1,2}, {1,4}}},
{ 0x04A, {{1,2}, {1,2}, {1,6}}},
{ 0x04C, {{1,2}, {1,2}, {1,8}}},
{ 0x05A, {{1,2}, {1,3}, {1,6}}},
{ 0x05C, {{1,2}, {1,3}, {1,6}}},
{ 0x063, {{1,2}, {1,4}, {1,4}}},
{ 0x06C, {{1,2}, {1,4}, {1,8}}},
{ 0x091, {{1,3}, {1,3}, {1,6}}},
{ 0x093, {{1,3}, {1,3}, {1,6}}},
{ 0x0A3, {{1,3}, {1,6}, {1,6}}},
{ 0x0DA, {{1,4}, {1,4}, {1,8}}},
{ 0x0DC, {{1,4}, {1,4}, {1,8}}},
{ 0x0EC, {{1,4}, {1,8}, {1,8}}},
{ 0x123, {{1,4}, {1,4}, {1,8}}},
{ 0x16C, {{1,4}, {1,8}, {1,8}}},
};
struct memclk_data {
unsigned char multiplier;
unsigned char divisor;
};
static struct memclk_data st40_memclk_table[8] = {
{1,1}, // 000
{1,2}, // 001
{1,3}, // 010
{2,3}, // 011
{1,4}, // 100
{1,6}, // 101
{1,8}, // 110
{1,8} // 111
};
unsigned long pvr;
/*
* This should probably be moved into the SH3 probing code, and then
* use the processor structure to determine which CPU we are running
* on.
*/
pvr = ctrl_inl(CCN_PVR);
printk("PVR %08x\n", pvr);
if (((pvr >> CCN_PVR_CHIP_SHIFT) & CCN_PVR_CHIP_MASK) == CCN_PVR_CHIP_ST40STB1) {
/*
* Unfortunatly the STB1 FRQCR values are different from the
* 7750 ones.
*/
struct frqcr_data *d;
int a;
unsigned long memclkcr;
struct memclk_data *e;
for (a=0; a<ARRAY_SIZE(st40_frqcr_table); a++) {
d = &st40_frqcr_table[a];
if (d->frqcr == (frqcr & 0x1ff))
break;
}
if (a == ARRAY_SIZE(st40_frqcr_table)) {
d = st40_frqcr_table;
printk("ERROR: Unrecognised FRQCR value, using default multipliers\n");
}
memclkcr = ctrl_inl(CLOCKGEN_MEMCLKCR);
e = &st40_memclk_table[memclkcr & MEMCLKCR_RATIO_MASK];
printk("Clock multipliers: CPU: %d/%d Bus: %d/%d Mem: %d/%d Periph: %d/%d\n",
d->factor[0].multiplier, d->factor[0].divisor,
d->factor[1].multiplier, d->factor[1].divisor,
e->multiplier, e->divisor,
d->factor[2].multiplier, d->factor[2].divisor);
current_cpu_data.master_clock = current_cpu_data.module_clock *
d->factor[2].divisor /
d->factor[2].multiplier;
current_cpu_data.bus_clock = current_cpu_data.master_clock *
d->factor[1].multiplier /
d->factor[1].divisor;
current_cpu_data.memory_clock = current_cpu_data.master_clock *
e->multiplier / e->divisor;
current_cpu_data.cpu_clock = current_cpu_data.master_clock *
d->factor[0].multiplier /
d->factor[0].divisor;
}
#
# Makefile for the Sega Saturn specific parts of the kernel
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
obj-y := mach.o setup.o io.o irq.o
obj-$(CONFIG_SMP) += smp.o
/*
* arch/sh/boards/saturn/io.c
*
* I/O routines for the Sega Saturn.
*
* Copyright (C) 2002 Paul Mundt
*
* Released under the terms of the GNU GPL v2.0.
*/
#include <asm/saturn/io.h>
#include <asm/machvec.h>
unsigned long saturn_isa_port2addr(unsigned long offset)
{
return offset;
}
void *saturn_ioremap(unsigned long offset, unsigned long size)
{
return (void *)offset;
}
void saturn_iounmap(void *addr)
{
}
/*
* arch/sh/boards/saturn/irq.c
*
* Copyright (C) 2002 Paul Mundt
*
* Released under the terms of the GNU GPL v2.0.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/saturn/saturn.h>
#include <asm/saturn/irq.h>
#include <asm/irq.h>
#include <asm/io.h>
/*
* Interrupts map out as follows:
*
* Vector Name Mask
*
* 64 VBLANKIN 0x0001
* 65 VBLANKOUT 0x0002
* 66 HBLANKIN 0x0004
* 67 TIMER0 0x0008
* 68 TIMER1 0x0010
* 69 DSPEND 0x0020
* 70 SOUNDREQUEST 0x0040
* 71 SYSTEMMANAGER 0x0080
* 72 PAD 0x0100
* 73 LEVEL2DMAEND 0x0200
* 74 LEVEL1DMAEND 0x0400
* 75 LEVEL0DMAEND 0x0800
* 76 DMAILLEGAL 0x1000
* 77 SRITEDRAWEND 0x2000
* 78 ABUS 0x8000
*
*/
#define SATURN_IRQ_MIN 64 /* VBLANKIN */
#define SATURN_IRQ_MAX 78 /* ABUS */
#define SATURN_IRQ_MASK 0xbfff
static inline u32 saturn_irq_mask(unsigned int irq_nr)
{
u32 mask;
mask = (1 << (irq_nr - SATURN_IRQ_MIN));
mask <<= (irq_nr == SATURN_IRQ_MAX);
mask &= SATURN_IRQ_MASK;
return mask;
}
static inline void mask_saturn_irq(unsigned int irq_nr)
{
u32 mask;
mask = ctrl_inl(SATURN_IMR);
mask |= saturn_irq_mask(irq_nr);
ctrl_outl(mask, SATURN_IMR);
}
static inline void unmask_saturn_irq(unsigned int irq_nr)
{
u32 mask;
mask = ctrl_inl(SATURN_IMR);
mask &= ~saturn_irq_mask(irq_nr);
ctrl_outl(SATURN_IMR);
}
static void disable_saturn_irq(unsigned int irq_nr)
{
mask_saturn_irq(irq_nr);
}
static void enable_saturn_irq(unsigned int irq_nr)
{
unmask_saturn_irq(irq_nr);
}
static void mask_and_ack_saturn_irq(unsigned int irq_nr)
{
mask_saturn_irq(irq_nr);
}
static void end_saturn_irq(unsigned int irq_nr)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
unmask_saturn_irq(irq_nr);
}
static unsigned int startup_saturn_irq(unsigned int irq_nr)
{
unmask_saturn_irq(irq_nr);
return 0;
}
static void shutdown_saturn_irq(unsigned int irq_nr)
{
mask_saturn_irq(irq_nr);
}
static struct hw_interrupt_type saturn_int = {
typename: "Saturn",
enable: enable_saturn_irq,
disable: disable_saturn_irq,
ack: mask_and_ack_saturn_irq,
end: end_saturn_irq,
startup: startup_saturn_irq,
shutdown: shutdown_saturn_irq,
};
int saturn_irq_demux(int irq_nr)
{
/* FIXME */
return irq_nr;
}
/*
* arch/sh/boards/saturn/mach.c
*
* machvec definitions for the Sega Saturn.
*
* Copyright (C) 2002 Paul Mundt
*
* Released under the terms of the GNU GPL v2.0.
*/
#include <asm/io.h>
#include <asm/io_generic.h>
#include <asm/machvec.h>
#include <asm/machvec_init.h>
#include <asm/rtc.h>
#include <asm/saturn/io.h>
/*
* The Machine Vector
*/
struct sh_machine_vector mv_saturn __initmv = {
mv_nr_irqs: 80, /* Fix this later */
mv_inb: generic_inb,
mv_inw: generic_inw,
mv_inl: generic_inl,
mv_outb: generic_outb,
mv_outw: generic_outw,
mv_outl: generic_outl,
mv_inb_p: generic_inb_p,
mv_inw_p: generic_inw_p,
mv_inl_p: generic_inl_p,
mv_outb_p: generic_outb_p,
mv_outw_p: generic_outw_p,
mv_outl_p: generic_outl_p,
mv_insb: generic_insb,
mv_insw: generic_insw,
mv_insl: generic_insl,
mv_outsb: generic_outsb,
mv_outsw: generic_outsw,
mv_outsl: generic_outsl,
mv_readb: generic_readb,
mv_readw: generic_readw,
mv_readl: generic_readl,
mv_writeb: generic_writeb,
mv_writew: generic_writew,
mv_writel: generic_writel,
mv_isa_port2addr: saturn_isa_port2addr,
mv_irq_demux: saturn_irq_demux,
mv_ioremap: saturn_ioremap,
mv_iounmap: saturn_iounmap,
mv_hw_saturn: 1,
};
ALIAS_MV(saturn)
/*
* arch/sh/boards/saturn/setup.c
*
* Hardware support for the Sega Saturn.
*
* Copyright (c) 2002 Paul Mundt
*
* Released under the terms of the GNU GPL v2.0.
*/
#include <linux/kernel.h>
#include <linux/init.h>
const char *get_system_type(void)
{
return "Sega Saturn";
}
int __init platform_setup(void)
{
return 0;
}
/*
* arch/sh/boards/saturn/smp.c
*
* SMP support for the Sega Saturn.
*
* Copyright (c) 2002 Paul Mundt
*
* Released under the terms of the GNU GPL v2.0.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/smp.h>
#include <asm/saturn/smpc.h>
extern void start_secondary(void);
void __smp_send_ipi(unsigned int cpu, unsigned int action)
{
/* Nothing here yet .. */
}
unsigned int __smp_probe_cpus(void)
{
/*
* This is just a straightforward master/slave configuration,
* and probing isn't really supported..
*/
return 2;
}
/*
* We're only allowed to do byte-access to SMPC registers. In
* addition to which, we treat them as write-only, since
* reading from them will return undefined data.
*/
static inline void smpc_slave_off(unsigned int cpu)
{
smpc_barrier();
ctrl_outb(1, SMPC_STATUS);
ctrl_outb(SMPC_CMD_SSHOFF, SMPC_COMMAND);
smpc_barrier();
}
static inline void smpc_slave_on(unsigned int cpu)
{
ctrl_outb(1, SMPC_STATUS);
ctrl_outb(SMPC_CMD_SSHON, SMPC_COMMAND);
smpc_barrier();
}
void __smp_slave_init(unsigned int cpu)
{
register unsigned long vbr;
void **entry;
__asm__ __volatile__ ("stc vbr, %0\n\t" : "=r" (vbr));
entry = (void **)(vbr + 0x310 + 0x94);
smpc_slave_stop(cpu);
*(void **)entry = (void *)start_secondary;
smpc_slave_start(cpu);
}
#
# Makefile for the 770x SolutionEngine specific parts of the kernel
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
obj-y := mach.o setup.o io.o irq.o led.o
/* $Id: io_se.c,v 1.12 2001/08/11 01:23:28 jzs Exp $
/* $Id: io.c,v 1.1.2.2 2002/01/20 05:03:25 mrbrown Exp $
*
* linux/arch/sh/kernel/io_se.c
*
......@@ -11,7 +11,7 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <asm/io.h>
#include <asm/hitachi_se.h>
#include <asm/se/se.h>
/* SH pcmcia io window base, start and end. */
int sh_pcic_io_wbase = 0xb8400000;
......
/* $Id: irq.c,v 1.1.2.2 2002/10/29 00:56:09 lethal Exp $
*
* linux/arch/sh/boards/se/770x/irq.c
*
* Copyright (C) 2000 Kazumoto Kojima
*
* Hitachi SolutionEngine Support.
*
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <asm/hitachi_se.h>
/*
* Initialize IRQ setting
*/
void __init init_se_IRQ(void)
{
/*
* Super I/O (Just mimic PC):
* 1: keyboard
* 3: serial 0
* 4: serial 1
* 5: printer
* 6: floppy
* 8: rtc
* 12: mouse
* 14: ide0
*/
make_ipr_irq(14, BCR_ILCRA, 2, 0x0f-14);
make_ipr_irq(12, BCR_ILCRA, 1, 0x0f-12);
make_ipr_irq( 8, BCR_ILCRB, 1, 0x0f- 8);
make_ipr_irq( 6, BCR_ILCRC, 3, 0x0f- 6);
make_ipr_irq( 5, BCR_ILCRC, 2, 0x0f- 5);
make_ipr_irq( 4, BCR_ILCRC, 1, 0x0f- 4);
make_ipr_irq( 3, BCR_ILCRC, 0, 0x0f- 3);
make_ipr_irq( 1, BCR_ILCRD, 3, 0x0f- 1);
make_ipr_irq(10, BCR_ILCRD, 1, 0x0f-10); /* LAN */
make_ipr_irq( 0, BCR_ILCRE, 3, 0x0f- 0); /* PCIRQ3 */
make_ipr_irq(11, BCR_ILCRE, 2, 0x0f-11); /* PCIRQ2 */
make_ipr_irq( 9, BCR_ILCRE, 1, 0x0f- 9); /* PCIRQ1 */
make_ipr_irq( 7, BCR_ILCRE, 0, 0x0f- 7); /* PCIRQ0 */
/* #2, #13 are allocated for SLOT IRQ #1 and #2 (for now) */
/* NOTE: #2 and #13 are not used on PC */
make_ipr_irq(13, BCR_ILCRG, 1, 0x0f-13); /* SLOTIRQ2 */
make_ipr_irq( 2, BCR_ILCRG, 0, 0x0f- 2); /* SLOTIRQ1 */
}
......@@ -10,7 +10,7 @@
*/
#include <linux/config.h>
#include <asm/hitachi_se.h>
#include <asm/se/se.h>
static void mach_led(int position, int value)
{
......
......@@ -16,7 +16,7 @@
#include <asm/rtc.h>
#include <asm/machvec_init.h>
#include <asm/io_se.h>
#include <asm/se/io.h>
void heartbeat_se(void);
void setup_se(void);
......@@ -27,58 +27,51 @@ void init_se_IRQ(void);
*/
struct sh_machine_vector mv_se __initmv = {
.mv_name = "SolutionEngine",
#if defined(__SH4__)
.mv_nr_irqs = 48,
#if defined(CONFIG_CPU_SH4)
mv_nr_irqs: 48,
#elif defined(CONFIG_CPU_SUBTYPE_SH7708)
.mv_nr_irqs = 32,
mv_nr_irqs: 32,
#elif defined(CONFIG_CPU_SUBTYPE_SH7709)
.mv_nr_irqs = 61,
mv_nr_irqs: 61,
#endif
.mv_inb = se_inb,
.mv_inw = se_inw,
.mv_inl = se_inl,
.mv_outb = se_outb,
.mv_outw = se_outw,
.mv_outl = se_outl,
.mv_inb_p = se_inb_p,
.mv_inw_p = se_inw,
.mv_inl_p = se_inl,
.mv_outb_p = se_outb_p,
.mv_outw_p = se_outw,
.mv_outl_p = se_outl,
.mv_insb = se_insb,
.mv_insw = se_insw,
.mv_insl = se_insl,
.mv_outsb = se_outsb,
.mv_outsw = se_outsw,
.mv_outsl = se_outsl,
.mv_readb = se_readb,
.mv_readw = se_readw,
.mv_readl = se_readl,
.mv_writeb = se_writeb,
.mv_writew = se_writew,
.mv_writel = se_writel,
.mv_ioremap = generic_ioremap,
.mv_iounmap = generic_iounmap,
.mv_isa_port2addr = se_isa_port2addr,
.mv_init_arch = setup_se,
.mv_init_irq = init_se_IRQ,
mv_inb: se_inb,
mv_inw: se_inw,
mv_inl: se_inl,
mv_outb: se_outb,
mv_outw: se_outw,
mv_outl: se_outl,
mv_inb_p: se_inb_p,
mv_inw_p: se_inw,
mv_inl_p: se_inl,
mv_outb_p: se_outb_p,
mv_outw_p: se_outw,
mv_outl_p: se_outl,
mv_insb: se_insb,
mv_insw: se_insw,
mv_insl: se_insl,
mv_outsb: se_outsb,
mv_outsw: se_outsw,
mv_outsl: se_outsl,
mv_readb: se_readb,
mv_readw: se_readw,
mv_readl: se_readl,
mv_writeb: se_writeb,
mv_writew: se_writew,
mv_writel: se_writel,
mv_ioremap: generic_ioremap,
mv_iounmap: generic_iounmap,
mv_isa_port2addr: se_isa_port2addr,
mv_init_irq: init_se_IRQ,
#ifdef CONFIG_HEARTBEAT
.mv_heartbeat = heartbeat_se,
mv_heartbeat: heartbeat_se,
#endif
.mv_rtc_gettimeofday = sh_rtc_gettimeofday,
.mv_rtc_settimeofday = sh_rtc_settimeofday,
.mv_hw_se = 1,
mv_hw_se: 1,
};
ALIAS_MV(se)
/* $Id: setup_se.c,v 1.6 2000/05/14 08:41:25 gniibe Exp $
/* $Id: setup.c,v 1.1.2.4 2002/03/02 21:57:07 lethal Exp $
*
* linux/arch/sh/kernel/setup_se.c
* linux/arch/sh/boards/se/770x/setup.c
*
* Copyright (C) 2000 Kazumoto Kojima
*
......@@ -15,8 +15,8 @@
#include <linux/hdreg.h>
#include <linux/ide.h>
#include <asm/io.h>
#include <asm/hitachi_se.h>
#include <asm/smc37c93x.h>
#include <asm/se/se.h>
#include <asm/se/smc37c93x.h>
/*
* Configure the Super I/O chip
......@@ -70,49 +70,15 @@ static void __init init_smsc(void)
outb_p(CONFIG_EXIT, CONFIG_PORT);
}
/*
* Initialize IRQ setting
*/
void __init init_se_IRQ(void)
const char *get_system_type(void)
{
/*
* Super I/O (Just mimic PC):
* 1: keyboard
* 3: serial 0
* 4: serial 1
* 5: printer
* 6: floppy
* 8: rtc
* 12: mouse
* 14: ide0
*/
make_ipr_irq(14, BCR_ILCRA, 2, 0x0f-14);
make_ipr_irq(12, BCR_ILCRA, 1, 0x0f-12);
make_ipr_irq( 8, BCR_ILCRB, 1, 0x0f- 8);
make_ipr_irq( 6, BCR_ILCRC, 3, 0x0f- 6);
make_ipr_irq( 5, BCR_ILCRC, 2, 0x0f- 5);
make_ipr_irq( 4, BCR_ILCRC, 1, 0x0f- 4);
make_ipr_irq( 3, BCR_ILCRC, 0, 0x0f- 3);
make_ipr_irq( 1, BCR_ILCRD, 3, 0x0f- 1);
make_ipr_irq(10, BCR_ILCRD, 1, 0x0f-10); /* LAN */
make_ipr_irq( 0, BCR_ILCRE, 3, 0x0f- 0); /* PCIRQ3 */
make_ipr_irq(11, BCR_ILCRE, 2, 0x0f-11); /* PCIRQ2 */
make_ipr_irq( 9, BCR_ILCRE, 1, 0x0f- 9); /* PCIRQ1 */
make_ipr_irq( 7, BCR_ILCRE, 0, 0x0f- 7); /* PCIRQ0 */
/* #2, #13 are allocated for SLOT IRQ #1 and #2 (for now) */
/* NOTE: #2 and #13 are not used on PC */
make_ipr_irq(13, BCR_ILCRG, 1, 0x0f-13); /* SLOTIRQ2 */
make_ipr_irq( 2, BCR_ILCRG, 0, 0x0f- 2); /* SLOTIRQ1 */
return "SolutionEngine";
}
/*
* Initialize the board
*/
void __init setup_se(void)
void __init platform_setup(void)
{
init_smsc();
/* XXX: RTC setting comes here */
......
#
# Makefile for the 7751 SolutionEngine specific parts of the kernel
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
obj-y := mach.o setup.o io.o irq.o led.o
obj-$(CONFIG_PCI) += pci.o
......@@ -14,7 +14,7 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <asm/io.h>
#include <asm/hitachi_7751se.h>
#include <asm/se7751/se7751.h>
#include <asm/addrspace.h>
#include <linux/pci.h>
......@@ -97,7 +97,7 @@ shifted_port(unsigned long port)
#define CHECK_SH7751_PCIIO(port) \
((port >= PCIBIOS_MIN_IO) && (port < (PCIBIOS_MIN_IO + SH7751_PCI_IO_SIZE)))
#else
#define CHECK_SH_7751_PCIIO(port) (0)
#define CHECK_SH7751_PCIIO(port) (0)
#endif
/*
......
/*
* linux/arch/sh/boards/se/7751/irq.c
*
* Copyright (C) 2000 Kazumoto Kojima
*
* Hitachi SolutionEngine Support.
*
* Modified for 7751 Solution Engine by
* Ian da Silva and Jeremy Siegel, 2001.
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <asm/se7751/se7751.h>
/*
* Initialize IRQ setting
*/
void __init init_7751se_IRQ(void)
{
/* Leave old Solution Engine code in for reference. */
#if defined(CONFIG_SH_SOLUTION_ENGINE)
/*
* Super I/O (Just mimic PC):
* 1: keyboard
* 3: serial 0
* 4: serial 1
* 5: printer
* 6: floppy
* 8: rtc
* 12: mouse
* 14: ide0
*/
make_ipr_irq(14, BCR_ILCRA, 2, 0x0f-14);
make_ipr_irq(12, BCR_ILCRA, 1, 0x0f-12);
make_ipr_irq( 8, BCR_ILCRB, 1, 0x0f- 8);
make_ipr_irq( 6, BCR_ILCRC, 3, 0x0f- 6);
make_ipr_irq( 5, BCR_ILCRC, 2, 0x0f- 5);
make_ipr_irq( 4, BCR_ILCRC, 1, 0x0f- 4);
make_ipr_irq( 3, BCR_ILCRC, 0, 0x0f- 3);
make_ipr_irq( 1, BCR_ILCRD, 3, 0x0f- 1);
make_ipr_irq(10, BCR_ILCRD, 1, 0x0f-10); /* LAN */
make_ipr_irq( 0, BCR_ILCRE, 3, 0x0f- 0); /* PCIRQ3 */
make_ipr_irq(11, BCR_ILCRE, 2, 0x0f-11); /* PCIRQ2 */
make_ipr_irq( 9, BCR_ILCRE, 1, 0x0f- 9); /* PCIRQ1 */
make_ipr_irq( 7, BCR_ILCRE, 0, 0x0f- 7); /* PCIRQ0 */
/* #2, #13 are allocated for SLOT IRQ #1 and #2 (for now) */
/* NOTE: #2 and #13 are not used on PC */
make_ipr_irq(13, BCR_ILCRG, 1, 0x0f-13); /* SLOTIRQ2 */
make_ipr_irq( 2, BCR_ILCRG, 0, 0x0f- 2); /* SLOTIRQ1 */
#elif defined(CONFIG_SH_7751_SOLUTION_ENGINE)
make_ipr_irq(13, BCR_ILCRD, 3, 2);
/* Add additional calls to make_ipr_irq() as drivers are added
* and tested.
*/
#endif
}
......@@ -10,7 +10,7 @@
*/
#include <linux/config.h>
#include <asm/hitachi_7751se.h>
#include <asm/se7751/se7751.h>
static void mach_led(int position, int value)
{
......
......@@ -16,10 +16,9 @@
#include <asm/rtc.h>
#include <asm/machvec_init.h>
#include <asm/io_7751se.h>
#include <asm/se7751/io.h>
void heartbeat_7751se(void);
void setup_7751se(void);
void init_7751se_IRQ(void);
/*
......@@ -27,52 +26,45 @@ void init_7751se_IRQ(void);
*/
struct sh_machine_vector mv_7751se __initmv = {
.mv_name = "7751 SolutionEngine",
.mv_nr_irqs = 72,
.mv_inb = sh7751se_inb,
.mv_inw = sh7751se_inw,
.mv_inl = sh7751se_inl,
.mv_outb = sh7751se_outb,
.mv_outw = sh7751se_outw,
.mv_outl = sh7751se_outl,
.mv_inb_p = sh7751se_inb_p,
.mv_inw_p = sh7751se_inw,
.mv_inl_p = sh7751se_inl,
.mv_outb_p = sh7751se_outb_p,
.mv_outw_p = sh7751se_outw,
.mv_outl_p = sh7751se_outl,
.mv_insb = sh7751se_insb,
.mv_insw = sh7751se_insw,
.mv_insl = sh7751se_insl,
.mv_outsb = sh7751se_outsb,
.mv_outsw = sh7751se_outsw,
.mv_outsl = sh7751se_outsl,
.mv_readb = sh7751se_readb,
.mv_readw = sh7751se_readw,
.mv_readl = sh7751se_readl,
.mv_writeb = sh7751se_writeb,
.mv_writew = sh7751se_writew,
.mv_writel = sh7751se_writel,
.mv_ioremap = generic_ioremap,
.mv_iounmap = generic_iounmap,
.mv_isa_port2addr = sh7751se_isa_port2addr,
.mv_init_arch = setup_7751se,
.mv_init_irq = init_7751se_IRQ,
mv_nr_irqs: 72,
mv_inb: sh7751se_inb,
mv_inw: sh7751se_inw,
mv_inl: sh7751se_inl,
mv_outb: sh7751se_outb,
mv_outw: sh7751se_outw,
mv_outl: sh7751se_outl,
mv_inb_p: sh7751se_inb_p,
mv_inw_p: sh7751se_inw,
mv_inl_p: sh7751se_inl,
mv_outb_p: sh7751se_outb_p,
mv_outw_p: sh7751se_outw,
mv_outl_p: sh7751se_outl,
mv_insb: sh7751se_insb,
mv_insw: sh7751se_insw,
mv_insl: sh7751se_insl,
mv_outsb: sh7751se_outsb,
mv_outsw: sh7751se_outsw,
mv_outsl: sh7751se_outsl,
mv_readb: sh7751se_readb,
mv_readw: sh7751se_readw,
mv_readl: sh7751se_readl,
mv_writeb: sh7751se_writeb,
mv_writew: sh7751se_writew,
mv_writel: sh7751se_writel,
mv_ioremap: generic_ioremap,
mv_iounmap: generic_iounmap,
mv_isa_port2addr: sh7751se_isa_port2addr,
mv_init_irq: init_7751se_IRQ,
#ifdef CONFIG_HEARTBEAT
.mv_heartbeat = heartbeat_7751se,
mv_heartbeat: heartbeat_7751se,
#endif
.mv_rtc_gettimeofday = sh_rtc_gettimeofday,
.mv_rtc_settimeofday = sh_rtc_settimeofday,
.mv_hw_7751se = 1,
mv_hw_7751se: 1,
};
ALIAS_MV(7751se)
......@@ -16,7 +16,11 @@
#include <linux/hdreg.h>
#include <linux/ide.h>
#include <asm/io.h>
#include <asm/hitachi_7751se.h>
#include <asm/se7751/se7751.h>
#ifdef CONFIG_SH_KGDB
#include <asm/kgdb.h>
#endif
/*
* Configure the Super I/O chip
......@@ -74,63 +78,151 @@ static void __init init_smsc(void)
}
#endif
const char *get_system_type(void)
{
return "7751 SolutionEngine";
}
#ifdef CONFIG_SH_KGDB
static int kgdb_uart_setup(void);
static struct kgdb_sermap kgdb_uart_sermap =
{ "ttyS", 0, kgdb_uart_setup, NULL };
#endif
/*
* Initialize IRQ setting
* Initialize the board
*/
void __init init_7751se_IRQ(void)
void __init platform_setup(void)
{
/* Leave old Solution Engine code in for reference. */
#if defined(CONFIG_SH_SOLUTION_ENGINE)
/*
* Super I/O (Just mimic PC):
* 1: keyboard
* 3: serial 0
* 4: serial 1
* 5: printer
* 6: floppy
* 8: rtc
* 12: mouse
* 14: ide0
*/
make_ipr_irq(14, BCR_ILCRA, 2, 0x0f-14);
make_ipr_irq(12, BCR_ILCRA, 1, 0x0f-12);
make_ipr_irq( 8, BCR_ILCRB, 1, 0x0f- 8);
make_ipr_irq( 6, BCR_ILCRC, 3, 0x0f- 6);
make_ipr_irq( 5, BCR_ILCRC, 2, 0x0f- 5);
make_ipr_irq( 4, BCR_ILCRC, 1, 0x0f- 4);
make_ipr_irq( 3, BCR_ILCRC, 0, 0x0f- 3);
make_ipr_irq( 1, BCR_ILCRD, 3, 0x0f- 1);
make_ipr_irq(10, BCR_ILCRD, 1, 0x0f-10); /* LAN */
make_ipr_irq( 0, BCR_ILCRE, 3, 0x0f- 0); /* PCIRQ3 */
make_ipr_irq(11, BCR_ILCRE, 2, 0x0f-11); /* PCIRQ2 */
make_ipr_irq( 9, BCR_ILCRE, 1, 0x0f- 9); /* PCIRQ1 */
make_ipr_irq( 7, BCR_ILCRE, 0, 0x0f- 7); /* PCIRQ0 */
/* #2, #13 are allocated for SLOT IRQ #1 and #2 (for now) */
/* NOTE: #2 and #13 are not used on PC */
make_ipr_irq(13, BCR_ILCRG, 1, 0x0f-13); /* SLOTIRQ2 */
make_ipr_irq( 2, BCR_ILCRG, 0, 0x0f- 2); /* SLOTIRQ1 */
#elif defined(CONFIG_SH_7751_SOLUTION_ENGINE)
make_ipr_irq(13, BCR_ILCRD, 3, 2);
/* Add additional calls to make_ipr_irq() as drivers are added
* and tested.
*/
/* Call init_smsc() replacement to set up SuperIO. */
/* XXX: RTC setting comes here */
#ifdef CONFIG_SH_KGDB
kgdb_register_sermap(&kgdb_uart_sermap);
#endif
}
/*********************************************************************
* Currently a hack (e.g. does not interact well w/serial.c, lots of *
* hardcoded stuff) but may be useful if SCI/F needs debugging. *
* Mostly copied from x86 code (see files asm-i386/kgdb_local.h and *
* arch/i386/lib/kgdb_serial.c). *
*********************************************************************/
#ifdef CONFIG_SH_KGDB
#include <linux/types.h>
#include <linux/serial.h>
#include <linux/serialP.h>
#include <linux/serial_reg.h>
#define COM1_PORT 0x3f8 /* Base I/O address */
#define COM1_IRQ 4 /* IRQ not used yet */
#define COM2_PORT 0x2f8 /* Base I/O address */
#define COM2_IRQ 3 /* IRQ not used yet */
#define SB_CLOCK 1843200 /* Serial baud clock */
#define SB_BASE (SB_CLOCK/16)
#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS
struct uart_port {
int base;
};
#define UART_NPORTS 2
struct uart_port uart_ports[] = {
{ COM1_PORT },
{ COM2_PORT },
};
struct uart_port *kgdb_uart_port;
#define UART_IN(reg) inb_p(kgdb_uart_port->base + reg)
#define UART_OUT(reg,v) outb_p((v), kgdb_uart_port->base + reg)
/* Basic read/write functions for the UART */
#define UART_LSR_RXCERR (UART_LSR_BI | UART_LSR_FE | UART_LSR_PE)
static int kgdb_uart_getchar(void)
{
int lsr;
int c = -1;
while (c == -1) {
lsr = UART_IN(UART_LSR);
if (lsr & UART_LSR_DR)
c = UART_IN(UART_RX);
if ((lsr & UART_LSR_RXCERR))
c = -1;
}
return c;
}
static void kgdb_uart_putchar(int c)
{
while ((UART_IN(UART_LSR) & UART_LSR_THRE) == 0)
;
UART_OUT(UART_TX, c);
}
/*
* Initialize the board
* Initialize UART to configured/requested values.
* (But we don't interrupts yet, or interact w/serial.c)
*/
void __init setup_7751se(void)
static int kgdb_uart_setup(void)
{
/* Call init_smsc() replacement to set up SuperIO. */
/* XXX: RTC setting comes here */
int port;
int lcr = 0;
int bdiv = 0;
if (kgdb_portnum >= UART_NPORTS) {
KGDB_PRINTK("uart port %d invalid.\n", kgdb_portnum);
return -1;
}
kgdb_uart_port = &uart_ports[kgdb_portnum];
/* Init sequence from gdb_hook_interrupt */
UART_IN(UART_RX);
UART_OUT(UART_IER, 0);
UART_IN(UART_RX); /* Serial driver comments say */
UART_IN(UART_IIR); /* this clears interrupt regs */
UART_IN(UART_MSR);
/* Figure basic LCR values */
switch (kgdb_bits) {
case '7':
lcr |= UART_LCR_WLEN7;
break;
default: case '8':
lcr |= UART_LCR_WLEN8;
break;
}
switch (kgdb_parity) {
case 'O':
lcr |= UART_LCR_PARITY;
break;
case 'E':
lcr |= (UART_LCR_PARITY | UART_LCR_EPAR);
break;
default: break;
}
/* Figure the baud rate divisor */
bdiv = (SB_BASE/kgdb_baud);
/* Set the baud rate and LCR values */
UART_OUT(UART_LCR, (lcr | UART_LCR_DLAB));
UART_OUT(UART_DLL, (bdiv & 0xff));
UART_OUT(UART_DLM, ((bdiv >> 8) & 0xff));
UART_OUT(UART_LCR, lcr);
/* Set the MCR */
UART_OUT(UART_MCR, SB_MCR);
/* Turn off FIFOs for now */
UART_OUT(UART_FCR, 0);
/* Setup complete: initialize function pointers */
kgdb_getchar = kgdb_uart_getchar;
kgdb_putchar = kgdb_uart_putchar;
return 0;
}
#endif /* CONFIG_SH_KGDB */
#
# Makefile for the SH2000 specific parts of the kernel
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
obj-y := mach.o setup.o io.o
/*
* linux/arch/sh/boards/sh2000/mach.c
*
* Original copyright message:
* Copyright (C) 2001 SUGIOKA Tochinobu
*
* Split into mach.c from setup.c by M. R. Brown <mrbrown@0xd6.org>
*/
#include <asm/io.h>
#include <asm/io_generic.h>
#include <asm/machvec.h>
#include <asm/machvec_init.h>
#include <asm/rtc.h>
#include <asm/sh2000/sh2000.h>
/*
* The Machine Vector
*/
struct sh_machine_vector mv_sh2000 __initmv = {
mv_nr_irqs: 80,
mv_inb: generic_inb,
mv_inw: generic_inw,
mv_inl: generic_inl,
mv_outb: generic_outb,
mv_outw: generic_outw,
mv_outl: generic_outl,
mv_inb_p: generic_inb_p,
mv_inw_p: generic_inw_p,
mv_inl_p: generic_inl_p,
mv_outb_p: generic_outb_p,
mv_outw_p: generic_outw_p,
mv_outl_p: generic_outl_p,
mv_insb: generic_insb,
mv_insw: generic_insw,
mv_insl: generic_insl,
mv_outsb: generic_outsb,
mv_outsw: generic_outsw,
mv_outsl: generic_outsl,
mv_readb: generic_readb,
mv_readw: generic_readw,
mv_readl: generic_readl,
mv_writeb: generic_writeb,
mv_writew: generic_writew,
mv_writel: generic_writel,
mv_isa_port2addr: sh2000_isa_port2addr,
mv_ioremap: generic_ioremap,
mv_iounmap: generic_iounmap,
mv_hw_sh2000: 1,
};
ALIAS_MV(sh2000)
......@@ -12,10 +12,6 @@
#include <linux/irq.h>
#include <asm/io.h>
#include <asm/io_generic.h>
#include <asm/machvec.h>
#include <asm/machvec_init.h>
#include <asm/rtc.h>
#define CF_CIS_BASE 0xb4200000
......@@ -24,10 +20,15 @@
#define PORT_ICR1 0xa4000010
#define PORT_IRR0 0xa4000004
const char *get_system_type(void)
{
return "sh2000";
}
/*
* Initialize the board
*/
int __init setup_sh2000(void)
int __init platform_setup(void)
{
/* XXX: RTC setting comes here */
......@@ -43,53 +44,3 @@ int __init setup_sh2000(void)
printk(KERN_INFO "SH-2000 Setup...done\n");
return 0;
}
/*
* The Machine Vector
*/
struct sh_machine_vector mv_sh2000 __initmv = {
.mv_name = "sh2000",
.mv_nr_irqs = 80,
.mv_inb = generic_inb,
.mv_inw = generic_inw,
.mv_inl = generic_inl,
.mv_outb = generic_outb,
.mv_outw = generic_outw,
.mv_outl = generic_outl,
.mv_inb_p = generic_inb_p,
.mv_inw_p = generic_inw_p,
.mv_inl_p = generic_inl_p,
.mv_outb_p = generic_outb_p,
.mv_outw_p = generic_outw_p,
.mv_outl_p = generic_outl_p,
.mv_insb = generic_insb,
.mv_insw = generic_insw,
.mv_insl = generic_insl,
.mv_outsb = generic_outsb,
.mv_outsw = generic_outsw,
.mv_outsl = generic_outsl,
.mv_readb = generic_readb,
.mv_readw = generic_readw,
.mv_readl = generic_readl,
.mv_writeb = generic_writeb,
.mv_writew = generic_writew,
.mv_writel = generic_writel,
.mv_init_arch = setup_sh2000,
.mv_isa_port2addr = sh2000_isa_port2addr,
.mv_ioremap = generic_ioremap,
.mv_iounmap = generic_iounmap,
.mv_rtc_gettimeofday = sh_rtc_gettimeofday,
.mv_rtc_settimeofday = sh_rtc_settimeofday,
.mv_hw_sh2000 = 1,
};
ALIAS_MV(sh2000)
#
# Makefile for unknown SH boards
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
obj-y := mach.o io.o setup.o
......@@ -23,50 +23,45 @@
*/
struct sh_machine_vector mv_unknown __initmv = {
.mv_name = "Unknown",
#if defined(__SH4__)
.mv_nr_irqs = 48,
#if defined(CONFIG_CPU_SH4)
mv_nr_irqs: 48,
#elif defined(CONFIG_CPU_SUBTYPE_SH7708)
.mv_nr_irqs = 32,
mv_nr_irqs: 32,
#elif defined(CONFIG_CPU_SUBTYPE_SH7709)
.mv_nr_irqs = 61,
mv_nr_irqs: 61,
#endif
.mv_inb = unknown_inb,
.mv_inw = unknown_inw,
.mv_inl = unknown_inl,
.mv_outb = unknown_outb,
.mv_outw = unknown_outw,
.mv_outl = unknown_outl,
.mv_inb_p = unknown_inb_p,
.mv_inw_p = unknown_inw_p,
.mv_inl_p = unknown_inl_p,
.mv_outb_p = unknown_outb_p,
.mv_outw_p = unknown_outw_p,
.mv_outl_p = unknown_outl_p,
mv_inb: unknown_inb,
mv_inw: unknown_inw,
mv_inl: unknown_inl,
mv_outb: unknown_outb,
mv_outw: unknown_outw,
mv_outl: unknown_outl,
.mv_insb = unknown_insb,
.mv_insw = unknown_insw,
.mv_insl = unknown_insl,
.mv_outsb = unknown_outsb,
.mv_outsw = unknown_outsw,
.mv_outsl = unknown_outsl,
mv_inb_p: unknown_inb_p,
mv_inw_p: unknown_inw_p,
mv_inl_p: unknown_inl_p,
mv_outb_p: unknown_outb_p,
mv_outw_p: unknown_outw_p,
mv_outl_p: unknown_outl_p,
.mv_readb = unknown_readb,
.mv_readw = unknown_readw,
.mv_readl = unknown_readl,
.mv_writeb = unknown_writeb,
.mv_writew = unknown_writew,
.mv_writel = unknown_writel,
mv_insb: unknown_insb,
mv_insw: unknown_insw,
mv_insl: unknown_insl,
mv_outsb: unknown_outsb,
mv_outsw: unknown_outsw,
mv_outsl: unknown_outsl,
.mv_ioremap = unknown_ioremap,
.mv_iounmap = unknown_iounmap,
mv_readb: unknown_readb,
mv_readw: unknown_readw,
mv_readl: unknown_readl,
mv_writeb: unknown_writeb,
mv_writew: unknown_writew,
mv_writel: unknown_writel,
.mv_isa_port2addr = unknown_isa_port2addr,
mv_ioremap: unknown_ioremap,
mv_iounmap: unknown_iounmap,
.mv_rtc_gettimeofday = sh_rtc_gettimeofday,
.mv_rtc_settimeofday = sh_rtc_settimeofday,
mv_isa_port2addr: unknown_isa_port2addr,
};
ALIAS_MV(unknown)
/*
* linux/arch/sh/boards/unknown/setup.c
*
* Copyright (C) 2002 Paul Mundt
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* Setup code for an unknown machine (internal peripherials only)
*/
#include <linux/config.h>
#include <linux/init.h>
const char *get_system_type(void)
{
return "Unknown";
}
void __init platform_setup(void)
{
}
#
# Makefile for the HD64461
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
obj-y := setup.o io.o
/*
* $Id: io_hd64461.c,v 1.6 2000/11/16 23:28:44 yaegashi Exp $
* $Id: io.c,v 1.1.2.2 2002/01/20 05:03:25 mrbrown Exp $
* Copyright (C) 2000 YAEGASHI Takeshi
* Typical I/O routines for HD64461 system.
*/
#include <linux/config.h>
#include <asm/io.h>
#include <asm/hd64461.h>
#include <asm/hd64461/hd64461.h>
static __inline__ unsigned long PORT2ADDR(unsigned long port)
{
......
/*
* $Id: setup_hd64461.c,v 1.9 2001/07/15 23:26:56 gniibe Exp $
* $Id: setup.c,v 1.1.2.3 2002/11/04 20:33:57 lethal Exp $
* Copyright (C) 2000 YAEGASHI Takeshi
* Hitachi HD64461 companion chip support
*/
......@@ -15,7 +15,7 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/hd64461.h>
#include <asm/hd64461/hd64461.h>
static void disable_hd64461_irq(unsigned int irq)
{
......@@ -23,11 +23,11 @@ static void disable_hd64461_irq(unsigned int irq)
unsigned short nimr;
unsigned short mask = 1 << (irq - HD64461_IRQBASE);
save_and_cli(flags);
local_irq_save(flags);
nimr = inw(HD64461_NIMR);
nimr |= mask;
outw(nimr, HD64461_NIMR);
restore_flags(flags);
local_irq_restore(flags);
}
......@@ -37,11 +37,11 @@ static void enable_hd64461_irq(unsigned int irq)
unsigned short nimr;
unsigned short mask = 1 << (irq - HD64461_IRQBASE);
save_and_cli(flags);
local_irq_save(flags);
nimr = inw(HD64461_NIMR);
nimr &= ~mask;
outw(nimr, HD64461_NIMR);
restore_flags(flags);
local_irq_restore(flags);
}
......
#
# Makefile for the HD64465
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
obj-y := setup.o io.o gpio.o
/*
* $Id: hd64465_gpio.c,v 1.2 2001/05/24 00:13:47 gniibe Exp $
* $Id: gpio.c,v 1.1.2.3 2002/11/04 20:33:57 lethal Exp $
* by Greg Banks <gbanks@pocketpenguins.com>
* (c) 2000 PocketPenguins Inc
*
......@@ -12,7 +12,7 @@
#include <linux/sched.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <asm/hd64465_gpio.h>
#include <asm/hd64465/gpio.h>
#define _PORTOF(portpin) (((portpin)>>3)&0x7)
#define _PINOF(portpin) ((portpin)&0x7)
......@@ -118,7 +118,7 @@ void hd64465_gpio_register_irq(int portpin, int mode,
if (handler == 0)
return;
save_and_cli(flags);
local_irq_save(flags);
handlers[portpin].func = handler;
handlers[portpin].dev = dev;
......@@ -140,7 +140,7 @@ void hd64465_gpio_register_irq(int portpin, int mode,
outw(icr, GPIO_ICR(_PORTOF(portpin)));
restore_flags(flags);
local_irq_restore(flags);
}
void hd64465_gpio_unregister_irq(int portpin)
......@@ -148,7 +148,7 @@ void hd64465_gpio_unregister_irq(int portpin)
unsigned long flags;
unsigned short icr;
save_and_cli(flags);
local_irq_save(flags);
/*
* Configure Interrupt Control Register
......@@ -160,24 +160,17 @@ void hd64465_gpio_unregister_irq(int portpin)
handlers[portpin].func = 0;
handlers[portpin].dev = 0;
restore_flags(flags);
local_irq_restore(flags);
}
static int __init hd64465_gpio_init(void)
{
int err;
if (!request_region(HD64465_REG_GPACR, 0x1000, MODNAME))
return -EIO;
err = request_irq (HD64465_IRQ_GPIO, hd64465_gpio_interrupt,
SA_INTERRUPT, MODNAME, 0);
if (err) {
printk(KERN_ERR"HD64465: Unable to get irq %d.\n", HD64465_IRQ_GPIO);
release_region(HD64465_REG_GPACR, 0x1000);
return err;
}
/* TODO: check return values */
request_region(HD64465_REG_GPACR, 0x1000, MODNAME);
request_irq(HD64465_IRQ_GPIO, hd64465_gpio_interrupt,
SA_INTERRUPT, MODNAME, 0);
printk("HD64465 GPIO layer on irq %d\n", HD64465_IRQ_GPIO);
printk("HD64465 GPIO layer on irq %d\n", HD64465_IRQ_GPIO);
return 0;
}
......
/*
* $Id: io_hd64465.c,v 1.7 2001/05/09 07:39:36 gniibe Exp $
* $Id: io.c,v 1.1.2.2 2002/01/20 05:03:25 mrbrown Exp $
* by Greg Banks <gbanks@pocketpenguins.com>
* (c) 2000 PocketPenguins Inc
*
......@@ -13,7 +13,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/io.h>
#include <asm/hd64465.h>
#include <asm/hd64465/hd64465.h>
#define HD64465_DEBUG 0
......
/*
* $Id: setup_hd64465.c,v 1.4 2001/07/15 23:26:56 gniibe Exp $
* $Id: setup.c,v 1.1.2.3 2002/11/04 20:33:57 lethal Exp $
*
* Setup and IRQ handling code for the HD64465 companion chip.
* by Greg Banks <gbanks@pocketpenguins.com>
......@@ -22,7 +22,7 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/hd64465.h>
#include <asm/hd64465/hd64465.h>
#undef HD64465_DEBUG
......@@ -39,11 +39,11 @@ static void disable_hd64465_irq(unsigned int irq)
unsigned short mask = 1 << (irq - HD64465_IRQ_BASE);
DPRINTK("disable_hd64465_irq(%d): mask=%x\n", irq, mask);
save_and_cli(flags);
local_irq_save(flags);
nimr = inw(HD64465_REG_NIMR);
nimr |= mask;
outw(nimr, HD64465_REG_NIMR);
restore_flags(flags);
local_irq_restore(flags);
}
......@@ -54,11 +54,11 @@ static void enable_hd64465_irq(unsigned int irq)
unsigned short mask = 1 << (irq - HD64465_IRQ_BASE);
DPRINTK("enable_hd64465_irq(%d): mask=%x\n", irq, mask);
save_and_cli(flags);
local_irq_save(flags);
nimr = inw(HD64465_REG_NIMR);
nimr &= ~mask;
outw(nimr, HD64465_REG_NIMR);
restore_flags(flags);
local_irq_restore(flags);
}
......@@ -89,13 +89,13 @@ static void shutdown_hd64465_irq(unsigned int irq)
static struct hw_interrupt_type hd64465_irq_type = {
.typename = "HD64465-IRQ",
.startup = startup_hd64465_irq,
.shutdown = shutdown_hd64465_irq,
.enable = enable_hd64465_irq,
.disable = disable_hd64465_irq,
.ack = mask_and_ack_hd64465,
.end = end_hd64465_irq
typename: "HD64465-IRQ",
startup: startup_hd64465_irq,
shutdown: shutdown_hd64465_irq,
enable: enable_hd64465_irq,
disable: disable_hd64465_irq,
ack: mask_and_ack_hd64465,
end: end_hd64465_irq
};
......
......@@ -4,68 +4,23 @@
extra-y := head.o init_task.o
obj-y := process.o signal.o entry.o traps.o irq.o irq_ipr.o \
obj-y := process.o signal.o entry.o traps.o irq.o \
ptrace.o setup.o time.o sys_sh.o semaphore.o \
irq_imask.o io.o io_generic.o sh_ksyms.o
io.o io_generic.o sh_ksyms.o
obj-y += cpu/
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_CF_ENABLER) += cf-enabler.o
obj-$(CONFIG_CPU_SH4) += fpu.o
obj-$(CONFIG_SH_RTC) += rtc.o
obj-$(CONFIG_SH_DMA) += dma.o
obj-$(CONFIG_SH_STANDARD_BIOS) += sh_bios.o
obj-$(CONFIG_SH_KGDB) += kgdb_stub.o kgdb_jmp.o
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
ifeq ($(CONFIG_PCI),y)
ifeq ($(CONFIG_SH_DREAMCAST),y)
obj-y += pci-dc.o pcibios.o
else
obj-y += pci-dma.o pcibios.o
obj-$(CONFIG_CPU_SUBTYPE_ST40STB1)+= pci_st40.o
obj-$(CONFIG_CPU_SUBTYPE_SH7751)+= pci-sh7751.o
obj-$(CONFIG_SH_BIGSUR)+= pci-bigsur.o
obj-$(CONFIG_SH_7751_SOLUTION_ENGINE)+= pci-7751se.o
endif
ifneq ($(CONFIG_SH_DREAMCAST),y)
obj-$(CONFIG_PCI) += pci-dma.o
endif
obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_PCI_AUTO) += pci_auto.o
obj-$(CONFIG_SH_HP600) += mach_hp600.o
machine-specific-objs += mach_hp600.o
obj-$(CONFIG_SH_SOLUTION_ENGINE)+= mach_se.o setup_se.o io_se.o led_se.o
machine-specific-objs += mach_se.o setup_se.o io_se.o led_se.o
obj-$(CONFIG_SH_7751_SOLUTION_ENGINE)+= mach_7751se.o setup_7751se.o \
io_7751se.o led_7751se.o
machine-specific-objs += mach_7751se.o 7751setup_se.o \
io_7751se.o led_7751se.o pci-7751se.o
obj-$(CONFIG_SH_BIGSUR) += mach_bigsur.o setup_bigsur.o io_bigsur.o led_bigsur.o
machine-specific-objs += mach_bigsur.o setup_bigsur.o io_bigsur.o led_bigsur.o
obj-$(CONFIG_SH_SH2000) += setup_sh2000.o io_sh2000.o
machine-specific-objs += setup_sh2000.o io_sh2000.o
obj-$(CONFIG_SH_CAT68701) += mach_cat68701.o io_cat68701.o
machine-specific-objs += mach_cat68701.o io_cat68701.o
USE_STANDARD_AS_RULE := true
obj-$(CONFIG_SH_CQREEK) += setup_cqreek.o
machine-specific-objs += setup_cqreek.o
obj-$(CONFIG_SH_UNKNOWN) += mach_unknown.o io_unknown.o
machine-specific-objs += mach_unknown.o io_unknown.o
obj-$(CONFIG_HD64461) += setup_hd64461.o io_hd64461.o
machine-specific-objs += setup_hd64461.o io_hd64461.o
obj-$(CONFIG_CPU_SUBTYPE_ST40STB1) +=irq_intc2.o
obj-$(CONFIG_SH_ADX) += mach_adx.o setup_adx.o io_adx.o irq_maskreg.o
machine-specific-objs += mach_adx.o setup_adx.o io_adx.o irq_maskreg.o
# Doesn't compile well, so don't include in machine-specific-objs
obj-$(CONFIG_HD64465) += setup_hd64465.o io_hd64465.o hd64465_gpio.o
obj-$(CONFIG_SH_DMIDA) += mach_dmida.o
obj-$(CONFIG_SH_EC3104) += setup_ec3104.o io_ec3104.o mach_ec3104.o
obj-$(CONFIG_SH_DREAMCAST) += mach_dc.o setup_dc.o io_dc.o rtc-aica.o
ifeq ($(CONFIG_SH_GENERIC),y)
obj-y += $(machine-specific-objs)
endif
/* $Id: io_generic.c,v 1.12 2000/11/14 16:45:11 sugioka Exp $
/* $Id: io_generic.c,v 1.1.1.1.4.2.2.1 2003/01/10 17:26:56 lethal Exp $
*
* linux/arch/sh/kernel/io_generic.c
*
......@@ -17,7 +17,7 @@
#include <asm/machvec.h>
#include <linux/module.h>
#if defined(__sh3__)
#if defined(CONFIG_CPU_SH3)
/* I'm not sure SH7709 has this kind of bug */
#define SH3_PCMCIA_BUG_WORKAROUND 1
#define DUMMY_READ_AREA6 0xba000000
......
/* $Id: irq_imask.c,v 1.13 2001/07/12 08:13:56 gniibe Exp $
*
* linux/arch/sh/kernel/irq_imask.c
*
* Copyright (C) 1999, 2000 Niibe Yutaka
*
* Simple interrupt handling using IMASK of SR register.
*
*/
/* NOTE: Will not work on level 15 */
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/kernel_stat.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <asm/system.h>
#include <asm/irq.h>
#include <asm/bitops.h>
#include <linux/spinlock.h>
#include <linux/cache.h>
#include <linux/irq.h>
/* Bitmap of IRQ masked */
static unsigned long imask_mask = 0x7fff;
static int interrupt_priority = 0;
static void enable_imask_irq(unsigned int irq);
static void disable_imask_irq(unsigned int irq);
static void shutdown_imask_irq(unsigned int irq);
static void mask_and_ack_imask(unsigned int);
static void end_imask_irq(unsigned int irq);
#define IMASK_PRIORITY 15
static unsigned int startup_imask_irq(unsigned int irq)
{
/* Nothing to do */
return 0; /* never anything pending */
}
static struct hw_interrupt_type imask_irq_type = {
"SR.IMASK",
startup_imask_irq,
shutdown_imask_irq,
enable_imask_irq,
disable_imask_irq,
mask_and_ack_imask,
end_imask_irq
};
void static inline set_interrupt_registers(int ip)
{
unsigned long __dummy;
asm volatile("ldc %2, r6_bank\n\t"
"stc sr, %0\n\t"
"and #0xf0, %0\n\t"
"shlr2 %0\n\t"
"cmp/eq #0x3c, %0\n\t"
"bt/s 1f ! CLI-ed\n\t"
" stc sr, %0\n\t"
"and %1, %0\n\t"
"or %2, %0\n\t"
"ldc %0, sr\n"
"1:"
: "=&z" (__dummy)
: "r" (~0xf0), "r" (ip << 4)
: "t");
}
static void disable_imask_irq(unsigned int irq)
{
clear_bit(irq, &imask_mask);
if (interrupt_priority < IMASK_PRIORITY - irq)
interrupt_priority = IMASK_PRIORITY - irq;
set_interrupt_registers(interrupt_priority);
}
static void enable_imask_irq(unsigned int irq)
{
set_bit(irq, &imask_mask);
interrupt_priority = IMASK_PRIORITY - ffz(imask_mask);
set_interrupt_registers(interrupt_priority);
}
static void mask_and_ack_imask(unsigned int irq)
{
disable_imask_irq(irq);
}
static void end_imask_irq(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
enable_imask_irq(irq);
}
static void shutdown_imask_irq(unsigned int irq)
{
/* Nothing to do */
}
void make_imask_irq(unsigned int irq)
{
disable_irq_nosync(irq);
irq_desc[irq].handler = &imask_irq_type;
enable_irq(irq);
}
/*
* linux/arch/sh/kernel/irq_intc2.c
*
* Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* Interrupt handling for INTC2-based IRQ.
*
* These are the "new Hitachi style" interrupts, as present on the
* Hitachi 7751 and the STM ST40 STB1.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/machvec.h>
struct intc2_data {
unsigned int addr; /* Address of Interrupt Priority Register */
int mask; /*Mask to apply */
};
static struct intc2_data intc2_data[NR_INTC2_IRQS];
static void enable_intc2_irq(unsigned int irq);
static void disable_intc2_irq(unsigned int irq);
/* shutdown is same as "disable" */
#define shutdown_intc2_irq disable_intc2_irq
static void mask_and_ack_intc2(unsigned int);
static void end_intc2_irq(unsigned int irq);
static unsigned int startup_intc2_irq(unsigned int irq)
{
enable_intc2_irq(irq);
return 0; /* never anything pending */
}
static struct hw_interrupt_type intc2_irq_type = {
"INTC2-IRQ",
startup_intc2_irq,
shutdown_intc2_irq,
enable_intc2_irq,
disable_intc2_irq,
mask_and_ack_intc2,
end_intc2_irq
};
static void disable_intc2_irq(unsigned int irq)
{
unsigned addr;
int offset=irq-INTC2_FIRST_IRQ;
unsigned val,flags;
// Sanity check
if(offset<0 || offset>=NR_INTC2_IRQS) return;
addr=intc2_data[offset].addr+INTC2_INTMSK_OFFSET;
save_and_cli(flags);
val=ctrl_inl(addr);
val|=intc2_data[offset].mask;
ctrl_outl(val,addr);
restore_flags(flags);
}
static void enable_intc2_irq(unsigned int irq)
{
int offset=irq-INTC2_FIRST_IRQ;
// Sanity check
if(offset<0 || offset>=NR_INTC2_IRQS) return;
ctrl_outl(intc2_data[offset].mask,
intc2_data[offset].addr+INTC2_INTMSKCLR_OFFSET);
}
static void mask_and_ack_intc2(unsigned int irq)
{
disable_intc2_irq(irq);
}
static void end_intc2_irq(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
enable_intc2_irq(irq);
}
void make_intc2_irq(unsigned int irq, unsigned int addr,
unsigned int group,int pos, int priority)
{
int offset=irq-INTC2_FIRST_IRQ;
unsigned flags,val;
if(offset<0 || offset>=NR_INTC2_IRQS) {
return;
}
disable_irq_nosync(irq);
/* Fill the data we need */
intc2_data[offset].addr=addr;
intc2_data[offset].mask=1<<pos;
/* Set the priority level */
save_and_cli(flags);
val=ctrl_inl(addr+INTC2_INTPRI_OFFSET);
val|=(priority)<< (group<<4);
ctrl_outl(val,addr+INTC2_INTPRI_OFFSET);
restore_flags(flags);
irq_desc[irq].handler=&intc2_irq_type;
disable_intc2_irq(irq);
}
/* $Id: irq_ipr.c,v 1.20 2001/07/15 23:26:56 gniibe Exp $
*
* linux/arch/sh/kernel/irq_ipr.c
*
* Copyright (C) 1999 Niibe Yutaka & Takeshi Yaegashi
* Copyright (C) 2000 Kazumoto Kojima
*
* Interrupt handling for IPR-based IRQ.
*
* Supported system:
* On-chip supporting modules (TMU, RTC, etc.).
* On-chip supporting modules for SH7709/SH7709A/SH7729.
* Hitachi SolutionEngine external I/O:
* MS7709SE01, MS7709ASE01, and MS7750SE01
*
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/machvec.h>
struct ipr_data {
unsigned int addr; /* Address of Interrupt Priority Register */
int shift; /* Shifts of the 16-bit data */
int priority; /* The priority */
};
static struct ipr_data ipr_data[NR_IRQS];
static void enable_ipr_irq(unsigned int irq);
static void disable_ipr_irq(unsigned int irq);
/* shutdown is same as "disable" */
#define shutdown_ipr_irq disable_ipr_irq
static void mask_and_ack_ipr(unsigned int);
static void end_ipr_irq(unsigned int irq);
static unsigned int startup_ipr_irq(unsigned int irq)
{
enable_ipr_irq(irq);
return 0; /* never anything pending */
}
static struct hw_interrupt_type ipr_irq_type = {
"IPR-IRQ",
startup_ipr_irq,
shutdown_ipr_irq,
enable_ipr_irq,
disable_ipr_irq,
mask_and_ack_ipr,
end_ipr_irq
};
static void disable_ipr_irq(unsigned int irq)
{
unsigned long val, flags;
unsigned int addr = ipr_data[irq].addr;
unsigned short mask = 0xffff ^ (0x0f << ipr_data[irq].shift);
/* Set the priority in IPR to 0 */
save_and_cli(flags);
val = ctrl_inw(addr);
val &= mask;
ctrl_outw(val, addr);
restore_flags(flags);
}
static void enable_ipr_irq(unsigned int irq)
{
unsigned long val, flags;
unsigned int addr = ipr_data[irq].addr;
int priority = ipr_data[irq].priority;
unsigned short value = (priority << ipr_data[irq].shift);
/* Set priority in IPR back to original value */
save_and_cli(flags);
val = ctrl_inw(addr);
val |= value;
ctrl_outw(val, addr);
restore_flags(flags);
}
static void mask_and_ack_ipr(unsigned int irq)
{
disable_ipr_irq(irq);
#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
/* This is needed when we use edge triggered setting */
/* XXX: Is it really needed? */
if (IRQ0_IRQ <= irq && irq <= IRQ5_IRQ) {
/* Clear external interrupt request */
int a = ctrl_inb(INTC_IRR0);
a &= ~(1 << (irq - IRQ0_IRQ));
ctrl_outb(a, INTC_IRR0);
}
#endif
}
static void end_ipr_irq(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
enable_ipr_irq(irq);
}
void make_ipr_irq(unsigned int irq, unsigned int addr, int pos, int priority)
{
disable_irq_nosync(irq);
ipr_data[irq].addr = addr;
ipr_data[irq].shift = pos*4; /* POSition (0-3) x 4 means shift */
ipr_data[irq].priority = priority;
irq_desc[irq].handler = &ipr_irq_type;
disable_ipr_irq(irq);
}
#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
static unsigned char pint_map[256];
static unsigned long portcr_mask = 0;
static void enable_pint_irq(unsigned int irq);
static void disable_pint_irq(unsigned int irq);
/* shutdown is same as "disable" */
#define shutdown_pint_irq disable_pint_irq
static void mask_and_ack_pint(unsigned int);
static void end_pint_irq(unsigned int irq);
static unsigned int startup_pint_irq(unsigned int irq)
{
enable_pint_irq(irq);
return 0; /* never anything pending */
}
static struct hw_interrupt_type pint_irq_type = {
"PINT-IRQ",
startup_pint_irq,
shutdown_pint_irq,
enable_pint_irq,
disable_pint_irq,
mask_and_ack_pint,
end_pint_irq
};
static void disable_pint_irq(unsigned int irq)
{
unsigned long val, flags;
save_and_cli(flags);
val = ctrl_inw(INTC_INTER);
val &= ~(1 << (irq - PINT_IRQ_BASE));
ctrl_outw(val, INTC_INTER); /* disable PINTn */
portcr_mask &= ~(3 << (irq - PINT_IRQ_BASE)*2);
restore_flags(flags);
}
static void enable_pint_irq(unsigned int irq)
{
unsigned long val, flags;
save_and_cli(flags);
val = ctrl_inw(INTC_INTER);
val |= 1 << (irq - PINT_IRQ_BASE);
ctrl_outw(val, INTC_INTER); /* enable PINTn */
portcr_mask |= 3 << (irq - PINT_IRQ_BASE)*2;
restore_flags(flags);
}
static void mask_and_ack_pint(unsigned int irq)
{
disable_pint_irq(irq);
}
static void end_pint_irq(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
enable_pint_irq(irq);
}
void make_pint_irq(unsigned int irq)
{
disable_irq_nosync(irq);
irq_desc[irq].handler = &pint_irq_type;
disable_pint_irq(irq);
}
#endif
void __init init_IRQ(void)
{
#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
int i;
#endif
make_ipr_irq(TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY);
make_ipr_irq(RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY);
#ifdef SCI_ERI_IRQ
make_ipr_irq(SCI_ERI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY);
make_ipr_irq(SCI_RXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY);
make_ipr_irq(SCI_TXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY);
#endif
#ifdef SCIF1_ERI_IRQ
make_ipr_irq(SCIF1_ERI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY);
make_ipr_irq(SCIF1_RXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY);
make_ipr_irq(SCIF1_BRI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY);
make_ipr_irq(SCIF1_TXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY);
#endif
#ifdef SCIF_ERI_IRQ
make_ipr_irq(SCIF_ERI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY);
make_ipr_irq(SCIF_RXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY);
make_ipr_irq(SCIF_BRI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY);
make_ipr_irq(SCIF_TXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY);
#endif
#ifdef IRDA_ERI_IRQ
make_ipr_irq(IRDA_ERI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY);
make_ipr_irq(IRDA_RXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY);
make_ipr_irq(IRDA_BRI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY);
make_ipr_irq(IRDA_TXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY);
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
/*
* Initialize the Interrupt Controller (INTC)
* registers to their power on values
*/
/*
* Enable external irq (INTC IRQ mode).
* You should set corresponding bits of PFC to "00"
* to enable these interrupts.
*/
make_ipr_irq(IRQ0_IRQ, IRQ0_IPR_ADDR, IRQ0_IPR_POS, IRQ0_PRIORITY);
make_ipr_irq(IRQ1_IRQ, IRQ1_IPR_ADDR, IRQ1_IPR_POS, IRQ1_PRIORITY);
make_ipr_irq(IRQ2_IRQ, IRQ2_IPR_ADDR, IRQ2_IPR_POS, IRQ2_PRIORITY);
make_ipr_irq(IRQ3_IRQ, IRQ3_IPR_ADDR, IRQ3_IPR_POS, IRQ3_PRIORITY);
make_ipr_irq(IRQ4_IRQ, IRQ4_IPR_ADDR, IRQ4_IPR_POS, IRQ4_PRIORITY);
make_ipr_irq(IRQ5_IRQ, IRQ5_IPR_ADDR, IRQ5_IPR_POS, IRQ5_PRIORITY);
make_ipr_irq(PINT0_IRQ, PINT0_IPR_ADDR, PINT0_IPR_POS, PINT0_PRIORITY);
make_ipr_irq(PINT8_IRQ, PINT8_IPR_ADDR, PINT8_IPR_POS, PINT8_PRIORITY);
enable_ipr_irq(PINT0_IRQ);
enable_ipr_irq(PINT8_IRQ);
for(i = 0; i < 16; i++)
make_pint_irq(PINT_IRQ_BASE + i);
for(i = 0; i < 256; i++)
{
if(i & 1) pint_map[i] = 0;
else if(i & 2) pint_map[i] = 1;
else if(i & 4) pint_map[i] = 2;
else if(i & 8) pint_map[i] = 3;
else if(i & 0x10) pint_map[i] = 4;
else if(i & 0x20) pint_map[i] = 5;
else if(i & 0x40) pint_map[i] = 6;
else if(i & 0x80) pint_map[i] = 7;
}
#endif /* CONFIG_CPU_SUBTYPE_SH7707 || CONFIG_CPU_SUBTYPE_SH7709 */
/* Perform the machine specific initialisation */
if (sh_mv.mv_init_irq != NULL) {
sh_mv.mv_init_irq();
}
}
#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
int ipr_irq_demux(int irq)
{
unsigned long creg, dreg, d, sav;
if(irq == PINT0_IRQ)
{
#if defined(CONFIG_CPU_SUBTYPE_SH7707)
creg = PORT_PACR;
dreg = PORT_PADR;
#else
creg = PORT_PCCR;
dreg = PORT_PCDR;
#endif
sav = ctrl_inw(creg);
ctrl_outw(sav | portcr_mask, creg);
d = (~ctrl_inb(dreg) ^ ctrl_inw(INTC_ICR2)) & ctrl_inw(INTC_INTER) & 0xff;
ctrl_outw(sav, creg);
if(d == 0) return irq;
return PINT_IRQ_BASE + pint_map[d];
}
else if(irq == PINT8_IRQ)
{
#if defined(CONFIG_CPU_SUBTYPE_SH7707)
creg = PORT_PBCR;
dreg = PORT_PBDR;
#else
creg = PORT_PFCR;
dreg = PORT_PFDR;
#endif
sav = ctrl_inw(creg);
ctrl_outw(sav | (portcr_mask >> 16), creg);
d = (~ctrl_inb(dreg) ^ (ctrl_inw(INTC_ICR2) >> 8)) & (ctrl_inw(INTC_INTER) >> 8) & 0xff;
ctrl_outw(sav, creg);
if(d == 0) return irq;
return PINT_IRQ_BASE + 8 + pint_map[d];
}
return irq;
}
#endif
/*
* $Id: mach_dc.c,v 1.5 2001/09/01 14:34:31 mrbrown Exp $
* SEGA Dreamcast machine vector
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/time.h>
#include <asm/machvec.h>
#include <asm/machvec_init.h>
#include <asm/io_generic.h>
#include <asm/io_dc.h>
#include <asm/irq.h>
void __init setup_dreamcast(void);
void __init dreamcast_pcibios_init(void);
/* Custom Dreamcast RTC routines */
void aica_rtc_gettimeofday(struct timeval *tv);
int aica_rtc_settimeofday(const struct timeval *tv);
/*
* The Machine Vector
*/
struct sh_machine_vector mv_dreamcast __initmv = {
.mv_name = "dreamcast",
.mv_nr_irqs = NR_IRQS,
.mv_inb = generic_inb,
.mv_inw = generic_inw,
.mv_inl = generic_inl,
.mv_outb = generic_outb,
.mv_outw = generic_outw,
.mv_outl = generic_outl,
.mv_inb_p = generic_inb_p,
.mv_inw_p = generic_inw,
.mv_inl_p = generic_inl,
.mv_outb_p = generic_outb_p,
.mv_outw_p = generic_outw,
.mv_outl_p = generic_outl,
.mv_insb = generic_insb,
.mv_insw = generic_insw,
.mv_insl = generic_insl,
.mv_outsb = generic_outsb,
.mv_outsw = generic_outsw,
.mv_outsl = generic_outsl,
.mv_readb = generic_readb,
.mv_readw = generic_readw,
.mv_readl = generic_readl,
.mv_writeb = generic_writeb,
.mv_writew = generic_writew,
.mv_writel = generic_writel,
.mv_ioremap = generic_ioremap,
.mv_iounmap = generic_iounmap,
.mv_init_arch = setup_dreamcast,
.mv_isa_port2addr = dreamcast_isa_port2addr,
.mv_irq_demux = systemasic_irq_demux,
.mv_rtc_gettimeofday = aica_rtc_gettimeofday,
.mv_rtc_settimeofday = aica_rtc_settimeofday,
.mv_hw_dreamcast = 1,
};
ALIAS_MV(dreamcast)
/*
* linux/arch/sh/kernel/mach_hp600.c
*
* Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* Machine vector for the HP600
*/
#include <linux/init.h>
#include <asm/machvec.h>
#include <asm/rtc.h>
#include <asm/machvec_init.h>
#include <asm/io.h>
#include <asm/hd64461.h>
#include <asm/irq.h>
/*
* The Machine Vector
*/
struct sh_machine_vector mv_hp620 __initmv = {
.mv_name = "hp620",
.mv_nr_irqs = HD64461_IRQBASE+HD64461_IRQ_NUM,
.mv_inb = hd64461_inb,
.mv_inw = hd64461_inw,
.mv_inl = hd64461_inl,
.mv_outb = hd64461_outb,
.mv_outw = hd64461_outw,
.mv_outl = hd64461_outl,
.mv_inb_p = hd64461_inb_p,
.mv_inw_p = hd64461_inw,
.mv_inl_p = hd64461_inl,
.mv_outb_p = hd64461_outb_p,
.mv_outw_p = hd64461_outw,
.mv_outl_p = hd64461_outl,
.mv_insb = hd64461_insb,
.mv_insw = hd64461_insw,
.mv_insl = hd64461_insl,
.mv_outsb = hd64461_outsb,
.mv_outsw = hd64461_outsw,
.mv_outsl = hd64461_outsl,
.mv_readb = generic_readb,
.mv_readw = generic_readw,
.mv_readl = generic_readl,
.mv_writeb = generic_writeb,
.mv_writew = generic_writew,
.mv_writel = generic_writel,
.mv_irq_demux = hd64461_irq_demux,
.mv_rtc_gettimeofday = sh_rtc_gettimeofday,
.mv_rtc_settimeofday = sh_rtc_settimeofday,
.mv_hw_hp600 = 1,
.mv_hw_hp620 = 1,
.mv_hw_hd64461 = 1,
};
ALIAS_MV(hp620)
struct sh_machine_vector mv_hp680 __initmv = {
.mv_name = "hp680",
.mv_nr_irqs = HD64461_IRQBASE+HD64461_IRQ_NUM,
.mv_inb = hd64461_inb,
.mv_inw = hd64461_inw,
.mv_inl = hd64461_inl,
.mv_outb = hd64461_outb,
.mv_outw = hd64461_outw,
.mv_outl = hd64461_outl,
.mv_inb_p = hd64461_inb_p,
.mv_inw_p = hd64461_inw,
.mv_inl_p = hd64461_inl,
.mv_outb_p = hd64461_outb_p,
.mv_outw_p = hd64461_outw,
.mv_outl_p = hd64461_outl,
.mv_insb = hd64461_insb,
.mv_insw = hd64461_insw,
.mv_insl = hd64461_insl,
.mv_outsb = hd64461_outsb,
.mv_outsw = hd64461_outsw,
.mv_outsl = hd64461_outsl,
.mv_readb = generic_readb,
.mv_readw = generic_readw,
.mv_readl = generic_readl,
.mv_writeb = generic_writeb,
.mv_writew = generic_writew,
.mv_writel = generic_writel,
.mv_irq_demux = hd64461_irq_demux,
.mv_rtc_gettimeofday = sh_rtc_gettimeofday,
.mv_rtc_settimeofday = sh_rtc_settimeofday,
.mv_hw_hp600 = 1,
.mv_hw_hp680 = 1,
.mv_hw_hd64461 = 1,
};
ALIAS_MV(hp680)
struct sh_machine_vector mv_hp690 __initmv = {
.mv_name = "hp690",
.mv_nr_irqs = HD64461_IRQBASE+HD64461_IRQ_NUM,
.mv_inb = hd64461_inb,
.mv_inw = hd64461_inw,
.mv_inl = hd64461_inl,
.mv_outb = hd64461_outb,
.mv_outw = hd64461_outw,
.mv_outl = hd64461_outl,
.mv_inb_p = hd64461_inb_p,
.mv_inw_p = hd64461_inw,
.mv_inl_p = hd64461_inl,
.mv_outb_p = hd64461_outb_p,
.mv_outw_p = hd64461_outw,
.mv_outl_p = hd64461_outl,
.mv_insb = hd64461_insb,
.mv_insw = hd64461_insw,
.mv_insl = hd64461_insl,
.mv_outsb = hd64461_outsb,
.mv_outsw = hd64461_outsw,
.mv_outsl = hd64461_outsl,
.mv_readb = generic_readb,
.mv_readw = generic_readw,
.mv_readl = generic_readl,
.mv_writeb = generic_writeb,
.mv_writew = generic_writew,
.mv_writel = generic_writel,
.mv_irq_demux = hd64461_irq_demux,
.mv_rtc_gettimeofday = sh_rtc_gettimeofday,
.mv_rtc_settimeofday = sh_rtc_settimeofday,
.mv_hw_hp600 = 1,
.mv_hw_hp690 = 1,
.mv_hw_hd64461 = 1,
};
ALIAS_MV(hp690)
/*
* Low-Level PCI Support for the SH7751
*
* Dustin McIntire (dustin@sensoria.com)
* Derived from arch/i386/kernel/pci-*.c which bore the message:
* (c) 1999--2000 Martin Mares <mj@ucw.cz>
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
*/
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/errno.h>
#include <linux/irq.h>
#include <asm/machvec.h>
#include <asm/io.h>
#include <asm/pci-sh7751.h>
struct pci_ops *pci_check_direct(void);
void pcibios_resource_survey(void);
static u8 pcibios_swizzle(struct pci_dev *dev, u8 *pin);
static int pcibios_lookup_irq(struct pci_dev *dev, u8 slot, u8 pin);
unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1;
int pcibios_last_bus = -1;
struct pci_bus *pci_root_bus;
struct pci_ops *pci_root_ops;
/*
* Direct access to PCI hardware...
*/
#ifdef CONFIG_PCI_DIRECT
#define CONFIG_CMD(bus, devfn, where) (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3))
#define PCI_REG(reg) (SH7751_PCIREG_BASE+reg)
/*
* Functions for accessing PCI configuration space with type 1 accesses
*/
static int pci_conf1_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
{
u32 word;
unsigned long flags;
/* PCIPDR may only be accessed as 32 bit words,
* so we must do byte alignment by hand
*/
save_and_cli(flags);
outl(CONFIG_CMD(bus,devfn,where), PCI_REG(SH7751_PCIPAR));
word = inl(PCI_REG(SH7751_PCIPDR));
restore_flags(flags);
switch (size) {
case 1:
switch (where & 0x3) {
case 3:
*value = (u8)(word >> 24);
break;
case 2:
*value = (u8)(word >> 16);
break;
case 1:
*value = (u8)(word >> 8);
break;
default:
*value = (u8)word;
break;
}
case 2:
switch (where & 0x3) {
case 3: /*This should never happen.*/
printk(KERN_ERR "PCI BIOS: read_config: Illegal u16 alignment");
return PCIBIOS_BAD_REGISTER_NUMBER;
case 2:
*value = (u16)(word >> 16);
break;
case 1:
*value = (u16)(word >> 8);
break;
default:
*value = (u16)word;
break;
}
case 4:
*value = word;
break;
}
PCIDBG(4,"pci_conf1_read@0x%08x=0x%x\n", CONFIG_CMD(bus,devfn,where),*value);
return PCIBIOS_SUCCESSFUL;
}
/*
* Since SH7751 only does 32bit access we'll have to do a read,mask,write operation.
* We'll allow an odd byte offset, though it should be illegal.
*/
static int pci_conf1_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
{
u32 word,mask;
unsigned long flags;
u32 shift = (where & 3) * 8;
if(size == 1) {
mask = ((1 << 8) - 1) << shift; // create the byte mask
} else if(size == 2){
if(shift == 24)
return PCIBIOS_BAD_REGISTER_NUMBER;
mask = ((1 << 16) - 1) << shift; // create the word mask
}
save_and_cli(flags);
outl(CONFIG_CMD(bus,devfn,where), PCI_REG(SH7751_PCIPAR));
if(size == 4){
outl(value, PCI_REG(SH7751_PCIPDR));
restore_flags(flags);
PCIDBG(4,"pci_conf1_write@0x%08x=0x%x\n", CONFIG_CMD(bus,devfn,where),value);
return PCIBIOS_SUCCESSFUL;
}
word = inl(PCI_REG(SH7751_PCIPDR)) ;
word &= ~mask;
word |= value << shift;
outl(word, PCI_REG(SH7751_PCIPDR));
restore_flags(flags);
PCIDBG(4,"pci_conf1_write@0x%08x=0x%x\n", CONFIG_CMD(bus,devfn,where),word);
return PCIBIOS_SUCCESSFUL;
}
#undef CONFIG_CMD
static struct pci_ops pci_direct_conf1 = {
.read = pci_conf1_read,
.write = pci_conf1_write,
};
struct pci_ops * __init pci_check_direct(void)
{
unsigned int tmp, id;
/* check for SH7751 hardware */
id = (SH7751_DEVICE_ID << 16) | SH7751_VENDOR_ID;
if(inl(SH7751_PCIREG_BASE+SH7751_PCICONF0) != id) {
PCIDBG(2,"PCI: This is not an SH7751\n");
return NULL;
}
/*
* Check if configuration works.
*/
if (pci_probe & PCI_PROBE_CONF1) {
tmp = inl (PCI_REG(SH7751_PCIPAR));
outl (0x80000000, PCI_REG(SH7751_PCIPAR));
if (inl (PCI_REG(SH7751_PCIPAR)) == 0x80000000) {
outl (tmp, PCI_REG(SH7751_PCIPAR));
printk(KERN_INFO "PCI: Using configuration type 1\n");
request_region(PCI_REG(SH7751_PCIPAR), 8, "PCI conf1");
return &pci_direct_conf1;
}
outl (tmp, PCI_REG(SH7751_PCIPAR));
}
PCIDBG(2,"PCI: pci_check_direct failed\n");
return NULL;
}
#endif
/*
* BIOS32 and PCI BIOS handling.
*
* The BIOS version of the pci functions is not yet implemented but it is left
* in for completeness. Currently an error will be generated at compile time.
*/
#ifdef CONFIG_PCI_BIOS
#error PCI BIOS is not yet supported on SH7751
#endif /* CONFIG_PCI_BIOS */
/***************************************************************************************/
/*
* Handle bus scanning and fixups ....
*/
/*
* Discover remaining PCI buses in case there are peer host bridges.
* We use the number of last PCI bus provided by the PCI BIOS.
*/
static void __init pcibios_fixup_peer_bridges(void)
{
int n;
struct pci_bus bus;
struct pci_dev dev;
u16 l;
if (pcibios_last_bus <= 0 || pcibios_last_bus >= 0xff)
return;
PCIDBG(2,"PCI: Peer bridge fixup\n");
for (n=0; n <= pcibios_last_bus; n++) {
if (pci_bus_exists(&pci_root_buses, n))
continue;
bus.number = n;
bus.ops = pci_root_ops;
dev.bus = &bus;
for(dev.devfn=0; dev.devfn<256; dev.devfn += 8)
if (!pci_read_config_word(&dev, PCI_VENDOR_ID, &l) &&
l != 0x0000 && l != 0xffff) {
PCIDBG(3,"Found device at %02x:%02x [%04x]\n", n, dev.devfn, l);
printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n);
pci_scan_bus(n, pci_root_ops, NULL);
break;
}
}
}
static void __init pci_fixup_ide_bases(struct pci_dev *d)
{
int i;
/*
* PCI IDE controllers use non-standard I/O port decoding, respect it.
*/
if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
return;
PCIDBG(3,"PCI: IDE base address fixup for %s\n", d->slot_name);
for(i=0; i<4; i++) {
struct resource *r = &d->resource[i];
if ((r->start & ~0x80) == 0x374) {
r->start |= 2;
r->end = r->start;
}
}
}
/* Add future fixups here... */
struct pci_fixup pcibios_fixups[] = {
{ PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases },
{ 0 }
};
/*
* Called after each bus is probed, but before its children
* are examined.
*/
void __init pcibios_fixup_bus(struct pci_bus *b)
{
pci_read_bridge_bases(b);
}
/*
* Initialization. Try all known PCI access methods. Note that we support
* using both PCI BIOS and direct access: in such cases, we use I/O ports
* to access config space.
*
* Note that the platform specific initialization (BSC registers, and memory
* space mapping) will be called via the machine vectors (sh_mv.mv_pci_init()) if it
* exitst and via the platform defined function pcibios_init_platform().
* See pci_bigsur.c for implementation;
*
* The BIOS version of the pci functions is not yet implemented but it is left
* in for completeness. Currently an error will be genereated at compile time.
*/
void __init pcibios_init(void)
{
struct pci_ops *bios = NULL;
struct pci_ops *dir = NULL;
PCIDBG(1,"PCI: Starting initialization.\n");
#ifdef CONFIG_PCI_BIOS
if ((pci_probe & PCI_PROBE_BIOS) && ((bios = pci_find_bios()))) {
pci_probe |= PCI_BIOS_SORT;
pci_bios_present = 1;
}
#endif
#ifdef CONFIG_PCI_DIRECT
if (pci_probe & PCI_PROBE_CONF1 )
dir = pci_check_direct();
#endif
if (dir) {
pci_root_ops = dir;
if(!pcibios_init_platform())
PCIDBG(1,"PCI: Initialization failed\n");
if (sh_mv.mv_init_pci != NULL)
sh_mv.mv_init_pci();
}
else if (bios)
pci_root_ops = bios;
else {
PCIDBG(1,"PCI: No PCI bus detected\n");
return;
}
PCIDBG(1,"PCI: Probing PCI hardware\n");
pci_root_bus = pci_scan_bus(0, pci_root_ops, NULL);
//pci_assign_unassigned_resources();
pci_fixup_irqs(pcibios_swizzle, pcibios_lookup_irq);
pcibios_fixup_peer_bridges();
pcibios_resource_survey();
#ifdef CONFIG_PCI_BIOS
if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT))
pcibios_sort();
#endif
}
char * __init pcibios_setup(char *str)
{
if (!strcmp(str, "off")) {
pci_probe = 0;
return NULL;
}
#ifdef CONFIG_PCI_BIOS
else if (!strcmp(str, "bios")) {
pci_probe = PCI_PROBE_BIOS;
return NULL;
} else if (!strcmp(str, "nobios")) {
pci_probe &= ~PCI_PROBE_BIOS;
return NULL;
} else if (!strcmp(str, "nosort")) {
pci_probe |= PCI_NO_SORT;
return NULL;
} else if (!strcmp(str, "biosirq")) {
pci_probe |= PCI_BIOS_IRQ_SCAN;
return NULL;
}
#endif
#ifdef CONFIG_PCI_DIRECT
else if (!strcmp(str, "conf1")) {
pci_probe = PCI_PROBE_CONF1 | PCI_NO_CHECKS;
return NULL;
}
#endif
else if (!strcmp(str, "rom")) {
pci_probe |= PCI_ASSIGN_ROMS;
return NULL;
} else if (!strncmp(str, "lastbus=", 8)) {
pcibios_last_bus = simple_strtol(str+8, NULL, 0);
return NULL;
}
return str;
}
/*
* Allocate the bridge and device resources
*/
static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
{
struct list_head *ln;
struct pci_bus *bus;
struct pci_dev *dev;
int idx;
struct resource *r, *pr;
PCIDBG(2,"PCI: pcibios_allocate_bus_reasources called\n" );
/* Depth-First Search on bus tree */
for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
bus = pci_bus_b(ln);
if ((dev = bus->self)) {
for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
r = &dev->resource[idx];
if (!r->start)
continue;
pr = pci_find_parent_resource(dev, r);
if (!pr || request_resource(pr, r) < 0)
printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, dev->slot_name);
}
}
pcibios_allocate_bus_resources(&bus->children);
}
}
static void __init pcibios_allocate_resources(int pass)
{
struct pci_dev *dev = NULL;
int idx, disabled;
u16 command;
struct resource *r, *pr;
PCIDBG(2,"PCI: pcibios_allocate_resources pass %d called\n", pass);
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
pci_read_config_word(dev, PCI_COMMAND, &command);
for(idx = 0; idx < 6; idx++) {
r = &dev->resource[idx];
if (r->parent) /* Already allocated */
continue;
if (!r->start) /* Address not assigned at all */
continue;
if (r->flags & IORESOURCE_IO)
disabled = !(command & PCI_COMMAND_IO);
else
disabled = !(command & PCI_COMMAND_MEMORY);
if (pass == disabled) {
PCIDBG(3,"PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n",
r->start, r->end, r->flags, disabled, pass);
pr = pci_find_parent_resource(dev, r);
if (!pr || request_resource(pr, r) < 0) {
printk(KERN_ERR "PCI: Cannot allocate resource region %d of device %s\n", idx, dev->slot_name);
/* We'll assign a new address later */
r->end -= r->start;
r->start = 0;
}
}
}
if (!pass) {
r = &dev->resource[PCI_ROM_RESOURCE];
if (r->flags & PCI_ROM_ADDRESS_ENABLE) {
/* Turn the ROM off, leave the resource region, but keep it unregistered. */
u32 reg;
PCIDBG(3,"PCI: Switching off ROM of %s\n", dev->slot_name);
r->flags &= ~PCI_ROM_ADDRESS_ENABLE;
pci_read_config_dword(dev, dev->rom_base_reg, &reg);
pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE);
}
}
}
}
static void __init pcibios_assign_resources(void)
{
struct pci_dev *devn = NULL;
int idx;
struct resource *r;
PCIDBG(2,"PCI: pcibios_assign_resources called\n");
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
int class = dev->class >> 8;
/* Don't touch classless devices and host bridges */
if (!class || class == PCI_CLASS_BRIDGE_HOST)
continue;
for(idx=0; idx<6; idx++) {
r = &dev->resource[idx];
/*
* Don't touch IDE controllers and I/O ports of video cards!
*/
if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) ||
(class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)))
continue;
/*
* We shall assign a new address to this resource, either because
* the BIOS forgot to do so or because we have decided the old
* address was unusable for some reason.
*/
if (!r->start && r->end)
pci_assign_resource(dev, idx);
}
if (pci_probe & PCI_ASSIGN_ROMS) {
r = &dev->resource[PCI_ROM_RESOURCE];
r->end -= r->start;
r->start = 0;
if (r->end)
pci_assign_resource(dev, PCI_ROM_RESOURCE);
}
}
}
void __init pcibios_resource_survey(void)
{
PCIDBG(1,"PCI: Allocating resources\n");
pcibios_allocate_bus_resources(&pci_root_buses);
pcibios_allocate_resources(0);
pcibios_allocate_resources(1);
pcibios_assign_resources();
}
/***************************************************************************************/
/*
* IRQ functions
*/
static u8 __init pcibios_swizzle(struct pci_dev *dev, u8 *pin)
{
/* no swizzling */
return PCI_SLOT(dev->devfn);
}
static int pcibios_lookup_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
int irq = -1;
/* now lookup the actual IRQ on a platform specific basis (pci-'platform'.c) */
irq = pcibios_map_platform_irq(slot,pin);
if( irq < 0 ) {
PCIDBG(3,"PCI: Error mapping IRQ on device %s\n", dev->name);
return irq;
}
PCIDBG(2,"Setting IRQ for slot %s to %d\n", dev->slot_name, irq);
return irq;
}
/*
* Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* Support functions for the ST40 PCI hardware.
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/types.h>
#include <asm/pci.h>
#include <linux/irq.h>
#include "pci_st40.h"
/* This is in P2 of course */
#define ST40PCI_BASE_ADDRESS (0xb0000000)
#define ST40PCI_MEM_ADDRESS (ST40PCI_BASE_ADDRESS+0x0)
#define ST40PCI_IO_ADDRESS (ST40PCI_BASE_ADDRESS+0x06000000)
#define ST40PCI_REG_ADDRESS (ST40PCI_BASE_ADDRESS+0x07000000)
#define ST40PCI_REG(x) (ST40PCI_REG_ADDRESS+(ST40PCI_##x))
#define ST40PCI_WRITE(reg,val) writel((val),ST40PCI_REG(reg))
#define ST40PCI_WRITE_SHORT(reg,val) writew((val),ST40PCI_REG(reg))
#define ST40PCI_WRITE_BYTE(reg,val) writeb((val),ST40PCI_REG(reg))
#define ST40PCI_READ(reg) readl(ST40PCI_REG(reg))
#define ST40PCI_READ_SHORT(reg) readw(ST40PCI_REG(reg))
#define ST40PCI_READ_BYTE(reg) readb(ST40PCI_REG(reg))
#define ST40PCI_SERR_IRQ 64
#define ST40PCI_SERR_INT_GROUP 0
#define ST40PCI_SERR_INT_POS 0
#define ST40PCI_SERR_INT_PRI 15
#define ST40PCI_ERR_IRQ 65
#define ST40PCI_ERR_INT_GROUP 1
#define ST40PCI_ERR_INT_POS 1
#define ST40PCI_ERR_INT_PRI 14
/* Macros to extract PLL params */
#define PLL_MDIV(reg) ( ((unsigned)reg) & 0xff )
#define PLL_NDIV(reg) ( (((unsigned)reg)>>8) & 0xff )
#define PLL_PDIV(reg) ( (((unsigned)reg)>>16) & 0x3 )
#define PLL_SETUP(reg) ( (((unsigned)reg)>>19) & 0x1ff )
/* Build up the appropriate settings */
#define PLL_SET(mdiv,ndiv,pdiv,setup) \
( ((mdiv)&0xff) | (((ndiv)&0xff)<<8) | (((pdiv)&3)<<16)| (((setup)&0x1ff)<<19))
#define PLLPCICR (0xbb040000+0x10)
#define PLLPCICR_POWERON (1<<28)
#define PLLPCICR_OUT_EN (1<<29)
#define PLLPCICR_LOCKSELECT (1<<30)
#define PLLPCICR_LOCK (1<<31)
#define PLL_25MHZ 0x793c8512
#define PLL_33MHZ PLL_SET(18,88,3,295)
static __init void SetPCIPLL(void)
{
/* Stop the PLL */
writel(0, PLLPCICR);
/* Always run at 33Mhz. The PCI clock is totally async
* to the rest of the system
*/
writel(PLL_33MHZ | PLLPCICR_POWERON, PLLPCICR);
printk("ST40PCI: Waiting for PCI PLL to lock\n");
while ((readl(PLLPCICR) & PLLPCICR_LOCK) == 0);
writel(readl(PLLPCICR) | PLLPCICR_OUT_EN, PLLPCICR);
}
static void st40_pci_irq(int irq, void *dev_instance, struct pt_regs *regs)
{
unsigned pci_int, pci_air, pci_cir, pci_aint;
pci_int = ST40PCI_READ(INT);
pci_cir = ST40PCI_READ(CIR);
pci_air = ST40PCI_READ(AIR);
if (pci_int) {
printk("PCI INTERRUPT!\n");
printk("PCI INT -> 0x%x\n", pci_int & 0xffff);
printk("PCI AIR -> 0x%x\n", pci_air);
printk("PCI CIR -> 0x%x\n", pci_cir);
ST40PCI_WRITE(INT, ~0);
}
pci_aint = ST40PCI_READ(AINT);
if (pci_aint) {
printk("PCI ARB INTERRUPT!\n");
printk("PCI AINT -> 0x%x\n", pci_aint);
printk("PCI AIR -> 0x%x\n", pci_air);
printk("PCI CIR -> 0x%x\n", pci_cir);
ST40PCI_WRITE(AINT, ~0);
}
}
/* Rounds a number UP to the nearest power of two. Used for
* sizing the PCI window.
*/
static u32 __init r2p2(u32 num)
{
int i = 31;
u32 tmp = num;
if (num == 0)
return 0;
do {
if (tmp & (1 << 31))
break;
i--;
tmp <<= 1;
} while (i >= 0);
tmp = 1 << i;
/* If the original number isn't a power of 2, round it up */
if (tmp != num)
tmp <<= 1;
return tmp;
}
static void __init pci_fixup_ide_bases(struct pci_dev *d)
{
int i;
/*
* PCI IDE controllers use non-standard I/O port decoding, respect it.
*/
if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
return;
printk("PCI: IDE base address fixup for %s\n", d->slot_name);
for(i=0; i<4; i++) {
struct resource *r = &d->resource[i];
if ((r->start & ~0x80) == 0x374) {
r->start |= 2;
r->end = r->start;
}
}
}
/* Add future fixups here... */
struct pci_fixup pcibios_fixups[] = {
{ PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases },
{ 0 }
};
int __init st40pci_init(unsigned memStart, unsigned memSize)
{
u32 lsr0;
SetPCIPLL();
/* Initialises the ST40 pci subsystem, performing a reset, then programming
* up the address space decoders appropriately
*/
/* Should reset core here as well methink */
ST40PCI_WRITE(CR, CR_LOCK_MASK | CR_SOFT_RESET);
/* Loop while core resets */
while (ST40PCI_READ(CR) & CR_SOFT_RESET);
/* Now, lets reset all the cards on the bus with extreme prejudice */
ST40PCI_WRITE(CR, CR_LOCK_MASK | CR_RSTCTL);
udelay(250);
/* Set bus active, take it out of reset */
ST40PCI_WRITE(CR, CR_LOCK_MASK | CR_CFINT | CR_PFCS | CR_PFE);
/* The PCI spec says that no access must be made to the bus until 1 second
* after reset. This seem ludicrously long, but some delay is needed here
*/
mdelay(1000);
/* Switch off interrupts */
ST40PCI_WRITE(INTM, 0);
ST40PCI_WRITE(AINT, 0);
/* Allow it to be a master */
ST40PCI_WRITE_SHORT(CSR_CMD,
PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
PCI_COMMAND_IO);
/* Accesse to the 0xb0000000 -> 0xb6000000 area will go through to 0x10000000 -> 0x16000000
* on the PCI bus. This allows a nice 1-1 bus to phys mapping.
*/
ST40PCI_WRITE(MBR, 0x10000000);
/* Always set the max size 128M (actually, it is only 96MB wide) */
ST40PCI_WRITE(MBMR, 0x07ff0000);
/* I/O addresses are mapped at 0xb6000000 -> 0xb7000000. These are changed to 0, to
* allow cards that have legacy io such as vga to function correctly. This gives a
* maximum of 64K of io/space as only the bottom 16 bits of the address are copied
* over to the bus when the transaction is made. 64K of io space is more than enough
*/
ST40PCI_WRITE(IOBR, 0x0);
/* Set up the 64K window */
ST40PCI_WRITE(IOBMR, 0x0);
/* Now we set up the mbars so the PCI bus can see the memory of the machine */
if (memSize < (64 * 1024)) {
printk("Ridiculous memory size of 0x%x?\n",memSize);
return 0;
}
lsr0 =
(memSize >
(512 * 1024 * 1024)) ? 0x1fff0001 : ((r2p2(memSize) -
0x10000) | 0x1);
ST40PCI_WRITE(LSR0, lsr0);
ST40PCI_WRITE(CSR_MBAR0, memStart);
ST40PCI_WRITE(LAR0, memStart);
/* Maximise timeout values */
ST40PCI_WRITE_BYTE(CSR_TRDY, 0xff);
ST40PCI_WRITE_BYTE(CSR_RETRY, 0xff);
ST40PCI_WRITE_BYTE(CSR_MIT, 0xff);
/* Install the pci interrupt handlers */
make_intc2_irq(ST40PCI_SERR_IRQ, INTC2_BASE0,
ST40PCI_SERR_INT_GROUP, ST40PCI_SERR_INT_POS,
ST40PCI_SERR_INT_PRI);
make_intc2_irq(ST40PCI_ERR_IRQ, INTC2_BASE0, ST40PCI_ERR_INT_GROUP,
ST40PCI_ERR_INT_POS, ST40PCI_ERR_INT_PRI);
return 1;
}
char * __init pcibios_setup(char *str)
{
return str;
}
#define SET_CONFIG_BITS(bus,devfn,where)\
(((bus) << 16) | ((devfn) << 8) | ((where) & ~3) | (bus!=0))
#define CONFIG_CMD(bus, devfn, where) SET_CONFIG_BITS(bus->number,devfn,where)
static int CheckForMasterAbort(void)
{
if (ST40PCI_READ(INT) & INT_MADIM) {
/* Should we clear config space version as well ??? */
ST40PCI_WRITE(INT, INT_MADIM);
ST40PCI_WRITE_SHORT(CSR_STATUS, 0);
return 1;
}
return 0;
}
/* Write to config register */
static int st40pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 * val)
{
ST40PCI_WRITE(PAR, CONFIG_CMD(bus, devfn, where));
switch (size) {
case 1:
*val = (u8)ST40PCI_READ_BYTE(PDR + (where & 3));
break;
case 2:
*val = (u16)ST40PCI_READ_SHORT(PDR + (where & 2));
break;
case 4:
*val = ST40PCI_READ(PDR);
break;
}
if (CheckForMasterAbort()){
switch (size) {
case 1:
*val = (u8)0xff;
break;
case 2:
*val = (u16)0xffff;
break;
case 4:
*val = 0xffffffff;
break;
}
}
return PCIBIOS_SUCCESSFUL;
}
static int st40pci_write(struct pci_bus *bus, unsigned int devfn; int where, int size, u32 val)
{
ST40PCI_WRITE(PAR, CONFIG_CMD(dev, where));
switch (size) {
case 1:
ST40PCI_WRITE_BYTE(PDR + (where & 3), (u8)val);
break;
case 2:
ST40PCI_WRITE_SHORT(PDR + (where & 2), (u16)val);
break;
case 4:
ST40PCI_WRITE(PDR, val);
break;
}
CheckForMasterAbort();
return PCIBIOS_SUCCESSFUL;
}
static struct pci_ops pci_config_ops = {
.read = st40pci_read,
.write = st40pci_write,
};
/* Everything hangs off this */
static struct pci_bus *pci_root_bus;
static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin)
{
return PCI_SLOT(dev->devfn);
}
/* This needs to be shunted out of here into the board specific bit */
#define HARP_PCI_IRQ 1
#define HARP_BRIDGE_IRQ 2
#define OVERDRIVE_SLOT0_IRQ 0
static int __init map_harp_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
switch (slot) {
#ifdef CONFIG_SH_STB1_HARP
case 2: /*This is the PCI slot on the */
return HARP_PCI_IRQ;
case 1: /* this is the bridge */
return HARP_BRIDGE_IRQ;
#elif defined(CONFIG_SH_STB1_OVERDRIVE)
case 1:
case 2:
case 3:
return slot - 1;
#else
#error Unknown board
#endif
default:
return -1;
}
}
void __init pcibios_init(void)
{
extern unsigned long memory_start, memory_end;
if (sh_mv.mv_init_pci != NULL) {
sh_mv.mv_init_pci();
}
/* The pci subsytem needs to know where memory is and how much
* of it there is. I've simply made these globals. A better mechanism
* is probably needed.
*/
st40pci_init(PHYSADDR(memory_start),
PHYSADDR(memory_end) - PHYSADDR(memory_start));
if (request_irq(ST40PCI_ERR_IRQ, st40_pci_irq,
SA_INTERRUPT, "st40pci", NULL)) {
printk(KERN_ERR "st40pci: Cannot hook interrupt\n");
return;
}
/* Enable the PCI interrupts on the device */
ST40PCI_WRITE(INTM, ~0);
ST40PCI_WRITE(AINT, ~0);
/* Map the io address apprioately */
#ifdef CONFIG_HD64465
hd64465_port_map(PCIBIOS_MIN_IO, (64 * 1024) - PCIBIOS_MIN_IO + 1,
ST40_IO_ADDR + PCIBIOS_MIN_IO, 0);
#endif
/* ok, do the scan man */
pci_root_bus = pci_scan_bus(0, &pci_config_ops, NULL);
pci_assign_unassigned_resources();
pci_fixup_irqs(no_swizzle, map_harp_irq);
}
void __init pcibios_fixup_bus(struct pci_bus *bus)
{
}
/*
* Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* Defintions for the ST40 PCI hardware.
*/
#ifndef __PCI_ST40_H__
#define __PCI_ST40_H__
#define ST40PCI_VCR_STATUS 0x00
#define ST40PCI_VCR_VERSION 0x08
#define ST40PCI_CR 0x10
#define CR_SOFT_RESET (1<<12)
#define CR_PFCS (1<<11)
#define CR_PFE (1<<9)
#define CR_BMAM (1<<6)
#define CR_HOST (1<<5)
#define CR_CLKEN (1<<4)
#define CR_SOCS (1<<3)
#define CR_IOCS (1<<2)
#define CR_RSTCTL (1<<1)
#define CR_CFINT (1<<0)
#define CR_LOCK_MASK 0x5a000000
#define ST40PCI_LSR0 0X14
#define ST40PCI_LAR0 0x1c
#define ST40PCI_INT 0x24
#define INT_MADIM (1<<2)
#define ST40PCI_INTM 0x28
#define ST40PCI_AIR 0x2c
#define ST40PCI_CIR 0x30
#define ST40PCI_AINT 0x40
#define ST40PCI_AINTM 0x44
#define ST40PCI_BMIR 0x48
#define ST40PCI_PAR 0x4c
#define ST40PCI_MBR 0x50
#define ST40PCI_IOBR 0x54
#define ST40PCI_PINT 0x58
#define ST40PCI_PINTM 0x5c
#define ST40PCI_MBMR 0x70
#define ST40PCI_IOBMR 0x74
#define ST40PCI_PDR 0x78
/* These are configs space registers */
#define ST40PCI_CSR_VID 0x10000
#define ST40PCI_CSR_DID 0x10002
#define ST40PCI_CSR_CMD 0x10004
#define ST40PCI_CSR_STATUS 0x10006
#define ST40PCI_CSR_MBAR0 0x10010
#define ST40PCI_CSR_TRDY 0x10040
#define ST40PCI_CSR_RETRY 0x10041
#define ST40PCI_CSR_MIT 0x1000d
#define ST40_IO_ADDR 0xb6000000
#endif /* __PCI_ST40_H__ */
/*
*
* By Dustin McIntire (dustin@sensoria.com) (c)2001
*
* Setup and IRQ handling code for the HD64465 companion chip.
* by Greg Banks <gbanks@pocketpenguins.com>
* Copyright (c) 2000 PocketPenguins Inc
*
* Derived from setup_hd64465.c which bore the message:
* Greg Banks <gbanks@pocketpenguins.com>
* Copyright (c) 2000 PocketPenguins Inc and
* Copyright (C) 2000 YAEGASHI Takeshi
* and setup_cqreek.c which bore message:
* Copyright (C) 2000 Niibe Yutaka
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* Setup and IRQ functions for a Hitachi Big Sur Evaluation Board.
*
*/
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/param.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/bitops.h>
#include <asm/io_bigsur.h>
#include <asm/hd64465.h>
#include <asm/bigsur.h>
//#define BIGSUR_DEBUG 3
#undef BIGSUR_DEBUG
#ifdef BIGSUR_DEBUG
#define DPRINTK(args...) printk(args)
#define DIPRINTK(n, args...) if (BIGSUR_DEBUG>(n)) printk(args)
#else
#define DPRINTK(args...)
#define DIPRINTK(n, args...)
#endif /* BIGSUR_DEBUG */
#ifdef CONFIG_HD64465
extern int hd64465_irq_demux(int irq);
#endif /* CONFIG_HD64465 */
/*===========================================================*/
// Big Sur CPLD IRQ Routines
/*===========================================================*/
/* Level 1 IRQ routines */
static void disable_bigsur_l1irq(unsigned int irq)
{
unsigned long flags;
unsigned char mask;
unsigned int mask_port = ((irq - BIGSUR_IRQ_LOW)/8) ? BIGSUR_IRLMR1 : BIGSUR_IRLMR0;
unsigned char bit = (1 << ((irq - MGATE_IRQ_LOW)%8) );
if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
DPRINTK("Disable L1 IRQ %d\n", irq);
DIPRINTK(2,"disable_bigsur_l1irq: IMR=0x%08x mask=0x%x\n",
mask_port, bit);
save_and_cli(flags);
/* Disable IRQ - set mask bit */
mask = inb(mask_port) | bit;
outb(mask, mask_port);
restore_flags(flags);
return;
}
DPRINTK("disable_bigsur_l1irq: Invalid IRQ %d\n", irq);
}
static void enable_bigsur_l1irq(unsigned int irq)
{
unsigned long flags;
unsigned char mask;
unsigned int mask_port = ((irq - BIGSUR_IRQ_LOW)/8) ? BIGSUR_IRLMR1 : BIGSUR_IRLMR0;
unsigned char bit = (1 << ((irq - MGATE_IRQ_LOW)%8) );
if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
DPRINTK("Enable L1 IRQ %d\n", irq);
DIPRINTK(2,"enable_bigsur_l1irq: IMR=0x%08x mask=0x%x\n",
mask_port, bit);
save_and_cli(flags);
/* Enable L1 IRQ - clear mask bit */
mask = inb(mask_port) & ~bit;
outb(mask, mask_port);
restore_flags(flags);
return;
}
DPRINTK("enable_bigsur_l1irq: Invalid IRQ %d\n", irq);
}
/* Level 2 irq masks and registers for L2 decoding */
/* Level2 bitmasks for each level 1 IRQ */
const u32 bigsur_l2irq_mask[] =
{0x40,0x80,0x08,0x01,0x01,0x3C,0x3E,0xFF,0x40,0x80,0x06,0x03};
/* Level2 to ISR[n] map for each level 1 IRQ */
const u32 bigsur_l2irq_reg[] =
{ 2, 2, 3, 3, 1, 2, 1, 0, 1, 1, 3, 2};
/* Level2 to Level 1 IRQ map */
const u32 bigsur_l2_l1_map[] =
{7,7,7,7,7,7,7,7, 4,6,6,6,6,6,8,9, 11,11,5,5,5,5,0,1, 3,10,10,2,-1,-1,-1,-1};
/* IRQ inactive level (high or low) */
const u32 bigsur_l2_inactv_state[] = {0x00, 0xBE, 0xFC, 0xF7};
/* CPLD external status and mask registers base and offsets */
static const u32 isr_base = BIGSUR_IRQ0;
static const u32 isr_offset = BIGSUR_IRQ0 - BIGSUR_IRQ1;
static const u32 imr_base = BIGSUR_IMR0;
static const u32 imr_offset = BIGSUR_IMR0 - BIGSUR_IMR1;
#define REG_NUM(irq) ((irq-BIGSUR_2NDLVL_IRQ_LOW)/8 )
/* Level 2 IRQ routines */
static void disable_bigsur_l2irq(unsigned int irq)
{
unsigned long flags;
unsigned char mask;
unsigned char bit = 1 << ((irq-BIGSUR_2NDLVL_IRQ_LOW)%8);
unsigned int mask_port = imr_base - REG_NUM(irq)*imr_offset;
if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
DPRINTK("Disable L2 IRQ %d\n", irq);
DIPRINTK(2,"disable_bigsur_l2irq: IMR=0x%08x mask=0x%x\n",
mask_port, bit);
save_and_cli(flags);
/* Disable L2 IRQ - set mask bit */
mask = inb(mask_port) | bit;
outb(mask, mask_port);
restore_flags(flags);
return;
}
DPRINTK("disable_bigsur_l2irq: Invalid IRQ %d\n", irq);
}
static void enable_bigsur_l2irq(unsigned int irq)
{
unsigned long flags;
unsigned char mask;
unsigned char bit = 1 << ((irq-BIGSUR_2NDLVL_IRQ_LOW)%8);
unsigned int mask_port = imr_base - REG_NUM(irq)*imr_offset;
if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
DPRINTK("Enable L2 IRQ %d\n", irq);
DIPRINTK(2,"enable_bigsur_l2irq: IMR=0x%08x mask=0x%x\n",
mask_port, bit);
save_and_cli(flags);
/* Enable L2 IRQ - clear mask bit */
mask = inb(mask_port) & ~bit;
outb(mask, mask_port);
restore_flags(flags);
return;
}
DPRINTK("enable_bigsur_l2irq: Invalid IRQ %d\n", irq);
}
static void mask_and_ack_bigsur(unsigned int irq)
{
DPRINTK("mask_and_ack_bigsur IRQ %d\n", irq);
if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH)
disable_bigsur_l1irq(irq);
else
disable_bigsur_l2irq(irq);
}
static void end_bigsur_irq(unsigned int irq)
{
DPRINTK("end_bigsur_irq IRQ %d\n", irq);
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH)
enable_bigsur_l1irq(irq);
else
enable_bigsur_l2irq(irq);
}
}
static unsigned int startup_bigsur_irq(unsigned int irq)
{
u8 mask;
u32 reg;
DPRINTK("startup_bigsur_irq IRQ %d\n", irq);
if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
/* Enable the L1 IRQ */
enable_bigsur_l1irq(irq);
/* Enable all L2 IRQs in this L1 IRQ */
mask = ~(bigsur_l2irq_mask[irq-BIGSUR_IRQ_LOW]);
reg = imr_base - bigsur_l2irq_reg[irq-BIGSUR_IRQ_LOW] * imr_offset;
mask &= inb(reg);
outb(mask,reg);
DIPRINTK(2,"startup_bigsur_irq: IMR=0x%08x mask=0x%x\n",reg,inb(reg));
}
else {
/* Enable the L2 IRQ - clear mask bit */
enable_bigsur_l2irq(irq);
/* Enable the L1 bit masking this L2 IRQ */
enable_bigsur_l1irq(bigsur_l2_l1_map[irq-BIGSUR_2NDLVL_IRQ_LOW]);
DIPRINTK(2,"startup_bigsur_irq: L1=%d L2=%d\n",
bigsur_l2_l1_map[irq-BIGSUR_2NDLVL_IRQ_LOW],irq);
}
return 0;
}
static void shutdown_bigsur_irq(unsigned int irq)
{
DPRINTK("shutdown_bigsur_irq IRQ %d\n", irq);
if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH)
disable_bigsur_l1irq(irq);
else
disable_bigsur_l2irq(irq);
}
/* Define the IRQ structures for the L1 and L2 IRQ types */
static struct hw_interrupt_type bigsur_l1irq_type = {
"BigSur-CPLD-Level1-IRQ",
startup_bigsur_irq,
shutdown_bigsur_irq,
enable_bigsur_l1irq,
disable_bigsur_l1irq,
mask_and_ack_bigsur,
end_bigsur_irq
};
static struct hw_interrupt_type bigsur_l2irq_type = {
"BigSur-CPLD-Level2-IRQ",
startup_bigsur_irq,
shutdown_bigsur_irq,
enable_bigsur_l2irq,
disable_bigsur_l2irq,
mask_and_ack_bigsur,
end_bigsur_irq
};
static void make_bigsur_l1isr(unsigned int irq) {
/* sanity check first */
if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
/* save the handler in the main description table */
irq_desc[irq].handler = &bigsur_l1irq_type;
irq_desc[irq].status = IRQ_DISABLED;
irq_desc[irq].action = 0;
irq_desc[irq].depth = 1;
disable_bigsur_l1irq(irq);
return;
}
DPRINTK("make_bigsur_l1isr: bad irq, %d\n", irq);
return;
}
static void make_bigsur_l2isr(unsigned int irq) {
/* sanity check first */
if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
/* save the handler in the main description table */
irq_desc[irq].handler = &bigsur_l2irq_type;
irq_desc[irq].status = IRQ_DISABLED;
irq_desc[irq].action = 0;
irq_desc[irq].depth = 1;
disable_bigsur_l2irq(irq);
return;
}
DPRINTK("make_bigsur_l2isr: bad irq, %d\n", irq);
return;
}
/* The IRQ's will be decoded as follows:
* If a level 2 handler exists and there is an unmasked active
* IRQ, the 2nd level handler will be called.
* If a level 2 handler does not exist for the active IRQ
* the 1st level handler will be called.
*/
int bigsur_irq_demux(int irq)
{
int dmux_irq = irq;
u8 mask, actv_irqs;
u32 reg_num;
DIPRINTK(3,"bigsur_irq_demux, irq=%d\n", irq);
/* decode the 1st level IRQ */
if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
/* Get corresponding L2 ISR bitmask and ISR number */
mask = bigsur_l2irq_mask[irq-BIGSUR_IRQ_LOW];
reg_num = bigsur_l2irq_reg[irq-BIGSUR_IRQ_LOW];
/* find the active IRQ's (XOR with inactive level)*/
actv_irqs = inb(isr_base-reg_num*isr_offset) ^
bigsur_l2_inactv_state[reg_num];
/* decode active IRQ's */
actv_irqs = actv_irqs & mask & ~(inb(imr_base-reg_num*imr_offset));
/* if NEZ then we have an active L2 IRQ */
if(actv_irqs) dmux_irq = ffz(~actv_irqs) + reg_num*8+BIGSUR_2NDLVL_IRQ_LOW;
/* if no 2nd level IRQ action, but has 1st level, use 1st level handler */
if(!irq_desc[dmux_irq].action && irq_desc[irq].action)
dmux_irq = irq;
DIPRINTK(1,"bigsur_irq_demux: irq=%d dmux_irq=%d mask=0x%04x reg=%d\n",
irq, dmux_irq, mask, reg_num);
}
#ifdef CONFIG_HD64465
dmux_irq = hd64465_irq_demux(dmux_irq);
#endif /* CONFIG_HD64465 */
DIPRINTK(3,"bigsur_irq_demux, demux_irq=%d\n", dmux_irq);
return dmux_irq;
}
/*===========================================================*/
// Big Sur Init Routines
/*===========================================================*/
void __init init_bigsur_IRQ(void)
{
int i;
if (!MACH_BIGSUR) return;
/* Create ISR's for Big Sur CPLD IRQ's */
/*==============================================================*/
for(i=BIGSUR_IRQ_LOW;i<BIGSUR_IRQ_HIGH;i++)
make_bigsur_l1isr(i);
printk(KERN_INFO "Big Sur CPLD L1 interrupts %d to %d.\n",
BIGSUR_IRQ_LOW,BIGSUR_IRQ_HIGH);
for(i=BIGSUR_2NDLVL_IRQ_LOW;i<BIGSUR_2NDLVL_IRQ_HIGH;i++)
make_bigsur_l2isr(i);
printk(KERN_INFO "Big Sur CPLD L2 interrupts %d to %d.\n",
BIGSUR_2NDLVL_IRQ_LOW,BIGSUR_2NDLVL_IRQ_HIGH);
}
int __init setup_bigsur(void)
{
static int done = 0; /* run this only once */
if (!MACH_BIGSUR || done) return 0;
done = 1;
/* Mask all 2nd level IRQ's */
outb(-1,BIGSUR_IMR0);
outb(-1,BIGSUR_IMR1);
outb(-1,BIGSUR_IMR2);
outb(-1,BIGSUR_IMR3);
/* Mask 1st level interrupts */
outb(-1,BIGSUR_IRLMR0);
outb(-1,BIGSUR_IRLMR1);
#if defined (CONFIG_HD64465) && defined (CONFIG_SERIAL)
/* remap IO ports for first ISA serial port to HD64465 UART */
bigsur_port_map(0x3f8, 8, CONFIG_HD64465_IOBASE + 0x8000, 1);
#endif /* CONFIG_HD64465 && CONFIG_SERIAL */
/* TODO: setup IDE registers */
bigsur_port_map(BIGSUR_IDECTL_IOPORT, 2, BIGSUR_ICTL, 8);
/* Setup the Ethernet port to BIGSUR_ETHER_IOPORT */
bigsur_port_map(BIGSUR_ETHER_IOPORT, 16, BIGSUR_ETHR+BIGSUR_ETHER_IOPORT, 0);
/* set page to 1 */
outw(1, BIGSUR_ETHR+0xe);
/* set the IO port to BIGSUR_ETHER_IOPORT */
outw(BIGSUR_ETHER_IOPORT<<3, BIGSUR_ETHR+0x2);
return 0;
}
module_init(setup_bigsur);
/*
* Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* Defintions applicable to the STMicroelectronics ST40STB1 HARP and
* compatible boards.
*/
#if defined(CONFIG_SH_STB1_HARP)
#define EPLD_BASE 0xa0800000
#define EPLD_LED (EPLD_BASE+0x000c0000)
#define EPLD_INTSTAT0 (EPLD_BASE+0x00200000)
#define EPLD_INTSTAT1 (EPLD_BASE+0x00240000)
#define EPLD_INTMASK0 (EPLD_BASE+0x00280000)
#define EPLD_INTMASK1 (EPLD_BASE+0x002c0000)
#define EPLD_PAGEADDR (EPLD_BASE+0x00300000)
#define EPLD_REVID1 (EPLD_BASE+0x00380000)
#define EPLD_REVID2 (EPLD_BASE+0x003c0000)
#define EPLD_LED_ON 1
#define EPLD_LED_OFF 0
#elif defined(CONFIG_SH_STB1_OVERDRIVE)
#define EPLD_BASE 0xa7000000
#define EPLD_REVID (EPLD_BASE+0x00000000)
#define EPLD_LED (EPLD_BASE+0x00040000)
#define EPLD_INTMASK0 (EPLD_BASE+0x001c0000)
#define EPLD_INTMASK1 (EPLD_BASE+0x00200000)
#define EPLD_INTSTAT0 (EPLD_BASE+0x00240000)
#define EPLD_INTSTAT1 (EPLD_BASE+0x00280000)
#define EPLD_LED_ON 0
#define EPLD_LED_OFF 1
#else
#error Unknown board
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment