?? mpc8xx.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/config.h>#include <linux/errno.h>#include <linux/sched.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/blk.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>#include "ide_modes.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 */ ide_ioreg_t 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 intm8xx_ide_default_irq(ide_ioreg_t 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 ide_ioreg_tm8xx_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 voidm8xx_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq){ ide_ioreg_t *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 dont 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, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq){ ide_ioreg_t *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 */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -