mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-17 09:14:19 +08:00
cd354f1ae7
After Al Viro (finally) succeeded in removing the sched.h #include in module.h recently, it makes sense again to remove other superfluous sched.h includes. There are quite a lot of files which include it but don't actually need anything defined in there. Presumably these includes were once needed for macros that used to live in sched.h, but moved to other header files in the course of cleaning it up. To ease the pain, this time I did not fiddle with any header files and only removed #includes from .c-files, which tend to cause less trouble. Compile tested against 2.6.20-rc2 and 2.6.20-rc2-mm2 (with offsets) on alpha, arm, i386, ia64, mips, powerpc, and x86_64 with allnoconfig, defconfig, allmodconfig, and allyesconfig as well as a few randconfigs on x86_64 and all configs in arch/arm/configs on arm. I also checked that no new warnings were introduced by the patch (actually, some warnings are removed that were emitted by unnecessarily included header files). Signed-off-by: Tim Schmielau <tim@physik3.uni-rostock.de> Acked-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
854 lines
20 KiB
C
854 lines
20 KiB
C
/*
|
|
* linux/drivers/ide/ppc/ide-m8xx.c
|
|
*
|
|
* Copyright (C) 2000, 2001 Wolfgang Denk, wd@denx.de
|
|
* Modified for direct IDE interface
|
|
* by Thomas Lange, thomas@corelatus.com
|
|
* Modified for direct IDE interface on 8xx without using the PCMCIA
|
|
* controller
|
|
* by Steven.Scholz@imc-berlin.de
|
|
* Moved out of arch/ppc/kernel/m8xx_setup.c, other minor cleanups
|
|
* by Mathew Locke <mattl@mvista.com>
|
|
*/
|
|
|
|
#include <linux/errno.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/stddef.h>
|
|
#include <linux/unistd.h>
|
|
#include <linux/ptrace.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/user.h>
|
|
#include <linux/a.out.h>
|
|
#include <linux/tty.h>
|
|
#include <linux/major.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/reboot.h>
|
|
#include <linux/init.h>
|
|
#include <linux/ioport.h>
|
|
#include <linux/ide.h>
|
|
#include <linux/bootmem.h>
|
|
|
|
#include <asm/mpc8xx.h>
|
|
#include <asm/mmu.h>
|
|
#include <asm/processor.h>
|
|
#include <asm/residual.h>
|
|
#include <asm/io.h>
|
|
#include <asm/pgtable.h>
|
|
#include <asm/ide.h>
|
|
#include <asm/8xx_immap.h>
|
|
#include <asm/machdep.h>
|
|
#include <asm/irq.h>
|
|
|
|
static int identify (volatile u8 *p);
|
|
static void print_fixed (volatile u8 *p);
|
|
static void print_funcid (int func);
|
|
static int check_ide_device (unsigned long base);
|
|
|
|
static void ide_interrupt_ack (void *dev);
|
|
static void m8xx_ide_tuneproc(ide_drive_t *drive, u8 pio);
|
|
|
|
typedef struct ide_ioport_desc {
|
|
unsigned long base_off; /* Offset to PCMCIA memory */
|
|
unsigned long reg_off[IDE_NR_PORTS]; /* controller register offsets */
|
|
int irq; /* IRQ */
|
|
} ide_ioport_desc_t;
|
|
|
|
ide_ioport_desc_t ioport_dsc[MAX_HWIFS] = {
|
|
#ifdef IDE0_BASE_OFFSET
|
|
{ IDE0_BASE_OFFSET,
|
|
{
|
|
IDE0_DATA_REG_OFFSET,
|
|
IDE0_ERROR_REG_OFFSET,
|
|
IDE0_NSECTOR_REG_OFFSET,
|
|
IDE0_SECTOR_REG_OFFSET,
|
|
IDE0_LCYL_REG_OFFSET,
|
|
IDE0_HCYL_REG_OFFSET,
|
|
IDE0_SELECT_REG_OFFSET,
|
|
IDE0_STATUS_REG_OFFSET,
|
|
IDE0_CONTROL_REG_OFFSET,
|
|
IDE0_IRQ_REG_OFFSET,
|
|
},
|
|
IDE0_INTERRUPT,
|
|
},
|
|
#ifdef IDE1_BASE_OFFSET
|
|
{ IDE1_BASE_OFFSET,
|
|
{
|
|
IDE1_DATA_REG_OFFSET,
|
|
IDE1_ERROR_REG_OFFSET,
|
|
IDE1_NSECTOR_REG_OFFSET,
|
|
IDE1_SECTOR_REG_OFFSET,
|
|
IDE1_LCYL_REG_OFFSET,
|
|
IDE1_HCYL_REG_OFFSET,
|
|
IDE1_SELECT_REG_OFFSET,
|
|
IDE1_STATUS_REG_OFFSET,
|
|
IDE1_CONTROL_REG_OFFSET,
|
|
IDE1_IRQ_REG_OFFSET,
|
|
},
|
|
IDE1_INTERRUPT,
|
|
},
|
|
#endif /* IDE1_BASE_OFFSET */
|
|
#endif /* IDE0_BASE_OFFSET */
|
|
};
|
|
|
|
ide_pio_timings_t ide_pio_clocks[6];
|
|
int hold_time[6] = {30, 20, 15, 10, 10, 10 }; /* PIO Mode 5 with IORDY (nonstandard) */
|
|
|
|
/*
|
|
* Warning: only 1 (ONE) PCMCIA slot supported here,
|
|
* which must be correctly initialized by the firmware (PPCBoot).
|
|
*/
|
|
static int _slot_ = -1; /* will be read from PCMCIA registers */
|
|
|
|
/* Make clock cycles and always round up */
|
|
#define PCMCIA_MK_CLKS( t, T ) (( (t) * ((T)/1000000) + 999U ) / 1000U )
|
|
|
|
|
|
|
|
/*
|
|
* IDE stuff.
|
|
*/
|
|
static int
|
|
m8xx_ide_default_irq(unsigned long base)
|
|
{
|
|
#ifdef CONFIG_BLK_DEV_MPC8xx_IDE
|
|
if (base >= MAX_HWIFS)
|
|
return 0;
|
|
|
|
printk("[%d] m8xx_ide_default_irq %d\n",__LINE__,ioport_dsc[base].irq);
|
|
|
|
return (ioport_dsc[base].irq);
|
|
#else
|
|
return 9;
|
|
#endif
|
|
}
|
|
|
|
static unsigned long
|
|
m8xx_ide_default_io_base(int index)
|
|
{
|
|
return index;
|
|
}
|
|
|
|
#define M8XX_PCMCIA_CD2(slot) (0x10000000 >> (slot << 4))
|
|
#define M8XX_PCMCIA_CD1(slot) (0x08000000 >> (slot << 4))
|
|
|
|
/*
|
|
* The TQM850L hardware has two pins swapped! Grrrrgh!
|
|
*/
|
|
#ifdef CONFIG_TQM850L
|
|
#define __MY_PCMCIA_GCRX_CXRESET PCMCIA_GCRX_CXOE
|
|
#define __MY_PCMCIA_GCRX_CXOE PCMCIA_GCRX_CXRESET
|
|
#else
|
|
#define __MY_PCMCIA_GCRX_CXRESET PCMCIA_GCRX_CXRESET
|
|
#define __MY_PCMCIA_GCRX_CXOE PCMCIA_GCRX_CXOE
|
|
#endif
|
|
|
|
#if defined(CONFIG_BLK_DEV_MPC8xx_IDE) && defined(CONFIG_IDE_8xx_PCCARD)
|
|
#define PCMCIA_SCHLVL IDE0_INTERRUPT /* Status Change Interrupt Level */
|
|
static int pcmcia_schlvl = PCMCIA_SCHLVL;
|
|
#endif
|
|
|
|
/*
|
|
* See include/linux/ide.h for definition of hw_regs_t (p, base)
|
|
*/
|
|
|
|
/*
|
|
* m8xx_ide_init_hwif_ports for a direct IDE interface _using_
|
|
*/
|
|
#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
|
|
static void
|
|
m8xx_ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port,
|
|
unsigned long ctrl_port, int *irq)
|
|
{
|
|
unsigned long *p = hw->io_ports;
|
|
int i;
|
|
|
|
typedef struct {
|
|
ulong br;
|
|
ulong or;
|
|
} pcmcia_win_t;
|
|
volatile pcmcia_win_t *win;
|
|
volatile pcmconf8xx_t *pcmp;
|
|
|
|
uint *pgcrx;
|
|
u32 pcmcia_phy_base;
|
|
u32 pcmcia_phy_end;
|
|
static unsigned long pcmcia_base = 0;
|
|
unsigned long base;
|
|
|
|
*p = 0;
|
|
if (irq)
|
|
*irq = 0;
|
|
|
|
pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia));
|
|
|
|
if (!pcmcia_base) {
|
|
/*
|
|
* Read out PCMCIA registers. Since the reset values
|
|
* are undefined, we sure hope that they have been
|
|
* set up by firmware
|
|
*/
|
|
|
|
/* Scan all registers for valid settings */
|
|
pcmcia_phy_base = 0xFFFFFFFF;
|
|
pcmcia_phy_end = 0;
|
|
/* br0 is start of brX and orX regs */
|
|
win = (pcmcia_win_t *) \
|
|
(&(((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0));
|
|
for (i = 0; i < 8; i++) {
|
|
if (win->or & 1) { /* This bank is marked as valid */
|
|
if (win->br < pcmcia_phy_base) {
|
|
pcmcia_phy_base = win->br;
|
|
}
|
|
if ((win->br + PCMCIA_MEM_SIZE) > pcmcia_phy_end) {
|
|
pcmcia_phy_end = win->br + PCMCIA_MEM_SIZE;
|
|
}
|
|
/* Check which slot that has been defined */
|
|
_slot_ = (win->or >> 2) & 1;
|
|
|
|
} /* Valid bank */
|
|
win++;
|
|
} /* for */
|
|
|
|
printk ("PCMCIA slot %c: phys mem %08x...%08x (size %08x)\n",
|
|
'A' + _slot_,
|
|
pcmcia_phy_base, pcmcia_phy_end,
|
|
pcmcia_phy_end - pcmcia_phy_base);
|
|
|
|
pcmcia_base=(unsigned long)ioremap(pcmcia_phy_base,
|
|
pcmcia_phy_end-pcmcia_phy_base);
|
|
|
|
#ifdef DEBUG
|
|
printk ("PCMCIA virt base: %08lx\n", pcmcia_base);
|
|
#endif
|
|
/* Compute clock cycles for PIO timings */
|
|
for (i=0; i<6; ++i) {
|
|
bd_t *binfo = (bd_t *)__res;
|
|
|
|
hold_time[i] =
|
|
PCMCIA_MK_CLKS (hold_time[i],
|
|
binfo->bi_busfreq);
|
|
ide_pio_clocks[i].setup_time =
|
|
PCMCIA_MK_CLKS (ide_pio_timings[i].setup_time,
|
|
binfo->bi_busfreq);
|
|
ide_pio_clocks[i].active_time =
|
|
PCMCIA_MK_CLKS (ide_pio_timings[i].active_time,
|
|
binfo->bi_busfreq);
|
|
ide_pio_clocks[i].cycle_time =
|
|
PCMCIA_MK_CLKS (ide_pio_timings[i].cycle_time,
|
|
binfo->bi_busfreq);
|
|
#if 0
|
|
printk ("PIO mode %d timings: %d/%d/%d => %d/%d/%d\n",
|
|
i,
|
|
ide_pio_clocks[i].setup_time,
|
|
ide_pio_clocks[i].active_time,
|
|
ide_pio_clocks[i].hold_time,
|
|
ide_pio_clocks[i].cycle_time,
|
|
ide_pio_timings[i].setup_time,
|
|
ide_pio_timings[i].active_time,
|
|
ide_pio_timings[i].hold_time,
|
|
ide_pio_timings[i].cycle_time);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (data_port >= MAX_HWIFS)
|
|
return;
|
|
|
|
if (_slot_ == -1) {
|
|
printk ("PCMCIA slot has not been defined! Using A as default\n");
|
|
_slot_ = 0;
|
|
}
|
|
|
|
#ifdef CONFIG_IDE_8xx_PCCARD
|
|
|
|
#ifdef DEBUG
|
|
printk ("PIPR = 0x%08X slot %c ==> mask = 0x%X\n",
|
|
pcmp->pcmc_pipr,
|
|
'A' + _slot_,
|
|
M8XX_PCMCIA_CD1(_slot_) | M8XX_PCMCIA_CD2(_slot_) );
|
|
#endif /* DEBUG */
|
|
|
|
if (pcmp->pcmc_pipr & (M8XX_PCMCIA_CD1(_slot_)|M8XX_PCMCIA_CD2(_slot_))) {
|
|
printk ("No card in slot %c: PIPR=%08x\n",
|
|
'A' + _slot_, (u32) pcmp->pcmc_pipr);
|
|
return; /* No card in slot */
|
|
}
|
|
|
|
check_ide_device (pcmcia_base);
|
|
|
|
#endif /* CONFIG_IDE_8xx_PCCARD */
|
|
|
|
base = pcmcia_base + ioport_dsc[data_port].base_off;
|
|
#ifdef DEBUG
|
|
printk ("base: %08x + %08x = %08x\n",
|
|
pcmcia_base, ioport_dsc[data_port].base_off, base);
|
|
#endif
|
|
|
|
for (i = 0; i < IDE_NR_PORTS; ++i) {
|
|
#ifdef DEBUG
|
|
printk ("port[%d]: %08x + %08x = %08x\n",
|
|
i,
|
|
base,
|
|
ioport_dsc[data_port].reg_off[i],
|
|
i, base + ioport_dsc[data_port].reg_off[i]);
|
|
#endif
|
|
*p++ = base + ioport_dsc[data_port].reg_off[i];
|
|
}
|
|
|
|
if (irq) {
|
|
#ifdef CONFIG_IDE_8xx_PCCARD
|
|
unsigned int reg;
|
|
|
|
*irq = ioport_dsc[data_port].irq;
|
|
if (_slot_)
|
|
pgcrx = &((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pgcrb;
|
|
else
|
|
pgcrx = &((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pgcra;
|
|
|
|
reg = *pgcrx;
|
|
reg |= mk_int_int_mask (pcmcia_schlvl) << 24;
|
|
reg |= mk_int_int_mask (pcmcia_schlvl) << 16;
|
|
*pgcrx = reg;
|
|
#else /* direct connected IDE drive, i.e. external IRQ, not the PCMCIA irq */
|
|
*irq = ioport_dsc[data_port].irq;
|
|
#endif /* CONFIG_IDE_8xx_PCCARD */
|
|
}
|
|
|
|
/* register routine to tune PIO mode */
|
|
ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
|
|
|
|
hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
|
|
/* Enable Harddisk Interrupt,
|
|
* and make it edge sensitive
|
|
*/
|
|
/* (11-18) Set edge detect for irq, no wakeup from low power mode */
|
|
((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel |=
|
|
(0x80000000 >> ioport_dsc[data_port].irq);
|
|
|
|
#ifdef CONFIG_IDE_8xx_PCCARD
|
|
/* Make sure we don't get garbage irq */
|
|
((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pscr = 0xFFFF;
|
|
|
|
/* Enable falling edge irq */
|
|
pcmp->pcmc_per = 0x100000 >> (16 * _slot_);
|
|
#endif /* CONFIG_IDE_8xx_PCCARD */
|
|
} /* m8xx_ide_init_hwif_ports() using 8xx internal PCMCIA interface */
|
|
#endif /* CONFIG_IDE_8xx_PCCARD || CONFIG_IDE_8xx_DIRECT */
|
|
|
|
/*
|
|
* m8xx_ide_init_hwif_ports for a direct IDE interface _not_ using
|
|
* MPC8xx's internal PCMCIA interface
|
|
*/
|
|
#if defined(CONFIG_IDE_EXT_DIRECT)
|
|
void m8xx_ide_init_hwif_ports (hw_regs_t *hw,
|
|
unsigned long data_port, unsigned long ctrl_port, int *irq)
|
|
{
|
|
unsigned long *p = hw->io_ports;
|
|
int i;
|
|
|
|
u32 ide_phy_base;
|
|
u32 ide_phy_end;
|
|
static unsigned long ide_base = 0;
|
|
unsigned long base;
|
|
|
|
*p = 0;
|
|
if (irq)
|
|
*irq = 0;
|
|
|
|
if (!ide_base) {
|
|
|
|
/* TODO:
|
|
* - add code to read ORx, BRx
|
|
*/
|
|
ide_phy_base = CFG_ATA_BASE_ADDR;
|
|
ide_phy_end = CFG_ATA_BASE_ADDR + 0x200;
|
|
|
|
printk ("IDE phys mem : %08x...%08x (size %08x)\n",
|
|
ide_phy_base, ide_phy_end,
|
|
ide_phy_end - ide_phy_base);
|
|
|
|
ide_base=(unsigned long)ioremap(ide_phy_base,
|
|
ide_phy_end-ide_phy_base);
|
|
|
|
#ifdef DEBUG
|
|
printk ("IDE virt base: %08lx\n", ide_base);
|
|
#endif
|
|
}
|
|
|
|
if (data_port >= MAX_HWIFS)
|
|
return;
|
|
|
|
base = ide_base + ioport_dsc[data_port].base_off;
|
|
#ifdef DEBUG
|
|
printk ("base: %08x + %08x = %08x\n",
|
|
ide_base, ioport_dsc[data_port].base_off, base);
|
|
#endif
|
|
|
|
for (i = 0; i < IDE_NR_PORTS; ++i) {
|
|
#ifdef DEBUG
|
|
printk ("port[%d]: %08x + %08x = %08x\n",
|
|
i,
|
|
base,
|
|
ioport_dsc[data_port].reg_off[i],
|
|
i, base + ioport_dsc[data_port].reg_off[i]);
|
|
#endif
|
|
*p++ = base + ioport_dsc[data_port].reg_off[i];
|
|
}
|
|
|
|
if (irq) {
|
|
/* direct connected IDE drive, i.e. external IRQ */
|
|
*irq = ioport_dsc[data_port].irq;
|
|
}
|
|
|
|
/* register routine to tune PIO mode */
|
|
ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
|
|
|
|
hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
|
|
/* Enable Harddisk Interrupt,
|
|
* and make it edge sensitive
|
|
*/
|
|
/* (11-18) Set edge detect for irq, no wakeup from low power mode */
|
|
((immap_t *) IMAP_ADDR)->im_siu_conf.sc_siel |=
|
|
(0x80000000 >> ioport_dsc[data_port].irq);
|
|
} /* m8xx_ide_init_hwif_ports() for CONFIG_IDE_8xx_DIRECT */
|
|
|
|
#endif /* CONFIG_IDE_8xx_DIRECT */
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
|
/* PCMCIA Timing */
|
|
#ifndef PCMCIA_SHT
|
|
#define PCMCIA_SHT(t) ((t & 0x0F)<<16) /* Strobe Hold Time */
|
|
#define PCMCIA_SST(t) ((t & 0x0F)<<12) /* Strobe Setup Time */
|
|
#define PCMCIA_SL(t) ((t==32) ? 0 : ((t & 0x1F)<<7)) /* Strobe Length */
|
|
#endif
|
|
|
|
|
|
/* Calculate PIO timings */
|
|
static void
|
|
m8xx_ide_tuneproc(ide_drive_t *drive, u8 pio)
|
|
{
|
|
ide_pio_data_t d;
|
|
#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
|
|
volatile pcmconf8xx_t *pcmp;
|
|
ulong timing, mask, reg;
|
|
#endif
|
|
|
|
pio = ide_get_best_pio_mode(drive, pio, 4, &d);
|
|
|
|
#if 1
|
|
printk("%s[%d] %s: best PIO mode: %d\n",
|
|
__FILE__,__LINE__,__FUNCTION__, pio);
|
|
#endif
|
|
|
|
#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
|
|
pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia));
|
|
|
|
mask = ~(PCMCIA_SHT(0xFF) | PCMCIA_SST(0xFF) | PCMCIA_SL(0xFF));
|
|
|
|
timing = PCMCIA_SHT(hold_time[pio] )
|
|
| PCMCIA_SST(ide_pio_clocks[pio].setup_time )
|
|
| PCMCIA_SL (ide_pio_clocks[pio].active_time)
|
|
;
|
|
|
|
#if 1
|
|
printk ("Setting timing bits 0x%08lx in PCMCIA controller\n", timing);
|
|
#endif
|
|
if ((reg = pcmp->pcmc_por0 & mask) != 0)
|
|
pcmp->pcmc_por0 = reg | timing;
|
|
|
|
if ((reg = pcmp->pcmc_por1 & mask) != 0)
|
|
pcmp->pcmc_por1 = reg | timing;
|
|
|
|
if ((reg = pcmp->pcmc_por2 & mask) != 0)
|
|
pcmp->pcmc_por2 = reg | timing;
|
|
|
|
if ((reg = pcmp->pcmc_por3 & mask) != 0)
|
|
pcmp->pcmc_por3 = reg | timing;
|
|
|
|
if ((reg = pcmp->pcmc_por4 & mask) != 0)
|
|
pcmp->pcmc_por4 = reg | timing;
|
|
|
|
if ((reg = pcmp->pcmc_por5 & mask) != 0)
|
|
pcmp->pcmc_por5 = reg | timing;
|
|
|
|
if ((reg = pcmp->pcmc_por6 & mask) != 0)
|
|
pcmp->pcmc_por6 = reg | timing;
|
|
|
|
if ((reg = pcmp->pcmc_por7 & mask) != 0)
|
|
pcmp->pcmc_por7 = reg | timing;
|
|
|
|
#elif defined(CONFIG_IDE_EXT_DIRECT)
|
|
|
|
printk("%s[%d] %s: not implemented yet!\n",
|
|
__FILE__,__LINE__,__FUNCTION__);
|
|
#endif /* defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_PCMCIA */
|
|
}
|
|
|
|
static void
|
|
ide_interrupt_ack (void *dev)
|
|
{
|
|
#ifdef CONFIG_IDE_8xx_PCCARD
|
|
u_int pscr, pipr;
|
|
|
|
#if (PCMCIA_SOCKETS_NO == 2)
|
|
u_int _slot_;
|
|
#endif
|
|
|
|
/* get interrupt sources */
|
|
|
|
pscr = ((volatile immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr;
|
|
pipr = ((volatile immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr;
|
|
|
|
/*
|
|
* report only if both card detect signals are the same
|
|
* not too nice done,
|
|
* we depend on that CD2 is the bit to the left of CD1...
|
|
*/
|
|
|
|
if(_slot_==-1){
|
|
printk("PCMCIA slot has not been defined! Using A as default\n");
|
|
_slot_=0;
|
|
}
|
|
|
|
if(((pipr & M8XX_PCMCIA_CD2(_slot_)) >> 1) ^
|
|
(pipr & M8XX_PCMCIA_CD1(_slot_)) ) {
|
|
printk ("card detect interrupt\n");
|
|
}
|
|
/* clear the interrupt sources */
|
|
((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr = pscr;
|
|
|
|
#else /* ! CONFIG_IDE_8xx_PCCARD */
|
|
/*
|
|
* Only CONFIG_IDE_8xx_PCCARD is using the interrupt of the
|
|
* MPC8xx's PCMCIA controller, so there is nothing to be done here
|
|
* for CONFIG_IDE_8xx_DIRECT and CONFIG_IDE_EXT_DIRECT.
|
|
* The interrupt is handled somewhere else. -- Steven
|
|
*/
|
|
#endif /* CONFIG_IDE_8xx_PCCARD */
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* CIS Tupel codes
|
|
*/
|
|
#define CISTPL_NULL 0x00
|
|
#define CISTPL_DEVICE 0x01
|
|
#define CISTPL_LONGLINK_CB 0x02
|
|
#define CISTPL_INDIRECT 0x03
|
|
#define CISTPL_CONFIG_CB 0x04
|
|
#define CISTPL_CFTABLE_ENTRY_CB 0x05
|
|
#define CISTPL_LONGLINK_MFC 0x06
|
|
#define CISTPL_BAR 0x07
|
|
#define CISTPL_PWR_MGMNT 0x08
|
|
#define CISTPL_EXTDEVICE 0x09
|
|
#define CISTPL_CHECKSUM 0x10
|
|
#define CISTPL_LONGLINK_A 0x11
|
|
#define CISTPL_LONGLINK_C 0x12
|
|
#define CISTPL_LINKTARGET 0x13
|
|
#define CISTPL_NO_LINK 0x14
|
|
#define CISTPL_VERS_1 0x15
|
|
#define CISTPL_ALTSTR 0x16
|
|
#define CISTPL_DEVICE_A 0x17
|
|
#define CISTPL_JEDEC_C 0x18
|
|
#define CISTPL_JEDEC_A 0x19
|
|
#define CISTPL_CONFIG 0x1a
|
|
#define CISTPL_CFTABLE_ENTRY 0x1b
|
|
#define CISTPL_DEVICE_OC 0x1c
|
|
#define CISTPL_DEVICE_OA 0x1d
|
|
#define CISTPL_DEVICE_GEO 0x1e
|
|
#define CISTPL_DEVICE_GEO_A 0x1f
|
|
#define CISTPL_MANFID 0x20
|
|
#define CISTPL_FUNCID 0x21
|
|
#define CISTPL_FUNCE 0x22
|
|
#define CISTPL_SWIL 0x23
|
|
#define CISTPL_END 0xff
|
|
|
|
/*
|
|
* CIS Function ID codes
|
|
*/
|
|
#define CISTPL_FUNCID_MULTI 0x00
|
|
#define CISTPL_FUNCID_MEMORY 0x01
|
|
#define CISTPL_FUNCID_SERIAL 0x02
|
|
#define CISTPL_FUNCID_PARALLEL 0x03
|
|
#define CISTPL_FUNCID_FIXED 0x04
|
|
#define CISTPL_FUNCID_VIDEO 0x05
|
|
#define CISTPL_FUNCID_NETWORK 0x06
|
|
#define CISTPL_FUNCID_AIMS 0x07
|
|
#define CISTPL_FUNCID_SCSI 0x08
|
|
|
|
/*
|
|
* Fixed Disk FUNCE codes
|
|
*/
|
|
#define CISTPL_IDE_INTERFACE 0x01
|
|
|
|
#define CISTPL_FUNCE_IDE_IFACE 0x01
|
|
#define CISTPL_FUNCE_IDE_MASTER 0x02
|
|
#define CISTPL_FUNCE_IDE_SLAVE 0x03
|
|
|
|
/* First feature byte */
|
|
#define CISTPL_IDE_SILICON 0x04
|
|
#define CISTPL_IDE_UNIQUE 0x08
|
|
#define CISTPL_IDE_DUAL 0x10
|
|
|
|
/* Second feature byte */
|
|
#define CISTPL_IDE_HAS_SLEEP 0x01
|
|
#define CISTPL_IDE_HAS_STANDBY 0x02
|
|
#define CISTPL_IDE_HAS_IDLE 0x04
|
|
#define CISTPL_IDE_LOW_POWER 0x08
|
|
#define CISTPL_IDE_REG_INHIBIT 0x10
|
|
#define CISTPL_IDE_HAS_INDEX 0x20
|
|
#define CISTPL_IDE_IOIS16 0x40
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
|
#define MAX_TUPEL_SZ 512
|
|
#define MAX_FEATURES 4
|
|
|
|
static int check_ide_device (unsigned long base)
|
|
{
|
|
volatile u8 *ident = NULL;
|
|
volatile u8 *feature_p[MAX_FEATURES];
|
|
volatile u8 *p, *start;
|
|
int n_features = 0;
|
|
u8 func_id = ~0;
|
|
u8 code, len;
|
|
unsigned short config_base = 0;
|
|
int found = 0;
|
|
int i;
|
|
|
|
#ifdef DEBUG
|
|
printk ("PCMCIA MEM: %08lX\n", base);
|
|
#endif
|
|
start = p = (volatile u8 *) base;
|
|
|
|
while ((p - start) < MAX_TUPEL_SZ) {
|
|
|
|
code = *p; p += 2;
|
|
|
|
if (code == 0xFF) { /* End of chain */
|
|
break;
|
|
}
|
|
|
|
len = *p; p += 2;
|
|
#ifdef DEBUG_PCMCIA
|
|
{ volatile u8 *q = p;
|
|
printk ("\nTuple code %02x length %d\n\tData:",
|
|
code, len);
|
|
|
|
for (i = 0; i < len; ++i) {
|
|
printk (" %02x", *q);
|
|
q+= 2;
|
|
}
|
|
}
|
|
#endif /* DEBUG_PCMCIA */
|
|
switch (code) {
|
|
case CISTPL_VERS_1:
|
|
ident = p + 4;
|
|
break;
|
|
case CISTPL_FUNCID:
|
|
func_id = *p;
|
|
break;
|
|
case CISTPL_FUNCE:
|
|
if (n_features < MAX_FEATURES)
|
|
feature_p[n_features++] = p;
|
|
break;
|
|
case CISTPL_CONFIG:
|
|
config_base = (*(p+6) << 8) + (*(p+4));
|
|
default:
|
|
break;
|
|
}
|
|
p += 2 * len;
|
|
}
|
|
|
|
found = identify (ident);
|
|
|
|
if (func_id != ((u8)~0)) {
|
|
print_funcid (func_id);
|
|
|
|
if (func_id == CISTPL_FUNCID_FIXED)
|
|
found = 1;
|
|
else
|
|
return (1); /* no disk drive */
|
|
}
|
|
|
|
for (i=0; i<n_features; ++i) {
|
|
print_fixed (feature_p[i]);
|
|
}
|
|
|
|
if (!found) {
|
|
printk ("unknown card type\n");
|
|
return (1);
|
|
}
|
|
|
|
/* set level mode irq and I/O mapped device in config reg*/
|
|
*((u8 *)(base + config_base)) = 0x41;
|
|
|
|
return (0);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
static void print_funcid (int func)
|
|
{
|
|
switch (func) {
|
|
case CISTPL_FUNCID_MULTI:
|
|
printk (" Multi-Function");
|
|
break;
|
|
case CISTPL_FUNCID_MEMORY:
|
|
printk (" Memory");
|
|
break;
|
|
case CISTPL_FUNCID_SERIAL:
|
|
printk (" Serial Port");
|
|
break;
|
|
case CISTPL_FUNCID_PARALLEL:
|
|
printk (" Parallel Port");
|
|
break;
|
|
case CISTPL_FUNCID_FIXED:
|
|
printk (" Fixed Disk");
|
|
break;
|
|
case CISTPL_FUNCID_VIDEO:
|
|
printk (" Video Adapter");
|
|
break;
|
|
case CISTPL_FUNCID_NETWORK:
|
|
printk (" Network Adapter");
|
|
break;
|
|
case CISTPL_FUNCID_AIMS:
|
|
printk (" AIMS Card");
|
|
break;
|
|
case CISTPL_FUNCID_SCSI:
|
|
printk (" SCSI Adapter");
|
|
break;
|
|
default:
|
|
printk (" Unknown");
|
|
break;
|
|
}
|
|
printk (" Card\n");
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
static void print_fixed (volatile u8 *p)
|
|
{
|
|
if (p == NULL)
|
|
return;
|
|
|
|
switch (*p) {
|
|
case CISTPL_FUNCE_IDE_IFACE:
|
|
{ u8 iface = *(p+2);
|
|
|
|
printk ((iface == CISTPL_IDE_INTERFACE) ? " IDE" : " unknown");
|
|
printk (" interface ");
|
|
break;
|
|
}
|
|
case CISTPL_FUNCE_IDE_MASTER:
|
|
case CISTPL_FUNCE_IDE_SLAVE:
|
|
{ u8 f1 = *(p+2);
|
|
u8 f2 = *(p+4);
|
|
|
|
printk ((f1 & CISTPL_IDE_SILICON) ? " [silicon]" : " [rotating]");
|
|
|
|
if (f1 & CISTPL_IDE_UNIQUE)
|
|
printk (" [unique]");
|
|
|
|
printk ((f1 & CISTPL_IDE_DUAL) ? " [dual]" : " [single]");
|
|
|
|
if (f2 & CISTPL_IDE_HAS_SLEEP)
|
|
printk (" [sleep]");
|
|
|
|
if (f2 & CISTPL_IDE_HAS_STANDBY)
|
|
printk (" [standby]");
|
|
|
|
if (f2 & CISTPL_IDE_HAS_IDLE)
|
|
printk (" [idle]");
|
|
|
|
if (f2 & CISTPL_IDE_LOW_POWER)
|
|
printk (" [low power]");
|
|
|
|
if (f2 & CISTPL_IDE_REG_INHIBIT)
|
|
printk (" [reg inhibit]");
|
|
|
|
if (f2 & CISTPL_IDE_HAS_INDEX)
|
|
printk (" [index]");
|
|
|
|
if (f2 & CISTPL_IDE_IOIS16)
|
|
printk (" [IOis16]");
|
|
|
|
break;
|
|
}
|
|
}
|
|
printk ("\n");
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
|
|
#define MAX_IDENT_CHARS 64
|
|
#define MAX_IDENT_FIELDS 4
|
|
|
|
static u8 *known_cards[] = {
|
|
"ARGOSY PnPIDE D5",
|
|
NULL
|
|
};
|
|
|
|
static int identify (volatile u8 *p)
|
|
{
|
|
u8 id_str[MAX_IDENT_CHARS];
|
|
u8 data;
|
|
u8 *t;
|
|
u8 **card;
|
|
int i, done;
|
|
|
|
if (p == NULL)
|
|
return (0); /* Don't know */
|
|
|
|
t = id_str;
|
|
done =0;
|
|
|
|
for (i=0; i<=4 && !done; ++i, p+=2) {
|
|
while ((data = *p) != '\0') {
|
|
if (data == 0xFF) {
|
|
done = 1;
|
|
break;
|
|
}
|
|
*t++ = data;
|
|
if (t == &id_str[MAX_IDENT_CHARS-1]) {
|
|
done = 1;
|
|
break;
|
|
}
|
|
p += 2;
|
|
}
|
|
if (!done)
|
|
*t++ = ' ';
|
|
}
|
|
*t = '\0';
|
|
while (--t > id_str) {
|
|
if (*t == ' ')
|
|
*t = '\0';
|
|
else
|
|
break;
|
|
}
|
|
printk ("Card ID: %s\n", id_str);
|
|
|
|
for (card=known_cards; *card; ++card) {
|
|
if (strcmp(*card, id_str) == 0) { /* found! */
|
|
return (1);
|
|
}
|
|
}
|
|
|
|
return (0); /* don't know */
|
|
}
|
|
|
|
void m8xx_ide_init(void)
|
|
{
|
|
ppc_ide_md.default_irq = m8xx_ide_default_irq;
|
|
ppc_ide_md.default_io_base = m8xx_ide_default_io_base;
|
|
ppc_ide_md.ide_init_hwif = m8xx_ide_init_hwif_ports;
|
|
}
|