Commit 8f29e650 authored by Jordan Crouse's avatar Jordan Crouse Committed by Bartlomiej Zolnierkiewicz

[PATCH] ide: AU1200 IDE update

Changes here include removing all of CONFIG_PM while it is being repeatedly
smacked with a lead pipe, moving the BURSTMODE param to a #define (it should
be defined almost always anyway), fixing the rqsize stuff, pulling ide_ioreg_t,
and general cleanups and whatnot.
Signed-off-by: default avatarJordan Crouse <jordan.crouse@amd.com>
Signed-off-by: default avatarBartlomiej Zolnierkiewicz <bzolnier@gmail.com>
parent 65e5f2e3
......@@ -807,14 +807,6 @@ config BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
depends on SOC_AU1200 && BLK_DEV_IDE_AU1XXX
endchoice
config BLK_DEV_IDE_AU1XXX_BURSTABLE_ON
bool "Enable burstable Mode on DbDMA"
default false
depends BLK_DEV_IDE_AU1XXX
help
This option enable the burstable Flag on DbDMA controller
(cf. "AMD Alchemy 'Au1200' Processor Data Book - PRELIMINARY").
config BLK_DEV_IDE_AU1XXX_SEQTS_PER_RQ
int "Maximum transfer size (KB) per request (up to 128)"
default "128"
......
obj-$(CONFIG_BLK_DEV_IDE_SWARM) += swarm.o
obj-$(CONFIG_BLK_DEV_IDE_AU1XXX) += au1xxx-ide.o
EXTRA_CFLAGS := -Idrivers/ide
......@@ -31,865 +31,638 @@
*/
#undef REALLY_SLOW_IO /* most systems can safely undef this */
#include <linux/config.h> /* for CONFIG_BLK_DEV_IDEPCI */
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/hdreg.h>
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/ide.h>
#include <linux/sysdev.h>
#include <linux/dma-mapping.h>
#include "ide-timing.h"
#include <asm/io.h>
#include <asm/mach-au1x00/au1xxx.h>
#include <asm/mach-au1x00/au1xxx_dbdma.h>
#if CONFIG_PM
#include <asm/mach-au1x00/au1xxx_pm.h>
#endif
#include <asm/mach-au1x00/au1xxx_ide.h>
#define DRV_NAME "au1200-ide"
#define DRV_VERSION "1.0"
#define DRV_AUTHOR "AMD PCS / Pete Popov <ppopov@embeddedalley.com>"
#define DRV_DESC "Au1200 IDE"
static _auide_hwif auide_hwif;
static spinlock_t ide_tune_drive_spin_lock = SPIN_LOCK_UNLOCKED;
static spinlock_t ide_tune_chipset_spin_lock = SPIN_LOCK_UNLOCKED;
static int dbdma_init_done = 0;
/*
* local I/O functions
*/
u8 auide_inb(unsigned long port)
{
return (au_readb(port));
}
#define DRV_AUTHOR "Enrico Walther <enrico.walther@amd.com> / Pete Popov <ppopov@embeddedalley.com>"
u16 auide_inw(unsigned long port)
{
return (au_readw(port));
}
/* enable the burstmode in the dbdma */
#define IDE_AU1XXX_BURSTMODE 1
u32 auide_inl(unsigned long port)
{
return (au_readl(port));
}
static _auide_hwif auide_hwif;
static int dbdma_init_done;
void auide_insw(unsigned long port, void *addr, u32 count)
{
#if defined(CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA)
_auide_hwif *ahwif = &auide_hwif;
chan_tab_t *ctp;
au1x_ddma_desc_t *dp;
if(!put_dest_flags(ahwif->rx_chan, (void*)addr, count << 1,
DDMA_FLAGS_NOIE)) {
printk(KERN_ERR "%s failed %d\n", __FUNCTION__, __LINE__);
return;
}
ctp = *((chan_tab_t **)ahwif->rx_chan);
dp = ctp->cur_ptr;
while (dp->dscr_cmd0 & DSCR_CMD0_V)
;
ctp->cur_ptr = au1xxx_ddma_get_nextptr_virt(dp);
#else
while (count--)
{
*(u16 *)addr = au_readw(port);
addr +=2 ;
}
#endif
}
void auide_insl(unsigned long port, void *addr, u32 count)
{
while (count--)
{
*(u32 *)addr = au_readl(port);
/* NOTE: For IDE interfaces over PCMCIA,
* 32-bit access does not work
*/
addr += 4;
}
}
void auide_outb(u8 addr, unsigned long port)
void auide_insw(unsigned long port, void *addr, u32 count)
{
return (au_writeb(addr, port));
}
_auide_hwif *ahwif = &auide_hwif;
chan_tab_t *ctp;
au1x_ddma_desc_t *dp;
void auide_outbsync(ide_drive_t *drive, u8 addr, unsigned long port)
{
return (au_writeb(addr, port));
if(!put_dest_flags(ahwif->rx_chan, (void*)addr, count << 1,
DDMA_FLAGS_NOIE)) {
printk(KERN_ERR "%s failed %d\n", __FUNCTION__, __LINE__);
return;
}
ctp = *((chan_tab_t **)ahwif->rx_chan);
dp = ctp->cur_ptr;
while (dp->dscr_cmd0 & DSCR_CMD0_V)
;
ctp->cur_ptr = au1xxx_ddma_get_nextptr_virt(dp);
}
void auide_outw(u16 addr, unsigned long port)
void auide_outsw(unsigned long port, void *addr, u32 count)
{
return (au_writew(addr, port));
}
_auide_hwif *ahwif = &auide_hwif;
chan_tab_t *ctp;
au1x_ddma_desc_t *dp;
void auide_outl(u32 addr, unsigned long port)
{
return (au_writel(addr, port));
if(!put_source_flags(ahwif->tx_chan, (void*)addr,
count << 1, DDMA_FLAGS_NOIE)) {
printk(KERN_ERR "%s failed %d\n", __FUNCTION__, __LINE__);
return;
}
ctp = *((chan_tab_t **)ahwif->tx_chan);
dp = ctp->cur_ptr;
while (dp->dscr_cmd0 & DSCR_CMD0_V)
;
ctp->cur_ptr = au1xxx_ddma_get_nextptr_virt(dp);
}
void auide_outsw(unsigned long port, void *addr, u32 count)
{
#if defined(CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA)
_auide_hwif *ahwif = &auide_hwif;
chan_tab_t *ctp;
au1x_ddma_desc_t *dp;
if(!put_source_flags(ahwif->tx_chan, (void*)addr,
count << 1, DDMA_FLAGS_NOIE)) {
printk(KERN_ERR "%s failed %d\n", __FUNCTION__, __LINE__);
return;
}
ctp = *((chan_tab_t **)ahwif->tx_chan);
dp = ctp->cur_ptr;
while (dp->dscr_cmd0 & DSCR_CMD0_V)
;
ctp->cur_ptr = au1xxx_ddma_get_nextptr_virt(dp);
#else
while (count--)
{
au_writew(*(u16 *)addr, port);
addr += 2;
}
#endif
}
void auide_outsl(unsigned long port, void *addr, u32 count)
{
while (count--)
{
au_writel(*(u32 *)addr, port);
/* NOTE: For IDE interfaces over PCMCIA,
* 32-bit access does not work
*/
addr += 4;
}
}
static void auide_tune_drive(ide_drive_t *drive, byte pio)
{
int mem_sttime;
int mem_stcfg;
unsigned long flags;
u8 speed;
/* get the best pio mode for the drive */
pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
printk("%s: setting Au1XXX IDE to PIO mode%d\n",
drive->name, pio);
spin_lock_irqsave(&ide_tune_drive_spin_lock, flags);
mem_sttime = 0;
mem_stcfg = au_readl(MEM_STCFG2);
/* set pio mode! */
switch(pio) {
case 0:
/* set timing parameters for RCS2# */
mem_sttime = SBC_IDE_PIO0_TWCS
| SBC_IDE_PIO0_TCSH
| SBC_IDE_PIO0_TCSOFF
| SBC_IDE_PIO0_TWP
| SBC_IDE_PIO0_TCSW
| SBC_IDE_PIO0_TPM
| SBC_IDE_PIO0_TA;
/* set configuration for RCS2# */
mem_stcfg |= TS_MASK;
mem_stcfg &= ~TCSOE_MASK;
mem_stcfg &= ~TOECS_MASK;
mem_stcfg |= SBC_IDE_PIO0_TCSOE | SBC_IDE_PIO0_TOECS;
au_writel(mem_sttime,MEM_STTIME2);
au_writel(mem_stcfg,MEM_STCFG2);
break;
case 1:
/* set timing parameters for RCS2# */
mem_sttime = SBC_IDE_PIO1_TWCS
| SBC_IDE_PIO1_TCSH
| SBC_IDE_PIO1_TCSOFF
| SBC_IDE_PIO1_TWP
| SBC_IDE_PIO1_TCSW
| SBC_IDE_PIO1_TPM
| SBC_IDE_PIO1_TA;
/* set configuration for RCS2# */
mem_stcfg |= TS_MASK;
mem_stcfg &= ~TCSOE_MASK;
mem_stcfg &= ~TOECS_MASK;
mem_stcfg |= SBC_IDE_PIO1_TCSOE | SBC_IDE_PIO1_TOECS;
break;
case 2:
/* set timing parameters for RCS2# */
mem_sttime = SBC_IDE_PIO2_TWCS
| SBC_IDE_PIO2_TCSH
| SBC_IDE_PIO2_TCSOFF
| SBC_IDE_PIO2_TWP
| SBC_IDE_PIO2_TCSW
| SBC_IDE_PIO2_TPM
| SBC_IDE_PIO2_TA;
/* set configuration for RCS2# */
mem_stcfg &= ~TS_MASK;
mem_stcfg &= ~TCSOE_MASK;
mem_stcfg &= ~TOECS_MASK;
mem_stcfg |= SBC_IDE_PIO2_TCSOE | SBC_IDE_PIO2_TOECS;
break;
case 3:
/* set timing parameters for RCS2# */
mem_sttime = SBC_IDE_PIO3_TWCS
| SBC_IDE_PIO3_TCSH
| SBC_IDE_PIO3_TCSOFF
| SBC_IDE_PIO3_TWP
| SBC_IDE_PIO3_TCSW
| SBC_IDE_PIO3_TPM
| SBC_IDE_PIO3_TA;
/* set configuration for RCS2# */
mem_stcfg |= TS_MASK;
mem_stcfg &= ~TS_MASK;
mem_stcfg &= ~TCSOE_MASK;
mem_stcfg &= ~TOECS_MASK;
mem_stcfg |= SBC_IDE_PIO3_TCSOE | SBC_IDE_PIO3_TOECS;
break;
case 4:
/* set timing parameters for RCS2# */
mem_sttime = SBC_IDE_PIO4_TWCS
| SBC_IDE_PIO4_TCSH
| SBC_IDE_PIO4_TCSOFF
| SBC_IDE_PIO4_TWP
| SBC_IDE_PIO4_TCSW
| SBC_IDE_PIO4_TPM
| SBC_IDE_PIO4_TA;
/* set configuration for RCS2# */
mem_stcfg &= ~TS_MASK;
mem_stcfg &= ~TCSOE_MASK;
mem_stcfg &= ~TOECS_MASK;
mem_stcfg |= SBC_IDE_PIO4_TCSOE | SBC_IDE_PIO4_TOECS;
break;
}
au_writel(mem_sttime,MEM_STTIME2);
au_writel(mem_stcfg,MEM_STCFG2);
spin_unlock_irqrestore(&ide_tune_drive_spin_lock, flags);
speed = pio + XFER_PIO_0;
ide_config_drive_speed(drive, speed);
int mem_sttime;
int mem_stcfg;
u8 speed;
/* get the best pio mode for the drive */
pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
printk(KERN_INFO "%s: setting Au1XXX IDE to PIO mode%d\n",
drive->name, pio);
mem_sttime = 0;
mem_stcfg = au_readl(MEM_STCFG2);
/* set pio mode! */
switch(pio) {
case 0:
mem_sttime = SBC_IDE_TIMING(PIO0);
/* set configuration for RCS2# */
mem_stcfg |= TS_MASK;
mem_stcfg &= ~TCSOE_MASK;
mem_stcfg &= ~TOECS_MASK;
mem_stcfg |= SBC_IDE_PIO0_TCSOE | SBC_IDE_PIO0_TOECS;
break;
case 1:
mem_sttime = SBC_IDE_TIMING(PIO1);
/* set configuration for RCS2# */
mem_stcfg |= TS_MASK;
mem_stcfg &= ~TCSOE_MASK;
mem_stcfg &= ~TOECS_MASK;
mem_stcfg |= SBC_IDE_PIO1_TCSOE | SBC_IDE_PIO1_TOECS;
break;
case 2:
mem_sttime = SBC_IDE_TIMING(PIO2);
/* set configuration for RCS2# */
mem_stcfg &= ~TS_MASK;
mem_stcfg &= ~TCSOE_MASK;
mem_stcfg &= ~TOECS_MASK;
mem_stcfg |= SBC_IDE_PIO2_TCSOE | SBC_IDE_PIO2_TOECS;
break;
case 3:
mem_sttime = SBC_IDE_TIMING(PIO3);
/* set configuration for RCS2# */
mem_stcfg &= ~TS_MASK;
mem_stcfg &= ~TCSOE_MASK;
mem_stcfg &= ~TOECS_MASK;
mem_stcfg |= SBC_IDE_PIO3_TCSOE | SBC_IDE_PIO3_TOECS;
break;
case 4:
mem_sttime = SBC_IDE_TIMING(PIO4);
/* set configuration for RCS2# */
mem_stcfg &= ~TS_MASK;
mem_stcfg &= ~TCSOE_MASK;
mem_stcfg &= ~TOECS_MASK;
mem_stcfg |= SBC_IDE_PIO4_TCSOE | SBC_IDE_PIO4_TOECS;
break;
}
au_writel(mem_sttime,MEM_STTIME2);
au_writel(mem_stcfg,MEM_STCFG2);
speed = pio + XFER_PIO_0;
ide_config_drive_speed(drive, speed);
}
static int auide_tune_chipset (ide_drive_t *drive, u8 speed)
{
u8 mode = 0;
int mem_sttime;
int mem_stcfg;
unsigned long flags;
int mem_sttime;
int mem_stcfg;
unsigned long mode;
#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
struct hd_driveid *id = drive->id;
/*
* Now see what the current drive is capable of,
* selecting UDMA only if the mate said it was ok.
*/
if (id && (id->capability & 1) && drive->autodma &&
!__ide_dma_bad_drive(drive)) {
if (!mode && (id->field_valid & 2) && (id->dma_mword & 7)) {
if (id->dma_mword & 4)
mode = XFER_MW_DMA_2;
else if (id->dma_mword & 2)
mode = XFER_MW_DMA_1;
else if (id->dma_mword & 1)
mode = XFER_MW_DMA_0;
}
}
if (ide_use_dma(drive))
mode = ide_dma_speed(drive, 0);
#endif
spin_lock_irqsave(&ide_tune_chipset_spin_lock, flags);
mem_sttime = 0;
mem_stcfg = au_readl(MEM_STCFG2);
mem_sttime = 0;
mem_stcfg = au_readl(MEM_STCFG2);
switch(speed) {
case XFER_PIO_4:
case XFER_PIO_3:
case XFER_PIO_2:
case XFER_PIO_1:
case XFER_PIO_0:
auide_tune_drive(drive, (speed - XFER_PIO_0));
break;
if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) {
auide_tune_drive(drive, speed - XFER_PIO_0);
return 0;
}
switch(speed) {
#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
case XFER_MW_DMA_2:
/* set timing parameters for RCS2# */
mem_sttime = SBC_IDE_MDMA2_TWCS
| SBC_IDE_MDMA2_TCSH
| SBC_IDE_MDMA2_TCSOFF
| SBC_IDE_MDMA2_TWP
| SBC_IDE_MDMA2_TCSW
| SBC_IDE_MDMA2_TPM
| SBC_IDE_MDMA2_TA;
/* set configuration for RCS2# */
mem_stcfg &= ~TS_MASK;
mem_stcfg &= ~TCSOE_MASK;
mem_stcfg &= ~TOECS_MASK;
mem_stcfg |= SBC_IDE_MDMA2_TCSOE | SBC_IDE_MDMA2_TOECS;
mode = XFER_MW_DMA_2;
break;
case XFER_MW_DMA_1:
/* set timing parameters for RCS2# */
mem_sttime = SBC_IDE_MDMA1_TWCS
| SBC_IDE_MDMA1_TCSH
| SBC_IDE_MDMA1_TCSOFF
| SBC_IDE_MDMA1_TWP
| SBC_IDE_MDMA1_TCSW
| SBC_IDE_MDMA1_TPM
| SBC_IDE_MDMA1_TA;
/* set configuration for RCS2# */
mem_stcfg &= ~TS_MASK;
mem_stcfg &= ~TCSOE_MASK;
mem_stcfg &= ~TOECS_MASK;
mem_stcfg |= SBC_IDE_MDMA1_TCSOE | SBC_IDE_MDMA1_TOECS;
mode = XFER_MW_DMA_1;
break;
case XFER_MW_DMA_0:
/* set timing parameters for RCS2# */
mem_sttime = SBC_IDE_MDMA0_TWCS
| SBC_IDE_MDMA0_TCSH
| SBC_IDE_MDMA0_TCSOFF
| SBC_IDE_MDMA0_TWP
| SBC_IDE_MDMA0_TCSW
| SBC_IDE_MDMA0_TPM
| SBC_IDE_MDMA0_TA;
/* set configuration for RCS2# */
mem_stcfg |= TS_MASK;
mem_stcfg &= ~TCSOE_MASK;
mem_stcfg &= ~TOECS_MASK;
mem_stcfg |= SBC_IDE_MDMA0_TCSOE | SBC_IDE_MDMA0_TOECS;
mode = XFER_MW_DMA_0;
break;
case XFER_MW_DMA_2:
mem_sttime = SBC_IDE_TIMING(MDMA2);
/* set configuration for RCS2# */
mem_stcfg &= ~TS_MASK;
mem_stcfg &= ~TCSOE_MASK;
mem_stcfg &= ~TOECS_MASK;
mem_stcfg |= SBC_IDE_MDMA2_TCSOE | SBC_IDE_MDMA2_TOECS;
mode = XFER_MW_DMA_2;
break;
case XFER_MW_DMA_1:
mem_sttime = SBC_IDE_TIMING(MDMA1);
/* set configuration for RCS2# */
mem_stcfg &= ~TS_MASK;
mem_stcfg &= ~TCSOE_MASK;
mem_stcfg &= ~TOECS_MASK;
mem_stcfg |= SBC_IDE_MDMA1_TCSOE | SBC_IDE_MDMA1_TOECS;
mode = XFER_MW_DMA_1;
break;
case XFER_MW_DMA_0:
mem_sttime = SBC_IDE_TIMING(MDMA0);
/* set configuration for RCS2# */
mem_stcfg |= TS_MASK;
mem_stcfg &= ~TCSOE_MASK;
mem_stcfg &= ~TOECS_MASK;
mem_stcfg |= SBC_IDE_MDMA0_TCSOE | SBC_IDE_MDMA0_TOECS;
mode = XFER_MW_DMA_0;
break;
#endif
default:
return 1;
}
/*
* Tell the drive to switch to the new mode; abort on failure.
*/
if (!mode || ide_config_drive_speed(drive, mode))
{
return 1; /* failure */
}
au_writel(mem_sttime,MEM_STTIME2);
au_writel(mem_stcfg,MEM_STCFG2);
default:
return 1;
}
if (ide_config_drive_speed(drive, mode))
return 1;
spin_unlock_irqrestore(&ide_tune_chipset_spin_lock, flags);
au_writel(mem_sttime,MEM_STTIME2);
au_writel(mem_stcfg,MEM_STCFG2);
return 0;
return 0;
}
/*
* Multi-Word DMA + DbDMA functions
*/
#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
static int in_drive_list(struct hd_driveid *id,
const struct drive_list_entry *drive_table)
{
for ( ; drive_table->id_model ; drive_table++){
if ((!strcmp(drive_table->id_model, id->model)) &&
((strstr(drive_table->id_firmware, id->fw_rev)) ||
(!strcmp(drive_table->id_firmware, "ALL")))
)
return 1;
}
return 0;
}
#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
static int auide_build_sglist(ide_drive_t *drive, struct request *rq)
{
ide_hwif_t *hwif = drive->hwif;
_auide_hwif *ahwif = (_auide_hwif*)hwif->hwif_data;
struct scatterlist *sg = hwif->sg_table;
ide_hwif_t *hwif = drive->hwif;
_auide_hwif *ahwif = (_auide_hwif*)hwif->hwif_data;
struct scatterlist *sg = hwif->sg_table;
ide_map_sg(drive, rq);
ide_map_sg(drive, rq);
if (rq_data_dir(rq) == READ)
hwif->sg_dma_direction = DMA_FROM_DEVICE;
else
hwif->sg_dma_direction = DMA_TO_DEVICE;
if (rq_data_dir(rq) == READ)
hwif->sg_dma_direction = DMA_FROM_DEVICE;
else
hwif->sg_dma_direction = DMA_TO_DEVICE;
return dma_map_sg(ahwif->dev, sg, hwif->sg_nents,
hwif->sg_dma_direction);
return dma_map_sg(ahwif->dev, sg, hwif->sg_nents,
hwif->sg_dma_direction);
}
static int auide_build_dmatable(ide_drive_t *drive)
{
int i, iswrite, count = 0;
ide_hwif_t *hwif = HWIF(drive);