2007-02-17 09:40:22 +08:00
|
|
|
/*
|
|
|
|
* Support for IDE interfaces on Celleb platform
|
|
|
|
*
|
|
|
|
* (C) Copyright 2006 TOSHIBA CORPORATION
|
|
|
|
*
|
|
|
|
* This code is based on drivers/ide/pci/siimage.c:
|
|
|
|
* Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org>
|
|
|
|
* Copyright (C) 2003 Red Hat <alan@redhat.com>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/pci.h>
|
|
|
|
#include <linux/delay.h>
|
|
|
|
#include <linux/hdreg.h>
|
|
|
|
#include <linux/ide.h>
|
|
|
|
#include <linux/init.h>
|
|
|
|
|
|
|
|
#define PCI_DEVICE_ID_TOSHIBA_SCC_ATA 0x01b4
|
|
|
|
|
|
|
|
#define SCC_PATA_NAME "scc IDE"
|
|
|
|
|
|
|
|
#define TDVHSEL_MASTER 0x00000001
|
|
|
|
#define TDVHSEL_SLAVE 0x00000004
|
|
|
|
|
|
|
|
#define MODE_JCUSFEN 0x00000080
|
|
|
|
|
|
|
|
#define CCKCTRL_ATARESET 0x00040000
|
|
|
|
#define CCKCTRL_BUFCNT 0x00020000
|
|
|
|
#define CCKCTRL_CRST 0x00010000
|
|
|
|
#define CCKCTRL_OCLKEN 0x00000100
|
|
|
|
#define CCKCTRL_ATACLKOEN 0x00000002
|
|
|
|
#define CCKCTRL_LCLKEN 0x00000001
|
|
|
|
|
|
|
|
#define QCHCD_IOS_SS 0x00000001
|
|
|
|
|
|
|
|
#define QCHSD_STPDIAG 0x00020000
|
|
|
|
|
|
|
|
#define INTMASK_MSK 0xD1000012
|
|
|
|
#define INTSTS_SERROR 0x80000000
|
|
|
|
#define INTSTS_PRERR 0x40000000
|
|
|
|
#define INTSTS_RERR 0x10000000
|
|
|
|
#define INTSTS_ICERR 0x01000000
|
|
|
|
#define INTSTS_BMSINT 0x00000010
|
|
|
|
#define INTSTS_BMHE 0x00000008
|
|
|
|
#define INTSTS_IOIRQS 0x00000004
|
|
|
|
#define INTSTS_INTRQ 0x00000002
|
|
|
|
#define INTSTS_ACTEINT 0x00000001
|
|
|
|
|
|
|
|
#define ECMODE_VALUE 0x01
|
|
|
|
|
|
|
|
static struct scc_ports {
|
|
|
|
unsigned long ctl, dma;
|
|
|
|
unsigned char hwif_id; /* for removing hwif from system */
|
|
|
|
} scc_ports[MAX_HWIFS];
|
|
|
|
|
|
|
|
/* PIO transfer mode table */
|
|
|
|
/* JCHST */
|
|
|
|
static unsigned long JCHSTtbl[2][7] = {
|
|
|
|
{0x0E, 0x05, 0x02, 0x03, 0x02, 0x00, 0x00}, /* 100MHz */
|
|
|
|
{0x13, 0x07, 0x04, 0x04, 0x03, 0x00, 0x00} /* 133MHz */
|
|
|
|
};
|
|
|
|
|
|
|
|
/* JCHHT */
|
|
|
|
static unsigned long JCHHTtbl[2][7] = {
|
|
|
|
{0x0E, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00}, /* 100MHz */
|
|
|
|
{0x13, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00} /* 133MHz */
|
|
|
|
};
|
|
|
|
|
|
|
|
/* JCHCT */
|
|
|
|
static unsigned long JCHCTtbl[2][7] = {
|
|
|
|
{0x1D, 0x1D, 0x1C, 0x0B, 0x06, 0x00, 0x00}, /* 100MHz */
|
|
|
|
{0x27, 0x26, 0x26, 0x0E, 0x09, 0x00, 0x00} /* 133MHz */
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/* DMA transfer mode table */
|
|
|
|
/* JCHDCTM/JCHDCTS */
|
|
|
|
static unsigned long JCHDCTxtbl[2][7] = {
|
|
|
|
{0x0A, 0x06, 0x04, 0x03, 0x01, 0x00, 0x00}, /* 100MHz */
|
|
|
|
{0x0E, 0x09, 0x06, 0x04, 0x02, 0x01, 0x00} /* 133MHz */
|
|
|
|
};
|
|
|
|
|
|
|
|
/* JCSTWTM/JCSTWTS */
|
|
|
|
static unsigned long JCSTWTxtbl[2][7] = {
|
|
|
|
{0x06, 0x04, 0x03, 0x02, 0x02, 0x02, 0x00}, /* 100MHz */
|
|
|
|
{0x09, 0x06, 0x04, 0x02, 0x02, 0x02, 0x02} /* 133MHz */
|
|
|
|
};
|
|
|
|
|
|
|
|
/* JCTSS */
|
|
|
|
static unsigned long JCTSStbl[2][7] = {
|
|
|
|
{0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00}, /* 100MHz */
|
|
|
|
{0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05} /* 133MHz */
|
|
|
|
};
|
|
|
|
|
|
|
|
/* JCENVT */
|
|
|
|
static unsigned long JCENVTtbl[2][7] = {
|
|
|
|
{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00}, /* 100MHz */
|
|
|
|
{0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02} /* 133MHz */
|
|
|
|
};
|
|
|
|
|
|
|
|
/* JCACTSELS/JCACTSELM */
|
|
|
|
static unsigned long JCACTSELtbl[2][7] = {
|
|
|
|
{0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00}, /* 100MHz */
|
|
|
|
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01} /* 133MHz */
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static u8 scc_ide_inb(unsigned long port)
|
|
|
|
{
|
|
|
|
u32 data = in_be32((void*)port);
|
|
|
|
return (u8)data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static u16 scc_ide_inw(unsigned long port)
|
|
|
|
{
|
|
|
|
u32 data = in_be32((void*)port);
|
|
|
|
return (u16)data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void scc_ide_insw(unsigned long port, void *addr, u32 count)
|
|
|
|
{
|
|
|
|
u16 *ptr = (u16 *)addr;
|
|
|
|
while (count--) {
|
|
|
|
*ptr++ = le16_to_cpu(in_be32((void*)port));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void scc_ide_insl(unsigned long port, void *addr, u32 count)
|
|
|
|
{
|
|
|
|
u16 *ptr = (u16 *)addr;
|
|
|
|
while (count--) {
|
|
|
|
*ptr++ = le16_to_cpu(in_be32((void*)port));
|
|
|
|
*ptr++ = le16_to_cpu(in_be32((void*)port));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void scc_ide_outb(u8 addr, unsigned long port)
|
|
|
|
{
|
|
|
|
out_be32((void*)port, addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void scc_ide_outw(u16 addr, unsigned long port)
|
|
|
|
{
|
|
|
|
out_be32((void*)port, addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
scc_ide_outbsync(ide_drive_t * drive, u8 addr, unsigned long port)
|
|
|
|
{
|
|
|
|
ide_hwif_t *hwif = HWIF(drive);
|
|
|
|
|
|
|
|
out_be32((void*)port, addr);
|
2007-07-20 07:11:53 +08:00
|
|
|
eieio();
|
2007-02-17 09:40:22 +08:00
|
|
|
in_be32((void*)(hwif->dma_base + 0x01c));
|
2007-07-20 07:11:53 +08:00
|
|
|
eieio();
|
2007-02-17 09:40:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
scc_ide_outsw(unsigned long port, void *addr, u32 count)
|
|
|
|
{
|
|
|
|
u16 *ptr = (u16 *)addr;
|
|
|
|
while (count--) {
|
|
|
|
out_be32((void*)port, cpu_to_le16(*ptr++));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
scc_ide_outsl(unsigned long port, void *addr, u32 count)
|
|
|
|
{
|
|
|
|
u16 *ptr = (u16 *)addr;
|
|
|
|
while (count--) {
|
|
|
|
out_be32((void*)port, cpu_to_le16(*ptr++));
|
|
|
|
out_be32((void*)port, cpu_to_le16(*ptr++));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
ide: move ide_config_drive_speed() calls to upper layers (take 2)
* Convert {ide_hwif_t,ide_pci_device_t}->host_flag to be u16.
* Add IDE_HFLAG_POST_SET_MODE host flag to indicate the need to program
the host for the transfer mode after programming the device. Set it
in au1xxx-ide, amd74xx, cs5530, cs5535, pdc202xx_new, sc1200, pmac
and via82cxxx host drivers.
* Add IDE_HFLAG_NO_SET_MODE host flag to indicate the need to completely
skip programming of host/device for the transfer mode ("smart" hosts).
Set it in it821x host driver and check it in ide_tune_dma().
* Add ide_set_pio_mode()/ide_set_dma_mode() helpers and convert all
direct ->set_pio_mode/->speedproc users to use these helpers.
* Move ide_config_drive_speed() calls from ->set_pio_mode/->speedproc
methods to callers.
* Rename ->speedproc method to ->set_dma_mode, make it void and update
all implementations accordingly.
* Update ide_set_xfer_rate() comments.
* Unexport ide_config_drive_speed().
v2:
* Fix issues noticed by Sergei:
- export ide_set_dma_mode() instead of moving ->set_pio_mode abuse wrt
to setting DMA modes from sc1200_set_pio_mode() to do_special()
- check IDE_HFLAG_NO_SET_MODE in ide_tune_dma()
- check for (hwif->set_pio_mode) == NULL in ide_set_pio_mode()
- check for (hwif->set_dma_mode) == NULL in ide_set_dma_mode()
- return -1 from ide_set_{pio,dma}_mode() if ->set_{pio,dma}_mode == NULL
- don't set ->set_{pio,dma}_mode on it821x in "smart" mode
- fix build problem in pmac.c
- minor fixes in au1xxx-ide.c/cs5530.c/siimage.c
- improve patch description
Changes in behavior caused by this patch:
- HDIO_SET_PIO_MODE ioctl would now return -ENOSYS for attempts to change
PIO mode if it821x controller is in "smart" mode
- removal of two debugging printk-s (from cs5530.c and sc1200.c)
- transfer modes 0x00-0x07 passed from user space may be programmed twice on
the device (not really an issue since 0x00 is not supported correctly by
any host driver ATM, 0x01 is not supported at all and 0x02-0x07 are invalid)
Acked-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
2007-10-13 23:47:51 +08:00
|
|
|
* scc_set_pio_mode - set host controller for PIO mode
|
|
|
|
* @drive: drive
|
|
|
|
* @pio: PIO mode number
|
2007-02-17 09:40:22 +08:00
|
|
|
*
|
|
|
|
* Load the timing settings for this device mode into the
|
|
|
|
* controller.
|
|
|
|
*/
|
|
|
|
|
ide: move ide_config_drive_speed() calls to upper layers (take 2)
* Convert {ide_hwif_t,ide_pci_device_t}->host_flag to be u16.
* Add IDE_HFLAG_POST_SET_MODE host flag to indicate the need to program
the host for the transfer mode after programming the device. Set it
in au1xxx-ide, amd74xx, cs5530, cs5535, pdc202xx_new, sc1200, pmac
and via82cxxx host drivers.
* Add IDE_HFLAG_NO_SET_MODE host flag to indicate the need to completely
skip programming of host/device for the transfer mode ("smart" hosts).
Set it in it821x host driver and check it in ide_tune_dma().
* Add ide_set_pio_mode()/ide_set_dma_mode() helpers and convert all
direct ->set_pio_mode/->speedproc users to use these helpers.
* Move ide_config_drive_speed() calls from ->set_pio_mode/->speedproc
methods to callers.
* Rename ->speedproc method to ->set_dma_mode, make it void and update
all implementations accordingly.
* Update ide_set_xfer_rate() comments.
* Unexport ide_config_drive_speed().
v2:
* Fix issues noticed by Sergei:
- export ide_set_dma_mode() instead of moving ->set_pio_mode abuse wrt
to setting DMA modes from sc1200_set_pio_mode() to do_special()
- check IDE_HFLAG_NO_SET_MODE in ide_tune_dma()
- check for (hwif->set_pio_mode) == NULL in ide_set_pio_mode()
- check for (hwif->set_dma_mode) == NULL in ide_set_dma_mode()
- return -1 from ide_set_{pio,dma}_mode() if ->set_{pio,dma}_mode == NULL
- don't set ->set_{pio,dma}_mode on it821x in "smart" mode
- fix build problem in pmac.c
- minor fixes in au1xxx-ide.c/cs5530.c/siimage.c
- improve patch description
Changes in behavior caused by this patch:
- HDIO_SET_PIO_MODE ioctl would now return -ENOSYS for attempts to change
PIO mode if it821x controller is in "smart" mode
- removal of two debugging printk-s (from cs5530.c and sc1200.c)
- transfer modes 0x00-0x07 passed from user space may be programmed twice on
the device (not really an issue since 0x00 is not supported correctly by
any host driver ATM, 0x01 is not supported at all and 0x02-0x07 are invalid)
Acked-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
2007-10-13 23:47:51 +08:00
|
|
|
static void scc_set_pio_mode(ide_drive_t *drive, const u8 pio)
|
2007-02-17 09:40:22 +08:00
|
|
|
{
|
|
|
|
ide_hwif_t *hwif = HWIF(drive);
|
|
|
|
struct scc_ports *ports = ide_get_hwifdata(hwif);
|
|
|
|
unsigned long ctl_base = ports->ctl;
|
|
|
|
unsigned long cckctrl_port = ctl_base + 0xff0;
|
|
|
|
unsigned long piosht_port = ctl_base + 0x000;
|
|
|
|
unsigned long pioct_port = ctl_base + 0x004;
|
|
|
|
unsigned long reg;
|
|
|
|
int offset;
|
|
|
|
|
2007-02-17 09:40:25 +08:00
|
|
|
reg = in_be32((void __iomem *)cckctrl_port);
|
2007-02-17 09:40:22 +08:00
|
|
|
if (reg & CCKCTRL_ATACLKOEN) {
|
|
|
|
offset = 1; /* 133MHz */
|
|
|
|
} else {
|
|
|
|
offset = 0; /* 100MHz */
|
|
|
|
}
|
2007-08-02 05:46:46 +08:00
|
|
|
reg = JCHSTtbl[offset][pio] << 16 | JCHHTtbl[offset][pio];
|
2007-02-17 09:40:25 +08:00
|
|
|
out_be32((void __iomem *)piosht_port, reg);
|
2007-08-02 05:46:46 +08:00
|
|
|
reg = JCHCTtbl[offset][pio];
|
2007-02-17 09:40:25 +08:00
|
|
|
out_be32((void __iomem *)pioct_port, reg);
|
2007-08-02 05:46:46 +08:00
|
|
|
}
|
2007-02-17 09:40:22 +08:00
|
|
|
|
|
|
|
/**
|
ide: move ide_config_drive_speed() calls to upper layers (take 2)
* Convert {ide_hwif_t,ide_pci_device_t}->host_flag to be u16.
* Add IDE_HFLAG_POST_SET_MODE host flag to indicate the need to program
the host for the transfer mode after programming the device. Set it
in au1xxx-ide, amd74xx, cs5530, cs5535, pdc202xx_new, sc1200, pmac
and via82cxxx host drivers.
* Add IDE_HFLAG_NO_SET_MODE host flag to indicate the need to completely
skip programming of host/device for the transfer mode ("smart" hosts).
Set it in it821x host driver and check it in ide_tune_dma().
* Add ide_set_pio_mode()/ide_set_dma_mode() helpers and convert all
direct ->set_pio_mode/->speedproc users to use these helpers.
* Move ide_config_drive_speed() calls from ->set_pio_mode/->speedproc
methods to callers.
* Rename ->speedproc method to ->set_dma_mode, make it void and update
all implementations accordingly.
* Update ide_set_xfer_rate() comments.
* Unexport ide_config_drive_speed().
v2:
* Fix issues noticed by Sergei:
- export ide_set_dma_mode() instead of moving ->set_pio_mode abuse wrt
to setting DMA modes from sc1200_set_pio_mode() to do_special()
- check IDE_HFLAG_NO_SET_MODE in ide_tune_dma()
- check for (hwif->set_pio_mode) == NULL in ide_set_pio_mode()
- check for (hwif->set_dma_mode) == NULL in ide_set_dma_mode()
- return -1 from ide_set_{pio,dma}_mode() if ->set_{pio,dma}_mode == NULL
- don't set ->set_{pio,dma}_mode on it821x in "smart" mode
- fix build problem in pmac.c
- minor fixes in au1xxx-ide.c/cs5530.c/siimage.c
- improve patch description
Changes in behavior caused by this patch:
- HDIO_SET_PIO_MODE ioctl would now return -ENOSYS for attempts to change
PIO mode if it821x controller is in "smart" mode
- removal of two debugging printk-s (from cs5530.c and sc1200.c)
- transfer modes 0x00-0x07 passed from user space may be programmed twice on
the device (not really an issue since 0x00 is not supported correctly by
any host driver ATM, 0x01 is not supported at all and 0x02-0x07 are invalid)
Acked-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
2007-10-13 23:47:51 +08:00
|
|
|
* scc_set_dma_mode - set host controller for DMA mode
|
|
|
|
* @drive: drive
|
|
|
|
* @speed: DMA mode
|
2007-02-17 09:40:22 +08:00
|
|
|
*
|
|
|
|
* Load the timing settings for this device mode into the
|
|
|
|
* controller.
|
|
|
|
*/
|
|
|
|
|
ide: move ide_config_drive_speed() calls to upper layers (take 2)
* Convert {ide_hwif_t,ide_pci_device_t}->host_flag to be u16.
* Add IDE_HFLAG_POST_SET_MODE host flag to indicate the need to program
the host for the transfer mode after programming the device. Set it
in au1xxx-ide, amd74xx, cs5530, cs5535, pdc202xx_new, sc1200, pmac
and via82cxxx host drivers.
* Add IDE_HFLAG_NO_SET_MODE host flag to indicate the need to completely
skip programming of host/device for the transfer mode ("smart" hosts).
Set it in it821x host driver and check it in ide_tune_dma().
* Add ide_set_pio_mode()/ide_set_dma_mode() helpers and convert all
direct ->set_pio_mode/->speedproc users to use these helpers.
* Move ide_config_drive_speed() calls from ->set_pio_mode/->speedproc
methods to callers.
* Rename ->speedproc method to ->set_dma_mode, make it void and update
all implementations accordingly.
* Update ide_set_xfer_rate() comments.
* Unexport ide_config_drive_speed().
v2:
* Fix issues noticed by Sergei:
- export ide_set_dma_mode() instead of moving ->set_pio_mode abuse wrt
to setting DMA modes from sc1200_set_pio_mode() to do_special()
- check IDE_HFLAG_NO_SET_MODE in ide_tune_dma()
- check for (hwif->set_pio_mode) == NULL in ide_set_pio_mode()
- check for (hwif->set_dma_mode) == NULL in ide_set_dma_mode()
- return -1 from ide_set_{pio,dma}_mode() if ->set_{pio,dma}_mode == NULL
- don't set ->set_{pio,dma}_mode on it821x in "smart" mode
- fix build problem in pmac.c
- minor fixes in au1xxx-ide.c/cs5530.c/siimage.c
- improve patch description
Changes in behavior caused by this patch:
- HDIO_SET_PIO_MODE ioctl would now return -ENOSYS for attempts to change
PIO mode if it821x controller is in "smart" mode
- removal of two debugging printk-s (from cs5530.c and sc1200.c)
- transfer modes 0x00-0x07 passed from user space may be programmed twice on
the device (not really an issue since 0x00 is not supported correctly by
any host driver ATM, 0x01 is not supported at all and 0x02-0x07 are invalid)
Acked-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
2007-10-13 23:47:51 +08:00
|
|
|
static void scc_set_dma_mode(ide_drive_t *drive, const u8 speed)
|
2007-02-17 09:40:22 +08:00
|
|
|
{
|
|
|
|
ide_hwif_t *hwif = HWIF(drive);
|
|
|
|
struct scc_ports *ports = ide_get_hwifdata(hwif);
|
|
|
|
unsigned long ctl_base = ports->ctl;
|
|
|
|
unsigned long cckctrl_port = ctl_base + 0xff0;
|
|
|
|
unsigned long mdmact_port = ctl_base + 0x008;
|
|
|
|
unsigned long mcrcst_port = ctl_base + 0x00c;
|
|
|
|
unsigned long sdmact_port = ctl_base + 0x010;
|
|
|
|
unsigned long scrcst_port = ctl_base + 0x014;
|
|
|
|
unsigned long udenvt_port = ctl_base + 0x018;
|
|
|
|
unsigned long tdvhsel_port = ctl_base + 0x020;
|
|
|
|
int is_slave = (&hwif->drives[1] == drive);
|
|
|
|
int offset, idx;
|
|
|
|
unsigned long reg;
|
|
|
|
unsigned long jcactsel;
|
|
|
|
|
2007-02-17 09:40:25 +08:00
|
|
|
reg = in_be32((void __iomem *)cckctrl_port);
|
2007-02-17 09:40:22 +08:00
|
|
|
if (reg & CCKCTRL_ATACLKOEN) {
|
|
|
|
offset = 1; /* 133MHz */
|
|
|
|
} else {
|
|
|
|
offset = 0; /* 100MHz */
|
|
|
|
}
|
|
|
|
|
2008-01-26 05:17:18 +08:00
|
|
|
idx = speed - XFER_UDMA_0;
|
2007-02-17 09:40:22 +08:00
|
|
|
|
|
|
|
jcactsel = JCACTSELtbl[offset][idx];
|
|
|
|
if (is_slave) {
|
2007-02-17 09:40:25 +08:00
|
|
|
out_be32((void __iomem *)sdmact_port, JCHDCTxtbl[offset][idx]);
|
|
|
|
out_be32((void __iomem *)scrcst_port, JCSTWTxtbl[offset][idx]);
|
|
|
|
jcactsel = jcactsel << 2;
|
|
|
|
out_be32((void __iomem *)tdvhsel_port, (in_be32((void __iomem *)tdvhsel_port) & ~TDVHSEL_SLAVE) | jcactsel);
|
2007-02-17 09:40:22 +08:00
|
|
|
} else {
|
2007-02-17 09:40:25 +08:00
|
|
|
out_be32((void __iomem *)mdmact_port, JCHDCTxtbl[offset][idx]);
|
|
|
|
out_be32((void __iomem *)mcrcst_port, JCSTWTxtbl[offset][idx]);
|
|
|
|
out_be32((void __iomem *)tdvhsel_port, (in_be32((void __iomem *)tdvhsel_port) & ~TDVHSEL_MASTER) | jcactsel);
|
2007-02-17 09:40:22 +08:00
|
|
|
}
|
|
|
|
reg = JCTSStbl[offset][idx] << 16 | JCENVTtbl[offset][idx];
|
2007-02-17 09:40:25 +08:00
|
|
|
out_be32((void __iomem *)udenvt_port, reg);
|
2007-02-17 09:40:22 +08:00
|
|
|
}
|
|
|
|
|
2007-02-17 09:40:25 +08:00
|
|
|
/**
|
|
|
|
* scc_ide_dma_setup - begin a DMA phase
|
|
|
|
* @drive: target device
|
|
|
|
*
|
|
|
|
* Build an IDE DMA PRD (IDE speak for scatter gather table)
|
|
|
|
* and then set up the DMA transfer registers.
|
|
|
|
*
|
|
|
|
* Returns 0 on success. If a PIO fallback is required then 1
|
|
|
|
* is returned.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int scc_dma_setup(ide_drive_t *drive)
|
|
|
|
{
|
|
|
|
ide_hwif_t *hwif = drive->hwif;
|
|
|
|
struct request *rq = HWGROUP(drive)->rq;
|
|
|
|
unsigned int reading;
|
|
|
|
u8 dma_stat;
|
|
|
|
|
|
|
|
if (rq_data_dir(rq))
|
|
|
|
reading = 0;
|
|
|
|
else
|
|
|
|
reading = 1 << 3;
|
|
|
|
|
|
|
|
/* fall back to pio! */
|
|
|
|
if (!ide_build_dmatable(drive, rq)) {
|
|
|
|
ide_map_sg(drive, rq);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* PRD table */
|
|
|
|
out_be32((void __iomem *)hwif->dma_prdtable, hwif->dmatable_dma);
|
|
|
|
|
|
|
|
/* specify r/w */
|
|
|
|
out_be32((void __iomem *)hwif->dma_command, reading);
|
|
|
|
|
|
|
|
/* read dma_status for INTR & ERROR flags */
|
|
|
|
dma_stat = in_be32((void __iomem *)hwif->dma_status);
|
|
|
|
|
|
|
|
/* clear INTR & ERROR flags */
|
|
|
|
out_be32((void __iomem *)hwif->dma_status, dma_stat|6);
|
|
|
|
drive->waiting_for_dma = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-02-17 09:40:22 +08:00
|
|
|
/**
|
|
|
|
* scc_ide_dma_end - Stop DMA
|
|
|
|
* @drive: IDE drive
|
|
|
|
*
|
|
|
|
* Check and clear INT Status register.
|
|
|
|
* Then call __ide_dma_end().
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int scc_ide_dma_end(ide_drive_t * drive)
|
|
|
|
{
|
|
|
|
ide_hwif_t *hwif = HWIF(drive);
|
|
|
|
unsigned long intsts_port = hwif->dma_base + 0x014;
|
|
|
|
u32 reg;
|
2007-07-20 07:11:53 +08:00
|
|
|
int dma_stat, data_loss = 0;
|
|
|
|
static int retry = 0;
|
|
|
|
|
|
|
|
/* errata A308 workaround: Step5 (check data loss) */
|
|
|
|
/* We don't check non ide_disk because it is limited to UDMA4 */
|
2008-04-18 06:46:26 +08:00
|
|
|
if (!(in_be32((void __iomem *)hwif->io_ports[IDE_ALTSTATUS_OFFSET])
|
|
|
|
& ERR_STAT) &&
|
2007-07-20 07:11:53 +08:00
|
|
|
drive->media == ide_disk && drive->current_speed > XFER_UDMA_4) {
|
|
|
|
reg = in_be32((void __iomem *)intsts_port);
|
|
|
|
if (!(reg & INTSTS_ACTEINT)) {
|
|
|
|
printk(KERN_WARNING "%s: operation failed (transfer data loss)\n",
|
|
|
|
drive->name);
|
|
|
|
data_loss = 1;
|
|
|
|
if (retry++) {
|
|
|
|
struct request *rq = HWGROUP(drive)->rq;
|
|
|
|
int unit;
|
|
|
|
/* ERROR_RESET and drive->crc_count are needed
|
|
|
|
* to reduce DMA transfer mode in retry process.
|
|
|
|
*/
|
|
|
|
if (rq)
|
|
|
|
rq->errors |= ERROR_RESET;
|
|
|
|
for (unit = 0; unit < MAX_DRIVES; unit++) {
|
|
|
|
ide_drive_t *drive = &hwif->drives[unit];
|
|
|
|
drive->crc_count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-02-17 09:40:22 +08:00
|
|
|
|
|
|
|
while (1) {
|
2007-02-17 09:40:25 +08:00
|
|
|
reg = in_be32((void __iomem *)intsts_port);
|
2007-02-17 09:40:22 +08:00
|
|
|
|
|
|
|
if (reg & INTSTS_SERROR) {
|
|
|
|
printk(KERN_WARNING "%s: SERROR\n", SCC_PATA_NAME);
|
2007-02-17 09:40:25 +08:00
|
|
|
out_be32((void __iomem *)intsts_port, INTSTS_SERROR|INTSTS_BMSINT);
|
2007-02-17 09:40:22 +08:00
|
|
|
|
2007-02-17 09:40:25 +08:00
|
|
|
out_be32((void __iomem *)hwif->dma_command, in_be32((void __iomem *)hwif->dma_command) & ~QCHCD_IOS_SS);
|
2007-02-17 09:40:22 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (reg & INTSTS_PRERR) {
|
|
|
|
u32 maea0, maec0;
|
|
|
|
unsigned long ctl_base = hwif->config_data;
|
|
|
|
|
2007-02-17 09:40:25 +08:00
|
|
|
maea0 = in_be32((void __iomem *)(ctl_base + 0xF50));
|
|
|
|
maec0 = in_be32((void __iomem *)(ctl_base + 0xF54));
|
2007-02-17 09:40:22 +08:00
|
|
|
|
|
|
|
printk(KERN_WARNING "%s: PRERR [addr:%x cmd:%x]\n", SCC_PATA_NAME, maea0, maec0);
|
|
|
|
|
2007-02-17 09:40:25 +08:00
|
|
|
out_be32((void __iomem *)intsts_port, INTSTS_PRERR|INTSTS_BMSINT);
|
2007-02-17 09:40:22 +08:00
|
|
|
|
2007-02-17 09:40:25 +08:00
|
|
|
out_be32((void __iomem *)hwif->dma_command, in_be32((void __iomem *)hwif->dma_command) & ~QCHCD_IOS_SS);
|
2007-02-17 09:40:22 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (reg & INTSTS_RERR) {
|
|
|
|
printk(KERN_WARNING "%s: Response Error\n", SCC_PATA_NAME);
|
2007-02-17 09:40:25 +08:00
|
|
|
out_be32((void __iomem *)intsts_port, INTSTS_RERR|INTSTS_BMSINT);
|
2007-02-17 09:40:22 +08:00
|
|
|
|
2007-02-17 09:40:25 +08:00
|
|
|
out_be32((void __iomem *)hwif->dma_command, in_be32((void __iomem *)hwif->dma_command) & ~QCHCD_IOS_SS);
|
2007-02-17 09:40:22 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (reg & INTSTS_ICERR) {
|
2007-02-17 09:40:25 +08:00
|
|
|
out_be32((void __iomem *)hwif->dma_command, in_be32((void __iomem *)hwif->dma_command) & ~QCHCD_IOS_SS);
|
2007-02-17 09:40:22 +08:00
|
|
|
|
|
|
|
printk(KERN_WARNING "%s: Illegal Configuration\n", SCC_PATA_NAME);
|
2007-02-17 09:40:25 +08:00
|
|
|
out_be32((void __iomem *)intsts_port, INTSTS_ICERR|INTSTS_BMSINT);
|
2007-02-17 09:40:22 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (reg & INTSTS_BMSINT) {
|
|
|
|
printk(KERN_WARNING "%s: Internal Bus Error\n", SCC_PATA_NAME);
|
2007-02-17 09:40:25 +08:00
|
|
|
out_be32((void __iomem *)intsts_port, INTSTS_BMSINT);
|
2007-02-17 09:40:22 +08:00
|
|
|
|
|
|
|
ide_do_reset(drive);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (reg & INTSTS_BMHE) {
|
2007-02-17 09:40:25 +08:00
|
|
|
out_be32((void __iomem *)intsts_port, INTSTS_BMHE);
|
2007-02-17 09:40:22 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (reg & INTSTS_ACTEINT) {
|
2007-02-17 09:40:25 +08:00
|
|
|
out_be32((void __iomem *)intsts_port, INTSTS_ACTEINT);
|
2007-02-17 09:40:22 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (reg & INTSTS_IOIRQS) {
|
2007-02-17 09:40:25 +08:00
|
|
|
out_be32((void __iomem *)intsts_port, INTSTS_IOIRQS);
|
2007-02-17 09:40:22 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-07-20 07:11:53 +08:00
|
|
|
dma_stat = __ide_dma_end(drive);
|
|
|
|
if (data_loss)
|
|
|
|
dma_stat |= 2; /* emulate DMA error (to retry command) */
|
|
|
|
return dma_stat;
|
2007-02-17 09:40:22 +08:00
|
|
|
}
|
|
|
|
|
2007-03-04 00:48:55 +08:00
|
|
|
/* returns 1 if dma irq issued, 0 otherwise */
|
|
|
|
static int scc_dma_test_irq(ide_drive_t *drive)
|
|
|
|
{
|
2007-07-20 07:11:53 +08:00
|
|
|
ide_hwif_t *hwif = HWIF(drive);
|
|
|
|
u32 int_stat = in_be32((void __iomem *)hwif->dma_base + 0x014);
|
2007-03-04 00:48:55 +08:00
|
|
|
|
2007-07-20 07:11:53 +08:00
|
|
|
/* SCC errata A252,A308 workaround: Step4 */
|
2008-04-18 06:46:26 +08:00
|
|
|
if ((in_be32((void __iomem *)hwif->io_ports[IDE_ALTSTATUS_OFFSET])
|
|
|
|
& ERR_STAT) &&
|
2007-07-20 07:11:53 +08:00
|
|
|
(int_stat & INTSTS_INTRQ))
|
2007-03-04 00:48:55 +08:00
|
|
|
return 1;
|
|
|
|
|
2007-07-20 07:11:53 +08:00
|
|
|
/* SCC errata A308 workaround: Step5 (polling IOIRQS) */
|
|
|
|
if (int_stat & INTSTS_IOIRQS)
|
2007-03-04 00:48:55 +08:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (!drive->waiting_for_dma)
|
|
|
|
printk(KERN_WARNING "%s: (%s) called while not waiting\n",
|
|
|
|
drive->name, __FUNCTION__);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-07-20 07:11:53 +08:00
|
|
|
static u8 scc_udma_filter(ide_drive_t *drive)
|
|
|
|
{
|
|
|
|
ide_hwif_t *hwif = drive->hwif;
|
|
|
|
u8 mask = hwif->ultra_mask;
|
|
|
|
|
|
|
|
/* errata A308 workaround: limit non ide_disk drive to UDMA4 */
|
|
|
|
if ((drive->media != ide_disk) && (mask & 0xE0)) {
|
|
|
|
printk(KERN_INFO "%s: limit %s to UDMA4\n",
|
|
|
|
SCC_PATA_NAME, drive->name);
|
2007-10-19 06:30:07 +08:00
|
|
|
mask = ATA_UDMA4;
|
2007-07-20 07:11:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return mask;
|
|
|
|
}
|
|
|
|
|
2007-02-17 09:40:22 +08:00
|
|
|
/**
|
|
|
|
* setup_mmio_scc - map CTRL/BMID region
|
|
|
|
* @dev: PCI device we are configuring
|
|
|
|
* @name: device name
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int setup_mmio_scc (struct pci_dev *dev, const char *name)
|
|
|
|
{
|
|
|
|
unsigned long ctl_base = pci_resource_start(dev, 0);
|
|
|
|
unsigned long dma_base = pci_resource_start(dev, 1);
|
|
|
|
unsigned long ctl_size = pci_resource_len(dev, 0);
|
|
|
|
unsigned long dma_size = pci_resource_len(dev, 1);
|
2007-07-27 00:36:09 +08:00
|
|
|
void __iomem *ctl_addr;
|
|
|
|
void __iomem *dma_addr;
|
2007-02-17 09:40:22 +08:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_HWIFS; i++) {
|
|
|
|
if (scc_ports[i].ctl == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i >= MAX_HWIFS)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
if (!request_mem_region(ctl_base, ctl_size, name)) {
|
|
|
|
printk(KERN_WARNING "%s: IDE controller MMIO ports not available.\n", SCC_PATA_NAME);
|
|
|
|
goto fail_0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!request_mem_region(dma_base, dma_size, name)) {
|
|
|
|
printk(KERN_WARNING "%s: IDE controller MMIO ports not available.\n", SCC_PATA_NAME);
|
|
|
|
goto fail_1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ctl_addr = ioremap(ctl_base, ctl_size)) == NULL)
|
|
|
|
goto fail_2;
|
|
|
|
|
|
|
|
if ((dma_addr = ioremap(dma_base, dma_size)) == NULL)
|
|
|
|
goto fail_3;
|
|
|
|
|
|
|
|
pci_set_master(dev);
|
|
|
|
scc_ports[i].ctl = (unsigned long)ctl_addr;
|
|
|
|
scc_ports[i].dma = (unsigned long)dma_addr;
|
|
|
|
pci_set_drvdata(dev, (void *) &scc_ports[i]);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
fail_3:
|
|
|
|
iounmap(ctl_addr);
|
|
|
|
fail_2:
|
|
|
|
release_mem_region(dma_base, dma_size);
|
|
|
|
fail_1:
|
|
|
|
release_mem_region(ctl_base, ctl_size);
|
|
|
|
fail_0:
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2008-04-18 06:46:25 +08:00
|
|
|
static int scc_ide_setup_pci_device(struct pci_dev *dev,
|
|
|
|
const struct ide_port_info *d)
|
|
|
|
{
|
|
|
|
struct scc_ports *ports = pci_get_drvdata(dev);
|
|
|
|
ide_hwif_t *hwif = NULL;
|
|
|
|
hw_regs_t hw;
|
|
|
|
u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_HWIFS; i++) {
|
|
|
|
hwif = &ide_hwifs[i];
|
|
|
|
if (hwif->chipset == ide_unknown)
|
|
|
|
break; /* pick an unused entry */
|
|
|
|
}
|
|
|
|
if (i == MAX_HWIFS) {
|
|
|
|
printk(KERN_ERR "%s: too many IDE interfaces, "
|
|
|
|
"no room in table\n", SCC_PATA_NAME);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&hw, 0, sizeof(hw));
|
|
|
|
for (i = IDE_DATA_OFFSET; i <= IDE_CONTROL_OFFSET; i++)
|
|
|
|
hw.io_ports[i] = ports->dma + 0x20 + i * 4;
|
|
|
|
hw.irq = dev->irq;
|
|
|
|
hw.dev = &dev->dev;
|
|
|
|
hw.chipset = ide_pci;
|
|
|
|
ide_init_port_hw(hwif, &hw);
|
|
|
|
hwif->dev = &dev->dev;
|
|
|
|
hwif->cds = d;
|
|
|
|
|
|
|
|
idx[0] = hwif->index;
|
|
|
|
|
|
|
|
ide_device_add(idx, d);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-02-17 09:40:22 +08:00
|
|
|
/**
|
|
|
|
* init_setup_scc - set up an SCC PATA Controller
|
|
|
|
* @dev: PCI device
|
2007-10-20 06:32:34 +08:00
|
|
|
* @d: IDE port info
|
2007-02-17 09:40:22 +08:00
|
|
|
*
|
|
|
|
* Perform the initial set up for this device.
|
|
|
|
*/
|
|
|
|
|
2007-10-20 06:32:34 +08:00
|
|
|
static int __devinit init_setup_scc(struct pci_dev *dev,
|
2007-10-20 06:32:34 +08:00
|
|
|
const struct ide_port_info *d)
|
2007-02-17 09:40:22 +08:00
|
|
|
{
|
|
|
|
unsigned long ctl_base;
|
|
|
|
unsigned long dma_base;
|
|
|
|
unsigned long cckctrl_port;
|
|
|
|
unsigned long intmask_port;
|
|
|
|
unsigned long mode_port;
|
|
|
|
unsigned long ecmode_port;
|
|
|
|
unsigned long dma_status_port;
|
|
|
|
u32 reg = 0;
|
|
|
|
struct scc_ports *ports;
|
|
|
|
int rc;
|
|
|
|
|
2008-04-18 06:46:25 +08:00
|
|
|
rc = pci_enable_device(dev);
|
|
|
|
if (rc)
|
|
|
|
goto end;
|
|
|
|
|
2007-02-17 09:40:22 +08:00
|
|
|
rc = setup_mmio_scc(dev, d->name);
|
2008-04-18 06:46:25 +08:00
|
|
|
if (rc < 0)
|
|
|
|
goto end;
|
2007-02-17 09:40:22 +08:00
|
|
|
|
|
|
|
ports = pci_get_drvdata(dev);
|
|
|
|
ctl_base = ports->ctl;
|
|
|
|
dma_base = ports->dma;
|
|
|
|
cckctrl_port = ctl_base + 0xff0;
|
|
|
|
intmask_port = dma_base + 0x010;
|
|
|
|
mode_port = ctl_base + 0x024;
|
|
|
|
ecmode_port = ctl_base + 0xf00;
|
|
|
|
dma_status_port = dma_base + 0x004;
|
|
|
|
|
|
|
|
/* controller initialization */
|
|
|
|
reg = 0;
|
|
|
|
out_be32((void*)cckctrl_port, reg);
|
|
|
|
reg |= CCKCTRL_ATACLKOEN;
|
|
|
|
out_be32((void*)cckctrl_port, reg);
|
|
|
|
reg |= CCKCTRL_LCLKEN | CCKCTRL_OCLKEN;
|
|
|
|
out_be32((void*)cckctrl_port, reg);
|
|
|
|
reg |= CCKCTRL_CRST;
|
|
|
|
out_be32((void*)cckctrl_port, reg);
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
reg = in_be32((void*)cckctrl_port);
|
|
|
|
if (reg & CCKCTRL_CRST)
|
|
|
|
break;
|
|
|
|
udelay(5000);
|
|
|
|
}
|
|
|
|
|
|
|
|
reg |= CCKCTRL_ATARESET;
|
|
|
|
out_be32((void*)cckctrl_port, reg);
|
|
|
|
|
|
|
|
out_be32((void*)ecmode_port, ECMODE_VALUE);
|
|
|
|
out_be32((void*)mode_port, MODE_JCUSFEN);
|
|
|
|
out_be32((void*)intmask_port, INTMASK_MSK);
|
|
|
|
|
2008-04-18 06:46:25 +08:00
|
|
|
rc = scc_ide_setup_pci_device(dev, d);
|
|
|
|
|
|
|
|
end:
|
|
|
|
return rc;
|
2007-02-17 09:40:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* init_mmio_iops_scc - set up the iops for MMIO
|
|
|
|
* @hwif: interface to set up
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void __devinit init_mmio_iops_scc(ide_hwif_t *hwif)
|
|
|
|
{
|
2008-02-02 06:09:31 +08:00
|
|
|
struct pci_dev *dev = to_pci_dev(hwif->dev);
|
2007-02-17 09:40:22 +08:00
|
|
|
struct scc_ports *ports = pci_get_drvdata(dev);
|
|
|
|
unsigned long dma_base = ports->dma;
|
|
|
|
|
|
|
|
ide_set_hwifdata(hwif, ports);
|
|
|
|
|
|
|
|
hwif->INB = scc_ide_inb;
|
|
|
|
hwif->INW = scc_ide_inw;
|
|
|
|
hwif->INSW = scc_ide_insw;
|
|
|
|
hwif->INSL = scc_ide_insl;
|
|
|
|
hwif->OUTB = scc_ide_outb;
|
|
|
|
hwif->OUTBSYNC = scc_ide_outbsync;
|
|
|
|
hwif->OUTW = scc_ide_outw;
|
|
|
|
hwif->OUTSW = scc_ide_outsw;
|
|
|
|
hwif->OUTSL = scc_ide_outsl;
|
|
|
|
|
|
|
|
hwif->dma_base = dma_base;
|
|
|
|
hwif->config_data = ports->ctl;
|
2007-02-17 09:40:25 +08:00
|
|
|
hwif->mmio = 1;
|
2007-02-17 09:40:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* init_iops_scc - set up iops
|
|
|
|
* @hwif: interface to set up
|
|
|
|
*
|
|
|
|
* Do the basic setup for the SCC hardware interface
|
|
|
|
* and then do the MMIO setup.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void __devinit init_iops_scc(ide_hwif_t *hwif)
|
|
|
|
{
|
2008-02-02 06:09:31 +08:00
|
|
|
struct pci_dev *dev = to_pci_dev(hwif->dev);
|
|
|
|
|
2007-02-17 09:40:22 +08:00
|
|
|
hwif->hwif_data = NULL;
|
|
|
|
if (pci_get_drvdata(dev) == NULL)
|
|
|
|
return;
|
|
|
|
init_mmio_iops_scc(hwif);
|
|
|
|
}
|
|
|
|
|
2008-02-03 02:56:29 +08:00
|
|
|
static u8 __devinit scc_cable_detect(ide_hwif_t *hwif)
|
|
|
|
{
|
|
|
|
return ATA_CBL_PATA80;
|
|
|
|
}
|
|
|
|
|
2007-02-17 09:40:22 +08:00
|
|
|
/**
|
|
|
|
* init_hwif_scc - set up hwif
|
|
|
|
* @hwif: interface to set up
|
|
|
|
*
|
|
|
|
* We do the basic set up of the interface structure. The SCC
|
|
|
|
* requires several custom handlers so we override the default
|
|
|
|
* ide DMA handlers appropriately.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void __devinit init_hwif_scc(ide_hwif_t *hwif)
|
|
|
|
{
|
|
|
|
struct scc_ports *ports = ide_get_hwifdata(hwif);
|
|
|
|
|
|
|
|
ports->hwif_id = hwif->index;
|
|
|
|
|
|
|
|
hwif->dma_command = hwif->dma_base;
|
|
|
|
hwif->dma_status = hwif->dma_base + 0x04;
|
|
|
|
hwif->dma_prdtable = hwif->dma_base + 0x08;
|
|
|
|
|
2007-02-17 09:40:25 +08:00
|
|
|
/* PTERADD */
|
|
|
|
out_be32((void __iomem *)(hwif->dma_base + 0x018), hwif->dmatable_dma);
|
2007-02-17 09:40:22 +08:00
|
|
|
|
2007-02-17 09:40:25 +08:00
|
|
|
hwif->dma_setup = scc_dma_setup;
|
2007-02-17 09:40:22 +08:00
|
|
|
hwif->ide_dma_end = scc_ide_dma_end;
|
2007-10-12 05:54:00 +08:00
|
|
|
hwif->set_pio_mode = scc_set_pio_mode;
|
ide: move ide_config_drive_speed() calls to upper layers (take 2)
* Convert {ide_hwif_t,ide_pci_device_t}->host_flag to be u16.
* Add IDE_HFLAG_POST_SET_MODE host flag to indicate the need to program
the host for the transfer mode after programming the device. Set it
in au1xxx-ide, amd74xx, cs5530, cs5535, pdc202xx_new, sc1200, pmac
and via82cxxx host drivers.
* Add IDE_HFLAG_NO_SET_MODE host flag to indicate the need to completely
skip programming of host/device for the transfer mode ("smart" hosts).
Set it in it821x host driver and check it in ide_tune_dma().
* Add ide_set_pio_mode()/ide_set_dma_mode() helpers and convert all
direct ->set_pio_mode/->speedproc users to use these helpers.
* Move ide_config_drive_speed() calls from ->set_pio_mode/->speedproc
methods to callers.
* Rename ->speedproc method to ->set_dma_mode, make it void and update
all implementations accordingly.
* Update ide_set_xfer_rate() comments.
* Unexport ide_config_drive_speed().
v2:
* Fix issues noticed by Sergei:
- export ide_set_dma_mode() instead of moving ->set_pio_mode abuse wrt
to setting DMA modes from sc1200_set_pio_mode() to do_special()
- check IDE_HFLAG_NO_SET_MODE in ide_tune_dma()
- check for (hwif->set_pio_mode) == NULL in ide_set_pio_mode()
- check for (hwif->set_dma_mode) == NULL in ide_set_dma_mode()
- return -1 from ide_set_{pio,dma}_mode() if ->set_{pio,dma}_mode == NULL
- don't set ->set_{pio,dma}_mode on it821x in "smart" mode
- fix build problem in pmac.c
- minor fixes in au1xxx-ide.c/cs5530.c/siimage.c
- improve patch description
Changes in behavior caused by this patch:
- HDIO_SET_PIO_MODE ioctl would now return -ENOSYS for attempts to change
PIO mode if it821x controller is in "smart" mode
- removal of two debugging printk-s (from cs5530.c and sc1200.c)
- transfer modes 0x00-0x07 passed from user space may be programmed twice on
the device (not really an issue since 0x00 is not supported correctly by
any host driver ATM, 0x01 is not supported at all and 0x02-0x07 are invalid)
Acked-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
2007-10-13 23:47:51 +08:00
|
|
|
hwif->set_dma_mode = scc_set_dma_mode;
|
2007-03-04 00:48:55 +08:00
|
|
|
hwif->ide_dma_test_irq = scc_dma_test_irq;
|
2007-07-20 07:11:53 +08:00
|
|
|
hwif->udma_filter = scc_udma_filter;
|
2007-02-17 09:40:22 +08:00
|
|
|
|
2007-10-19 06:30:07 +08:00
|
|
|
if (in_be32((void __iomem *)(hwif->config_data + 0xff0)) & CCKCTRL_ATACLKOEN)
|
|
|
|
hwif->ultra_mask = ATA_UDMA6; /* 133MHz */
|
|
|
|
else
|
|
|
|
hwif->ultra_mask = ATA_UDMA5; /* 100MHz */
|
2007-02-17 09:40:22 +08:00
|
|
|
|
2008-02-03 02:56:31 +08:00
|
|
|
hwif->cable_detect = scc_cable_detect;
|
2007-02-17 09:40:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#define DECLARE_SCC_DEV(name_str) \
|
|
|
|
{ \
|
|
|
|
.name = name_str, \
|
|
|
|
.init_iops = init_iops_scc, \
|
|
|
|
.init_hwif = init_hwif_scc, \
|
2007-10-19 06:30:06 +08:00
|
|
|
.host_flags = IDE_HFLAG_SINGLE | \
|
|
|
|
IDE_HFLAG_BOOTABLE, \
|
2007-07-20 07:11:59 +08:00
|
|
|
.pio_mask = ATA_PIO4, \
|
2007-02-17 09:40:22 +08:00
|
|
|
}
|
|
|
|
|
2007-10-20 06:32:34 +08:00
|
|
|
static const struct ide_port_info scc_chipsets[] __devinitdata = {
|
2007-02-17 09:40:22 +08:00
|
|
|
/* 0 */ DECLARE_SCC_DEV("sccIDE"),
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* scc_init_one - pci layer discovery entry
|
|
|
|
* @dev: PCI device
|
|
|
|
* @id: ident table entry
|
|
|
|
*
|
|
|
|
* Called by the PCI code when it finds an SCC PATA controller.
|
|
|
|
* We then use the IDE PCI generic helper to do most of the work.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int __devinit scc_init_one(struct pci_dev *dev, const struct pci_device_id *id)
|
|
|
|
{
|
2007-10-20 06:32:34 +08:00
|
|
|
return init_setup_scc(dev, &scc_chipsets[id->driver_data]);
|
2007-02-17 09:40:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* scc_remove - pci layer remove entry
|
|
|
|
* @dev: PCI device
|
|
|
|
*
|
|
|
|
* Called by the PCI code when it removes an SCC PATA controller.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void __devexit scc_remove(struct pci_dev *dev)
|
|
|
|
{
|
|
|
|
struct scc_ports *ports = pci_get_drvdata(dev);
|
|
|
|
ide_hwif_t *hwif = &ide_hwifs[ports->hwif_id];
|
|
|
|
unsigned long ctl_base = pci_resource_start(dev, 0);
|
|
|
|
unsigned long dma_base = pci_resource_start(dev, 1);
|
|
|
|
unsigned long ctl_size = pci_resource_len(dev, 0);
|
|
|
|
unsigned long dma_size = pci_resource_len(dev, 1);
|
|
|
|
|
|
|
|
if (hwif->dmatable_cpu) {
|
2008-02-02 06:09:31 +08:00
|
|
|
pci_free_consistent(dev, PRD_ENTRIES * PRD_BYTES,
|
|
|
|
hwif->dmatable_cpu, hwif->dmatable_dma);
|
2007-02-17 09:40:22 +08:00
|
|
|
hwif->dmatable_cpu = NULL;
|
|
|
|
}
|
|
|
|
|
ide: remove broken/dangerous HDIO_[UNREGISTER,SCAN]_HWIF ioctls (take 3)
hdparm explicitely marks HDIO_[UNREGISTER,SCAN]_HWIF ioctls as DANGEROUS
and given the number of bugs we can assume that there are no real users:
* DMA has no chance of working because DMA resources are released by
ide_unregister() and they are never allocated again.
* Since ide_init_hwif_ports() is used for ->io_ports[] setup the ioctls
don't work for almost all hosts with "non-standard" (== non ISA-like)
layout of IDE taskfile registers (there is a lot of such host drivers).
* ide_port_init_devices() is not called when probing IDE devices so:
- drive->autotune is never set and IDE host/devices are not programmed
for the correct PIO/DMA transfer modes (=> possible data corruption)
- host specific I/O 32-bit and IRQ unmasking settings are not applied
(=> possible data corruption)
- host specific ->port_init_devs method is not called (=> no luck with
ht6560b, qd65xx and opti621 host drivers)
* ->rw_disk method is not preserved (=> no HPT3xxN chipsets support).
* ->serialized flag is not preserved (=> possible data corruption when
using icside, aec62xx (ATP850UF chipset), cmd640, cs5530, hpt366
(HPT3xxN chipsets), rz1000, sc1200, dtc2278 and ht6560b host drivers).
* ->ack_intr method is not preserved (=> needed by ide-cris, buddha,
gayle and macide host drivers).
* ->sata_scr[] and sata_misc[] is cleared by ide_unregister() and it
isn't initialized again (SiI3112 support needs them).
* To issue an ioctl() there need to be at least one IDE device present
in the system.
* ->cable_detect method is not preserved + it is not called when probing
IDE devices so cable detection is broken (however since DMA support is
also broken it doesn't really matter ;-).
* Some objects which may have already been freed in ide_unregister()
are restored by ide_hwif_restore() (i.e. ->hwgroup).
* ide_register_hw() may unregister unrelated IDE ports if free ide_hwifs[]
slot cannot be found.
* When IDE host drivers are modular unregistered port may be re-used by
different host driver that owned it first causing subtle bugs.
Since we now have a proper warm-plug support remove these ioctls,
then remove no longer needed:
- ide_register_hw() and ide_hwif_restore() functions
- 'init_default' and 'restore' arguments of ide_unregister()
- zeroeing of hwif->{dma,extra}_* fields in ide_unregister()
As an added bonus IDE core code size shrinks by ~3kB (x86-32).
v2:
* fix ide_unregister() arguments in cleanup_module() (Andrew Morton).
v3:
* fix ide_unregister() arguments in palm_bk3710.c.
Acked-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
2008-04-18 06:46:24 +08:00
|
|
|
ide_unregister(hwif->index);
|
2007-02-17 09:40:22 +08:00
|
|
|
|
|
|
|
hwif->chipset = ide_unknown;
|
|
|
|
iounmap((void*)ports->dma);
|
|
|
|
iounmap((void*)ports->ctl);
|
|
|
|
release_mem_region(dma_base, dma_size);
|
|
|
|
release_mem_region(ctl_base, ctl_size);
|
|
|
|
memset(ports, 0, sizeof(*ports));
|
|
|
|
}
|
|
|
|
|
2007-10-17 04:29:56 +08:00
|
|
|
static const struct pci_device_id scc_pci_tbl[] = {
|
|
|
|
{ PCI_VDEVICE(TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SCC_ATA), 0 },
|
2007-02-17 09:40:22 +08:00
|
|
|
{ 0, },
|
|
|
|
};
|
|
|
|
MODULE_DEVICE_TABLE(pci, scc_pci_tbl);
|
|
|
|
|
|
|
|
static struct pci_driver driver = {
|
|
|
|
.name = "SCC IDE",
|
|
|
|
.id_table = scc_pci_tbl,
|
|
|
|
.probe = scc_init_one,
|
|
|
|
.remove = scc_remove,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int scc_ide_init(void)
|
|
|
|
{
|
|
|
|
return ide_pci_register_driver(&driver);
|
|
|
|
}
|
|
|
|
|
|
|
|
module_init(scc_ide_init);
|
|
|
|
/* -- No exit code?
|
|
|
|
static void scc_ide_exit(void)
|
|
|
|
{
|
|
|
|
ide_pci_unregister_driver(&driver);
|
|
|
|
}
|
|
|
|
module_exit(scc_ide_exit);
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
MODULE_DESCRIPTION("PCI driver module for Toshiba SCC IDE");
|
|
|
|
MODULE_LICENSE("GPL");
|