Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
このコミットが含まれているのは:
8
arch/sh/boards/mpc1211/Makefile
ノーマルファイル
8
arch/sh/boards/mpc1211/Makefile
ノーマルファイル
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# Makefile for the Interface (CTP/PCI/MPC-SH02) specific parts of the kernel
|
||||
#
|
||||
|
||||
obj-y := setup.o rtc.o led.o
|
||||
|
||||
obj-$(CONFIG_PCI) += pci.o
|
||||
|
64
arch/sh/boards/mpc1211/led.c
ノーマルファイル
64
arch/sh/boards/mpc1211/led.c
ノーマルファイル
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* linux/arch/sh/kernel/led_mpc1211.c
|
||||
*
|
||||
* Copyright (C) 2001 Saito.K & Jeanne
|
||||
*
|
||||
* This file contains Interface MPC-1211 specific LED code.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
|
||||
static void mach_led(int position, int value)
|
||||
{
|
||||
volatile unsigned char* p = (volatile unsigned char*)0xa2000000;
|
||||
|
||||
if (value) {
|
||||
*p |= 1;
|
||||
} else {
|
||||
*p &= ~1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HEARTBEAT
|
||||
|
||||
#include <linux/sched.h>
|
||||
|
||||
/* Cycle the LED's in the clasic Knightrider/Sun pattern */
|
||||
void heartbeat_mpc1211(void)
|
||||
{
|
||||
static unsigned int cnt = 0, period = 0;
|
||||
volatile unsigned char* p = (volatile unsigned char*)0xa2000000;
|
||||
static unsigned bit = 0, up = 1;
|
||||
|
||||
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 (up) {
|
||||
if (bit == 7) {
|
||||
bit--;
|
||||
up=0;
|
||||
} else {
|
||||
bit ++;
|
||||
}
|
||||
} else {
|
||||
if (bit == 0) {
|
||||
bit++;
|
||||
up=1;
|
||||
} else {
|
||||
bit--;
|
||||
}
|
||||
}
|
||||
*p = 1<<bit;
|
||||
|
||||
}
|
||||
#endif /* CONFIG_HEARTBEAT */
|
296
arch/sh/boards/mpc1211/pci.c
ノーマルファイル
296
arch/sh/boards/mpc1211/pci.c
ノーマルファイル
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
* Low-Level PCI Support for the MPC-1211(CTP/PCI/MPC-SH02)
|
||||
*
|
||||
* (c) 2002-2003 Saito.K & Jeanne
|
||||
*
|
||||
* 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/delay.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <asm/machvec.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/mpc1211/pci.h>
|
||||
|
||||
static struct resource mpcpci_io_resource = {
|
||||
"MPCPCI IO",
|
||||
0x00000000,
|
||||
0xffffffff,
|
||||
IORESOURCE_IO
|
||||
};
|
||||
|
||||
static struct resource mpcpci_mem_resource = {
|
||||
"MPCPCI mem",
|
||||
0x00000000,
|
||||
0xffffffff,
|
||||
IORESOURCE_MEM
|
||||
};
|
||||
|
||||
static struct pci_ops pci_direct_conf1;
|
||||
struct pci_channel board_pci_channels[] = {
|
||||
{&pci_direct_conf1, &mpcpci_io_resource, &mpcpci_mem_resource, 0, 256},
|
||||
{NULL, NULL, NULL, 0, 0},
|
||||
};
|
||||
|
||||
/*
|
||||
* Direct access to PCI hardware...
|
||||
*/
|
||||
|
||||
|
||||
#define CONFIG_CMD(bus, devfn, where) (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3))
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
local_irq_save(flags);
|
||||
writel(CONFIG_CMD(bus,devfn,where), PCIPAR);
|
||||
word = readl(PCIPDR);
|
||||
local_irq_restore(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;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
switch (where & 0x3) {
|
||||
case 3:
|
||||
*value = (u16)(word >> 24);
|
||||
local_irq_save(flags);
|
||||
writel(CONFIG_CMD(bus,devfn,(where+1)), PCIPAR);
|
||||
word = readl(PCIPDR);
|
||||
local_irq_restore(flags);
|
||||
*value |= ((word & 0xff) << 8);
|
||||
break;
|
||||
case 2:
|
||||
*value = (u16)(word >> 16);
|
||||
break;
|
||||
case 1:
|
||||
*value = (u16)(word >> 8);
|
||||
break;
|
||||
default:
|
||||
*value = (u16)word;
|
||||
break;
|
||||
}
|
||||
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 MPC-1211 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 = 0;
|
||||
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
|
||||
}
|
||||
local_irq_save(flags);
|
||||
writel(CONFIG_CMD(bus,devfn,where), PCIPAR);
|
||||
if(size == 4){
|
||||
writel(value, PCIPDR);
|
||||
local_irq_restore(flags);
|
||||
PCIDBG(4,"pci_conf1_write@0x%08x=0x%x\n", CONFIG_CMD(bus,devfn,where),value);
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
word = readl(PCIPDR);
|
||||
word &= ~mask;
|
||||
word |= ((value << shift) & mask);
|
||||
writel(word, PCIPDR);
|
||||
local_irq_restore(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,
|
||||
};
|
||||
|
||||
static void __devinit quirk_ali_ide_ports(struct pci_dev *dev)
|
||||
{
|
||||
dev->resource[0].start = 0x1f0;
|
||||
dev->resource[0].end = 0x1f7;
|
||||
dev->resource[0].flags = IORESOURCE_IO;
|
||||
dev->resource[1].start = 0x3f6;
|
||||
dev->resource[1].end = 0x3f6;
|
||||
dev->resource[1].flags = IORESOURCE_IO;
|
||||
dev->resource[2].start = 0x170;
|
||||
dev->resource[2].end = 0x177;
|
||||
dev->resource[2].flags = IORESOURCE_IO;
|
||||
dev->resource[3].start = 0x376;
|
||||
dev->resource[3].end = 0x376;
|
||||
dev->resource[3].flags = IORESOURCE_IO;
|
||||
dev->resource[4].start = 0xf000;
|
||||
dev->resource[4].end = 0xf00f;
|
||||
dev->resource[4].flags = IORESOURCE_IO;
|
||||
}
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229, quirk_ali_ide_ports);
|
||||
|
||||
char * __devinit pcibios_setup(char *str)
|
||||
{
|
||||
return str;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* IRQ functions
|
||||
*/
|
||||
static inline u8 bridge_swizzle(u8 pin, u8 slot)
|
||||
{
|
||||
return (((pin-1) + slot) % 4) + 1;
|
||||
}
|
||||
|
||||
static inline u8 bridge_swizzle_pci_1(u8 pin, u8 slot)
|
||||
{
|
||||
return (((pin-1) - slot) & 3) + 1;
|
||||
}
|
||||
|
||||
static u8 __init mpc1211_swizzle(struct pci_dev *dev, u8 *pinp)
|
||||
{
|
||||
unsigned long flags;
|
||||
u8 pin = *pinp;
|
||||
u32 word;
|
||||
|
||||
for ( ; dev->bus->self; dev = dev->bus->self) {
|
||||
if (!pin)
|
||||
continue;
|
||||
|
||||
if (dev->bus->number == 1) {
|
||||
local_irq_save(flags);
|
||||
writel(0x80000000 | 0x2c, PCIPAR);
|
||||
word = readl(PCIPDR);
|
||||
local_irq_restore(flags);
|
||||
word >>= 16;
|
||||
|
||||
if (word == 0x0001)
|
||||
pin = bridge_swizzle_pci_1(pin, PCI_SLOT(dev->devfn));
|
||||
else
|
||||
pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
|
||||
} else
|
||||
pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
|
||||
}
|
||||
|
||||
*pinp = pin;
|
||||
|
||||
return PCI_SLOT(dev->devfn);
|
||||
}
|
||||
|
||||
static int __init map_mpc1211_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) */
|
||||
if (dev->bus->number == 0) {
|
||||
switch (slot) {
|
||||
case 13: irq = 9; break; /* USB */
|
||||
case 22: irq = 10; break; /* LAN */
|
||||
default: irq = 0; break;
|
||||
}
|
||||
} else {
|
||||
switch (pin) {
|
||||
case 0: irq = 0; break;
|
||||
case 1: irq = 7; break;
|
||||
case 2: irq = 9; break;
|
||||
case 3: irq = 10; break;
|
||||
case 4: irq = 11; break;
|
||||
}
|
||||
}
|
||||
|
||||
if( irq < 0 ) {
|
||||
PCIDBG(3, "PCI: Error mapping IRQ on device %s\n", pci_name(dev));
|
||||
return irq;
|
||||
}
|
||||
|
||||
PCIDBG(2, "Setting IRQ for slot %s to %d\n", pci_name(dev), irq);
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
void __init pcibios_fixup_irqs(void)
|
||||
{
|
||||
pci_fixup_irqs(mpc1211_swizzle, map_mpc1211_irq);
|
||||
}
|
||||
|
||||
void pcibios_align_resource(void *data, struct resource *res,
|
||||
unsigned long size, unsigned long align)
|
||||
{
|
||||
unsigned long start = res->start;
|
||||
|
||||
if (res->flags & IORESOURCE_IO) {
|
||||
if (start >= 0x10000UL) {
|
||||
if ((start & 0xffffUL) < 0x4000UL) {
|
||||
start = (start & 0xffff0000UL) + 0x4000UL;
|
||||
} else if ((start & 0xffffUL) >= 0xf000UL) {
|
||||
start = (start & 0xffff0000UL) + 0x10000UL;
|
||||
}
|
||||
res->start = start;
|
||||
} else {
|
||||
if (start & 0x300) {
|
||||
start = (start + 0x3ff) & ~0x3ff;
|
||||
res->start = start;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
152
arch/sh/boards/mpc1211/rtc.c
ノーマルファイル
152
arch/sh/boards/mpc1211/rtc.c
ノーマルファイル
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* linux/arch/sh/kernel/rtc-mpc1211.c -- MPC-1211 on-chip RTC support
|
||||
*
|
||||
* Copyright (C) 2002 Saito.K & Jeanne
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/mc146818rtc.h>
|
||||
|
||||
#ifndef BCD_TO_BIN
|
||||
#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
|
||||
#endif
|
||||
|
||||
#ifndef BIN_TO_BCD
|
||||
#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
|
||||
#endif
|
||||
|
||||
/* arc/i386/kernel/time.c */
|
||||
unsigned long get_cmos_time(void)
|
||||
{
|
||||
unsigned int year, mon, day, hour, min, sec;
|
||||
int i;
|
||||
|
||||
spin_lock(&rtc_lock);
|
||||
/* The Linux interpretation of the CMOS clock register contents:
|
||||
* When the Update-In-Progress (UIP) flag goes from 1 to 0, the
|
||||
* RTC registers show the second which has precisely just started.
|
||||
* Let's hope other operating systems interpret the RTC the same way.
|
||||
*/
|
||||
/* read RTC exactly on falling edge of update flag */
|
||||
for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
|
||||
if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
|
||||
break;
|
||||
for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
|
||||
if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
|
||||
break;
|
||||
do { /* Isn't this overkill ? UIP above should guarantee consistency */
|
||||
sec = CMOS_READ(RTC_SECONDS);
|
||||
min = CMOS_READ(RTC_MINUTES);
|
||||
hour = CMOS_READ(RTC_HOURS);
|
||||
day = CMOS_READ(RTC_DAY_OF_MONTH);
|
||||
mon = CMOS_READ(RTC_MONTH);
|
||||
year = CMOS_READ(RTC_YEAR);
|
||||
} while (sec != CMOS_READ(RTC_SECONDS));
|
||||
if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
|
||||
{
|
||||
BCD_TO_BIN(sec);
|
||||
BCD_TO_BIN(min);
|
||||
BCD_TO_BIN(hour);
|
||||
BCD_TO_BIN(day);
|
||||
BCD_TO_BIN(mon);
|
||||
BCD_TO_BIN(year);
|
||||
}
|
||||
spin_unlock(&rtc_lock);
|
||||
if ((year += 1900) < 1970)
|
||||
year += 100;
|
||||
return mktime(year, mon, day, hour, min, sec);
|
||||
}
|
||||
|
||||
void mpc1211_rtc_gettimeofday(struct timeval *tv)
|
||||
{
|
||||
|
||||
tv->tv_sec = get_cmos_time();
|
||||
tv->tv_usec = 0;
|
||||
}
|
||||
|
||||
/* arc/i386/kernel/time.c */
|
||||
/*
|
||||
* In order to set the CMOS clock precisely, set_rtc_mmss has to be
|
||||
* called 500 ms after the second nowtime has started, because when
|
||||
* nowtime is written into the registers of the CMOS clock, it will
|
||||
* jump to the next second precisely 500 ms later. Check the Motorola
|
||||
* MC146818A or Dallas DS12887 data sheet for details.
|
||||
*
|
||||
* BUG: This routine does not handle hour overflow properly; it just
|
||||
* sets the minutes. Usually you'll only notice that after reboot!
|
||||
*/
|
||||
static int set_rtc_mmss(unsigned long nowtime)
|
||||
{
|
||||
int retval = 0;
|
||||
int real_seconds, real_minutes, cmos_minutes;
|
||||
unsigned char save_control, save_freq_select;
|
||||
|
||||
/* gets recalled with irq locally disabled */
|
||||
spin_lock(&rtc_lock);
|
||||
save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
|
||||
CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
|
||||
|
||||
save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
|
||||
CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
|
||||
|
||||
cmos_minutes = CMOS_READ(RTC_MINUTES);
|
||||
if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
|
||||
BCD_TO_BIN(cmos_minutes);
|
||||
|
||||
/*
|
||||
* since we're only adjusting minutes and seconds,
|
||||
* don't interfere with hour overflow. This avoids
|
||||
* messing with unknown time zones but requires your
|
||||
* RTC not to be off by more than 15 minutes
|
||||
*/
|
||||
real_seconds = nowtime % 60;
|
||||
real_minutes = nowtime / 60;
|
||||
if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
|
||||
real_minutes += 30; /* correct for half hour time zone */
|
||||
real_minutes %= 60;
|
||||
|
||||
if (abs(real_minutes - cmos_minutes) < 30) {
|
||||
if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
|
||||
BIN_TO_BCD(real_seconds);
|
||||
BIN_TO_BCD(real_minutes);
|
||||
}
|
||||
CMOS_WRITE(real_seconds,RTC_SECONDS);
|
||||
CMOS_WRITE(real_minutes,RTC_MINUTES);
|
||||
} else {
|
||||
printk(KERN_WARNING
|
||||
"set_rtc_mmss: can't update from %d to %d\n",
|
||||
cmos_minutes, real_minutes);
|
||||
retval = -1;
|
||||
}
|
||||
|
||||
/* The following flags have to be released exactly in this order,
|
||||
* otherwise the DS12887 (popular MC146818A clone with integrated
|
||||
* battery and quartz) will not reset the oscillator and will not
|
||||
* update precisely 500 ms later. You won't find this mentioned in
|
||||
* the Dallas Semiconductor data sheets, but who believes data
|
||||
* sheets anyway ... -- Markus Kuhn
|
||||
*/
|
||||
CMOS_WRITE(save_control, RTC_CONTROL);
|
||||
CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
|
||||
spin_unlock(&rtc_lock);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int mpc1211_rtc_settimeofday(const struct timeval *tv)
|
||||
{
|
||||
unsigned long nowtime = tv->tv_sec;
|
||||
|
||||
return set_rtc_mmss(nowtime);
|
||||
}
|
||||
|
||||
void mpc1211_time_init(void)
|
||||
{
|
||||
rtc_get_time = mpc1211_rtc_gettimeofday;
|
||||
rtc_set_time = mpc1211_rtc_settimeofday;
|
||||
}
|
||||
|
360
arch/sh/boards/mpc1211/setup.c
ノーマルファイル
360
arch/sh/boards/mpc1211/setup.c
ノーマルファイル
@@ -0,0 +1,360 @@
|
||||
/*
|
||||
* linux/arch/sh/board/mpc1211/setup.c
|
||||
*
|
||||
* Copyright (C) 2002 Saito.K & Jeanne, Fujii.Y
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/hdreg.h>
|
||||
#include <linux/ide.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/machvec.h>
|
||||
#include <asm/mpc1211/mpc1211.h>
|
||||
#include <asm/mpc1211/pci.h>
|
||||
#include <asm/mpc1211/m1543c.h>
|
||||
|
||||
|
||||
/* ALI15X3 SMBus address offsets */
|
||||
#define SMBHSTSTS (0 + 0x3100)
|
||||
#define SMBHSTCNT (1 + 0x3100)
|
||||
#define SMBHSTSTART (2 + 0x3100)
|
||||
#define SMBHSTCMD (7 + 0x3100)
|
||||
#define SMBHSTADD (3 + 0x3100)
|
||||
#define SMBHSTDAT0 (4 + 0x3100)
|
||||
#define SMBHSTDAT1 (5 + 0x3100)
|
||||
#define SMBBLKDAT (6 + 0x3100)
|
||||
|
||||
/* Other settings */
|
||||
#define MAX_TIMEOUT 500 /* times 1/100 sec */
|
||||
|
||||
/* ALI15X3 command constants */
|
||||
#define ALI15X3_ABORT 0x04
|
||||
#define ALI15X3_T_OUT 0x08
|
||||
#define ALI15X3_QUICK 0x00
|
||||
#define ALI15X3_BYTE 0x10
|
||||
#define ALI15X3_BYTE_DATA 0x20
|
||||
#define ALI15X3_WORD_DATA 0x30
|
||||
#define ALI15X3_BLOCK_DATA 0x40
|
||||
#define ALI15X3_BLOCK_CLR 0x80
|
||||
|
||||
/* ALI15X3 status register bits */
|
||||
#define ALI15X3_STS_IDLE 0x04
|
||||
#define ALI15X3_STS_BUSY 0x08
|
||||
#define ALI15X3_STS_DONE 0x10
|
||||
#define ALI15X3_STS_DEV 0x20 /* device error */
|
||||
#define ALI15X3_STS_COLL 0x40 /* collision or no response */
|
||||
#define ALI15X3_STS_TERM 0x80 /* terminated by abort */
|
||||
#define ALI15X3_STS_ERR 0xE0 /* all the bad error bits */
|
||||
|
||||
const char *get_system_type(void)
|
||||
{
|
||||
return "Interface MPC-1211(CTP/PCI/MPC-SH02)";
|
||||
}
|
||||
|
||||
static void __init pci_write_config(unsigned long busNo,
|
||||
unsigned long devNo,
|
||||
unsigned long fncNo,
|
||||
unsigned long cnfAdd,
|
||||
unsigned long cnfData)
|
||||
{
|
||||
ctrl_outl((0x80000000
|
||||
+ ((busNo & 0xff) << 16)
|
||||
+ ((devNo & 0x1f) << 11)
|
||||
+ ((fncNo & 0x07) << 8)
|
||||
+ (cnfAdd & 0xfc)), PCIPAR);
|
||||
|
||||
ctrl_outl(cnfData, PCIPDR);
|
||||
}
|
||||
|
||||
/*
|
||||
Initialize IRQ setting
|
||||
*/
|
||||
|
||||
static unsigned char m_irq_mask = 0xfb;
|
||||
static unsigned char s_irq_mask = 0xff;
|
||||
volatile unsigned long irq_err_count;
|
||||
|
||||
static void disable_mpc1211_irq(unsigned int irq)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
save_and_cli(flags);
|
||||
if( irq < 8) {
|
||||
m_irq_mask |= (1 << irq);
|
||||
outb(m_irq_mask,I8259_M_MR);
|
||||
} else {
|
||||
s_irq_mask |= (1 << (irq - 8));
|
||||
outb(s_irq_mask,I8259_S_MR);
|
||||
}
|
||||
restore_flags(flags);
|
||||
|
||||
}
|
||||
|
||||
static void enable_mpc1211_irq(unsigned int irq)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
save_and_cli(flags);
|
||||
|
||||
if( irq < 8) {
|
||||
m_irq_mask &= ~(1 << irq);
|
||||
outb(m_irq_mask,I8259_M_MR);
|
||||
} else {
|
||||
s_irq_mask &= ~(1 << (irq - 8));
|
||||
outb(s_irq_mask,I8259_S_MR);
|
||||
}
|
||||
restore_flags(flags);
|
||||
}
|
||||
|
||||
static inline int mpc1211_irq_real(unsigned int irq)
|
||||
{
|
||||
int value;
|
||||
int irqmask;
|
||||
|
||||
if ( irq < 8) {
|
||||
irqmask = 1<<irq;
|
||||
outb(0x0b,I8259_M_CR); /* ISR register */
|
||||
value = inb(I8259_M_CR) & irqmask;
|
||||
outb(0x0a,I8259_M_CR); /* back ro the IPR reg */
|
||||
return value;
|
||||
}
|
||||
irqmask = 1<<(irq - 8);
|
||||
outb(0x0b,I8259_S_CR); /* ISR register */
|
||||
value = inb(I8259_S_CR) & irqmask;
|
||||
outb(0x0a,I8259_S_CR); /* back ro the IPR reg */
|
||||
return value;
|
||||
}
|
||||
|
||||
static void mask_and_ack_mpc1211(unsigned int irq)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
save_and_cli(flags);
|
||||
|
||||
if(irq < 8) {
|
||||
if(m_irq_mask & (1<<irq)){
|
||||
if(!mpc1211_irq_real(irq)){
|
||||
irq_err_count++;
|
||||
printk("spurious 8259A interrupt: IRQ %x\n",irq);
|
||||
}
|
||||
} else {
|
||||
m_irq_mask |= (1<<irq);
|
||||
}
|
||||
inb(I8259_M_MR); /* DUMMY */
|
||||
outb(m_irq_mask,I8259_M_MR); /* disable */
|
||||
outb(0x60+irq,I8259_M_CR); /* EOI */
|
||||
|
||||
} else {
|
||||
if(s_irq_mask & (1<<(irq - 8))){
|
||||
if(!mpc1211_irq_real(irq)){
|
||||
irq_err_count++;
|
||||
printk("spurious 8259A interrupt: IRQ %x\n",irq);
|
||||
}
|
||||
} else {
|
||||
s_irq_mask |= (1<<(irq - 8));
|
||||
}
|
||||
inb(I8259_S_MR); /* DUMMY */
|
||||
outb(s_irq_mask,I8259_S_MR); /* disable */
|
||||
outb(0x60+(irq-8),I8259_S_CR); /* EOI */
|
||||
outb(0x60+2,I8259_M_CR);
|
||||
}
|
||||
restore_flags(flags);
|
||||
}
|
||||
|
||||
static void end_mpc1211_irq(unsigned int irq)
|
||||
{
|
||||
enable_mpc1211_irq(irq);
|
||||
}
|
||||
|
||||
static unsigned int startup_mpc1211_irq(unsigned int irq)
|
||||
{
|
||||
enable_mpc1211_irq(irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void shutdown_mpc1211_irq(unsigned int irq)
|
||||
{
|
||||
disable_mpc1211_irq(irq);
|
||||
}
|
||||
|
||||
static struct hw_interrupt_type mpc1211_irq_type = {
|
||||
.typename = "MPC1211-IRQ",
|
||||
.startup = startup_mpc1211_irq,
|
||||
.shutdown = shutdown_mpc1211_irq,
|
||||
.enable = enable_mpc1211_irq,
|
||||
.disable = disable_mpc1211_irq,
|
||||
.ack = mask_and_ack_mpc1211,
|
||||
.end = end_mpc1211_irq
|
||||
};
|
||||
|
||||
static void make_mpc1211_irq(unsigned int irq)
|
||||
{
|
||||
irq_desc[irq].handler = &mpc1211_irq_type;
|
||||
irq_desc[irq].status = IRQ_DISABLED;
|
||||
irq_desc[irq].action = 0;
|
||||
irq_desc[irq].depth = 1;
|
||||
disable_mpc1211_irq(irq);
|
||||
}
|
||||
|
||||
int mpc1211_irq_demux(int irq)
|
||||
{
|
||||
unsigned int poll;
|
||||
|
||||
if( irq == 2 ) {
|
||||
outb(0x0c,I8259_M_CR);
|
||||
poll = inb(I8259_M_CR);
|
||||
if(poll & 0x80) {
|
||||
irq = (poll & 0x07);
|
||||
}
|
||||
if( irq == 2) {
|
||||
outb(0x0c,I8259_S_CR);
|
||||
poll = inb(I8259_S_CR);
|
||||
irq = (poll & 0x07) + 8;
|
||||
}
|
||||
}
|
||||
return irq;
|
||||
}
|
||||
|
||||
void __init init_mpc1211_IRQ(void)
|
||||
{
|
||||
int i;
|
||||
/*
|
||||
* Super I/O (Just mimic PC):
|
||||
* 1: keyboard
|
||||
* 3: serial 1
|
||||
* 4: serial 0
|
||||
* 5: printer
|
||||
* 6: floppy
|
||||
* 8: rtc
|
||||
* 10: lan
|
||||
* 12: mouse
|
||||
* 14: ide0
|
||||
* 15: ide1
|
||||
*/
|
||||
|
||||
pci_write_config(0,0,0,0x54, 0xb0b0002d);
|
||||
outb(0x11, I8259_M_CR); /* mater icw1 edge trigger */
|
||||
outb(0x11, I8259_S_CR); /* slave icw1 edge trigger */
|
||||
outb(0x20, I8259_M_MR); /* m icw2 base vec 0x08 */
|
||||
outb(0x28, I8259_S_MR); /* s icw2 base vec 0x70 */
|
||||
outb(0x04, I8259_M_MR); /* m icw3 slave irq2 */
|
||||
outb(0x02, I8259_S_MR); /* s icw3 slave id */
|
||||
outb(0x01, I8259_M_MR); /* m icw4 non buf normal eoi*/
|
||||
outb(0x01, I8259_S_MR); /* s icw4 non buf normal eo1*/
|
||||
outb(0xfb, I8259_M_MR); /* disable irq0--irq7 */
|
||||
outb(0xff, I8259_S_MR); /* disable irq8--irq15 */
|
||||
|
||||
for ( i=0; i < 16; i++) {
|
||||
if(i != 2) {
|
||||
make_mpc1211_irq(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Initialize the board
|
||||
*/
|
||||
|
||||
|
||||
static void delay (void)
|
||||
{
|
||||
volatile unsigned short tmp;
|
||||
tmp = *(volatile unsigned short *) 0xa0000000;
|
||||
}
|
||||
|
||||
static void delay1000 (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<1000; i++)
|
||||
delay ();
|
||||
}
|
||||
|
||||
static int put_smb_blk(unsigned char *p, int address, int command, int no)
|
||||
{
|
||||
int temp;
|
||||
int timeout;
|
||||
int i;
|
||||
|
||||
outb(0xff, SMBHSTSTS);
|
||||
temp = inb(SMBHSTSTS);
|
||||
for (timeout = 0; (timeout < MAX_TIMEOUT) && !(temp & ALI15X3_STS_IDLE); timeout++) {
|
||||
delay1000();
|
||||
temp = inb(SMBHSTSTS);
|
||||
}
|
||||
if (timeout >= MAX_TIMEOUT){
|
||||
return -1;
|
||||
}
|
||||
|
||||
outb(((address & 0x7f) << 1), SMBHSTADD);
|
||||
outb(0xc0, SMBHSTCNT);
|
||||
outb(command & 0xff, SMBHSTCMD);
|
||||
outb(no & 0x1f, SMBHSTDAT0);
|
||||
|
||||
for(i = 1; i <= no; i++) {
|
||||
outb(*p++, SMBBLKDAT);
|
||||
}
|
||||
outb(0xff, SMBHSTSTART);
|
||||
|
||||
temp = inb(SMBHSTSTS);
|
||||
for (timeout = 0; (timeout < MAX_TIMEOUT) && !(temp & (ALI15X3_STS_ERR | ALI15X3_STS_DONE)); timeout++) {
|
||||
delay1000();
|
||||
temp = inb(SMBHSTSTS);
|
||||
}
|
||||
if (timeout >= MAX_TIMEOUT) {
|
||||
return -2;
|
||||
}
|
||||
if ( temp & ALI15X3_STS_ERR ){
|
||||
return -3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The Machine Vector
|
||||
*/
|
||||
|
||||
struct sh_machine_vector mv_mpc1211 __initmv = {
|
||||
.mv_nr_irqs = 48,
|
||||
.mv_irq_demux = mpc1211_irq_demux,
|
||||
.mv_init_irq = init_mpc1211_IRQ,
|
||||
|
||||
#ifdef CONFIG_HEARTBEAT
|
||||
.mv_heartbeat = heartbeat_mpc1211,
|
||||
#endif
|
||||
};
|
||||
|
||||
ALIAS_MV(mpc1211)
|
||||
|
||||
/* arch/sh/boards/mpc1211/rtc.c */
|
||||
void mpc1211_time_init(void);
|
||||
|
||||
int __init platform_setup(void)
|
||||
{
|
||||
unsigned char spd_buf[128];
|
||||
|
||||
__set_io_port_base(PA_PCI_IO);
|
||||
|
||||
pci_write_config(0,0,0,0x54, 0xb0b00000);
|
||||
|
||||
do {
|
||||
outb(ALI15X3_ABORT, SMBHSTCNT);
|
||||
spd_buf[0] = 0x0c;
|
||||
spd_buf[1] = 0x43;
|
||||
spd_buf[2] = 0x7f;
|
||||
spd_buf[3] = 0x03;
|
||||
spd_buf[4] = 0x00;
|
||||
spd_buf[5] = 0x03;
|
||||
spd_buf[6] = 0x00;
|
||||
} while (put_smb_blk(spd_buf, 0x69, 0, 7) < 0);
|
||||
|
||||
board_time_init = mpc1211_time_init;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
新しいイシューから参照
ユーザーをブロックする