9066 lines
257 KiB
C
9066 lines
257 KiB
C
/* $OpenBSD: pciide.c,v 1.363 2022/03/11 18:00:51 mpi Exp $ */
|
|
/* $NetBSD: pciide.c,v 1.127 2001/08/03 01:31:08 tsutsui Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 1999, 2000, 2001 Manuel Bouyer.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 1996, 1998 Christopher G. Demetriou. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by Christopher G. Demetriou
|
|
* for the NetBSD Project.
|
|
* 4. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/*
|
|
* PCI IDE controller driver.
|
|
*
|
|
* Author: Christopher G. Demetriou, March 2, 1998 (derived from NetBSD
|
|
* sys/dev/pci/ppb.c, revision 1.16).
|
|
*
|
|
* See "PCI IDE Controller Specification, Revision 1.0 3/4/94" and
|
|
* "Programming Interface for Bus Master IDE Controller, Revision 1.0
|
|
* 5/16/94" from the PCI SIG.
|
|
*
|
|
*/
|
|
|
|
#define DEBUG_DMA 0x01
|
|
#define DEBUG_XFERS 0x02
|
|
#define DEBUG_FUNCS 0x08
|
|
#define DEBUG_PROBE 0x10
|
|
|
|
#ifdef WDCDEBUG
|
|
#ifndef WDCDEBUG_PCIIDE_MASK
|
|
#define WDCDEBUG_PCIIDE_MASK 0x00
|
|
#endif
|
|
int wdcdebug_pciide_mask = WDCDEBUG_PCIIDE_MASK;
|
|
#define WDCDEBUG_PRINT(args, level) do { \
|
|
if ((wdcdebug_pciide_mask & (level)) != 0) \
|
|
printf args; \
|
|
} while (0)
|
|
#else
|
|
#define WDCDEBUG_PRINT(args, level)
|
|
#endif
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/device.h>
|
|
#include <sys/malloc.h>
|
|
#include <sys/endian.h>
|
|
|
|
#include <machine/bus.h>
|
|
|
|
#include <dev/ata/atavar.h>
|
|
#include <dev/ata/satareg.h>
|
|
#include <dev/ic/wdcreg.h>
|
|
#include <dev/ic/wdcvar.h>
|
|
|
|
#include <dev/pci/pcireg.h>
|
|
#include <dev/pci/pcivar.h>
|
|
#include <dev/pci/pcidevs.h>
|
|
|
|
#include <dev/pci/pciidereg.h>
|
|
#include <dev/pci/pciidevar.h>
|
|
#include <dev/pci/pciide_piix_reg.h>
|
|
#include <dev/pci/pciide_amd_reg.h>
|
|
#include <dev/pci/pciide_apollo_reg.h>
|
|
#include <dev/pci/pciide_cmd_reg.h>
|
|
#include <dev/pci/pciide_sii3112_reg.h>
|
|
#include <dev/pci/pciide_cy693_reg.h>
|
|
#include <dev/pci/pciide_sis_reg.h>
|
|
#include <dev/pci/pciide_acer_reg.h>
|
|
#include <dev/pci/pciide_pdc202xx_reg.h>
|
|
#include <dev/pci/pciide_opti_reg.h>
|
|
#include <dev/pci/pciide_hpt_reg.h>
|
|
#include <dev/pci/pciide_acard_reg.h>
|
|
#include <dev/pci/pciide_natsemi_reg.h>
|
|
#include <dev/pci/pciide_nforce_reg.h>
|
|
#include <dev/pci/pciide_ite_reg.h>
|
|
#include <dev/pci/pciide_ixp_reg.h>
|
|
#include <dev/pci/pciide_svwsata_reg.h>
|
|
#include <dev/pci/pciide_jmicron_reg.h>
|
|
#include <dev/pci/pciide_rdc_reg.h>
|
|
#include <dev/pci/cy82c693var.h>
|
|
|
|
int pciide_skip_ata;
|
|
int pciide_skip_atapi;
|
|
|
|
/* functions for reading/writing 8-bit PCI registers */
|
|
|
|
u_int8_t pciide_pci_read(pci_chipset_tag_t, pcitag_t,
|
|
int);
|
|
void pciide_pci_write(pci_chipset_tag_t, pcitag_t,
|
|
int, u_int8_t);
|
|
|
|
u_int8_t
|
|
pciide_pci_read(pci_chipset_tag_t pc, pcitag_t pa, int reg)
|
|
{
|
|
return (pci_conf_read(pc, pa, (reg & ~0x03)) >>
|
|
((reg & 0x03) * 8) & 0xff);
|
|
}
|
|
|
|
void
|
|
pciide_pci_write(pci_chipset_tag_t pc, pcitag_t pa, int reg, u_int8_t val)
|
|
{
|
|
pcireg_t pcival;
|
|
|
|
pcival = pci_conf_read(pc, pa, (reg & ~0x03));
|
|
pcival &= ~(0xff << ((reg & 0x03) * 8));
|
|
pcival |= (val << ((reg & 0x03) * 8));
|
|
pci_conf_write(pc, pa, (reg & ~0x03), pcival);
|
|
}
|
|
|
|
void default_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
|
|
void sata_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
void sata_setup_channel(struct channel_softc *);
|
|
|
|
void piix_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
void piixsata_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
void piix_setup_channel(struct channel_softc *);
|
|
void piix3_4_setup_channel(struct channel_softc *);
|
|
void piix_timing_debug(struct pciide_softc *);
|
|
|
|
u_int32_t piix_setup_idetim_timings(u_int8_t, u_int8_t, u_int8_t);
|
|
u_int32_t piix_setup_idetim_drvs(struct ata_drive_datas *);
|
|
u_int32_t piix_setup_sidetim_timings(u_int8_t, u_int8_t, u_int8_t);
|
|
|
|
void amd756_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
void amd756_setup_channel(struct channel_softc *);
|
|
|
|
void apollo_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
void apollo_setup_channel(struct channel_softc *);
|
|
|
|
void cmd_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
void cmd0643_9_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
void cmd0643_9_setup_channel(struct channel_softc *);
|
|
void cmd680_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
void cmd680_setup_channel(struct channel_softc *);
|
|
void cmd680_channel_map(struct pci_attach_args *, struct pciide_softc *, int);
|
|
void cmd_channel_map(struct pci_attach_args *,
|
|
struct pciide_softc *, int);
|
|
int cmd_pci_intr(void *);
|
|
void cmd646_9_irqack(struct channel_softc *);
|
|
|
|
void sii_fixup_cacheline(struct pciide_softc *, struct pci_attach_args *);
|
|
void sii3112_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
void sii3112_setup_channel(struct channel_softc *);
|
|
void sii3112_drv_probe(struct channel_softc *);
|
|
void sii3114_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
void sii3114_mapreg_dma(struct pciide_softc *, struct pci_attach_args *);
|
|
int sii3114_chansetup(struct pciide_softc *, int);
|
|
void sii3114_mapchan(struct pciide_channel *);
|
|
u_int8_t sii3114_dmacmd_read(struct pciide_softc *, int);
|
|
void sii3114_dmacmd_write(struct pciide_softc *, int, u_int8_t);
|
|
u_int8_t sii3114_dmactl_read(struct pciide_softc *, int);
|
|
void sii3114_dmactl_write(struct pciide_softc *, int, u_int8_t);
|
|
void sii3114_dmatbl_write(struct pciide_softc *, int, u_int32_t);
|
|
|
|
void cy693_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
void cy693_setup_channel(struct channel_softc *);
|
|
|
|
void sis_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
void sis_setup_channel(struct channel_softc *);
|
|
void sis96x_setup_channel(struct channel_softc *);
|
|
int sis_hostbr_match(struct pci_attach_args *);
|
|
int sis_south_match(struct pci_attach_args *);
|
|
|
|
void natsemi_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
void natsemi_setup_channel(struct channel_softc *);
|
|
int natsemi_pci_intr(void *);
|
|
void natsemi_irqack(struct channel_softc *);
|
|
void ns_scx200_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
void ns_scx200_setup_channel(struct channel_softc *);
|
|
|
|
void acer_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
void acer_setup_channel(struct channel_softc *);
|
|
int acer_pci_intr(void *);
|
|
int acer_dma_init(void *, int, int, void *, size_t, int);
|
|
|
|
void pdc202xx_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
void pdc202xx_setup_channel(struct channel_softc *);
|
|
void pdc20268_setup_channel(struct channel_softc *);
|
|
int pdc202xx_pci_intr(void *);
|
|
int pdc20265_pci_intr(void *);
|
|
void pdc20262_dma_start(void *, int, int);
|
|
int pdc20262_dma_finish(void *, int, int, int);
|
|
|
|
u_int8_t pdc268_config_read(struct channel_softc *, int);
|
|
|
|
void pdcsata_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
void pdc203xx_setup_channel(struct channel_softc *);
|
|
int pdc203xx_pci_intr(void *);
|
|
void pdc203xx_irqack(struct channel_softc *);
|
|
void pdc203xx_dma_start(void *,int ,int);
|
|
int pdc203xx_dma_finish(void *, int, int, int);
|
|
int pdc205xx_pci_intr(void *);
|
|
void pdc205xx_do_reset(struct channel_softc *);
|
|
void pdc205xx_drv_probe(struct channel_softc *);
|
|
|
|
void opti_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
void opti_setup_channel(struct channel_softc *);
|
|
|
|
void hpt_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
void hpt_setup_channel(struct channel_softc *);
|
|
int hpt_pci_intr(void *);
|
|
|
|
void acard_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
void acard_setup_channel(struct channel_softc *);
|
|
|
|
void serverworks_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
void serverworks_setup_channel(struct channel_softc *);
|
|
int serverworks_pci_intr(void *);
|
|
|
|
void svwsata_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
void svwsata_mapreg_dma(struct pciide_softc *, struct pci_attach_args *);
|
|
void svwsata_mapchan(struct pciide_channel *);
|
|
u_int8_t svwsata_dmacmd_read(struct pciide_softc *, int);
|
|
void svwsata_dmacmd_write(struct pciide_softc *, int, u_int8_t);
|
|
u_int8_t svwsata_dmactl_read(struct pciide_softc *, int);
|
|
void svwsata_dmactl_write(struct pciide_softc *, int, u_int8_t);
|
|
void svwsata_dmatbl_write(struct pciide_softc *, int, u_int32_t);
|
|
void svwsata_drv_probe(struct channel_softc *);
|
|
|
|
void nforce_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
void nforce_setup_channel(struct channel_softc *);
|
|
int nforce_pci_intr(void *);
|
|
|
|
void artisea_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
|
|
void ite_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
void ite_setup_channel(struct channel_softc *);
|
|
|
|
void ixp_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
void ixp_setup_channel(struct channel_softc *);
|
|
|
|
void jmicron_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
void jmicron_setup_channel(struct channel_softc *);
|
|
|
|
void phison_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
void phison_setup_channel(struct channel_softc *);
|
|
|
|
void sch_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
void sch_setup_channel(struct channel_softc *);
|
|
|
|
void rdc_chip_map(struct pciide_softc *, struct pci_attach_args *);
|
|
void rdc_setup_channel(struct channel_softc *);
|
|
|
|
struct pciide_product_desc {
|
|
u_int32_t ide_product;
|
|
u_short ide_flags;
|
|
/* map and setup chip, probe drives */
|
|
void (*chip_map)(struct pciide_softc *, struct pci_attach_args *);
|
|
};
|
|
|
|
/* Flags for ide_flags */
|
|
#define IDE_PCI_CLASS_OVERRIDE 0x0001 /* accept even if class != pciide */
|
|
#define IDE_16BIT_IOSPACE 0x0002 /* I/O space BARS ignore upper word */
|
|
|
|
/* Default product description for devices not known from this controller */
|
|
const struct pciide_product_desc default_product_desc = {
|
|
0, /* Generic PCI IDE controller */
|
|
0,
|
|
default_chip_map
|
|
};
|
|
|
|
const struct pciide_product_desc pciide_intel_products[] = {
|
|
{ PCI_PRODUCT_INTEL_31244, /* Intel 31244 SATA */
|
|
0,
|
|
artisea_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82092AA, /* Intel 82092AA IDE */
|
|
0,
|
|
default_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82371FB_IDE, /* Intel 82371FB IDE (PIIX) */
|
|
0,
|
|
piix_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82371FB_ISA, /* Intel 82371FB IDE (PIIX) */
|
|
0,
|
|
piix_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82372FB_IDE, /* Intel 82372FB IDE (PIIX4) */
|
|
0,
|
|
piix_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82371SB_IDE, /* Intel 82371SB IDE (PIIX3) */
|
|
0,
|
|
piix_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82371AB_IDE, /* Intel 82371AB IDE (PIIX4) */
|
|
0,
|
|
piix_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82371MX, /* Intel 82371MX IDE */
|
|
0,
|
|
piix_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82440MX_IDE, /* Intel 82440MX IDE */
|
|
0,
|
|
piix_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82451NX, /* Intel 82451NX (PIIX4) IDE */
|
|
0,
|
|
piix_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801AA_IDE, /* Intel 82801AA IDE (ICH) */
|
|
0,
|
|
piix_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801AB_IDE, /* Intel 82801AB IDE (ICH0) */
|
|
0,
|
|
piix_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801BAM_IDE, /* Intel 82801BAM IDE (ICH2) */
|
|
0,
|
|
piix_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801BA_IDE, /* Intel 82801BA IDE (ICH2) */
|
|
0,
|
|
piix_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801CAM_IDE, /* Intel 82801CAM IDE (ICH3) */
|
|
0,
|
|
piix_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801CA_IDE, /* Intel 82801CA IDE (ICH3) */
|
|
0,
|
|
piix_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801DB_IDE, /* Intel 82801DB IDE (ICH4) */
|
|
0,
|
|
piix_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801DBL_IDE, /* Intel 82801DBL IDE (ICH4-L) */
|
|
0,
|
|
piix_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801DBM_IDE, /* Intel 82801DBM IDE (ICH4-M) */
|
|
0,
|
|
piix_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801EB_IDE, /* Intel 82801EB/ER (ICH5/5R) IDE */
|
|
0,
|
|
piix_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801EB_SATA, /* Intel 82801EB (ICH5) SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801ER_SATA, /* Intel 82801ER (ICH5R) SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_6300ESB_IDE, /* Intel 6300ESB IDE */
|
|
0,
|
|
piix_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_6300ESB_SATA, /* Intel 6300ESB SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_6300ESB_SATA2, /* Intel 6300ESB SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_6321ESB_IDE, /* Intel 6321ESB IDE */
|
|
0,
|
|
piix_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801FB_IDE, /* Intel 82801FB (ICH6) IDE */
|
|
0,
|
|
piix_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801FBM_SATA, /* Intel 82801FBM (ICH6M) SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801FB_SATA, /* Intel 82801FB (ICH6) SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801FR_SATA, /* Intel 82801FR (ICH6R) SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801GB_IDE, /* Intel 82801GB (ICH7) IDE */
|
|
0,
|
|
piix_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801GB_SATA, /* Intel 82801GB (ICH7) SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801GR_AHCI, /* Intel 82801GR (ICH7R) AHCI */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801GR_RAID, /* Intel 82801GR (ICH7R) RAID */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801GBM_SATA, /* Intel 82801GBM (ICH7M) SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801GBM_AHCI, /* Intel 82801GBM (ICH7M) AHCI */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801GHM_RAID, /* Intel 82801GHM (ICH7M DH) RAID */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801H_SATA_1, /* Intel 82801H (ICH8) SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801H_AHCI_6P, /* Intel 82801H (ICH8) AHCI */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801H_RAID, /* Intel 82801H (ICH8) RAID */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801H_AHCI_4P, /* Intel 82801H (ICH8) AHCI */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801H_SATA_2, /* Intel 82801H (ICH8) SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801HBM_SATA, /* Intel 82801HBM (ICH8M) SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801HBM_AHCI, /* Intel 82801HBM (ICH8M) AHCI */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801HBM_RAID, /* Intel 82801HBM (ICH8M) RAID */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801HBM_IDE, /* Intel 82801HBM (ICH8M) IDE */
|
|
0,
|
|
piix_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801I_SATA_1, /* Intel 82801I (ICH9) SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801I_SATA_2, /* Intel 82801I (ICH9) SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801I_SATA_3, /* Intel 82801I (ICH9) SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801I_SATA_4, /* Intel 82801I (ICH9) SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801I_SATA_5, /* Intel 82801I (ICH9M) SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801I_SATA_6, /* Intel 82801I (ICH9M) SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801JD_SATA_1, /* Intel 82801JD (ICH10) SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801JD_SATA_2, /* Intel 82801JD (ICH10) SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801JI_SATA_1, /* Intel 82801JI (ICH10) SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_82801JI_SATA_2, /* Intel 82801JI (ICH10) SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_6321ESB_SATA, /* Intel 6321ESB SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_3400_SATA_1, /* Intel 3400 SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_3400_SATA_2, /* Intel 3400 SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_3400_SATA_3, /* Intel 3400 SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_3400_SATA_4, /* Intel 3400 SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_3400_SATA_5, /* Intel 3400 SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_3400_SATA_6, /* Intel 3400 SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_C600_SATA, /* Intel C600 SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_C610_SATA_1, /* Intel C610 SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_C610_SATA_2, /* Intel C610 SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_C610_SATA_3, /* Intel C610 SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_6SERIES_SATA_1, /* Intel 6 Series SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_6SERIES_SATA_2, /* Intel 6 Series SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_6SERIES_SATA_3, /* Intel 6 Series SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_6SERIES_SATA_4, /* Intel 6 Series SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_7SERIES_SATA_1, /* Intel 7 Series SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_7SERIES_SATA_2, /* Intel 7 Series SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_7SERIES_SATA_3, /* Intel 7 Series SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_7SERIES_SATA_4, /* Intel 7 Series SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_8SERIES_SATA_1, /* Intel 8 Series SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_8SERIES_SATA_2, /* Intel 8 Series SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_8SERIES_SATA_3, /* Intel 8 Series SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_8SERIES_SATA_4, /* Intel 8 Series SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_8SERIES_LP_SATA_1, /* Intel 8 Series SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_8SERIES_LP_SATA_2, /* Intel 8 Series SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_8SERIES_LP_SATA_3, /* Intel 8 Series SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_8SERIES_LP_SATA_4, /* Intel 8 Series SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_9SERIES_SATA_1, /* Intel 9 Series SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_9SERIES_SATA_2, /* Intel 9 Series SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_ATOMC2000_SATA_1, /* Intel Atom C2000 SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_ATOMC2000_SATA_2, /* Intel Atom C2000 SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_ATOMC2000_SATA_3, /* Intel Atom C2000 SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_ATOMC2000_SATA_4, /* Intel Atom C2000 SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_BAYTRAIL_SATA_1, /* Intel Baytrail SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_BAYTRAIL_SATA_2, /* Intel Baytrail SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_EP80579_SATA, /* Intel EP80579 SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_DH8900_SATA_1, /* Intel DH8900 SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_DH8900_SATA_2, /* Intel DH8900 SATA */
|
|
0,
|
|
piixsata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_INTEL_SCH_IDE, /* Intel SCH IDE */
|
|
0,
|
|
sch_chip_map
|
|
}
|
|
};
|
|
|
|
const struct pciide_product_desc pciide_amd_products[] = {
|
|
{ PCI_PRODUCT_AMD_PBC756_IDE, /* AMD 756 */
|
|
0,
|
|
amd756_chip_map
|
|
},
|
|
{ PCI_PRODUCT_AMD_766_IDE, /* AMD 766 */
|
|
0,
|
|
amd756_chip_map
|
|
},
|
|
{ PCI_PRODUCT_AMD_PBC768_IDE,
|
|
0,
|
|
amd756_chip_map
|
|
},
|
|
{ PCI_PRODUCT_AMD_8111_IDE,
|
|
0,
|
|
amd756_chip_map
|
|
},
|
|
{ PCI_PRODUCT_AMD_CS5536_IDE,
|
|
0,
|
|
amd756_chip_map
|
|
},
|
|
{ PCI_PRODUCT_AMD_HUDSON2_IDE,
|
|
0,
|
|
ixp_chip_map
|
|
}
|
|
};
|
|
|
|
const struct pciide_product_desc pciide_cmd_products[] = {
|
|
{ PCI_PRODUCT_CMDTECH_640, /* CMD Technology PCI0640 */
|
|
0,
|
|
cmd_chip_map
|
|
},
|
|
{ PCI_PRODUCT_CMDTECH_643, /* CMD Technology PCI0643 */
|
|
0,
|
|
cmd0643_9_chip_map
|
|
},
|
|
{ PCI_PRODUCT_CMDTECH_646, /* CMD Technology PCI0646 */
|
|
0,
|
|
cmd0643_9_chip_map
|
|
},
|
|
{ PCI_PRODUCT_CMDTECH_648, /* CMD Technology PCI0648 */
|
|
0,
|
|
cmd0643_9_chip_map
|
|
},
|
|
{ PCI_PRODUCT_CMDTECH_649, /* CMD Technology PCI0649 */
|
|
0,
|
|
cmd0643_9_chip_map
|
|
},
|
|
{ PCI_PRODUCT_CMDTECH_680, /* CMD Technology PCI0680 */
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
cmd680_chip_map
|
|
},
|
|
{ PCI_PRODUCT_CMDTECH_3112, /* SiI3112 SATA */
|
|
0,
|
|
sii3112_chip_map
|
|
},
|
|
{ PCI_PRODUCT_CMDTECH_3512, /* SiI3512 SATA */
|
|
0,
|
|
sii3112_chip_map
|
|
},
|
|
{ PCI_PRODUCT_CMDTECH_AAR_1210SA, /* Adaptec AAR-1210SA */
|
|
0,
|
|
sii3112_chip_map
|
|
},
|
|
{ PCI_PRODUCT_CMDTECH_3114, /* SiI3114 SATA */
|
|
0,
|
|
sii3114_chip_map
|
|
}
|
|
};
|
|
|
|
const struct pciide_product_desc pciide_via_products[] = {
|
|
{ PCI_PRODUCT_VIATECH_VT82C416, /* VIA VT82C416 IDE */
|
|
0,
|
|
apollo_chip_map
|
|
},
|
|
{ PCI_PRODUCT_VIATECH_VT82C571, /* VIA VT82C571 IDE */
|
|
0,
|
|
apollo_chip_map
|
|
},
|
|
{ PCI_PRODUCT_VIATECH_VT6410, /* VIA VT6410 IDE */
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
apollo_chip_map
|
|
},
|
|
{ PCI_PRODUCT_VIATECH_VT6415, /* VIA VT6415 IDE */
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
apollo_chip_map
|
|
},
|
|
{ PCI_PRODUCT_VIATECH_CX700_IDE, /* VIA CX700 IDE */
|
|
0,
|
|
apollo_chip_map
|
|
},
|
|
{ PCI_PRODUCT_VIATECH_VX700_IDE, /* VIA VX700 IDE */
|
|
0,
|
|
apollo_chip_map
|
|
},
|
|
{ PCI_PRODUCT_VIATECH_VX855_IDE, /* VIA VX855 IDE */
|
|
0,
|
|
apollo_chip_map
|
|
},
|
|
{ PCI_PRODUCT_VIATECH_VX900_IDE, /* VIA VX900 IDE */
|
|
0,
|
|
apollo_chip_map
|
|
},
|
|
{ PCI_PRODUCT_VIATECH_VT6420_SATA, /* VIA VT6420 SATA */
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_VIATECH_VT6421_SATA, /* VIA VT6421 SATA */
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_VIATECH_VT8237A_SATA, /* VIA VT8237A SATA */
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_VIATECH_VT8237A_SATA_2, /* VIA VT8237A SATA */
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_VIATECH_VT8237S_SATA, /* VIA VT8237S SATA */
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_VIATECH_VT8251_SATA, /* VIA VT8251 SATA */
|
|
0,
|
|
sata_chip_map
|
|
}
|
|
};
|
|
|
|
const struct pciide_product_desc pciide_cypress_products[] = {
|
|
{ PCI_PRODUCT_CONTAQ_82C693, /* Contaq CY82C693 IDE */
|
|
IDE_16BIT_IOSPACE,
|
|
cy693_chip_map
|
|
}
|
|
};
|
|
|
|
const struct pciide_product_desc pciide_sis_products[] = {
|
|
{ PCI_PRODUCT_SIS_5513, /* SIS 5513 EIDE */
|
|
0,
|
|
sis_chip_map
|
|
},
|
|
{ PCI_PRODUCT_SIS_180, /* SIS 180 SATA */
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_SIS_181, /* SIS 181 SATA */
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_SIS_182, /* SIS 182 SATA */
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_SIS_1183, /* SIS 1183 SATA */
|
|
0,
|
|
sata_chip_map
|
|
}
|
|
};
|
|
|
|
/*
|
|
* The National/AMD CS5535 requires MSRs to set DMA/PIO modes so it
|
|
* has been banished to the MD i386 pciide_machdep
|
|
*/
|
|
const struct pciide_product_desc pciide_natsemi_products[] = {
|
|
#ifdef __i386__
|
|
{ PCI_PRODUCT_NS_CS5535_IDE, /* National/AMD CS5535 IDE */
|
|
0,
|
|
gcsc_chip_map
|
|
},
|
|
#endif
|
|
{ PCI_PRODUCT_NS_PC87415, /* National Semi PC87415 IDE */
|
|
0,
|
|
natsemi_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NS_SCX200_IDE, /* National Semi SCx200 IDE */
|
|
0,
|
|
ns_scx200_chip_map
|
|
}
|
|
};
|
|
|
|
const struct pciide_product_desc pciide_acer_products[] = {
|
|
{ PCI_PRODUCT_ALI_M5229, /* Acer Labs M5229 UDMA IDE */
|
|
0,
|
|
acer_chip_map
|
|
}
|
|
};
|
|
|
|
const struct pciide_product_desc pciide_triones_products[] = {
|
|
{ PCI_PRODUCT_TRIONES_HPT366, /* Highpoint HPT36x/37x IDE */
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
hpt_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_TRIONES_HPT372A, /* Highpoint HPT372A IDE */
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
hpt_chip_map
|
|
},
|
|
{ PCI_PRODUCT_TRIONES_HPT302, /* Highpoint HPT302 IDE */
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
hpt_chip_map
|
|
},
|
|
{ PCI_PRODUCT_TRIONES_HPT371, /* Highpoint HPT371 IDE */
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
hpt_chip_map
|
|
},
|
|
{ PCI_PRODUCT_TRIONES_HPT374, /* Highpoint HPT374 IDE */
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
hpt_chip_map
|
|
}
|
|
};
|
|
|
|
const struct pciide_product_desc pciide_promise_products[] = {
|
|
{ PCI_PRODUCT_PROMISE_PDC20246,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
pdc202xx_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_PROMISE_PDC20262,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
pdc202xx_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_PROMISE_PDC20265,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
pdc202xx_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_PROMISE_PDC20267,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
pdc202xx_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_PROMISE_PDC20268,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
pdc202xx_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_PROMISE_PDC20268R,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
pdc202xx_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_PROMISE_PDC20269,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
pdc202xx_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_PROMISE_PDC20271,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
pdc202xx_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_PROMISE_PDC20275,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
pdc202xx_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_PROMISE_PDC20276,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
pdc202xx_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_PROMISE_PDC20277,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
pdc202xx_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_PROMISE_PDC20318,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
pdcsata_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_PROMISE_PDC20319,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
pdcsata_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_PROMISE_PDC20371,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
pdcsata_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_PROMISE_PDC20375,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
pdcsata_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_PROMISE_PDC20376,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
pdcsata_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_PROMISE_PDC20377,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
pdcsata_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_PROMISE_PDC20378,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
pdcsata_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_PROMISE_PDC20379,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
pdcsata_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_PROMISE_PDC40518,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
pdcsata_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_PROMISE_PDC40519,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
pdcsata_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_PROMISE_PDC40718,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
pdcsata_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_PROMISE_PDC40719,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
pdcsata_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_PROMISE_PDC40779,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
pdcsata_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_PROMISE_PDC20571,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
pdcsata_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_PROMISE_PDC20575,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
pdcsata_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_PROMISE_PDC20579,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
pdcsata_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_PROMISE_PDC20771,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
pdcsata_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_PROMISE_PDC20775,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
pdcsata_chip_map,
|
|
}
|
|
};
|
|
|
|
const struct pciide_product_desc pciide_acard_products[] = {
|
|
{ PCI_PRODUCT_ACARD_ATP850U, /* Acard ATP850U Ultra33 Controller */
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
acard_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_ACARD_ATP860, /* Acard ATP860 Ultra66 Controller */
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
acard_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_ACARD_ATP860A, /* Acard ATP860-A Ultra66 Controller */
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
acard_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_ACARD_ATP865A, /* Acard ATP865-A Ultra133 Controller */
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
acard_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_ACARD_ATP865R, /* Acard ATP865-R Ultra133 Controller */
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
acard_chip_map,
|
|
}
|
|
};
|
|
|
|
const struct pciide_product_desc pciide_serverworks_products[] = {
|
|
{ PCI_PRODUCT_RCC_OSB4_IDE,
|
|
0,
|
|
serverworks_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_RCC_CSB5_IDE,
|
|
0,
|
|
serverworks_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_RCC_CSB6_IDE,
|
|
0,
|
|
serverworks_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_RCC_CSB6_RAID_IDE,
|
|
0,
|
|
serverworks_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_RCC_HT_1000_IDE,
|
|
0,
|
|
serverworks_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_RCC_K2_SATA,
|
|
0,
|
|
svwsata_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_RCC_FRODO4_SATA,
|
|
0,
|
|
svwsata_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_RCC_FRODO8_SATA,
|
|
0,
|
|
svwsata_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_RCC_HT_1000_SATA_1,
|
|
0,
|
|
svwsata_chip_map,
|
|
},
|
|
{ PCI_PRODUCT_RCC_HT_1000_SATA_2,
|
|
0,
|
|
svwsata_chip_map,
|
|
}
|
|
};
|
|
|
|
const struct pciide_product_desc pciide_nvidia_products[] = {
|
|
{ PCI_PRODUCT_NVIDIA_NFORCE_IDE,
|
|
0,
|
|
nforce_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_NFORCE2_IDE,
|
|
0,
|
|
nforce_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_NFORCE2_400_IDE,
|
|
0,
|
|
nforce_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_NFORCE3_IDE,
|
|
0,
|
|
nforce_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_NFORCE3_250_IDE,
|
|
0,
|
|
nforce_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_NFORCE4_ATA133,
|
|
0,
|
|
nforce_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP04_IDE,
|
|
0,
|
|
nforce_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP51_IDE,
|
|
0,
|
|
nforce_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP55_IDE,
|
|
0,
|
|
nforce_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP61_IDE,
|
|
0,
|
|
nforce_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP65_IDE,
|
|
0,
|
|
nforce_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP67_IDE,
|
|
0,
|
|
nforce_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP73_IDE,
|
|
0,
|
|
nforce_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP77_IDE,
|
|
0,
|
|
nforce_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_NFORCE2_400_SATA,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_NFORCE3_250_SATA,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_NFORCE3_250_SATA2,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_NFORCE4_SATA1,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_NFORCE4_SATA2,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP04_SATA,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP04_SATA2,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP51_SATA,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP51_SATA2,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP55_SATA,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP55_SATA2,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP61_SATA,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP61_SATA2,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP61_SATA3,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP65_SATA_1,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP65_SATA_2,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP65_SATA_3,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP65_SATA_4,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP67_SATA_1,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP67_SATA_2,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP67_SATA_3,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP67_SATA_4,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP77_SATA_1,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP79_SATA_1,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP79_SATA_2,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP79_SATA_3,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP79_SATA_4,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP89_SATA_1,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP89_SATA_2,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP89_SATA_3,
|
|
0,
|
|
sata_chip_map
|
|
},
|
|
{ PCI_PRODUCT_NVIDIA_MCP89_SATA_4,
|
|
0,
|
|
sata_chip_map
|
|
}
|
|
};
|
|
|
|
const struct pciide_product_desc pciide_ite_products[] = {
|
|
{ PCI_PRODUCT_ITEXPRESS_IT8211F,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
ite_chip_map
|
|
},
|
|
{ PCI_PRODUCT_ITEXPRESS_IT8212F,
|
|
IDE_PCI_CLASS_OVERRIDE,
|
|
ite_chip_map
|
|
}
|
|
};
|
|
|
|
const struct pciide_product_desc pciide_ati_products[] = {
|
|
{ PCI_PRODUCT_ATI_SB200_IDE,
|
|
0,
|
|
ixp_chip_map
|
|
},
|
|
{ PCI_PRODUCT_ATI_SB300_IDE,
|
|
0,
|
|
ixp_chip_map
|
|
},
|
|
{ PCI_PRODUCT_ATI_SB400_IDE,
|
|
0,
|
|
ixp_chip_map
|
|
},
|
|
{ PCI_PRODUCT_ATI_SB600_IDE,
|
|
0,
|
|
ixp_chip_map
|
|
},
|
|
{ PCI_PRODUCT_ATI_SB700_IDE,
|
|
0,
|
|
ixp_chip_map
|
|
},
|
|
{ PCI_PRODUCT_ATI_SB300_SATA,
|
|
0,
|
|
sii3112_chip_map
|
|
},
|
|
{ PCI_PRODUCT_ATI_SB400_SATA_1,
|
|
0,
|
|
sii3112_chip_map
|
|
},
|
|
{ PCI_PRODUCT_ATI_SB400_SATA_2,
|
|
0,
|
|
sii3112_chip_map
|
|
}
|
|
};
|
|
|
|
const struct pciide_product_desc pciide_jmicron_products[] = {
|
|
{ PCI_PRODUCT_JMICRON_JMB361,
|
|
0,
|
|
jmicron_chip_map
|
|
},
|
|
{ PCI_PRODUCT_JMICRON_JMB363,
|
|
0,
|
|
jmicron_chip_map
|
|
},
|
|
{ PCI_PRODUCT_JMICRON_JMB365,
|
|
0,
|
|
jmicron_chip_map
|
|
},
|
|
{ PCI_PRODUCT_JMICRON_JMB366,
|
|
0,
|
|
jmicron_chip_map
|
|
},
|
|
{ PCI_PRODUCT_JMICRON_JMB368,
|
|
0,
|
|
jmicron_chip_map
|
|
}
|
|
};
|
|
|
|
const struct pciide_product_desc pciide_phison_products[] = {
|
|
{ PCI_PRODUCT_PHISON_PS5000,
|
|
0,
|
|
phison_chip_map
|
|
},
|
|
};
|
|
|
|
const struct pciide_product_desc pciide_rdc_products[] = {
|
|
{ PCI_PRODUCT_RDC_R1012_IDE,
|
|
0,
|
|
rdc_chip_map
|
|
},
|
|
};
|
|
|
|
struct pciide_vendor_desc {
|
|
u_int32_t ide_vendor;
|
|
const struct pciide_product_desc *ide_products;
|
|
int ide_nproducts;
|
|
};
|
|
|
|
const struct pciide_vendor_desc pciide_vendors[] = {
|
|
{ PCI_VENDOR_INTEL, pciide_intel_products,
|
|
nitems(pciide_intel_products) },
|
|
{ PCI_VENDOR_AMD, pciide_amd_products,
|
|
nitems(pciide_amd_products) },
|
|
{ PCI_VENDOR_CMDTECH, pciide_cmd_products,
|
|
nitems(pciide_cmd_products) },
|
|
{ PCI_VENDOR_VIATECH, pciide_via_products,
|
|
nitems(pciide_via_products) },
|
|
{ PCI_VENDOR_CONTAQ, pciide_cypress_products,
|
|
nitems(pciide_cypress_products) },
|
|
{ PCI_VENDOR_SIS, pciide_sis_products,
|
|
nitems(pciide_sis_products) },
|
|
{ PCI_VENDOR_NS, pciide_natsemi_products,
|
|
nitems(pciide_natsemi_products) },
|
|
{ PCI_VENDOR_ALI, pciide_acer_products,
|
|
nitems(pciide_acer_products) },
|
|
{ PCI_VENDOR_TRIONES, pciide_triones_products,
|
|
nitems(pciide_triones_products) },
|
|
{ PCI_VENDOR_ACARD, pciide_acard_products,
|
|
nitems(pciide_acard_products) },
|
|
{ PCI_VENDOR_RCC, pciide_serverworks_products,
|
|
nitems(pciide_serverworks_products) },
|
|
{ PCI_VENDOR_PROMISE, pciide_promise_products,
|
|
nitems(pciide_promise_products) },
|
|
{ PCI_VENDOR_NVIDIA, pciide_nvidia_products,
|
|
nitems(pciide_nvidia_products) },
|
|
{ PCI_VENDOR_ITEXPRESS, pciide_ite_products,
|
|
nitems(pciide_ite_products) },
|
|
{ PCI_VENDOR_ATI, pciide_ati_products,
|
|
nitems(pciide_ati_products) },
|
|
{ PCI_VENDOR_JMICRON, pciide_jmicron_products,
|
|
nitems(pciide_jmicron_products) },
|
|
{ PCI_VENDOR_PHISON, pciide_phison_products,
|
|
nitems(pciide_phison_products) },
|
|
{ PCI_VENDOR_RDC, pciide_rdc_products,
|
|
nitems(pciide_rdc_products) }
|
|
};
|
|
|
|
/* options passed via the 'flags' config keyword */
|
|
#define PCIIDE_OPTIONS_DMA 0x01
|
|
|
|
int pciide_match(struct device *, void *, void *);
|
|
void pciide_attach(struct device *, struct device *, void *);
|
|
int pciide_detach(struct device *, int);
|
|
int pciide_activate(struct device *, int);
|
|
|
|
const struct cfattach pciide_pci_ca = {
|
|
sizeof(struct pciide_softc), pciide_match, pciide_attach,
|
|
pciide_detach, pciide_activate
|
|
};
|
|
|
|
const struct cfattach pciide_jmb_ca = {
|
|
sizeof(struct pciide_softc), pciide_match, pciide_attach,
|
|
pciide_detach, pciide_activate
|
|
};
|
|
|
|
struct cfdriver pciide_cd = {
|
|
NULL, "pciide", DV_DULL
|
|
};
|
|
|
|
const struct pciide_product_desc *pciide_lookup_product(u_int32_t);
|
|
|
|
const struct pciide_product_desc *
|
|
pciide_lookup_product(u_int32_t id)
|
|
{
|
|
const struct pciide_product_desc *pp;
|
|
const struct pciide_vendor_desc *vp;
|
|
int i;
|
|
|
|
for (i = 0, vp = pciide_vendors; i < nitems(pciide_vendors); vp++, i++)
|
|
if (PCI_VENDOR(id) == vp->ide_vendor)
|
|
break;
|
|
|
|
if (i == nitems(pciide_vendors))
|
|
return (NULL);
|
|
|
|
for (pp = vp->ide_products, i = 0; i < vp->ide_nproducts; pp++, i++)
|
|
if (PCI_PRODUCT(id) == pp->ide_product)
|
|
break;
|
|
|
|
if (i == vp->ide_nproducts)
|
|
return (NULL);
|
|
return (pp);
|
|
}
|
|
|
|
int
|
|
pciide_match(struct device *parent, void *match, void *aux)
|
|
{
|
|
struct pci_attach_args *pa = aux;
|
|
const struct pciide_product_desc *pp;
|
|
|
|
/*
|
|
* Some IDE controllers have severe bugs when used in PCI mode.
|
|
* We punt and attach them to the ISA bus instead.
|
|
*/
|
|
if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_PCTECH &&
|
|
PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_PCTECH_RZ1000)
|
|
return (0);
|
|
|
|
/*
|
|
* Some controllers (e.g. promise Ultra-33) don't claim to be PCI IDE
|
|
* controllers. Let see if we can deal with it anyway.
|
|
*/
|
|
pp = pciide_lookup_product(pa->pa_id);
|
|
if (pp && (pp->ide_flags & IDE_PCI_CLASS_OVERRIDE))
|
|
return (1);
|
|
|
|
/*
|
|
* Check the ID register to see that it's a PCI IDE controller.
|
|
* If it is, we assume that we can deal with it; it _should_
|
|
* work in a standardized way...
|
|
*/
|
|
if (PCI_CLASS(pa->pa_class) == PCI_CLASS_MASS_STORAGE) {
|
|
switch (PCI_SUBCLASS(pa->pa_class)) {
|
|
case PCI_SUBCLASS_MASS_STORAGE_IDE:
|
|
return (1);
|
|
|
|
/*
|
|
* We only match these if we know they have
|
|
* a match, as we may not support native interfaces
|
|
* on them.
|
|
*/
|
|
case PCI_SUBCLASS_MASS_STORAGE_SATA:
|
|
case PCI_SUBCLASS_MASS_STORAGE_RAID:
|
|
case PCI_SUBCLASS_MASS_STORAGE_MISC:
|
|
if (pp)
|
|
return (1);
|
|
else
|
|
return (0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
pciide_attach(struct device *parent, struct device *self, void *aux)
|
|
{
|
|
struct pciide_softc *sc = (struct pciide_softc *)self;
|
|
struct pci_attach_args *pa = aux;
|
|
|
|
sc->sc_pp = pciide_lookup_product(pa->pa_id);
|
|
if (sc->sc_pp == NULL)
|
|
sc->sc_pp = &default_product_desc;
|
|
sc->sc_rev = PCI_REVISION(pa->pa_class);
|
|
|
|
sc->sc_pc = pa->pa_pc;
|
|
sc->sc_tag = pa->pa_tag;
|
|
|
|
/* Set up DMA defaults; these might be adjusted by chip_map. */
|
|
sc->sc_dma_maxsegsz = IDEDMA_BYTE_COUNT_MAX;
|
|
sc->sc_dma_boundary = IDEDMA_BYTE_COUNT_ALIGN;
|
|
|
|
sc->sc_dmacmd_read = pciide_dmacmd_read;
|
|
sc->sc_dmacmd_write = pciide_dmacmd_write;
|
|
sc->sc_dmactl_read = pciide_dmactl_read;
|
|
sc->sc_dmactl_write = pciide_dmactl_write;
|
|
sc->sc_dmatbl_write = pciide_dmatbl_write;
|
|
|
|
WDCDEBUG_PRINT((" sc_pc=%p, sc_tag=0x%x, pa_class=0x%x\n", sc->sc_pc,
|
|
(u_int32_t)sc->sc_tag, pa->pa_class), DEBUG_PROBE);
|
|
|
|
if (pciide_skip_ata)
|
|
sc->sc_wdcdev.quirks |= WDC_QUIRK_NOATA;
|
|
if (pciide_skip_atapi)
|
|
sc->sc_wdcdev.quirks |= WDC_QUIRK_NOATAPI;
|
|
|
|
sc->sc_pp->chip_map(sc, pa);
|
|
|
|
WDCDEBUG_PRINT(("pciide: command/status register=0x%x\n",
|
|
pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG)),
|
|
DEBUG_PROBE);
|
|
}
|
|
|
|
int
|
|
pciide_detach(struct device *self, int flags)
|
|
{
|
|
struct pciide_softc *sc = (struct pciide_softc *)self;
|
|
if (sc->chip_unmap == NULL)
|
|
panic("unmap not yet implemented for this chipset");
|
|
else
|
|
sc->chip_unmap(sc, flags);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
pciide_activate(struct device *self, int act)
|
|
{
|
|
int rv = 0;
|
|
struct pciide_softc *sc = (struct pciide_softc *)self;
|
|
int i;
|
|
|
|
switch (act) {
|
|
case DVACT_SUSPEND:
|
|
rv = config_activate_children(self, act);
|
|
|
|
for (i = 0; i < nitems(sc->sc_save); i++)
|
|
sc->sc_save[i] = pci_conf_read(sc->sc_pc,
|
|
sc->sc_tag, PCI_MAPREG_END + 0x18 + (i * 4));
|
|
|
|
if (sc->sc_pp->chip_map == sch_chip_map) {
|
|
sc->sc_save2[0] = pci_conf_read(sc->sc_pc,
|
|
sc->sc_tag, SCH_D0TIM);
|
|
sc->sc_save2[1] = pci_conf_read(sc->sc_pc,
|
|
sc->sc_tag, SCH_D1TIM);
|
|
} else if (sc->sc_pp->chip_map == piixsata_chip_map) {
|
|
sc->sc_save2[0] = pciide_pci_read(sc->sc_pc,
|
|
sc->sc_tag, ICH5_SATA_MAP);
|
|
sc->sc_save2[1] = pciide_pci_read(sc->sc_pc,
|
|
sc->sc_tag, ICH5_SATA_PI);
|
|
sc->sc_save2[2] = pciide_pci_read(sc->sc_pc,
|
|
sc->sc_tag, ICH_SATA_PCS);
|
|
} else if (sc->sc_pp->chip_map == sii3112_chip_map) {
|
|
sc->sc_save2[0] = pci_conf_read(sc->sc_pc,
|
|
sc->sc_tag, SII3112_SCS_CMD);
|
|
sc->sc_save2[1] = pci_conf_read(sc->sc_pc,
|
|
sc->sc_tag, SII3112_PCI_CFGCTL);
|
|
} else if (sc->sc_pp->chip_map == ite_chip_map) {
|
|
sc->sc_save2[0] = pci_conf_read(sc->sc_pc,
|
|
sc->sc_tag, IT_TIM(0));
|
|
} else if (sc->sc_pp->chip_map == nforce_chip_map) {
|
|
sc->sc_save2[0] = pci_conf_read(sc->sc_pc,
|
|
sc->sc_tag, NFORCE_PIODMATIM);
|
|
sc->sc_save2[1] = pci_conf_read(sc->sc_pc,
|
|
sc->sc_tag, NFORCE_PIOTIM);
|
|
sc->sc_save2[2] = pci_conf_read(sc->sc_pc,
|
|
sc->sc_tag, NFORCE_UDMATIM);
|
|
}
|
|
break;
|
|
case DVACT_RESUME:
|
|
for (i = 0; i < nitems(sc->sc_save); i++)
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag,
|
|
PCI_MAPREG_END + 0x18 + (i * 4),
|
|
sc->sc_save[i]);
|
|
|
|
if (sc->sc_pp->chip_map == default_chip_map ||
|
|
sc->sc_pp->chip_map == sata_chip_map ||
|
|
sc->sc_pp->chip_map == piix_chip_map ||
|
|
sc->sc_pp->chip_map == amd756_chip_map ||
|
|
sc->sc_pp->chip_map == phison_chip_map ||
|
|
sc->sc_pp->chip_map == rdc_chip_map ||
|
|
sc->sc_pp->chip_map == ixp_chip_map ||
|
|
sc->sc_pp->chip_map == acard_chip_map ||
|
|
sc->sc_pp->chip_map == apollo_chip_map ||
|
|
sc->sc_pp->chip_map == sis_chip_map) {
|
|
/* nothing to restore -- uses only 0x40 - 0x56 */
|
|
} else if (sc->sc_pp->chip_map == sch_chip_map) {
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag,
|
|
SCH_D0TIM, sc->sc_save2[0]);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag,
|
|
SCH_D1TIM, sc->sc_save2[1]);
|
|
} else if (sc->sc_pp->chip_map == piixsata_chip_map) {
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag,
|
|
ICH5_SATA_MAP, sc->sc_save2[0]);
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag,
|
|
ICH5_SATA_PI, sc->sc_save2[1]);
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag,
|
|
ICH_SATA_PCS, sc->sc_save2[2]);
|
|
} else if (sc->sc_pp->chip_map == sii3112_chip_map) {
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag,
|
|
SII3112_SCS_CMD, sc->sc_save2[0]);
|
|
delay(50 * 1000);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag,
|
|
SII3112_PCI_CFGCTL, sc->sc_save2[1]);
|
|
delay(50 * 1000);
|
|
} else if (sc->sc_pp->chip_map == ite_chip_map) {
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag,
|
|
IT_TIM(0), sc->sc_save2[0]);
|
|
} else if (sc->sc_pp->chip_map == nforce_chip_map) {
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag,
|
|
NFORCE_PIODMATIM, sc->sc_save2[0]);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag,
|
|
NFORCE_PIOTIM, sc->sc_save2[1]);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag,
|
|
NFORCE_UDMATIM, sc->sc_save2[2]);
|
|
} else {
|
|
printf("%s: restore for unknown chip map %x\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname,
|
|
sc->sc_pp->ide_product);
|
|
}
|
|
|
|
rv = config_activate_children(self, act);
|
|
break;
|
|
default:
|
|
rv = config_activate_children(self, act);
|
|
break;
|
|
}
|
|
return (rv);
|
|
}
|
|
|
|
int
|
|
pciide_mapregs_compat(struct pci_attach_args *pa, struct pciide_channel *cp,
|
|
int compatchan, bus_size_t *cmdsizep, bus_size_t *ctlsizep)
|
|
{
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
struct channel_softc *wdc_cp = &cp->wdc_channel;
|
|
pcireg_t csr;
|
|
|
|
cp->compat = 1;
|
|
*cmdsizep = PCIIDE_COMPAT_CMD_SIZE;
|
|
*ctlsizep = PCIIDE_COMPAT_CTL_SIZE;
|
|
|
|
csr = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG,
|
|
csr | PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MASTER_ENABLE);
|
|
|
|
wdc_cp->cmd_iot = pa->pa_iot;
|
|
|
|
if (bus_space_map(wdc_cp->cmd_iot, PCIIDE_COMPAT_CMD_BASE(compatchan),
|
|
PCIIDE_COMPAT_CMD_SIZE, 0, &wdc_cp->cmd_ioh) != 0) {
|
|
printf("%s: couldn't map %s cmd regs\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
|
|
return (0);
|
|
}
|
|
|
|
wdc_cp->ctl_iot = pa->pa_iot;
|
|
|
|
if (bus_space_map(wdc_cp->ctl_iot, PCIIDE_COMPAT_CTL_BASE(compatchan),
|
|
PCIIDE_COMPAT_CTL_SIZE, 0, &wdc_cp->ctl_ioh) != 0) {
|
|
printf("%s: couldn't map %s ctl regs\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
|
|
bus_space_unmap(wdc_cp->cmd_iot, wdc_cp->cmd_ioh,
|
|
PCIIDE_COMPAT_CMD_SIZE);
|
|
return (0);
|
|
}
|
|
wdc_cp->cmd_iosz = *cmdsizep;
|
|
wdc_cp->ctl_iosz = *ctlsizep;
|
|
|
|
return (1);
|
|
}
|
|
|
|
int
|
|
pciide_unmapregs_compat(struct pciide_softc *sc, struct pciide_channel *cp)
|
|
{
|
|
struct channel_softc *wdc_cp = &cp->wdc_channel;
|
|
|
|
bus_space_unmap(wdc_cp->cmd_iot, wdc_cp->cmd_ioh, wdc_cp->cmd_iosz);
|
|
bus_space_unmap(wdc_cp->ctl_iot, wdc_cp->cmd_ioh, wdc_cp->ctl_iosz);
|
|
|
|
if (sc->sc_pci_ih != NULL) {
|
|
pciide_machdep_compat_intr_disestablish(sc->sc_pc, sc->sc_pci_ih);
|
|
sc->sc_pci_ih = NULL;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
pciide_mapregs_native(struct pci_attach_args *pa, struct pciide_channel *cp,
|
|
bus_size_t *cmdsizep, bus_size_t *ctlsizep, int (*pci_intr)(void *))
|
|
{
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
struct channel_softc *wdc_cp = &cp->wdc_channel;
|
|
const char *intrstr;
|
|
pci_intr_handle_t intrhandle;
|
|
pcireg_t maptype;
|
|
|
|
cp->compat = 0;
|
|
|
|
if (sc->sc_pci_ih == NULL) {
|
|
if (pci_intr_map(pa, &intrhandle) != 0) {
|
|
printf("%s: couldn't map native-PCI interrupt\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname);
|
|
return (0);
|
|
}
|
|
intrstr = pci_intr_string(pa->pa_pc, intrhandle);
|
|
sc->sc_pci_ih = pci_intr_establish(pa->pa_pc,
|
|
intrhandle, IPL_BIO, pci_intr, sc,
|
|
sc->sc_wdcdev.sc_dev.dv_xname);
|
|
if (sc->sc_pci_ih != NULL) {
|
|
printf("%s: using %s for native-PCI interrupt\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname,
|
|
intrstr ? intrstr : "unknown interrupt");
|
|
} else {
|
|
printf("%s: couldn't establish native-PCI interrupt",
|
|
sc->sc_wdcdev.sc_dev.dv_xname);
|
|
if (intrstr != NULL)
|
|
printf(" at %s", intrstr);
|
|
printf("\n");
|
|
return (0);
|
|
}
|
|
}
|
|
cp->ih = sc->sc_pci_ih;
|
|
sc->sc_pc = pa->pa_pc;
|
|
|
|
maptype = pci_mapreg_type(pa->pa_pc, pa->pa_tag,
|
|
PCIIDE_REG_CMD_BASE(wdc_cp->channel));
|
|
WDCDEBUG_PRINT(("%s: %s cmd regs mapping: %s\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name,
|
|
(maptype == PCI_MAPREG_TYPE_IO ? "I/O" : "memory")), DEBUG_PROBE);
|
|
if (pci_mapreg_map(pa, PCIIDE_REG_CMD_BASE(wdc_cp->channel),
|
|
maptype, 0,
|
|
&wdc_cp->cmd_iot, &wdc_cp->cmd_ioh, NULL, cmdsizep, 0) != 0) {
|
|
printf("%s: couldn't map %s cmd regs\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
|
|
return (0);
|
|
}
|
|
|
|
maptype = pci_mapreg_type(pa->pa_pc, pa->pa_tag,
|
|
PCIIDE_REG_CTL_BASE(wdc_cp->channel));
|
|
WDCDEBUG_PRINT(("%s: %s ctl regs mapping: %s\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name,
|
|
(maptype == PCI_MAPREG_TYPE_IO ? "I/O": "memory")), DEBUG_PROBE);
|
|
if (pci_mapreg_map(pa, PCIIDE_REG_CTL_BASE(wdc_cp->channel),
|
|
maptype, 0,
|
|
&wdc_cp->ctl_iot, &cp->ctl_baseioh, NULL, ctlsizep, 0) != 0) {
|
|
printf("%s: couldn't map %s ctl regs\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
|
|
bus_space_unmap(wdc_cp->cmd_iot, wdc_cp->cmd_ioh, *cmdsizep);
|
|
return (0);
|
|
}
|
|
/*
|
|
* In native mode, 4 bytes of I/O space are mapped for the control
|
|
* register, the control register is at offset 2. Pass the generic
|
|
* code a handle for only one byte at the right offset.
|
|
*/
|
|
if (bus_space_subregion(wdc_cp->ctl_iot, cp->ctl_baseioh, 2, 1,
|
|
&wdc_cp->ctl_ioh) != 0) {
|
|
printf("%s: unable to subregion %s ctl regs\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
|
|
bus_space_unmap(wdc_cp->cmd_iot, wdc_cp->cmd_ioh, *cmdsizep);
|
|
bus_space_unmap(wdc_cp->cmd_iot, cp->ctl_baseioh, *ctlsizep);
|
|
return (0);
|
|
}
|
|
wdc_cp->cmd_iosz = *cmdsizep;
|
|
wdc_cp->ctl_iosz = *ctlsizep;
|
|
|
|
return (1);
|
|
}
|
|
|
|
int
|
|
pciide_unmapregs_native(struct pciide_softc *sc, struct pciide_channel *cp)
|
|
{
|
|
struct channel_softc *wdc_cp = &cp->wdc_channel;
|
|
|
|
bus_space_unmap(wdc_cp->cmd_iot, wdc_cp->cmd_ioh, wdc_cp->cmd_iosz);
|
|
|
|
/* Unmap the whole control space, not just the sub-region */
|
|
bus_space_unmap(wdc_cp->ctl_iot, cp->ctl_baseioh, wdc_cp->ctl_iosz);
|
|
|
|
if (sc->sc_pci_ih != NULL) {
|
|
pci_intr_disestablish(sc->sc_pc, sc->sc_pci_ih);
|
|
sc->sc_pci_ih = NULL;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
pciide_mapreg_dma(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
pcireg_t maptype;
|
|
bus_addr_t addr;
|
|
|
|
/*
|
|
* Map DMA registers
|
|
*
|
|
* Note that sc_dma_ok is the right variable to test to see if
|
|
* DMA can be done. If the interface doesn't support DMA,
|
|
* sc_dma_ok will never be non-zero. If the DMA regs couldn't
|
|
* be mapped, it'll be zero. I.e., sc_dma_ok will only be
|
|
* non-zero if the interface supports DMA and the registers
|
|
* could be mapped.
|
|
*
|
|
* XXX Note that despite the fact that the Bus Master IDE specs
|
|
* XXX say that "The bus master IDE function uses 16 bytes of IO
|
|
* XXX space", some controllers (at least the United
|
|
* XXX Microelectronics UM8886BF) place it in memory space.
|
|
*/
|
|
|
|
maptype = pci_mapreg_type(pa->pa_pc, pa->pa_tag,
|
|
PCIIDE_REG_BUS_MASTER_DMA);
|
|
|
|
switch (maptype) {
|
|
case PCI_MAPREG_TYPE_IO:
|
|
sc->sc_dma_ok = (pci_mapreg_info(pa->pa_pc, pa->pa_tag,
|
|
PCIIDE_REG_BUS_MASTER_DMA, PCI_MAPREG_TYPE_IO,
|
|
&addr, NULL, NULL) == 0);
|
|
if (sc->sc_dma_ok == 0) {
|
|
printf(", unused (couldn't query registers)");
|
|
break;
|
|
}
|
|
if ((sc->sc_pp->ide_flags & IDE_16BIT_IOSPACE)
|
|
&& addr >= 0x10000) {
|
|
sc->sc_dma_ok = 0;
|
|
printf(", unused (registers at unsafe address %#lx)", addr);
|
|
break;
|
|
}
|
|
/* FALLTHROUGH */
|
|
|
|
case PCI_MAPREG_MEM_TYPE_32BIT:
|
|
sc->sc_dma_ok = (pci_mapreg_map(pa,
|
|
PCIIDE_REG_BUS_MASTER_DMA, maptype, 0,
|
|
&sc->sc_dma_iot, &sc->sc_dma_ioh, NULL, &sc->sc_dma_iosz,
|
|
0) == 0);
|
|
sc->sc_dmat = pa->pa_dmat;
|
|
if (sc->sc_dma_ok == 0) {
|
|
printf(", unused (couldn't map registers)");
|
|
} else {
|
|
sc->sc_wdcdev.dma_arg = sc;
|
|
sc->sc_wdcdev.dma_init = pciide_dma_init;
|
|
sc->sc_wdcdev.dma_start = pciide_dma_start;
|
|
sc->sc_wdcdev.dma_finish = pciide_dma_finish;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
sc->sc_dma_ok = 0;
|
|
printf(", (unsupported maptype 0x%x)", maptype);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
pciide_unmapreg_dma(struct pciide_softc *sc)
|
|
{
|
|
bus_space_unmap(sc->sc_dma_iot, sc->sc_dma_ioh, sc->sc_dma_iosz);
|
|
}
|
|
|
|
int
|
|
pciide_intr_flag(struct pciide_channel *cp)
|
|
{
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
int chan = cp->wdc_channel.channel;
|
|
|
|
if (cp->dma_in_progress) {
|
|
int retry = 10;
|
|
int status;
|
|
|
|
/* Check the status register */
|
|
for (retry = 10; retry > 0; retry--) {
|
|
status = PCIIDE_DMACTL_READ(sc, chan);
|
|
if (status & IDEDMA_CTL_INTR) {
|
|
break;
|
|
}
|
|
DELAY(5);
|
|
}
|
|
|
|
/* Not for us. */
|
|
if (retry == 0)
|
|
return (0);
|
|
|
|
return (1);
|
|
}
|
|
|
|
return (-1);
|
|
}
|
|
|
|
int
|
|
pciide_compat_intr(void *arg)
|
|
{
|
|
struct pciide_channel *cp = arg;
|
|
|
|
if (pciide_intr_flag(cp) == 0)
|
|
return (0);
|
|
|
|
#ifdef DIAGNOSTIC
|
|
/* should only be called for a compat channel */
|
|
if (cp->compat == 0)
|
|
panic("pciide compat intr called for non-compat chan %p", cp);
|
|
#endif
|
|
return (wdcintr(&cp->wdc_channel));
|
|
}
|
|
|
|
int
|
|
pciide_pci_intr(void *arg)
|
|
{
|
|
struct pciide_softc *sc = arg;
|
|
struct pciide_channel *cp;
|
|
struct channel_softc *wdc_cp;
|
|
int i, rv, crv;
|
|
|
|
rv = 0;
|
|
for (i = 0; i < sc->sc_wdcdev.nchannels; i++) {
|
|
cp = &sc->pciide_channels[i];
|
|
wdc_cp = &cp->wdc_channel;
|
|
|
|
/* If a compat channel skip. */
|
|
if (cp->compat)
|
|
continue;
|
|
|
|
if (cp->hw_ok == 0)
|
|
continue;
|
|
|
|
if (pciide_intr_flag(cp) == 0)
|
|
continue;
|
|
|
|
crv = wdcintr(wdc_cp);
|
|
if (crv == 0)
|
|
; /* leave rv alone */
|
|
else if (crv == 1)
|
|
rv = 1; /* claim the intr */
|
|
else if (rv == 0) /* crv should be -1 in this case */
|
|
rv = crv; /* if we've done no better, take it */
|
|
}
|
|
return (rv);
|
|
}
|
|
|
|
u_int8_t
|
|
pciide_dmacmd_read(struct pciide_softc *sc, int chan)
|
|
{
|
|
return (bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CMD(chan)));
|
|
}
|
|
|
|
void
|
|
pciide_dmacmd_write(struct pciide_softc *sc, int chan, u_int8_t val)
|
|
{
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CMD(chan), val);
|
|
}
|
|
|
|
u_int8_t
|
|
pciide_dmactl_read(struct pciide_softc *sc, int chan)
|
|
{
|
|
return (bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(chan)));
|
|
}
|
|
|
|
void
|
|
pciide_dmactl_write(struct pciide_softc *sc, int chan, u_int8_t val)
|
|
{
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(chan), val);
|
|
}
|
|
|
|
void
|
|
pciide_dmatbl_write(struct pciide_softc *sc, int chan, u_int32_t val)
|
|
{
|
|
bus_space_write_4(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_TBL(chan), val);
|
|
}
|
|
|
|
void
|
|
pciide_channel_dma_setup(struct pciide_channel *cp)
|
|
{
|
|
int drive;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
struct ata_drive_datas *drvp;
|
|
|
|
for (drive = 0; drive < 2; drive++) {
|
|
drvp = &cp->wdc_channel.ch_drive[drive];
|
|
/* If no drive, skip */
|
|
if ((drvp->drive_flags & DRIVE) == 0)
|
|
continue;
|
|
/* setup DMA if needed */
|
|
if (((drvp->drive_flags & DRIVE_DMA) == 0 &&
|
|
(drvp->drive_flags & DRIVE_UDMA) == 0) ||
|
|
sc->sc_dma_ok == 0) {
|
|
drvp->drive_flags &= ~(DRIVE_DMA | DRIVE_UDMA);
|
|
continue;
|
|
}
|
|
if (pciide_dma_table_setup(sc, cp->wdc_channel.channel, drive)
|
|
!= 0) {
|
|
/* Abort DMA setup */
|
|
drvp->drive_flags &= ~(DRIVE_DMA | DRIVE_UDMA);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
pciide_dma_table_setup(struct pciide_softc *sc, int channel, int drive)
|
|
{
|
|
bus_dma_segment_t seg;
|
|
int error, rseg;
|
|
const bus_size_t dma_table_size =
|
|
sizeof(struct idedma_table) * NIDEDMA_TABLES;
|
|
struct pciide_dma_maps *dma_maps =
|
|
&sc->pciide_channels[channel].dma_maps[drive];
|
|
|
|
/* If table was already allocated, just return */
|
|
if (dma_maps->dma_table)
|
|
return (0);
|
|
|
|
/* Allocate memory for the DMA tables and map it */
|
|
if ((error = bus_dmamem_alloc(sc->sc_dmat, dma_table_size,
|
|
IDEDMA_TBL_ALIGN, IDEDMA_TBL_ALIGN, &seg, 1, &rseg,
|
|
BUS_DMA_NOWAIT)) != 0) {
|
|
printf("%s:%d: unable to allocate table DMA for "
|
|
"drive %d, error=%d\n", sc->sc_wdcdev.sc_dev.dv_xname,
|
|
channel, drive, error);
|
|
return (error);
|
|
}
|
|
|
|
if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg,
|
|
dma_table_size,
|
|
(caddr_t *)&dma_maps->dma_table,
|
|
BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
|
|
printf("%s:%d: unable to map table DMA for"
|
|
"drive %d, error=%d\n", sc->sc_wdcdev.sc_dev.dv_xname,
|
|
channel, drive, error);
|
|
return (error);
|
|
}
|
|
|
|
WDCDEBUG_PRINT(("pciide_dma_table_setup: table at %p len %ld, "
|
|
"phy 0x%lx\n", dma_maps->dma_table, dma_table_size,
|
|
seg.ds_addr), DEBUG_PROBE);
|
|
|
|
/* Create and load table DMA map for this disk */
|
|
if ((error = bus_dmamap_create(sc->sc_dmat, dma_table_size,
|
|
1, dma_table_size, IDEDMA_TBL_ALIGN, BUS_DMA_NOWAIT,
|
|
&dma_maps->dmamap_table)) != 0) {
|
|
printf("%s:%d: unable to create table DMA map for "
|
|
"drive %d, error=%d\n", sc->sc_wdcdev.sc_dev.dv_xname,
|
|
channel, drive, error);
|
|
return (error);
|
|
}
|
|
if ((error = bus_dmamap_load(sc->sc_dmat,
|
|
dma_maps->dmamap_table,
|
|
dma_maps->dma_table,
|
|
dma_table_size, NULL, BUS_DMA_NOWAIT)) != 0) {
|
|
printf("%s:%d: unable to load table DMA map for "
|
|
"drive %d, error=%d\n", sc->sc_wdcdev.sc_dev.dv_xname,
|
|
channel, drive, error);
|
|
return (error);
|
|
}
|
|
WDCDEBUG_PRINT(("pciide_dma_table_setup: phy addr of table 0x%lx\n",
|
|
dma_maps->dmamap_table->dm_segs[0].ds_addr), DEBUG_PROBE);
|
|
/* Create a xfer DMA map for this drive */
|
|
if ((error = bus_dmamap_create(sc->sc_dmat, IDEDMA_BYTE_COUNT_MAX,
|
|
NIDEDMA_TABLES, sc->sc_dma_maxsegsz, sc->sc_dma_boundary,
|
|
BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
|
|
&dma_maps->dmamap_xfer)) != 0) {
|
|
printf("%s:%d: unable to create xfer DMA map for "
|
|
"drive %d, error=%d\n", sc->sc_wdcdev.sc_dev.dv_xname,
|
|
channel, drive, error);
|
|
return (error);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
pciide_dma_init(void *v, int channel, int drive, void *databuf,
|
|
size_t datalen, int flags)
|
|
{
|
|
struct pciide_softc *sc = v;
|
|
int error, seg;
|
|
struct pciide_channel *cp = &sc->pciide_channels[channel];
|
|
struct pciide_dma_maps *dma_maps =
|
|
&sc->pciide_channels[channel].dma_maps[drive];
|
|
#ifndef BUS_DMA_RAW
|
|
#define BUS_DMA_RAW 0
|
|
#endif
|
|
|
|
error = bus_dmamap_load(sc->sc_dmat,
|
|
dma_maps->dmamap_xfer,
|
|
databuf, datalen, NULL, BUS_DMA_NOWAIT|BUS_DMA_RAW);
|
|
if (error) {
|
|
printf("%s:%d: unable to load xfer DMA map for "
|
|
"drive %d, error=%d\n", sc->sc_wdcdev.sc_dev.dv_xname,
|
|
channel, drive, error);
|
|
return (error);
|
|
}
|
|
|
|
bus_dmamap_sync(sc->sc_dmat, dma_maps->dmamap_xfer, 0,
|
|
dma_maps->dmamap_xfer->dm_mapsize,
|
|
(flags & WDC_DMA_READ) ?
|
|
BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
|
|
|
|
for (seg = 0; seg < dma_maps->dmamap_xfer->dm_nsegs; seg++) {
|
|
#ifdef DIAGNOSTIC
|
|
/* A segment must not cross a 64k boundary */
|
|
{
|
|
u_long phys = dma_maps->dmamap_xfer->dm_segs[seg].ds_addr;
|
|
u_long len = dma_maps->dmamap_xfer->dm_segs[seg].ds_len;
|
|
if ((phys & ~IDEDMA_BYTE_COUNT_MASK) !=
|
|
((phys + len - 1) & ~IDEDMA_BYTE_COUNT_MASK)) {
|
|
printf("pciide_dma: segment %d physical addr 0x%lx"
|
|
" len 0x%lx not properly aligned\n",
|
|
seg, phys, len);
|
|
panic("pciide_dma: buf align");
|
|
}
|
|
}
|
|
#endif
|
|
dma_maps->dma_table[seg].base_addr =
|
|
htole32(dma_maps->dmamap_xfer->dm_segs[seg].ds_addr);
|
|
dma_maps->dma_table[seg].byte_count =
|
|
htole32(dma_maps->dmamap_xfer->dm_segs[seg].ds_len &
|
|
IDEDMA_BYTE_COUNT_MASK);
|
|
WDCDEBUG_PRINT(("\t seg %d len %d addr 0x%x\n",
|
|
seg, letoh32(dma_maps->dma_table[seg].byte_count),
|
|
letoh32(dma_maps->dma_table[seg].base_addr)), DEBUG_DMA);
|
|
|
|
}
|
|
dma_maps->dma_table[dma_maps->dmamap_xfer->dm_nsegs -1].byte_count |=
|
|
htole32(IDEDMA_BYTE_COUNT_EOT);
|
|
|
|
bus_dmamap_sync(sc->sc_dmat, dma_maps->dmamap_table, 0,
|
|
dma_maps->dmamap_table->dm_mapsize,
|
|
BUS_DMASYNC_PREWRITE);
|
|
|
|
/* Maps are ready. Start DMA function */
|
|
#ifdef DIAGNOSTIC
|
|
if (dma_maps->dmamap_table->dm_segs[0].ds_addr & ~IDEDMA_TBL_MASK) {
|
|
printf("pciide_dma_init: addr 0x%lx not properly aligned\n",
|
|
dma_maps->dmamap_table->dm_segs[0].ds_addr);
|
|
panic("pciide_dma_init: table align");
|
|
}
|
|
#endif
|
|
|
|
/* Clear status bits */
|
|
PCIIDE_DMACTL_WRITE(sc, channel, PCIIDE_DMACTL_READ(sc, channel));
|
|
/* Write table addr */
|
|
PCIIDE_DMATBL_WRITE(sc, channel,
|
|
dma_maps->dmamap_table->dm_segs[0].ds_addr);
|
|
/* set read/write */
|
|
PCIIDE_DMACMD_WRITE(sc, channel,
|
|
((flags & WDC_DMA_READ) ? IDEDMA_CMD_WRITE : 0) | cp->idedma_cmd);
|
|
/* remember flags */
|
|
dma_maps->dma_flags = flags;
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
pciide_dma_start(void *v, int channel, int drive)
|
|
{
|
|
struct pciide_softc *sc = v;
|
|
|
|
WDCDEBUG_PRINT(("pciide_dma_start\n"), DEBUG_XFERS);
|
|
PCIIDE_DMACMD_WRITE(sc, channel, PCIIDE_DMACMD_READ(sc, channel) |
|
|
IDEDMA_CMD_START);
|
|
|
|
sc->pciide_channels[channel].dma_in_progress = 1;
|
|
}
|
|
|
|
int
|
|
pciide_dma_finish(void *v, int channel, int drive, int force)
|
|
{
|
|
struct pciide_softc *sc = v;
|
|
struct pciide_channel *cp = &sc->pciide_channels[channel];
|
|
u_int8_t status;
|
|
int error = 0;
|
|
struct pciide_dma_maps *dma_maps =
|
|
&sc->pciide_channels[channel].dma_maps[drive];
|
|
|
|
status = PCIIDE_DMACTL_READ(sc, channel);
|
|
WDCDEBUG_PRINT(("pciide_dma_finish: status 0x%x\n", status),
|
|
DEBUG_XFERS);
|
|
if (status == 0xff)
|
|
return (status);
|
|
|
|
if (force == 0 && (status & IDEDMA_CTL_INTR) == 0) {
|
|
error = WDC_DMAST_NOIRQ;
|
|
goto done;
|
|
}
|
|
|
|
/* stop DMA channel */
|
|
PCIIDE_DMACMD_WRITE(sc, channel,
|
|
((dma_maps->dma_flags & WDC_DMA_READ) ?
|
|
0x00 : IDEDMA_CMD_WRITE) | cp->idedma_cmd);
|
|
|
|
/* Unload the map of the data buffer */
|
|
bus_dmamap_sync(sc->sc_dmat, dma_maps->dmamap_xfer, 0,
|
|
dma_maps->dmamap_xfer->dm_mapsize,
|
|
(dma_maps->dma_flags & WDC_DMA_READ) ?
|
|
BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
|
|
bus_dmamap_unload(sc->sc_dmat, dma_maps->dmamap_xfer);
|
|
|
|
/* Clear status bits */
|
|
PCIIDE_DMACTL_WRITE(sc, channel, status);
|
|
|
|
if ((status & IDEDMA_CTL_ERR) != 0) {
|
|
printf("%s:%d:%d: bus-master DMA error: status=0x%x\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, channel, drive, status);
|
|
error |= WDC_DMAST_ERR;
|
|
}
|
|
|
|
if ((status & IDEDMA_CTL_INTR) == 0) {
|
|
printf("%s:%d:%d: bus-master DMA error: missing interrupt, "
|
|
"status=0x%x\n", sc->sc_wdcdev.sc_dev.dv_xname, channel,
|
|
drive, status);
|
|
error |= WDC_DMAST_NOIRQ;
|
|
}
|
|
|
|
if ((status & IDEDMA_CTL_ACT) != 0) {
|
|
/* data underrun, may be a valid condition for ATAPI */
|
|
error |= WDC_DMAST_UNDER;
|
|
}
|
|
|
|
done:
|
|
sc->pciide_channels[channel].dma_in_progress = 0;
|
|
return (error);
|
|
}
|
|
|
|
void
|
|
pciide_irqack(struct channel_softc *chp)
|
|
{
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
int chan = chp->channel;
|
|
|
|
/* clear status bits in IDE DMA registers */
|
|
PCIIDE_DMACTL_WRITE(sc, chan, PCIIDE_DMACTL_READ(sc, chan));
|
|
}
|
|
|
|
/* some common code used by several chip_map */
|
|
int
|
|
pciide_chansetup(struct pciide_softc *sc, int channel, pcireg_t interface)
|
|
{
|
|
struct pciide_channel *cp = &sc->pciide_channels[channel];
|
|
sc->wdc_chanarray[channel] = &cp->wdc_channel;
|
|
cp->name = PCIIDE_CHANNEL_NAME(channel);
|
|
cp->wdc_channel.channel = channel;
|
|
cp->wdc_channel.wdc = &sc->sc_wdcdev;
|
|
cp->wdc_channel.ch_queue = wdc_alloc_queue();
|
|
if (cp->wdc_channel.ch_queue == NULL) {
|
|
printf("%s: %s "
|
|
"cannot allocate channel queue",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
|
|
return (0);
|
|
}
|
|
cp->hw_ok = 1;
|
|
|
|
return (1);
|
|
}
|
|
|
|
void
|
|
pciide_chanfree(struct pciide_softc *sc, int channel)
|
|
{
|
|
struct pciide_channel *cp = &sc->pciide_channels[channel];
|
|
if (cp->wdc_channel.ch_queue)
|
|
wdc_free_queue(cp->wdc_channel.ch_queue);
|
|
}
|
|
|
|
/* some common code used by several chip channel_map */
|
|
void
|
|
pciide_mapchan(struct pci_attach_args *pa, struct pciide_channel *cp,
|
|
pcireg_t interface, bus_size_t *cmdsizep, bus_size_t *ctlsizep,
|
|
int (*pci_intr)(void *))
|
|
{
|
|
struct channel_softc *wdc_cp = &cp->wdc_channel;
|
|
|
|
if (interface & PCIIDE_INTERFACE_PCI(wdc_cp->channel))
|
|
cp->hw_ok = pciide_mapregs_native(pa, cp, cmdsizep, ctlsizep,
|
|
pci_intr);
|
|
else
|
|
cp->hw_ok = pciide_mapregs_compat(pa, cp,
|
|
wdc_cp->channel, cmdsizep, ctlsizep);
|
|
if (cp->hw_ok == 0)
|
|
return;
|
|
wdc_cp->data32iot = wdc_cp->cmd_iot;
|
|
wdc_cp->data32ioh = wdc_cp->cmd_ioh;
|
|
wdcattach(wdc_cp);
|
|
}
|
|
|
|
void
|
|
pciide_unmap_chan(struct pciide_softc *sc, struct pciide_channel *cp, int flags)
|
|
{
|
|
struct channel_softc *wdc_cp = &cp->wdc_channel;
|
|
|
|
wdcdetach(wdc_cp, flags);
|
|
|
|
if (cp->compat != 0)
|
|
pciide_unmapregs_compat(sc, cp);
|
|
else
|
|
pciide_unmapregs_native(sc, cp);
|
|
}
|
|
|
|
/*
|
|
* Generic code to call to know if a channel can be disabled. Return 1
|
|
* if channel can be disabled, 0 if not
|
|
*/
|
|
int
|
|
pciide_chan_candisable(struct pciide_channel *cp)
|
|
{
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
struct channel_softc *wdc_cp = &cp->wdc_channel;
|
|
|
|
if ((wdc_cp->ch_drive[0].drive_flags & DRIVE) == 0 &&
|
|
(wdc_cp->ch_drive[1].drive_flags & DRIVE) == 0) {
|
|
printf("%s: %s disabled (no drives)\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
|
|
cp->hw_ok = 0;
|
|
return (1);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* generic code to map the compat intr if hw_ok=1 and it is a compat channel.
|
|
* Set hw_ok=0 on failure
|
|
*/
|
|
void
|
|
pciide_map_compat_intr(struct pci_attach_args *pa, struct pciide_channel *cp,
|
|
int compatchan, int interface)
|
|
{
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
struct channel_softc *wdc_cp = &cp->wdc_channel;
|
|
|
|
if ((interface & PCIIDE_INTERFACE_PCI(wdc_cp->channel)) != 0)
|
|
return;
|
|
|
|
cp->compat = 1;
|
|
cp->ih = pciide_machdep_compat_intr_establish(&sc->sc_wdcdev.sc_dev,
|
|
pa, compatchan, pciide_compat_intr, cp);
|
|
if (cp->ih == NULL) {
|
|
printf("%s: no compatibility interrupt for use by %s\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
|
|
cp->hw_ok = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* generic code to unmap the compat intr if hw_ok=1 and it is a compat channel.
|
|
* Set hw_ok=0 on failure
|
|
*/
|
|
void
|
|
pciide_unmap_compat_intr(struct pci_attach_args *pa, struct pciide_channel *cp,
|
|
int compatchan, int interface)
|
|
{
|
|
struct channel_softc *wdc_cp = &cp->wdc_channel;
|
|
|
|
if ((interface & PCIIDE_INTERFACE_PCI(wdc_cp->channel)) != 0)
|
|
return;
|
|
|
|
pciide_machdep_compat_intr_disestablish(pa->pa_pc, cp->ih);
|
|
}
|
|
|
|
void
|
|
pciide_print_channels(int nchannels, pcireg_t interface)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < nchannels; i++) {
|
|
printf(", %s %s to %s", PCIIDE_CHANNEL_NAME(i),
|
|
(interface & PCIIDE_INTERFACE_SETTABLE(i)) ?
|
|
"configured" : "wired",
|
|
(interface & PCIIDE_INTERFACE_PCI(i)) ? "native-PCI" :
|
|
"compatibility");
|
|
}
|
|
|
|
printf("\n");
|
|
}
|
|
|
|
void
|
|
pciide_print_modes(struct pciide_channel *cp)
|
|
{
|
|
wdc_print_current_modes(&cp->wdc_channel);
|
|
}
|
|
|
|
void
|
|
default_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_channel *cp;
|
|
pcireg_t interface = PCI_INTERFACE(pa->pa_class);
|
|
pcireg_t csr;
|
|
int channel, drive;
|
|
struct ata_drive_datas *drvp;
|
|
u_int8_t idedma_ctl;
|
|
bus_size_t cmdsize, ctlsize;
|
|
char *failreason;
|
|
|
|
if (interface & PCIIDE_INTERFACE_BUS_MASTER_DMA) {
|
|
printf(": DMA");
|
|
if (sc->sc_pp == &default_product_desc &&
|
|
(sc->sc_wdcdev.sc_dev.dv_cfdata->cf_flags &
|
|
PCIIDE_OPTIONS_DMA) == 0) {
|
|
printf(" (unsupported)");
|
|
sc->sc_dma_ok = 0;
|
|
} else {
|
|
pciide_mapreg_dma(sc, pa);
|
|
if (sc->sc_dma_ok != 0)
|
|
printf(", (partial support)");
|
|
}
|
|
} else {
|
|
printf(": no DMA");
|
|
sc->sc_dma_ok = 0;
|
|
}
|
|
if (sc->sc_dma_ok) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_IRQACK;
|
|
sc->sc_wdcdev.irqack = pciide_irqack;
|
|
}
|
|
sc->sc_wdcdev.PIO_cap = 0;
|
|
sc->sc_wdcdev.DMA_cap = 0;
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16;
|
|
|
|
pciide_print_channels(sc->sc_wdcdev.nchannels, interface);
|
|
|
|
for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
|
|
cp = &sc->pciide_channels[channel];
|
|
if (pciide_chansetup(sc, channel, interface) == 0)
|
|
continue;
|
|
if (interface & PCIIDE_INTERFACE_PCI(channel)) {
|
|
cp->hw_ok = pciide_mapregs_native(pa, cp, &cmdsize,
|
|
&ctlsize, pciide_pci_intr);
|
|
} else {
|
|
cp->hw_ok = pciide_mapregs_compat(pa, cp,
|
|
channel, &cmdsize, &ctlsize);
|
|
}
|
|
if (cp->hw_ok == 0)
|
|
continue;
|
|
/*
|
|
* Check to see if something appears to be there.
|
|
*/
|
|
failreason = NULL;
|
|
pciide_map_compat_intr(pa, cp, channel, interface);
|
|
if (cp->hw_ok == 0)
|
|
continue;
|
|
if (!wdcprobe(&cp->wdc_channel)) {
|
|
failreason = "not responding; disabled or no drives?";
|
|
goto next;
|
|
}
|
|
/*
|
|
* Now, make sure it's actually attributable to this PCI IDE
|
|
* channel by trying to access the channel again while the
|
|
* PCI IDE controller's I/O space is disabled. (If the
|
|
* channel no longer appears to be there, it belongs to
|
|
* this controller.) YUCK!
|
|
*/
|
|
csr = pci_conf_read(sc->sc_pc, sc->sc_tag,
|
|
PCI_COMMAND_STATUS_REG);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG,
|
|
csr & ~PCI_COMMAND_IO_ENABLE);
|
|
if (wdcprobe(&cp->wdc_channel))
|
|
failreason = "other hardware responding at addresses";
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag,
|
|
PCI_COMMAND_STATUS_REG, csr);
|
|
next:
|
|
if (failreason) {
|
|
printf("%s: %s ignored (%s)\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name,
|
|
failreason);
|
|
cp->hw_ok = 0;
|
|
pciide_unmap_compat_intr(pa, cp, channel, interface);
|
|
bus_space_unmap(cp->wdc_channel.cmd_iot,
|
|
cp->wdc_channel.cmd_ioh, cmdsize);
|
|
if (interface & PCIIDE_INTERFACE_PCI(channel))
|
|
bus_space_unmap(cp->wdc_channel.ctl_iot,
|
|
cp->ctl_baseioh, ctlsize);
|
|
else
|
|
bus_space_unmap(cp->wdc_channel.ctl_iot,
|
|
cp->wdc_channel.ctl_ioh, ctlsize);
|
|
}
|
|
if (cp->hw_ok) {
|
|
cp->wdc_channel.data32iot = cp->wdc_channel.cmd_iot;
|
|
cp->wdc_channel.data32ioh = cp->wdc_channel.cmd_ioh;
|
|
wdcattach(&cp->wdc_channel);
|
|
}
|
|
}
|
|
|
|
if (sc->sc_dma_ok == 0)
|
|
return;
|
|
|
|
/* Allocate DMA maps */
|
|
for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
|
|
idedma_ctl = 0;
|
|
cp = &sc->pciide_channels[channel];
|
|
for (drive = 0; drive < 2; drive++) {
|
|
drvp = &cp->wdc_channel.ch_drive[drive];
|
|
/* If no drive, skip */
|
|
if ((drvp->drive_flags & DRIVE) == 0)
|
|
continue;
|
|
if ((drvp->drive_flags & DRIVE_DMA) == 0)
|
|
continue;
|
|
if (pciide_dma_table_setup(sc, channel, drive) != 0) {
|
|
/* Abort DMA setup */
|
|
printf("%s:%d:%d: cannot allocate DMA maps, "
|
|
"using PIO transfers\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname,
|
|
channel, drive);
|
|
drvp->drive_flags &= ~DRIVE_DMA;
|
|
}
|
|
printf("%s:%d:%d: using DMA data transfers\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname,
|
|
channel, drive);
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
}
|
|
if (idedma_ctl != 0) {
|
|
/* Add software bits in status register */
|
|
PCIIDE_DMACTL_WRITE(sc, channel, idedma_ctl);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
default_chip_unmap(struct pciide_softc *sc, int flags)
|
|
{
|
|
struct pciide_channel *cp;
|
|
int channel;
|
|
|
|
for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
|
|
cp = &sc->pciide_channels[channel];
|
|
pciide_unmap_chan(sc, cp, flags);
|
|
pciide_chanfree(sc, channel);
|
|
}
|
|
|
|
pciide_unmapreg_dma(sc);
|
|
|
|
if (sc->sc_cookie)
|
|
free(sc->sc_cookie, M_DEVBUF, sc->sc_cookielen);
|
|
}
|
|
|
|
void
|
|
sata_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_channel *cp;
|
|
pcireg_t interface = PCI_INTERFACE(pa->pa_class);
|
|
int channel;
|
|
bus_size_t cmdsize, ctlsize;
|
|
|
|
if (interface == 0) {
|
|
WDCDEBUG_PRINT(("sata_chip_map interface == 0\n"),
|
|
DEBUG_PROBE);
|
|
interface = PCIIDE_INTERFACE_BUS_MASTER_DMA |
|
|
PCIIDE_INTERFACE_PCI(0) | PCIIDE_INTERFACE_PCI(1);
|
|
}
|
|
|
|
printf(": DMA");
|
|
pciide_mapreg_dma(sc, pa);
|
|
printf("\n");
|
|
|
|
if (sc->sc_dma_ok) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_UDMA |
|
|
WDC_CAPABILITY_DMA | WDC_CAPABILITY_IRQACK;
|
|
sc->sc_wdcdev.irqack = pciide_irqack;
|
|
}
|
|
sc->sc_wdcdev.PIO_cap = 4;
|
|
sc->sc_wdcdev.DMA_cap = 2;
|
|
sc->sc_wdcdev.UDMA_cap = 6;
|
|
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
|
|
WDC_CAPABILITY_MODE | WDC_CAPABILITY_SATA;
|
|
sc->sc_wdcdev.set_modes = sata_setup_channel;
|
|
sc->chip_unmap = default_chip_unmap;
|
|
|
|
for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
|
|
cp = &sc->pciide_channels[channel];
|
|
if (pciide_chansetup(sc, channel, interface) == 0)
|
|
continue;
|
|
pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
|
|
pciide_pci_intr);
|
|
sata_setup_channel(&cp->wdc_channel);
|
|
}
|
|
}
|
|
|
|
void
|
|
sata_setup_channel(struct channel_softc *chp)
|
|
{
|
|
struct ata_drive_datas *drvp;
|
|
int drive;
|
|
u_int32_t idedma_ctl;
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
|
|
/* setup DMA if needed */
|
|
pciide_channel_dma_setup(cp);
|
|
|
|
idedma_ctl = 0;
|
|
|
|
for (drive = 0; drive < 2; drive++) {
|
|
drvp = &chp->ch_drive[drive];
|
|
/* If no drive, skip */
|
|
if ((drvp->drive_flags & DRIVE) == 0)
|
|
continue;
|
|
if (drvp->drive_flags & DRIVE_UDMA) {
|
|
/* use Ultra/DMA */
|
|
drvp->drive_flags &= ~DRIVE_DMA;
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
} else if (drvp->drive_flags & DRIVE_DMA) {
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Nothing to do to setup modes; it is meaningless in S-ATA
|
|
* (but many S-ATA drives still want to get the SET_FEATURE
|
|
* command).
|
|
*/
|
|
if (idedma_ctl != 0) {
|
|
/* Add software bits in status register */
|
|
PCIIDE_DMACTL_WRITE(sc, chp->channel, idedma_ctl);
|
|
}
|
|
pciide_print_modes(cp);
|
|
}
|
|
|
|
void
|
|
piix_timing_debug(struct pciide_softc *sc)
|
|
{
|
|
WDCDEBUG_PRINT(("piix_setup_chip: idetim=0x%x",
|
|
pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_IDETIM)),
|
|
DEBUG_PROBE);
|
|
if (sc->sc_pp->ide_product != PCI_PRODUCT_INTEL_82371FB_IDE &&
|
|
sc->sc_pp->ide_product != PCI_PRODUCT_INTEL_82371FB_ISA) {
|
|
WDCDEBUG_PRINT((", sidetim=0x%x",
|
|
pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_SIDETIM)),
|
|
DEBUG_PROBE);
|
|
if (sc->sc_wdcdev.cap & WDC_CAPABILITY_UDMA) {
|
|
WDCDEBUG_PRINT((", udmareg 0x%x",
|
|
pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_UDMAREG)),
|
|
DEBUG_PROBE);
|
|
}
|
|
if (sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_6300ESB_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_6321ESB_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801AA_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801AB_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801BAM_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801BA_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801CAM_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801CA_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801DB_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801DBL_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801DBM_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801EB_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801FB_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801GB_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801HBM_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82372FB_IDE) {
|
|
WDCDEBUG_PRINT((", IDE_CONTROL 0x%x",
|
|
pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_CONFIG)),
|
|
DEBUG_PROBE);
|
|
}
|
|
}
|
|
WDCDEBUG_PRINT(("\n"), DEBUG_PROBE);
|
|
}
|
|
|
|
void
|
|
piix_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_channel *cp;
|
|
int channel;
|
|
u_int32_t idetim;
|
|
bus_size_t cmdsize, ctlsize;
|
|
|
|
pcireg_t interface = PCI_INTERFACE(pa->pa_class);
|
|
|
|
printf(": DMA");
|
|
pciide_mapreg_dma(sc, pa);
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
|
|
WDC_CAPABILITY_MODE;
|
|
if (sc->sc_dma_ok) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_IRQACK;
|
|
sc->sc_wdcdev.irqack = pciide_irqack;
|
|
switch (sc->sc_pp->ide_product) {
|
|
case PCI_PRODUCT_INTEL_6300ESB_IDE:
|
|
case PCI_PRODUCT_INTEL_6321ESB_IDE:
|
|
case PCI_PRODUCT_INTEL_82371AB_IDE:
|
|
case PCI_PRODUCT_INTEL_82372FB_IDE:
|
|
case PCI_PRODUCT_INTEL_82440MX_IDE:
|
|
case PCI_PRODUCT_INTEL_82451NX:
|
|
case PCI_PRODUCT_INTEL_82801AA_IDE:
|
|
case PCI_PRODUCT_INTEL_82801AB_IDE:
|
|
case PCI_PRODUCT_INTEL_82801BAM_IDE:
|
|
case PCI_PRODUCT_INTEL_82801BA_IDE:
|
|
case PCI_PRODUCT_INTEL_82801CAM_IDE:
|
|
case PCI_PRODUCT_INTEL_82801CA_IDE:
|
|
case PCI_PRODUCT_INTEL_82801DB_IDE:
|
|
case PCI_PRODUCT_INTEL_82801DBL_IDE:
|
|
case PCI_PRODUCT_INTEL_82801DBM_IDE:
|
|
case PCI_PRODUCT_INTEL_82801EB_IDE:
|
|
case PCI_PRODUCT_INTEL_82801FB_IDE:
|
|
case PCI_PRODUCT_INTEL_82801GB_IDE:
|
|
case PCI_PRODUCT_INTEL_82801HBM_IDE:
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_UDMA;
|
|
break;
|
|
}
|
|
}
|
|
sc->sc_wdcdev.PIO_cap = 4;
|
|
sc->sc_wdcdev.DMA_cap = 2;
|
|
switch (sc->sc_pp->ide_product) {
|
|
case PCI_PRODUCT_INTEL_82801AA_IDE:
|
|
case PCI_PRODUCT_INTEL_82372FB_IDE:
|
|
sc->sc_wdcdev.UDMA_cap = 4;
|
|
break;
|
|
case PCI_PRODUCT_INTEL_6300ESB_IDE:
|
|
case PCI_PRODUCT_INTEL_6321ESB_IDE:
|
|
case PCI_PRODUCT_INTEL_82801BAM_IDE:
|
|
case PCI_PRODUCT_INTEL_82801BA_IDE:
|
|
case PCI_PRODUCT_INTEL_82801CAM_IDE:
|
|
case PCI_PRODUCT_INTEL_82801CA_IDE:
|
|
case PCI_PRODUCT_INTEL_82801DB_IDE:
|
|
case PCI_PRODUCT_INTEL_82801DBL_IDE:
|
|
case PCI_PRODUCT_INTEL_82801DBM_IDE:
|
|
case PCI_PRODUCT_INTEL_82801EB_IDE:
|
|
case PCI_PRODUCT_INTEL_82801FB_IDE:
|
|
case PCI_PRODUCT_INTEL_82801GB_IDE:
|
|
case PCI_PRODUCT_INTEL_82801HBM_IDE:
|
|
sc->sc_wdcdev.UDMA_cap = 5;
|
|
break;
|
|
default:
|
|
sc->sc_wdcdev.UDMA_cap = 2;
|
|
break;
|
|
}
|
|
|
|
if (sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82371FB_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82371FB_ISA) {
|
|
sc->sc_wdcdev.set_modes = piix_setup_channel;
|
|
} else {
|
|
sc->sc_wdcdev.set_modes = piix3_4_setup_channel;
|
|
}
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
|
|
|
|
pciide_print_channels(sc->sc_wdcdev.nchannels, interface);
|
|
|
|
piix_timing_debug(sc);
|
|
|
|
for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
|
|
cp = &sc->pciide_channels[channel];
|
|
|
|
if (pciide_chansetup(sc, channel, interface) == 0)
|
|
continue;
|
|
idetim = pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_IDETIM);
|
|
if ((PIIX_IDETIM_READ(idetim, channel) &
|
|
PIIX_IDETIM_IDE) == 0) {
|
|
printf("%s: %s ignored (disabled)\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
|
|
cp->hw_ok = 0;
|
|
continue;
|
|
}
|
|
pciide_map_compat_intr(pa, cp, channel, interface);
|
|
if (cp->hw_ok == 0)
|
|
continue;
|
|
pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
|
|
pciide_pci_intr);
|
|
if (cp->hw_ok == 0)
|
|
goto next;
|
|
if (pciide_chan_candisable(cp)) {
|
|
idetim = PIIX_IDETIM_CLEAR(idetim, PIIX_IDETIM_IDE,
|
|
channel);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, PIIX_IDETIM,
|
|
idetim);
|
|
}
|
|
if (cp->hw_ok == 0)
|
|
goto next;
|
|
sc->sc_wdcdev.set_modes(&cp->wdc_channel);
|
|
next:
|
|
if (cp->hw_ok == 0)
|
|
pciide_unmap_compat_intr(pa, cp, channel, interface);
|
|
}
|
|
|
|
piix_timing_debug(sc);
|
|
}
|
|
|
|
void
|
|
piixsata_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_channel *cp;
|
|
pcireg_t interface = PCI_INTERFACE(pa->pa_class);
|
|
int channel;
|
|
bus_size_t cmdsize, ctlsize;
|
|
u_int8_t reg, ich = 0;
|
|
|
|
printf(": DMA");
|
|
pciide_mapreg_dma(sc, pa);
|
|
|
|
if (sc->sc_dma_ok) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_UDMA |
|
|
WDC_CAPABILITY_DMA | WDC_CAPABILITY_IRQACK;
|
|
sc->sc_wdcdev.irqack = pciide_irqack;
|
|
sc->sc_wdcdev.DMA_cap = 2;
|
|
sc->sc_wdcdev.UDMA_cap = 6;
|
|
}
|
|
sc->sc_wdcdev.PIO_cap = 4;
|
|
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
|
|
WDC_CAPABILITY_MODE | WDC_CAPABILITY_SATA;
|
|
sc->sc_wdcdev.set_modes = sata_setup_channel;
|
|
|
|
switch(sc->sc_pp->ide_product) {
|
|
case PCI_PRODUCT_INTEL_6300ESB_SATA:
|
|
case PCI_PRODUCT_INTEL_6300ESB_SATA2:
|
|
case PCI_PRODUCT_INTEL_82801EB_SATA:
|
|
case PCI_PRODUCT_INTEL_82801ER_SATA:
|
|
ich = 5;
|
|
break;
|
|
case PCI_PRODUCT_INTEL_82801FB_SATA:
|
|
case PCI_PRODUCT_INTEL_82801FR_SATA:
|
|
case PCI_PRODUCT_INTEL_82801FBM_SATA:
|
|
ich = 6;
|
|
break;
|
|
default:
|
|
ich = 7;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Put the SATA portion of controllers that don't operate in combined
|
|
* mode into native PCI modes so the maximum number of devices can be
|
|
* used. Intel calls this "enhanced mode"
|
|
*/
|
|
if (ich == 5) {
|
|
reg = pciide_pci_read(sc->sc_pc, sc->sc_tag, ICH5_SATA_MAP);
|
|
if ((reg & ICH5_SATA_MAP_COMBINED) == 0) {
|
|
reg = pciide_pci_read(pa->pa_pc, pa->pa_tag,
|
|
ICH5_SATA_PI);
|
|
reg |= ICH5_SATA_PI_PRI_NATIVE |
|
|
ICH5_SATA_PI_SEC_NATIVE;
|
|
pciide_pci_write(pa->pa_pc, pa->pa_tag,
|
|
ICH5_SATA_PI, reg);
|
|
interface |= PCIIDE_INTERFACE_PCI(0) |
|
|
PCIIDE_INTERFACE_PCI(1);
|
|
}
|
|
} else {
|
|
reg = pciide_pci_read(sc->sc_pc, sc->sc_tag, ICH5_SATA_MAP) &
|
|
ICH6_SATA_MAP_CMB_MASK;
|
|
if (reg != ICH6_SATA_MAP_CMB_PRI &&
|
|
reg != ICH6_SATA_MAP_CMB_SEC) {
|
|
reg = pciide_pci_read(pa->pa_pc, pa->pa_tag,
|
|
ICH5_SATA_PI);
|
|
reg |= ICH5_SATA_PI_PRI_NATIVE |
|
|
ICH5_SATA_PI_SEC_NATIVE;
|
|
|
|
pciide_pci_write(pa->pa_pc, pa->pa_tag,
|
|
ICH5_SATA_PI, reg);
|
|
interface |= PCIIDE_INTERFACE_PCI(0) |
|
|
PCIIDE_INTERFACE_PCI(1);
|
|
|
|
/*
|
|
* Ask for SATA IDE Mode, we don't need to do this
|
|
* for the combined mode case as combined mode is
|
|
* only allowed in IDE Mode
|
|
*/
|
|
if (ich >= 7) {
|
|
reg = pciide_pci_read(sc->sc_pc, sc->sc_tag,
|
|
ICH5_SATA_MAP) & ~ICH7_SATA_MAP_SMS_MASK;
|
|
pciide_pci_write(pa->pa_pc, pa->pa_tag,
|
|
ICH5_SATA_MAP, reg);
|
|
}
|
|
}
|
|
}
|
|
|
|
pciide_print_channels(sc->sc_wdcdev.nchannels, interface);
|
|
|
|
for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
|
|
cp = &sc->pciide_channels[channel];
|
|
if (pciide_chansetup(sc, channel, interface) == 0)
|
|
continue;
|
|
|
|
pciide_map_compat_intr(pa, cp, channel, interface);
|
|
if (cp->hw_ok == 0)
|
|
continue;
|
|
|
|
pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
|
|
pciide_pci_intr);
|
|
if (cp->hw_ok != 0)
|
|
sc->sc_wdcdev.set_modes(&cp->wdc_channel);
|
|
|
|
if (cp->hw_ok == 0)
|
|
pciide_unmap_compat_intr(pa, cp, channel, interface);
|
|
}
|
|
}
|
|
|
|
void
|
|
piix_setup_channel(struct channel_softc *chp)
|
|
{
|
|
u_int8_t mode[2], drive;
|
|
u_int32_t oidetim, idetim, idedma_ctl;
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
struct ata_drive_datas *drvp = cp->wdc_channel.ch_drive;
|
|
|
|
oidetim = pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_IDETIM);
|
|
idetim = PIIX_IDETIM_CLEAR(oidetim, 0xffff, chp->channel);
|
|
idedma_ctl = 0;
|
|
|
|
/* set up new idetim: Enable IDE registers decode */
|
|
idetim = PIIX_IDETIM_SET(idetim, PIIX_IDETIM_IDE,
|
|
chp->channel);
|
|
|
|
/* setup DMA */
|
|
pciide_channel_dma_setup(cp);
|
|
|
|
/*
|
|
* Here we have to mess up with drives mode: PIIX can't have
|
|
* different timings for master and slave drives.
|
|
* We need to find the best combination.
|
|
*/
|
|
|
|
/* If both drives supports DMA, take the lower mode */
|
|
if ((drvp[0].drive_flags & DRIVE_DMA) &&
|
|
(drvp[1].drive_flags & DRIVE_DMA)) {
|
|
mode[0] = mode[1] =
|
|
min(drvp[0].DMA_mode, drvp[1].DMA_mode);
|
|
drvp[0].DMA_mode = mode[0];
|
|
drvp[1].DMA_mode = mode[1];
|
|
goto ok;
|
|
}
|
|
/*
|
|
* If only one drive supports DMA, use its mode, and
|
|
* put the other one in PIO mode 0 if mode not compatible
|
|
*/
|
|
if (drvp[0].drive_flags & DRIVE_DMA) {
|
|
mode[0] = drvp[0].DMA_mode;
|
|
mode[1] = drvp[1].PIO_mode;
|
|
if (piix_isp_pio[mode[1]] != piix_isp_dma[mode[0]] ||
|
|
piix_rtc_pio[mode[1]] != piix_rtc_dma[mode[0]])
|
|
mode[1] = drvp[1].PIO_mode = 0;
|
|
goto ok;
|
|
}
|
|
if (drvp[1].drive_flags & DRIVE_DMA) {
|
|
mode[1] = drvp[1].DMA_mode;
|
|
mode[0] = drvp[0].PIO_mode;
|
|
if (piix_isp_pio[mode[0]] != piix_isp_dma[mode[1]] ||
|
|
piix_rtc_pio[mode[0]] != piix_rtc_dma[mode[1]])
|
|
mode[0] = drvp[0].PIO_mode = 0;
|
|
goto ok;
|
|
}
|
|
/*
|
|
* If both drives are not DMA, takes the lower mode, unless
|
|
* one of them is PIO mode < 2
|
|
*/
|
|
if (drvp[0].PIO_mode < 2) {
|
|
mode[0] = drvp[0].PIO_mode = 0;
|
|
mode[1] = drvp[1].PIO_mode;
|
|
} else if (drvp[1].PIO_mode < 2) {
|
|
mode[1] = drvp[1].PIO_mode = 0;
|
|
mode[0] = drvp[0].PIO_mode;
|
|
} else {
|
|
mode[0] = mode[1] =
|
|
min(drvp[1].PIO_mode, drvp[0].PIO_mode);
|
|
drvp[0].PIO_mode = mode[0];
|
|
drvp[1].PIO_mode = mode[1];
|
|
}
|
|
ok: /* The modes are setup */
|
|
for (drive = 0; drive < 2; drive++) {
|
|
if (drvp[drive].drive_flags & DRIVE_DMA) {
|
|
idetim |= piix_setup_idetim_timings(
|
|
mode[drive], 1, chp->channel);
|
|
goto end;
|
|
}
|
|
}
|
|
/* If we are there, none of the drives are DMA */
|
|
if (mode[0] >= 2)
|
|
idetim |= piix_setup_idetim_timings(
|
|
mode[0], 0, chp->channel);
|
|
else
|
|
idetim |= piix_setup_idetim_timings(
|
|
mode[1], 0, chp->channel);
|
|
end: /*
|
|
* timing mode is now set up in the controller. Enable
|
|
* it per-drive
|
|
*/
|
|
for (drive = 0; drive < 2; drive++) {
|
|
/* If no drive, skip */
|
|
if ((drvp[drive].drive_flags & DRIVE) == 0)
|
|
continue;
|
|
idetim |= piix_setup_idetim_drvs(&drvp[drive]);
|
|
if (drvp[drive].drive_flags & DRIVE_DMA)
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
}
|
|
if (idedma_ctl != 0) {
|
|
/* Add software bits in status register */
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(chp->channel),
|
|
idedma_ctl);
|
|
}
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, PIIX_IDETIM, idetim);
|
|
pciide_print_modes(cp);
|
|
}
|
|
|
|
void
|
|
piix3_4_setup_channel(struct channel_softc *chp)
|
|
{
|
|
struct ata_drive_datas *drvp;
|
|
u_int32_t oidetim, idetim, sidetim, udmareg, ideconf, idedma_ctl;
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
int drive;
|
|
int channel = chp->channel;
|
|
|
|
oidetim = pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_IDETIM);
|
|
sidetim = pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_SIDETIM);
|
|
udmareg = pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_UDMAREG);
|
|
ideconf = pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_CONFIG);
|
|
idetim = PIIX_IDETIM_CLEAR(oidetim, 0xffff, channel);
|
|
sidetim &= ~(PIIX_SIDETIM_ISP_MASK(channel) |
|
|
PIIX_SIDETIM_RTC_MASK(channel));
|
|
|
|
idedma_ctl = 0;
|
|
/* If channel disabled, no need to go further */
|
|
if ((PIIX_IDETIM_READ(oidetim, channel) & PIIX_IDETIM_IDE) == 0)
|
|
return;
|
|
/* set up new idetim: Enable IDE registers decode */
|
|
idetim = PIIX_IDETIM_SET(idetim, PIIX_IDETIM_IDE, channel);
|
|
|
|
/* setup DMA if needed */
|
|
pciide_channel_dma_setup(cp);
|
|
|
|
for (drive = 0; drive < 2; drive++) {
|
|
udmareg &= ~(PIIX_UDMACTL_DRV_EN(channel, drive) |
|
|
PIIX_UDMATIM_SET(0x3, channel, drive));
|
|
drvp = &chp->ch_drive[drive];
|
|
/* If no drive, skip */
|
|
if ((drvp->drive_flags & DRIVE) == 0)
|
|
continue;
|
|
if (((drvp->drive_flags & DRIVE_DMA) == 0 &&
|
|
(drvp->drive_flags & DRIVE_UDMA) == 0))
|
|
goto pio;
|
|
|
|
if (sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_6300ESB_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_6321ESB_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801AA_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801AB_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801BAM_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801BA_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801CAM_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801CA_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801DB_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801DBL_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801DBM_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801EB_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801FB_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801GB_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801HBM_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82372FB_IDE) {
|
|
ideconf |= PIIX_CONFIG_PINGPONG;
|
|
}
|
|
if (sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_6300ESB_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_6321ESB_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801BAM_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801BA_IDE||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801CAM_IDE||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801CA_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801DB_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801DBL_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801DBM_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801EB_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801FB_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801GB_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801HBM_IDE) {
|
|
/* setup Ultra/100 */
|
|
if (drvp->UDMA_mode > 2 &&
|
|
(ideconf & PIIX_CONFIG_CR(channel, drive)) == 0)
|
|
drvp->UDMA_mode = 2;
|
|
if (drvp->UDMA_mode > 4) {
|
|
ideconf |= PIIX_CONFIG_UDMA100(channel, drive);
|
|
} else {
|
|
ideconf &= ~PIIX_CONFIG_UDMA100(channel, drive);
|
|
if (drvp->UDMA_mode > 2) {
|
|
ideconf |= PIIX_CONFIG_UDMA66(channel,
|
|
drive);
|
|
} else {
|
|
ideconf &= ~PIIX_CONFIG_UDMA66(channel,
|
|
drive);
|
|
}
|
|
}
|
|
}
|
|
if (sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82801AA_IDE ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_INTEL_82372FB_IDE) {
|
|
/* setup Ultra/66 */
|
|
if (drvp->UDMA_mode > 2 &&
|
|
(ideconf & PIIX_CONFIG_CR(channel, drive)) == 0)
|
|
drvp->UDMA_mode = 2;
|
|
if (drvp->UDMA_mode > 2)
|
|
ideconf |= PIIX_CONFIG_UDMA66(channel, drive);
|
|
else
|
|
ideconf &= ~PIIX_CONFIG_UDMA66(channel, drive);
|
|
}
|
|
|
|
if ((chp->wdc->cap & WDC_CAPABILITY_UDMA) &&
|
|
(drvp->drive_flags & DRIVE_UDMA)) {
|
|
/* use Ultra/DMA */
|
|
drvp->drive_flags &= ~DRIVE_DMA;
|
|
udmareg |= PIIX_UDMACTL_DRV_EN( channel, drive);
|
|
udmareg |= PIIX_UDMATIM_SET(
|
|
piix4_sct_udma[drvp->UDMA_mode], channel, drive);
|
|
} else {
|
|
/* use Multiword DMA */
|
|
drvp->drive_flags &= ~DRIVE_UDMA;
|
|
if (drive == 0) {
|
|
idetim |= piix_setup_idetim_timings(
|
|
drvp->DMA_mode, 1, channel);
|
|
} else {
|
|
sidetim |= piix_setup_sidetim_timings(
|
|
drvp->DMA_mode, 1, channel);
|
|
idetim = PIIX_IDETIM_SET(idetim,
|
|
PIIX_IDETIM_SITRE, channel);
|
|
}
|
|
}
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
|
|
pio: /* use PIO mode */
|
|
idetim |= piix_setup_idetim_drvs(drvp);
|
|
if (drive == 0) {
|
|
idetim |= piix_setup_idetim_timings(
|
|
drvp->PIO_mode, 0, channel);
|
|
} else {
|
|
sidetim |= piix_setup_sidetim_timings(
|
|
drvp->PIO_mode, 0, channel);
|
|
idetim = PIIX_IDETIM_SET(idetim,
|
|
PIIX_IDETIM_SITRE, channel);
|
|
}
|
|
}
|
|
if (idedma_ctl != 0) {
|
|
/* Add software bits in status register */
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(channel),
|
|
idedma_ctl);
|
|
}
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, PIIX_IDETIM, idetim);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, PIIX_SIDETIM, sidetim);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, PIIX_UDMAREG, udmareg);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, PIIX_CONFIG, ideconf);
|
|
pciide_print_modes(cp);
|
|
}
|
|
|
|
|
|
/* setup ISP and RTC fields, based on mode */
|
|
u_int32_t
|
|
piix_setup_idetim_timings(u_int8_t mode, u_int8_t dma, u_int8_t channel)
|
|
{
|
|
|
|
if (dma)
|
|
return (PIIX_IDETIM_SET(0,
|
|
PIIX_IDETIM_ISP_SET(piix_isp_dma[mode]) |
|
|
PIIX_IDETIM_RTC_SET(piix_rtc_dma[mode]),
|
|
channel));
|
|
else
|
|
return (PIIX_IDETIM_SET(0,
|
|
PIIX_IDETIM_ISP_SET(piix_isp_pio[mode]) |
|
|
PIIX_IDETIM_RTC_SET(piix_rtc_pio[mode]),
|
|
channel));
|
|
}
|
|
|
|
/* setup DTE, PPE, IE and TIME field based on PIO mode */
|
|
u_int32_t
|
|
piix_setup_idetim_drvs(struct ata_drive_datas *drvp)
|
|
{
|
|
u_int32_t ret = 0;
|
|
struct channel_softc *chp = drvp->chnl_softc;
|
|
u_int8_t channel = chp->channel;
|
|
u_int8_t drive = drvp->drive;
|
|
|
|
/*
|
|
* If drive is using UDMA, timing setup is independent
|
|
* so just check DMA and PIO here.
|
|
*/
|
|
if (drvp->drive_flags & DRIVE_DMA) {
|
|
/* if mode = DMA mode 0, use compatible timings */
|
|
if ((drvp->drive_flags & DRIVE_DMA) &&
|
|
drvp->DMA_mode == 0) {
|
|
drvp->PIO_mode = 0;
|
|
return (ret);
|
|
}
|
|
ret = PIIX_IDETIM_SET(ret, PIIX_IDETIM_TIME(drive), channel);
|
|
/*
|
|
* PIO and DMA timings are the same, use fast timings for PIO
|
|
* too, else use compat timings.
|
|
*/
|
|
if ((piix_isp_pio[drvp->PIO_mode] !=
|
|
piix_isp_dma[drvp->DMA_mode]) ||
|
|
(piix_rtc_pio[drvp->PIO_mode] !=
|
|
piix_rtc_dma[drvp->DMA_mode]))
|
|
drvp->PIO_mode = 0;
|
|
/* if PIO mode <= 2, use compat timings for PIO */
|
|
if (drvp->PIO_mode <= 2) {
|
|
ret = PIIX_IDETIM_SET(ret, PIIX_IDETIM_DTE(drive),
|
|
channel);
|
|
return (ret);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Now setup PIO modes. If mode < 2, use compat timings.
|
|
* Else enable fast timings. Enable IORDY and prefetch/post
|
|
* if PIO mode >= 3.
|
|
*/
|
|
|
|
if (drvp->PIO_mode < 2)
|
|
return (ret);
|
|
|
|
ret = PIIX_IDETIM_SET(ret, PIIX_IDETIM_TIME(drive), channel);
|
|
if (drvp->PIO_mode >= 3) {
|
|
ret = PIIX_IDETIM_SET(ret, PIIX_IDETIM_IE(drive), channel);
|
|
ret = PIIX_IDETIM_SET(ret, PIIX_IDETIM_PPE(drive), channel);
|
|
}
|
|
return (ret);
|
|
}
|
|
|
|
/* setup values in SIDETIM registers, based on mode */
|
|
u_int32_t
|
|
piix_setup_sidetim_timings(u_int8_t mode, u_int8_t dma, u_int8_t channel)
|
|
{
|
|
if (dma)
|
|
return (PIIX_SIDETIM_ISP_SET(piix_isp_dma[mode], channel) |
|
|
PIIX_SIDETIM_RTC_SET(piix_rtc_dma[mode], channel));
|
|
else
|
|
return (PIIX_SIDETIM_ISP_SET(piix_isp_pio[mode], channel) |
|
|
PIIX_SIDETIM_RTC_SET(piix_rtc_pio[mode], channel));
|
|
}
|
|
|
|
void
|
|
amd756_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_channel *cp;
|
|
pcireg_t interface = PCI_INTERFACE(pa->pa_class);
|
|
int channel;
|
|
pcireg_t chanenable;
|
|
bus_size_t cmdsize, ctlsize;
|
|
|
|
printf(": DMA");
|
|
pciide_mapreg_dma(sc, pa);
|
|
sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
|
|
WDC_CAPABILITY_MODE;
|
|
if (sc->sc_dma_ok) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_UDMA;
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_IRQACK;
|
|
sc->sc_wdcdev.irqack = pciide_irqack;
|
|
}
|
|
sc->sc_wdcdev.PIO_cap = 4;
|
|
sc->sc_wdcdev.DMA_cap = 2;
|
|
switch (sc->sc_pp->ide_product) {
|
|
case PCI_PRODUCT_AMD_8111_IDE:
|
|
sc->sc_wdcdev.UDMA_cap = 6;
|
|
break;
|
|
case PCI_PRODUCT_AMD_766_IDE:
|
|
case PCI_PRODUCT_AMD_PBC768_IDE:
|
|
sc->sc_wdcdev.UDMA_cap = 5;
|
|
break;
|
|
default:
|
|
sc->sc_wdcdev.UDMA_cap = 4;
|
|
break;
|
|
}
|
|
sc->sc_wdcdev.set_modes = amd756_setup_channel;
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
|
|
chanenable = pci_conf_read(sc->sc_pc, sc->sc_tag, AMD756_CHANSTATUS_EN);
|
|
|
|
pciide_print_channels(sc->sc_wdcdev.nchannels, interface);
|
|
|
|
for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
|
|
cp = &sc->pciide_channels[channel];
|
|
if (pciide_chansetup(sc, channel, interface) == 0)
|
|
continue;
|
|
|
|
if ((chanenable & AMD756_CHAN_EN(channel)) == 0) {
|
|
printf("%s: %s ignored (disabled)\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
|
|
cp->hw_ok = 0;
|
|
continue;
|
|
}
|
|
pciide_map_compat_intr(pa, cp, channel, interface);
|
|
if (cp->hw_ok == 0)
|
|
continue;
|
|
|
|
pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
|
|
pciide_pci_intr);
|
|
|
|
if (pciide_chan_candisable(cp)) {
|
|
chanenable &= ~AMD756_CHAN_EN(channel);
|
|
}
|
|
if (cp->hw_ok == 0) {
|
|
pciide_unmap_compat_intr(pa, cp, channel, interface);
|
|
continue;
|
|
}
|
|
|
|
amd756_setup_channel(&cp->wdc_channel);
|
|
}
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, AMD756_CHANSTATUS_EN,
|
|
chanenable);
|
|
return;
|
|
}
|
|
|
|
void
|
|
amd756_setup_channel(struct channel_softc *chp)
|
|
{
|
|
u_int32_t udmatim_reg, datatim_reg;
|
|
u_int8_t idedma_ctl;
|
|
int mode, drive;
|
|
struct ata_drive_datas *drvp;
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
pcireg_t chanenable;
|
|
#ifndef PCIIDE_AMD756_ENABLEDMA
|
|
int product = sc->sc_pp->ide_product;
|
|
int rev = sc->sc_rev;
|
|
#endif
|
|
|
|
idedma_ctl = 0;
|
|
datatim_reg = pci_conf_read(sc->sc_pc, sc->sc_tag, AMD756_DATATIM);
|
|
udmatim_reg = pci_conf_read(sc->sc_pc, sc->sc_tag, AMD756_UDMA);
|
|
datatim_reg &= ~AMD756_DATATIM_MASK(chp->channel);
|
|
udmatim_reg &= ~AMD756_UDMA_MASK(chp->channel);
|
|
chanenable = pci_conf_read(sc->sc_pc, sc->sc_tag,
|
|
AMD756_CHANSTATUS_EN);
|
|
|
|
/* setup DMA if needed */
|
|
pciide_channel_dma_setup(cp);
|
|
|
|
for (drive = 0; drive < 2; drive++) {
|
|
drvp = &chp->ch_drive[drive];
|
|
/* If no drive, skip */
|
|
if ((drvp->drive_flags & DRIVE) == 0)
|
|
continue;
|
|
/* add timing values, setup DMA if needed */
|
|
if (((drvp->drive_flags & DRIVE_DMA) == 0 &&
|
|
(drvp->drive_flags & DRIVE_UDMA) == 0)) {
|
|
mode = drvp->PIO_mode;
|
|
goto pio;
|
|
}
|
|
if ((chp->wdc->cap & WDC_CAPABILITY_UDMA) &&
|
|
(drvp->drive_flags & DRIVE_UDMA)) {
|
|
/* use Ultra/DMA */
|
|
drvp->drive_flags &= ~DRIVE_DMA;
|
|
|
|
/* Check cable */
|
|
if ((chanenable & AMD756_CABLE(chp->channel,
|
|
drive)) == 0 && drvp->UDMA_mode > 2) {
|
|
WDCDEBUG_PRINT(("%s(%s:%d:%d): 80-wire "
|
|
"cable not detected\n", drvp->drive_name,
|
|
sc->sc_wdcdev.sc_dev.dv_xname,
|
|
chp->channel, drive), DEBUG_PROBE);
|
|
drvp->UDMA_mode = 2;
|
|
}
|
|
|
|
udmatim_reg |= AMD756_UDMA_EN(chp->channel, drive) |
|
|
AMD756_UDMA_EN_MTH(chp->channel, drive) |
|
|
AMD756_UDMA_TIME(chp->channel, drive,
|
|
amd756_udma_tim[drvp->UDMA_mode]);
|
|
/* can use PIO timings, MW DMA unused */
|
|
mode = drvp->PIO_mode;
|
|
} else {
|
|
/* use Multiword DMA, but only if revision is OK */
|
|
drvp->drive_flags &= ~DRIVE_UDMA;
|
|
#ifndef PCIIDE_AMD756_ENABLEDMA
|
|
/*
|
|
* The workaround doesn't seem to be necessary
|
|
* with all drives, so it can be disabled by
|
|
* PCIIDE_AMD756_ENABLEDMA. It causes a hard hang if
|
|
* triggered.
|
|
*/
|
|
if (AMD756_CHIPREV_DISABLEDMA(product, rev)) {
|
|
printf("%s:%d:%d: multi-word DMA disabled due "
|
|
"to chip revision\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname,
|
|
chp->channel, drive);
|
|
mode = drvp->PIO_mode;
|
|
drvp->drive_flags &= ~DRIVE_DMA;
|
|
goto pio;
|
|
}
|
|
#endif
|
|
/* mode = min(pio, dma+2) */
|
|
if (drvp->PIO_mode <= (drvp->DMA_mode +2))
|
|
mode = drvp->PIO_mode;
|
|
else
|
|
mode = drvp->DMA_mode + 2;
|
|
}
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
|
|
pio: /* setup PIO mode */
|
|
if (mode <= 2) {
|
|
drvp->DMA_mode = 0;
|
|
drvp->PIO_mode = 0;
|
|
mode = 0;
|
|
} else {
|
|
drvp->PIO_mode = mode;
|
|
drvp->DMA_mode = mode - 2;
|
|
}
|
|
datatim_reg |=
|
|
AMD756_DATATIM_PULSE(chp->channel, drive,
|
|
amd756_pio_set[mode]) |
|
|
AMD756_DATATIM_RECOV(chp->channel, drive,
|
|
amd756_pio_rec[mode]);
|
|
}
|
|
if (idedma_ctl != 0) {
|
|
/* Add software bits in status register */
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(chp->channel),
|
|
idedma_ctl);
|
|
}
|
|
pciide_print_modes(cp);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, AMD756_DATATIM, datatim_reg);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, AMD756_UDMA, udmatim_reg);
|
|
}
|
|
|
|
void
|
|
apollo_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_channel *cp;
|
|
pcireg_t interface;
|
|
int no_ideconf = 0, channel;
|
|
u_int32_t ideconf;
|
|
bus_size_t cmdsize, ctlsize;
|
|
pcitag_t tag;
|
|
pcireg_t id, class;
|
|
|
|
/*
|
|
* Fake interface since VT6410 is claimed to be a ``RAID'' device.
|
|
*/
|
|
if (PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_IDE) {
|
|
interface = PCI_INTERFACE(pa->pa_class);
|
|
} else {
|
|
interface = PCIIDE_INTERFACE_BUS_MASTER_DMA |
|
|
PCIIDE_INTERFACE_PCI(0) | PCIIDE_INTERFACE_PCI(1);
|
|
}
|
|
|
|
switch (PCI_PRODUCT(pa->pa_id)) {
|
|
case PCI_PRODUCT_VIATECH_VT6410:
|
|
case PCI_PRODUCT_VIATECH_VT6415:
|
|
no_ideconf = 1;
|
|
/* FALLTHROUGH */
|
|
case PCI_PRODUCT_VIATECH_CX700_IDE:
|
|
case PCI_PRODUCT_VIATECH_VX700_IDE:
|
|
case PCI_PRODUCT_VIATECH_VX855_IDE:
|
|
case PCI_PRODUCT_VIATECH_VX900_IDE:
|
|
printf(": ATA133");
|
|
sc->sc_wdcdev.UDMA_cap = 6;
|
|
break;
|
|
default:
|
|
/*
|
|
* Determine the DMA capabilities by looking at the
|
|
* ISA bridge.
|
|
*/
|
|
tag = pci_make_tag(pa->pa_pc, pa->pa_bus, pa->pa_device, 0);
|
|
id = pci_conf_read(sc->sc_pc, tag, PCI_ID_REG);
|
|
class = pci_conf_read(sc->sc_pc, tag, PCI_CLASS_REG);
|
|
|
|
/*
|
|
* XXX On the VT8237, the ISA bridge is on a different
|
|
* device.
|
|
*/
|
|
if (PCI_CLASS(class) != PCI_CLASS_BRIDGE &&
|
|
pa->pa_device == 15) {
|
|
tag = pci_make_tag(pa->pa_pc, pa->pa_bus, 17, 0);
|
|
id = pci_conf_read(sc->sc_pc, tag, PCI_ID_REG);
|
|
class = pci_conf_read(sc->sc_pc, tag, PCI_CLASS_REG);
|
|
}
|
|
|
|
switch (PCI_PRODUCT(id)) {
|
|
case PCI_PRODUCT_VIATECH_VT82C586_ISA:
|
|
if (PCI_REVISION(class) >= 0x02) {
|
|
printf(": ATA33");
|
|
sc->sc_wdcdev.UDMA_cap = 2;
|
|
} else {
|
|
printf(": DMA");
|
|
sc->sc_wdcdev.UDMA_cap = 0;
|
|
}
|
|
break;
|
|
case PCI_PRODUCT_VIATECH_VT82C596A:
|
|
if (PCI_REVISION(class) >= 0x12) {
|
|
printf(": ATA66");
|
|
sc->sc_wdcdev.UDMA_cap = 4;
|
|
} else {
|
|
printf(": ATA33");
|
|
sc->sc_wdcdev.UDMA_cap = 2;
|
|
}
|
|
break;
|
|
|
|
case PCI_PRODUCT_VIATECH_VT82C686A_ISA:
|
|
if (PCI_REVISION(class) >= 0x40) {
|
|
printf(": ATA100");
|
|
sc->sc_wdcdev.UDMA_cap = 5;
|
|
} else {
|
|
printf(": ATA66");
|
|
sc->sc_wdcdev.UDMA_cap = 4;
|
|
}
|
|
break;
|
|
case PCI_PRODUCT_VIATECH_VT8231_ISA:
|
|
case PCI_PRODUCT_VIATECH_VT8233_ISA:
|
|
printf(": ATA100");
|
|
sc->sc_wdcdev.UDMA_cap = 5;
|
|
break;
|
|
case PCI_PRODUCT_VIATECH_VT8233A_ISA:
|
|
case PCI_PRODUCT_VIATECH_VT8235_ISA:
|
|
case PCI_PRODUCT_VIATECH_VT8237_ISA:
|
|
printf(": ATA133");
|
|
sc->sc_wdcdev.UDMA_cap = 6;
|
|
break;
|
|
default:
|
|
printf(": DMA");
|
|
sc->sc_wdcdev.UDMA_cap = 0;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
pciide_mapreg_dma(sc, pa);
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
|
|
WDC_CAPABILITY_MODE;
|
|
if (sc->sc_dma_ok) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_IRQACK;
|
|
sc->sc_wdcdev.irqack = pciide_irqack;
|
|
if (sc->sc_wdcdev.UDMA_cap > 0)
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_UDMA;
|
|
}
|
|
sc->sc_wdcdev.PIO_cap = 4;
|
|
sc->sc_wdcdev.DMA_cap = 2;
|
|
sc->sc_wdcdev.set_modes = apollo_setup_channel;
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
|
|
|
|
pciide_print_channels(sc->sc_wdcdev.nchannels, interface);
|
|
|
|
WDCDEBUG_PRINT(("apollo_chip_map: old APO_IDECONF=0x%x, "
|
|
"APO_CTLMISC=0x%x, APO_DATATIM=0x%x, APO_UDMA=0x%x\n",
|
|
pci_conf_read(sc->sc_pc, sc->sc_tag, APO_IDECONF),
|
|
pci_conf_read(sc->sc_pc, sc->sc_tag, APO_CTLMISC),
|
|
pci_conf_read(sc->sc_pc, sc->sc_tag, APO_DATATIM),
|
|
pci_conf_read(sc->sc_pc, sc->sc_tag, APO_UDMA)),
|
|
DEBUG_PROBE);
|
|
|
|
for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
|
|
cp = &sc->pciide_channels[channel];
|
|
if (pciide_chansetup(sc, channel, interface) == 0)
|
|
continue;
|
|
|
|
if (no_ideconf == 0) {
|
|
ideconf = pci_conf_read(sc->sc_pc, sc->sc_tag,
|
|
APO_IDECONF);
|
|
if ((ideconf & APO_IDECONF_EN(channel)) == 0) {
|
|
printf("%s: %s ignored (disabled)\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
|
|
cp->hw_ok = 0;
|
|
continue;
|
|
}
|
|
}
|
|
pciide_map_compat_intr(pa, cp, channel, interface);
|
|
if (cp->hw_ok == 0)
|
|
continue;
|
|
|
|
pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
|
|
pciide_pci_intr);
|
|
if (cp->hw_ok == 0) {
|
|
goto next;
|
|
}
|
|
if (pciide_chan_candisable(cp)) {
|
|
if (no_ideconf == 0) {
|
|
ideconf &= ~APO_IDECONF_EN(channel);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag,
|
|
APO_IDECONF, ideconf);
|
|
}
|
|
}
|
|
|
|
if (cp->hw_ok == 0)
|
|
goto next;
|
|
apollo_setup_channel(&sc->pciide_channels[channel].wdc_channel);
|
|
next:
|
|
if (cp->hw_ok == 0)
|
|
pciide_unmap_compat_intr(pa, cp, channel, interface);
|
|
}
|
|
WDCDEBUG_PRINT(("apollo_chip_map: APO_DATATIM=0x%x, APO_UDMA=0x%x\n",
|
|
pci_conf_read(sc->sc_pc, sc->sc_tag, APO_DATATIM),
|
|
pci_conf_read(sc->sc_pc, sc->sc_tag, APO_UDMA)), DEBUG_PROBE);
|
|
}
|
|
|
|
void
|
|
apollo_setup_channel(struct channel_softc *chp)
|
|
{
|
|
u_int32_t udmatim_reg, datatim_reg;
|
|
u_int8_t idedma_ctl;
|
|
int mode, drive;
|
|
struct ata_drive_datas *drvp;
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
|
|
idedma_ctl = 0;
|
|
datatim_reg = pci_conf_read(sc->sc_pc, sc->sc_tag, APO_DATATIM);
|
|
udmatim_reg = pci_conf_read(sc->sc_pc, sc->sc_tag, APO_UDMA);
|
|
datatim_reg &= ~APO_DATATIM_MASK(chp->channel);
|
|
udmatim_reg &= ~APO_UDMA_MASK(chp->channel);
|
|
|
|
/* setup DMA if needed */
|
|
pciide_channel_dma_setup(cp);
|
|
|
|
/*
|
|
* We can't mix Ultra/33 and Ultra/66 on the same channel, so
|
|
* downgrade to Ultra/33 if needed
|
|
*/
|
|
if ((chp->ch_drive[0].drive_flags & DRIVE_UDMA) &&
|
|
(chp->ch_drive[1].drive_flags & DRIVE_UDMA)) {
|
|
/* both drives UDMA */
|
|
if (chp->ch_drive[0].UDMA_mode > 2 &&
|
|
chp->ch_drive[1].UDMA_mode <= 2) {
|
|
/* drive 0 Ultra/66, drive 1 Ultra/33 */
|
|
chp->ch_drive[0].UDMA_mode = 2;
|
|
} else if (chp->ch_drive[1].UDMA_mode > 2 &&
|
|
chp->ch_drive[0].UDMA_mode <= 2) {
|
|
/* drive 1 Ultra/66, drive 0 Ultra/33 */
|
|
chp->ch_drive[1].UDMA_mode = 2;
|
|
}
|
|
}
|
|
|
|
for (drive = 0; drive < 2; drive++) {
|
|
drvp = &chp->ch_drive[drive];
|
|
/* If no drive, skip */
|
|
if ((drvp->drive_flags & DRIVE) == 0)
|
|
continue;
|
|
/* add timing values, setup DMA if needed */
|
|
if (((drvp->drive_flags & DRIVE_DMA) == 0 &&
|
|
(drvp->drive_flags & DRIVE_UDMA) == 0)) {
|
|
mode = drvp->PIO_mode;
|
|
goto pio;
|
|
}
|
|
if ((chp->wdc->cap & WDC_CAPABILITY_UDMA) &&
|
|
(drvp->drive_flags & DRIVE_UDMA)) {
|
|
/* use Ultra/DMA */
|
|
drvp->drive_flags &= ~DRIVE_DMA;
|
|
udmatim_reg |= APO_UDMA_EN(chp->channel, drive) |
|
|
APO_UDMA_EN_MTH(chp->channel, drive);
|
|
if (sc->sc_wdcdev.UDMA_cap == 6) {
|
|
udmatim_reg |= APO_UDMA_TIME(chp->channel,
|
|
drive, apollo_udma133_tim[drvp->UDMA_mode]);
|
|
} else if (sc->sc_wdcdev.UDMA_cap == 5) {
|
|
/* 686b */
|
|
udmatim_reg |= APO_UDMA_TIME(chp->channel,
|
|
drive, apollo_udma100_tim[drvp->UDMA_mode]);
|
|
} else if (sc->sc_wdcdev.UDMA_cap == 4) {
|
|
/* 596b or 686a */
|
|
udmatim_reg |= APO_UDMA_CLK66(chp->channel);
|
|
udmatim_reg |= APO_UDMA_TIME(chp->channel,
|
|
drive, apollo_udma66_tim[drvp->UDMA_mode]);
|
|
} else {
|
|
/* 596a or 586b */
|
|
udmatim_reg |= APO_UDMA_TIME(chp->channel,
|
|
drive, apollo_udma33_tim[drvp->UDMA_mode]);
|
|
}
|
|
/* can use PIO timings, MW DMA unused */
|
|
mode = drvp->PIO_mode;
|
|
} else {
|
|
/* use Multiword DMA */
|
|
drvp->drive_flags &= ~DRIVE_UDMA;
|
|
/* mode = min(pio, dma+2) */
|
|
if (drvp->PIO_mode <= (drvp->DMA_mode +2))
|
|
mode = drvp->PIO_mode;
|
|
else
|
|
mode = drvp->DMA_mode + 2;
|
|
}
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
|
|
pio: /* setup PIO mode */
|
|
if (mode <= 2) {
|
|
drvp->DMA_mode = 0;
|
|
drvp->PIO_mode = 0;
|
|
mode = 0;
|
|
} else {
|
|
drvp->PIO_mode = mode;
|
|
drvp->DMA_mode = mode - 2;
|
|
}
|
|
datatim_reg |=
|
|
APO_DATATIM_PULSE(chp->channel, drive,
|
|
apollo_pio_set[mode]) |
|
|
APO_DATATIM_RECOV(chp->channel, drive,
|
|
apollo_pio_rec[mode]);
|
|
}
|
|
if (idedma_ctl != 0) {
|
|
/* Add software bits in status register */
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(chp->channel),
|
|
idedma_ctl);
|
|
}
|
|
pciide_print_modes(cp);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, APO_DATATIM, datatim_reg);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, APO_UDMA, udmatim_reg);
|
|
}
|
|
|
|
void
|
|
cmd_channel_map(struct pci_attach_args *pa, struct pciide_softc *sc,
|
|
int channel)
|
|
{
|
|
struct pciide_channel *cp = &sc->pciide_channels[channel];
|
|
bus_size_t cmdsize, ctlsize;
|
|
u_int8_t ctrl = pciide_pci_read(sc->sc_pc, sc->sc_tag, CMD_CTRL);
|
|
pcireg_t interface;
|
|
int one_channel;
|
|
|
|
/*
|
|
* The 0648/0649 can be told to identify as a RAID controller.
|
|
* In this case, we have to fake interface
|
|
*/
|
|
if (PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_MASS_STORAGE_IDE) {
|
|
interface = PCIIDE_INTERFACE_SETTABLE(0) |
|
|
PCIIDE_INTERFACE_SETTABLE(1);
|
|
if (pciide_pci_read(pa->pa_pc, pa->pa_tag, CMD_CONF) &
|
|
CMD_CONF_DSA1)
|
|
interface |= PCIIDE_INTERFACE_PCI(0) |
|
|
PCIIDE_INTERFACE_PCI(1);
|
|
} else {
|
|
interface = PCI_INTERFACE(pa->pa_class);
|
|
}
|
|
|
|
sc->wdc_chanarray[channel] = &cp->wdc_channel;
|
|
cp->name = PCIIDE_CHANNEL_NAME(channel);
|
|
cp->wdc_channel.channel = channel;
|
|
cp->wdc_channel.wdc = &sc->sc_wdcdev;
|
|
|
|
/*
|
|
* Older CMD64X doesn't have independent channels
|
|
*/
|
|
switch (sc->sc_pp->ide_product) {
|
|
case PCI_PRODUCT_CMDTECH_649:
|
|
one_channel = 0;
|
|
break;
|
|
default:
|
|
one_channel = 1;
|
|
break;
|
|
}
|
|
|
|
if (channel > 0 && one_channel) {
|
|
cp->wdc_channel.ch_queue =
|
|
sc->pciide_channels[0].wdc_channel.ch_queue;
|
|
} else {
|
|
cp->wdc_channel.ch_queue = wdc_alloc_queue();
|
|
}
|
|
if (cp->wdc_channel.ch_queue == NULL) {
|
|
printf(
|
|
"%s: %s cannot allocate channel queue",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* with a CMD PCI64x, if we get here, the first channel is enabled:
|
|
* there's no way to disable the first channel without disabling
|
|
* the whole device
|
|
*/
|
|
if (channel != 0 && (ctrl & CMD_CTRL_2PORT) == 0) {
|
|
printf("%s: %s ignored (disabled)\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
|
|
cp->hw_ok = 0;
|
|
return;
|
|
}
|
|
cp->hw_ok = 1;
|
|
pciide_map_compat_intr(pa, cp, channel, interface);
|
|
if (cp->hw_ok == 0)
|
|
return;
|
|
pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize, cmd_pci_intr);
|
|
if (cp->hw_ok == 0) {
|
|
pciide_unmap_compat_intr(pa, cp, channel, interface);
|
|
return;
|
|
}
|
|
if (pciide_chan_candisable(cp)) {
|
|
if (channel == 1) {
|
|
ctrl &= ~CMD_CTRL_2PORT;
|
|
pciide_pci_write(pa->pa_pc, pa->pa_tag,
|
|
CMD_CTRL, ctrl);
|
|
pciide_unmap_compat_intr(pa, cp, channel, interface);
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
cmd_pci_intr(void *arg)
|
|
{
|
|
struct pciide_softc *sc = arg;
|
|
struct pciide_channel *cp;
|
|
struct channel_softc *wdc_cp;
|
|
int i, rv, crv;
|
|
u_int32_t priirq, secirq;
|
|
|
|
rv = 0;
|
|
priirq = pciide_pci_read(sc->sc_pc, sc->sc_tag, CMD_CONF);
|
|
secirq = pciide_pci_read(sc->sc_pc, sc->sc_tag, CMD_ARTTIM23);
|
|
for (i = 0; i < sc->sc_wdcdev.nchannels; i++) {
|
|
cp = &sc->pciide_channels[i];
|
|
wdc_cp = &cp->wdc_channel;
|
|
/* If a compat channel skip. */
|
|
if (cp->compat)
|
|
continue;
|
|
if ((i == 0 && (priirq & CMD_CONF_DRV0_INTR)) ||
|
|
(i == 1 && (secirq & CMD_ARTTIM23_IRQ))) {
|
|
crv = wdcintr(wdc_cp);
|
|
if (crv == 0) {
|
|
#if 0
|
|
printf("%s:%d: bogus intr\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, i);
|
|
#endif
|
|
} else
|
|
rv = 1;
|
|
}
|
|
}
|
|
return (rv);
|
|
}
|
|
|
|
void
|
|
cmd_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
int channel;
|
|
pcireg_t interface = PCI_INTERFACE(pa->pa_class);
|
|
|
|
printf(": no DMA");
|
|
sc->sc_dma_ok = 0;
|
|
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
|
|
sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16;
|
|
|
|
pciide_print_channels(sc->sc_wdcdev.nchannels, interface);
|
|
|
|
for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
|
|
cmd_channel_map(pa, sc, channel);
|
|
}
|
|
}
|
|
|
|
void
|
|
cmd0643_9_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_channel *cp;
|
|
int channel;
|
|
int rev = sc->sc_rev;
|
|
pcireg_t interface;
|
|
|
|
/*
|
|
* The 0648/0649 can be told to identify as a RAID controller.
|
|
* In this case, we have to fake interface
|
|
*/
|
|
if (PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_MASS_STORAGE_IDE) {
|
|
interface = PCIIDE_INTERFACE_SETTABLE(0) |
|
|
PCIIDE_INTERFACE_SETTABLE(1);
|
|
if (pciide_pci_read(pa->pa_pc, pa->pa_tag, CMD_CONF) &
|
|
CMD_CONF_DSA1)
|
|
interface |= PCIIDE_INTERFACE_PCI(0) |
|
|
PCIIDE_INTERFACE_PCI(1);
|
|
} else {
|
|
interface = PCI_INTERFACE(pa->pa_class);
|
|
}
|
|
|
|
printf(": DMA");
|
|
pciide_mapreg_dma(sc, pa);
|
|
sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
|
|
WDC_CAPABILITY_MODE;
|
|
if (sc->sc_dma_ok) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_IRQACK;
|
|
switch (sc->sc_pp->ide_product) {
|
|
case PCI_PRODUCT_CMDTECH_649:
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_UDMA;
|
|
sc->sc_wdcdev.UDMA_cap = 5;
|
|
sc->sc_wdcdev.irqack = cmd646_9_irqack;
|
|
break;
|
|
case PCI_PRODUCT_CMDTECH_648:
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_UDMA;
|
|
sc->sc_wdcdev.UDMA_cap = 4;
|
|
sc->sc_wdcdev.irqack = cmd646_9_irqack;
|
|
break;
|
|
case PCI_PRODUCT_CMDTECH_646:
|
|
if (rev >= CMD0646U2_REV) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_UDMA;
|
|
sc->sc_wdcdev.UDMA_cap = 2;
|
|
} else if (rev >= CMD0646U_REV) {
|
|
/*
|
|
* Linux's driver claims that the 646U is broken
|
|
* with UDMA. Only enable it if we know what we're
|
|
* doing
|
|
*/
|
|
#ifdef PCIIDE_CMD0646U_ENABLEUDMA
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_UDMA;
|
|
sc->sc_wdcdev.UDMA_cap = 2;
|
|
#endif
|
|
/* explicitly disable UDMA */
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag,
|
|
CMD_UDMATIM(0), 0);
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag,
|
|
CMD_UDMATIM(1), 0);
|
|
}
|
|
sc->sc_wdcdev.irqack = cmd646_9_irqack;
|
|
break;
|
|
default:
|
|
sc->sc_wdcdev.irqack = pciide_irqack;
|
|
}
|
|
}
|
|
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
|
|
sc->sc_wdcdev.PIO_cap = 4;
|
|
sc->sc_wdcdev.DMA_cap = 2;
|
|
sc->sc_wdcdev.set_modes = cmd0643_9_setup_channel;
|
|
|
|
pciide_print_channels(sc->sc_wdcdev.nchannels, interface);
|
|
|
|
WDCDEBUG_PRINT(("cmd0643_9_chip_map: old timings reg 0x%x 0x%x\n",
|
|
pci_conf_read(sc->sc_pc, sc->sc_tag, 0x54),
|
|
pci_conf_read(sc->sc_pc, sc->sc_tag, 0x58)),
|
|
DEBUG_PROBE);
|
|
for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
|
|
cp = &sc->pciide_channels[channel];
|
|
cmd_channel_map(pa, sc, channel);
|
|
if (cp->hw_ok == 0)
|
|
continue;
|
|
cmd0643_9_setup_channel(&cp->wdc_channel);
|
|
}
|
|
/*
|
|
* note - this also makes sure we clear the irq disable and reset
|
|
* bits
|
|
*/
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag, CMD_DMA_MODE, CMD_DMA_MULTIPLE);
|
|
WDCDEBUG_PRINT(("cmd0643_9_chip_map: timings reg now 0x%x 0x%x\n",
|
|
pci_conf_read(sc->sc_pc, sc->sc_tag, 0x54),
|
|
pci_conf_read(sc->sc_pc, sc->sc_tag, 0x58)),
|
|
DEBUG_PROBE);
|
|
}
|
|
|
|
void
|
|
cmd0643_9_setup_channel(struct channel_softc *chp)
|
|
{
|
|
struct ata_drive_datas *drvp;
|
|
u_int8_t tim;
|
|
u_int32_t idedma_ctl, udma_reg;
|
|
int drive;
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
|
|
idedma_ctl = 0;
|
|
/* setup DMA if needed */
|
|
pciide_channel_dma_setup(cp);
|
|
|
|
for (drive = 0; drive < 2; drive++) {
|
|
drvp = &chp->ch_drive[drive];
|
|
/* If no drive, skip */
|
|
if ((drvp->drive_flags & DRIVE) == 0)
|
|
continue;
|
|
/* add timing values, setup DMA if needed */
|
|
tim = cmd0643_9_data_tim_pio[drvp->PIO_mode];
|
|
if (drvp->drive_flags & (DRIVE_DMA | DRIVE_UDMA)) {
|
|
if (drvp->drive_flags & DRIVE_UDMA) {
|
|
/* UltraDMA on a 646U2, 0648 or 0649 */
|
|
drvp->drive_flags &= ~DRIVE_DMA;
|
|
udma_reg = pciide_pci_read(sc->sc_pc,
|
|
sc->sc_tag, CMD_UDMATIM(chp->channel));
|
|
if (drvp->UDMA_mode > 2 &&
|
|
(pciide_pci_read(sc->sc_pc, sc->sc_tag,
|
|
CMD_BICSR) &
|
|
CMD_BICSR_80(chp->channel)) == 0) {
|
|
WDCDEBUG_PRINT(("%s(%s:%d:%d): "
|
|
"80-wire cable not detected\n",
|
|
drvp->drive_name,
|
|
sc->sc_wdcdev.sc_dev.dv_xname,
|
|
chp->channel, drive), DEBUG_PROBE);
|
|
drvp->UDMA_mode = 2;
|
|
}
|
|
if (drvp->UDMA_mode > 2)
|
|
udma_reg &= ~CMD_UDMATIM_UDMA33(drive);
|
|
else if (sc->sc_wdcdev.UDMA_cap > 2)
|
|
udma_reg |= CMD_UDMATIM_UDMA33(drive);
|
|
udma_reg |= CMD_UDMATIM_UDMA(drive);
|
|
udma_reg &= ~(CMD_UDMATIM_TIM_MASK <<
|
|
CMD_UDMATIM_TIM_OFF(drive));
|
|
udma_reg |=
|
|
(cmd0646_9_tim_udma[drvp->UDMA_mode] <<
|
|
CMD_UDMATIM_TIM_OFF(drive));
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag,
|
|
CMD_UDMATIM(chp->channel), udma_reg);
|
|
} else {
|
|
/*
|
|
* use Multiword DMA.
|
|
* Timings will be used for both PIO and DMA,
|
|
* so adjust DMA mode if needed
|
|
* if we have a 0646U2/8/9, turn off UDMA
|
|
*/
|
|
if (sc->sc_wdcdev.cap & WDC_CAPABILITY_UDMA) {
|
|
udma_reg = pciide_pci_read(sc->sc_pc,
|
|
sc->sc_tag,
|
|
CMD_UDMATIM(chp->channel));
|
|
udma_reg &= ~CMD_UDMATIM_UDMA(drive);
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag,
|
|
CMD_UDMATIM(chp->channel),
|
|
udma_reg);
|
|
}
|
|
if (drvp->PIO_mode >= 3 &&
|
|
(drvp->DMA_mode + 2) > drvp->PIO_mode) {
|
|
drvp->DMA_mode = drvp->PIO_mode - 2;
|
|
}
|
|
tim = cmd0643_9_data_tim_dma[drvp->DMA_mode];
|
|
}
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
}
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag,
|
|
CMD_DATA_TIM(chp->channel, drive), tim);
|
|
}
|
|
if (idedma_ctl != 0) {
|
|
/* Add software bits in status register */
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(chp->channel),
|
|
idedma_ctl);
|
|
}
|
|
pciide_print_modes(cp);
|
|
#ifdef __sparc64__
|
|
/*
|
|
* The Ultra 5 has a tendency to hang during reboot. This is due
|
|
* to the PCI0646U asserting a PCI interrupt line when the chip
|
|
* registers claim that it is not. Performing a reset at this
|
|
* point appears to eliminate the symptoms. It is likely the
|
|
* real cause is still lurking somewhere in the code.
|
|
*/
|
|
wdcreset(chp, SILENT);
|
|
#endif /* __sparc64__ */
|
|
}
|
|
|
|
void
|
|
cmd646_9_irqack(struct channel_softc *chp)
|
|
{
|
|
u_int32_t priirq, secirq;
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
|
|
if (chp->channel == 0) {
|
|
priirq = pciide_pci_read(sc->sc_pc, sc->sc_tag, CMD_CONF);
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag, CMD_CONF, priirq);
|
|
} else {
|
|
secirq = pciide_pci_read(sc->sc_pc, sc->sc_tag, CMD_ARTTIM23);
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag, CMD_ARTTIM23, secirq);
|
|
}
|
|
pciide_irqack(chp);
|
|
}
|
|
|
|
void
|
|
cmd680_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_channel *cp;
|
|
int channel;
|
|
|
|
printf("\n%s: bus-master DMA support present",
|
|
sc->sc_wdcdev.sc_dev.dv_xname);
|
|
pciide_mapreg_dma(sc, pa);
|
|
printf("\n");
|
|
sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
|
|
WDC_CAPABILITY_MODE;
|
|
if (sc->sc_dma_ok) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_IRQACK;
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_UDMA;
|
|
sc->sc_wdcdev.UDMA_cap = 6;
|
|
sc->sc_wdcdev.irqack = pciide_irqack;
|
|
}
|
|
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
|
|
sc->sc_wdcdev.PIO_cap = 4;
|
|
sc->sc_wdcdev.DMA_cap = 2;
|
|
sc->sc_wdcdev.set_modes = cmd680_setup_channel;
|
|
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag, 0x80, 0x00);
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag, 0x84, 0x00);
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag, 0x8a,
|
|
pciide_pci_read(sc->sc_pc, sc->sc_tag, 0x8a) | 0x01);
|
|
for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
|
|
cp = &sc->pciide_channels[channel];
|
|
cmd680_channel_map(pa, sc, channel);
|
|
if (cp->hw_ok == 0)
|
|
continue;
|
|
cmd680_setup_channel(&cp->wdc_channel);
|
|
}
|
|
}
|
|
|
|
void
|
|
cmd680_channel_map(struct pci_attach_args *pa, struct pciide_softc *sc,
|
|
int channel)
|
|
{
|
|
struct pciide_channel *cp = &sc->pciide_channels[channel];
|
|
bus_size_t cmdsize, ctlsize;
|
|
int interface, i, reg;
|
|
static const u_int8_t init_val[] =
|
|
{ 0x8a, 0x32, 0x8a, 0x32, 0x8a, 0x32,
|
|
0x92, 0x43, 0x92, 0x43, 0x09, 0x40, 0x09, 0x40 };
|
|
|
|
if (PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_MASS_STORAGE_IDE) {
|
|
interface = PCIIDE_INTERFACE_SETTABLE(0) |
|
|
PCIIDE_INTERFACE_SETTABLE(1);
|
|
interface |= PCIIDE_INTERFACE_PCI(0) |
|
|
PCIIDE_INTERFACE_PCI(1);
|
|
} else {
|
|
interface = PCI_INTERFACE(pa->pa_class);
|
|
}
|
|
|
|
sc->wdc_chanarray[channel] = &cp->wdc_channel;
|
|
cp->name = PCIIDE_CHANNEL_NAME(channel);
|
|
cp->wdc_channel.channel = channel;
|
|
cp->wdc_channel.wdc = &sc->sc_wdcdev;
|
|
|
|
cp->wdc_channel.ch_queue = wdc_alloc_queue();
|
|
if (cp->wdc_channel.ch_queue == NULL) {
|
|
printf("%s %s: "
|
|
"cannot allocate channel queue",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
|
|
return;
|
|
}
|
|
|
|
/* XXX */
|
|
reg = 0xa2 + channel * 16;
|
|
for (i = 0; i < sizeof(init_val); i++)
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag, reg + i, init_val[i]);
|
|
|
|
printf("%s: %s %s to %s mode\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name,
|
|
(interface & PCIIDE_INTERFACE_SETTABLE(channel)) ?
|
|
"configured" : "wired",
|
|
(interface & PCIIDE_INTERFACE_PCI(channel)) ?
|
|
"native-PCI" : "compatibility");
|
|
|
|
pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize, pciide_pci_intr);
|
|
if (cp->hw_ok == 0)
|
|
return;
|
|
pciide_map_compat_intr(pa, cp, channel, interface);
|
|
}
|
|
|
|
void
|
|
cmd680_setup_channel(struct channel_softc *chp)
|
|
{
|
|
struct ata_drive_datas *drvp;
|
|
u_int8_t mode, off, scsc;
|
|
u_int16_t val;
|
|
u_int32_t idedma_ctl;
|
|
int drive;
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
pci_chipset_tag_t pc = sc->sc_pc;
|
|
pcitag_t pa = sc->sc_tag;
|
|
static const u_int8_t udma2_tbl[] =
|
|
{ 0x0f, 0x0b, 0x07, 0x06, 0x03, 0x02, 0x01 };
|
|
static const u_int8_t udma_tbl[] =
|
|
{ 0x0c, 0x07, 0x05, 0x04, 0x02, 0x01, 0x00 };
|
|
static const u_int16_t dma_tbl[] =
|
|
{ 0x2208, 0x10c2, 0x10c1 };
|
|
static const u_int16_t pio_tbl[] =
|
|
{ 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 };
|
|
|
|
idedma_ctl = 0;
|
|
pciide_channel_dma_setup(cp);
|
|
mode = pciide_pci_read(pc, pa, 0x80 + chp->channel * 4);
|
|
|
|
for (drive = 0; drive < 2; drive++) {
|
|
drvp = &chp->ch_drive[drive];
|
|
/* If no drive, skip */
|
|
if ((drvp->drive_flags & DRIVE) == 0)
|
|
continue;
|
|
mode &= ~(0x03 << (drive * 4));
|
|
if (drvp->drive_flags & DRIVE_UDMA) {
|
|
drvp->drive_flags &= ~DRIVE_DMA;
|
|
off = 0xa0 + chp->channel * 16;
|
|
if (drvp->UDMA_mode > 2 &&
|
|
(pciide_pci_read(pc, pa, off) & 0x01) == 0)
|
|
drvp->UDMA_mode = 2;
|
|
scsc = pciide_pci_read(pc, pa, 0x8a);
|
|
if (drvp->UDMA_mode == 6 && (scsc & 0x30) == 0) {
|
|
pciide_pci_write(pc, pa, 0x8a, scsc | 0x01);
|
|
scsc = pciide_pci_read(pc, pa, 0x8a);
|
|
if ((scsc & 0x30) == 0)
|
|
drvp->UDMA_mode = 5;
|
|
}
|
|
mode |= 0x03 << (drive * 4);
|
|
off = 0xac + chp->channel * 16 + drive * 2;
|
|
val = pciide_pci_read(pc, pa, off) & ~0x3f;
|
|
if (scsc & 0x30)
|
|
val |= udma2_tbl[drvp->UDMA_mode];
|
|
else
|
|
val |= udma_tbl[drvp->UDMA_mode];
|
|
pciide_pci_write(pc, pa, off, val);
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
} else if (drvp->drive_flags & DRIVE_DMA) {
|
|
mode |= 0x02 << (drive * 4);
|
|
off = 0xa8 + chp->channel * 16 + drive * 2;
|
|
val = dma_tbl[drvp->DMA_mode];
|
|
pciide_pci_write(pc, pa, off, val & 0xff);
|
|
pciide_pci_write(pc, pa, off, val >> 8);
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
} else {
|
|
mode |= 0x01 << (drive * 4);
|
|
off = 0xa4 + chp->channel * 16 + drive * 2;
|
|
val = pio_tbl[drvp->PIO_mode];
|
|
pciide_pci_write(pc, pa, off, val & 0xff);
|
|
pciide_pci_write(pc, pa, off, val >> 8);
|
|
}
|
|
}
|
|
|
|
pciide_pci_write(pc, pa, 0x80 + chp->channel * 4, mode);
|
|
if (idedma_ctl != 0) {
|
|
/* Add software bits in status register */
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(chp->channel),
|
|
idedma_ctl);
|
|
}
|
|
pciide_print_modes(cp);
|
|
}
|
|
|
|
/*
|
|
* When the Silicon Image 3112 retries a PCI memory read command,
|
|
* it may retry it as a memory read multiple command under some
|
|
* circumstances. This can totally confuse some PCI controllers,
|
|
* so ensure that it will never do this by making sure that the
|
|
* Read Threshold (FIFO Read Request Control) field of the FIFO
|
|
* Valid Byte Count and Control registers for both channels (BA5
|
|
* offset 0x40 and 0x44) are set to be at least as large as the
|
|
* cacheline size register.
|
|
*/
|
|
void
|
|
sii_fixup_cacheline(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
pcireg_t cls, reg40, reg44;
|
|
|
|
cls = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG);
|
|
cls = (cls >> PCI_CACHELINE_SHIFT) & PCI_CACHELINE_MASK;
|
|
cls *= 4;
|
|
if (cls > 224) {
|
|
cls = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG);
|
|
cls &= ~(PCI_CACHELINE_MASK << PCI_CACHELINE_SHIFT);
|
|
cls |= ((224/4) << PCI_CACHELINE_SHIFT);
|
|
pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG, cls);
|
|
cls = 224;
|
|
}
|
|
if (cls < 32)
|
|
cls = 32;
|
|
cls = (cls + 31) / 32;
|
|
reg40 = ba5_read_4(sc, 0x40);
|
|
reg44 = ba5_read_4(sc, 0x44);
|
|
if ((reg40 & 0x7) < cls)
|
|
ba5_write_4(sc, 0x40, (reg40 & ~0x07) | cls);
|
|
if ((reg44 & 0x7) < cls)
|
|
ba5_write_4(sc, 0x44, (reg44 & ~0x07) | cls);
|
|
}
|
|
|
|
void
|
|
sii3112_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_channel *cp;
|
|
bus_size_t cmdsize, ctlsize;
|
|
pcireg_t interface, scs_cmd, cfgctl;
|
|
int channel;
|
|
struct pciide_satalink *sl;
|
|
|
|
/* Allocate memory for private data */
|
|
sc->sc_cookielen = sizeof(*sl);
|
|
sc->sc_cookie = malloc(sc->sc_cookielen, M_DEVBUF, M_NOWAIT | M_ZERO);
|
|
sl = sc->sc_cookie;
|
|
|
|
sc->chip_unmap = default_chip_unmap;
|
|
|
|
#define SII3112_RESET_BITS \
|
|
(SCS_CMD_PBM_RESET | SCS_CMD_ARB_RESET | \
|
|
SCS_CMD_FF1_RESET | SCS_CMD_FF0_RESET | \
|
|
SCS_CMD_IDE1_RESET | SCS_CMD_IDE0_RESET)
|
|
|
|
/*
|
|
* Reset everything and then unblock all of the interrupts.
|
|
*/
|
|
scs_cmd = pci_conf_read(pa->pa_pc, pa->pa_tag, SII3112_SCS_CMD);
|
|
pci_conf_write(pa->pa_pc, pa->pa_tag, SII3112_SCS_CMD,
|
|
scs_cmd | SII3112_RESET_BITS);
|
|
delay(50 * 1000);
|
|
pci_conf_write(pa->pa_pc, pa->pa_tag, SII3112_SCS_CMD,
|
|
scs_cmd & SCS_CMD_BA5_EN);
|
|
delay(50 * 1000);
|
|
|
|
if (scs_cmd & SCS_CMD_BA5_EN) {
|
|
if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x14,
|
|
PCI_MAPREG_TYPE_MEM |
|
|
PCI_MAPREG_MEM_TYPE_32BIT, 0,
|
|
&sl->ba5_st, &sl->ba5_sh,
|
|
NULL, NULL, 0) != 0)
|
|
printf(": unable to map BA5 register space\n");
|
|
else
|
|
sl->ba5_en = 1;
|
|
} else {
|
|
cfgctl = pci_conf_read(pa->pa_pc, pa->pa_tag,
|
|
SII3112_PCI_CFGCTL);
|
|
pci_conf_write(pa->pa_pc, pa->pa_tag, SII3112_PCI_CFGCTL,
|
|
cfgctl | CFGCTL_BA5INDEN);
|
|
}
|
|
|
|
printf(": DMA");
|
|
pciide_mapreg_dma(sc, pa);
|
|
printf("\n");
|
|
|
|
/*
|
|
* Rev. <= 0x01 of the 3112 have a bug that can cause data
|
|
* corruption if DMA transfers cross an 8K boundary. This is
|
|
* apparently hard to tickle, but we'll go ahead and play it
|
|
* safe.
|
|
*/
|
|
if (sc->sc_rev <= 0x01) {
|
|
sc->sc_dma_maxsegsz = 8192;
|
|
sc->sc_dma_boundary = 8192;
|
|
}
|
|
|
|
sii_fixup_cacheline(sc, pa);
|
|
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32;
|
|
sc->sc_wdcdev.PIO_cap = 4;
|
|
if (sc->sc_dma_ok) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_UDMA;
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_IRQACK;
|
|
sc->sc_wdcdev.irqack = pciide_irqack;
|
|
sc->sc_wdcdev.DMA_cap = 2;
|
|
sc->sc_wdcdev.UDMA_cap = 6;
|
|
}
|
|
sc->sc_wdcdev.set_modes = sii3112_setup_channel;
|
|
|
|
/* We can use SControl and SStatus to probe for drives. */
|
|
sc->sc_wdcdev.drv_probe = sii3112_drv_probe;
|
|
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
|
|
|
|
/*
|
|
* The 3112 either identifies itself as a RAID storage device
|
|
* or a Misc storage device. Fake up the interface bits for
|
|
* what our driver expects.
|
|
*/
|
|
if (PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_IDE) {
|
|
interface = PCI_INTERFACE(pa->pa_class);
|
|
} else {
|
|
interface = PCIIDE_INTERFACE_BUS_MASTER_DMA |
|
|
PCIIDE_INTERFACE_PCI(0) | PCIIDE_INTERFACE_PCI(1);
|
|
}
|
|
|
|
for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
|
|
cp = &sc->pciide_channels[channel];
|
|
if (pciide_chansetup(sc, channel, interface) == 0)
|
|
continue;
|
|
pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
|
|
pciide_pci_intr);
|
|
if (cp->hw_ok == 0)
|
|
continue;
|
|
sc->sc_wdcdev.set_modes(&cp->wdc_channel);
|
|
}
|
|
}
|
|
|
|
void
|
|
sii3112_setup_channel(struct channel_softc *chp)
|
|
{
|
|
struct ata_drive_datas *drvp;
|
|
int drive;
|
|
u_int32_t idedma_ctl, dtm;
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
|
|
/* setup DMA if needed */
|
|
pciide_channel_dma_setup(cp);
|
|
|
|
idedma_ctl = 0;
|
|
dtm = 0;
|
|
|
|
for (drive = 0; drive < 2; drive++) {
|
|
drvp = &chp->ch_drive[drive];
|
|
/* If no drive, skip */
|
|
if ((drvp->drive_flags & DRIVE) == 0)
|
|
continue;
|
|
if (drvp->drive_flags & DRIVE_UDMA) {
|
|
/* use Ultra/DMA */
|
|
drvp->drive_flags &= ~DRIVE_DMA;
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
dtm |= DTM_IDEx_DMA;
|
|
} else if (drvp->drive_flags & DRIVE_DMA) {
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
dtm |= DTM_IDEx_DMA;
|
|
} else {
|
|
dtm |= DTM_IDEx_PIO;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Nothing to do to setup modes; it is meaningless in S-ATA
|
|
* (but many S-ATA drives still want to get the SET_FEATURE
|
|
* command).
|
|
*/
|
|
if (idedma_ctl != 0) {
|
|
/* Add software bits in status register */
|
|
PCIIDE_DMACTL_WRITE(sc, chp->channel, idedma_ctl);
|
|
}
|
|
BA5_WRITE_4(sc, chp->channel, ba5_IDE_DTM, dtm);
|
|
pciide_print_modes(cp);
|
|
}
|
|
|
|
void
|
|
sii3112_drv_probe(struct channel_softc *chp)
|
|
{
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
uint32_t scontrol, sstatus;
|
|
uint8_t scnt, sn, cl, ch;
|
|
int s;
|
|
|
|
/*
|
|
* The 3112 is a 2-port part, and only has one drive per channel
|
|
* (each port emulates a master drive).
|
|
*
|
|
* The 3114 is similar, but has 4 channels.
|
|
*/
|
|
|
|
/*
|
|
* Request communication initialization sequence, any speed.
|
|
* Performing this is the equivalent of an ATA Reset.
|
|
*/
|
|
scontrol = SControl_DET_INIT | SControl_SPD_ANY;
|
|
|
|
/*
|
|
* XXX We don't yet support SATA power management; disable all
|
|
* power management state transitions.
|
|
*/
|
|
scontrol |= SControl_IPM_NONE;
|
|
|
|
BA5_WRITE_4(sc, chp->channel, ba5_SControl, scontrol);
|
|
delay(50 * 1000);
|
|
scontrol &= ~SControl_DET_INIT;
|
|
BA5_WRITE_4(sc, chp->channel, ba5_SControl, scontrol);
|
|
delay(50 * 1000);
|
|
|
|
sstatus = BA5_READ_4(sc, chp->channel, ba5_SStatus);
|
|
#if 0
|
|
printf("%s: port %d: SStatus=0x%08x, SControl=0x%08x\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, chp->channel, sstatus,
|
|
BA5_READ_4(sc, chp->channel, ba5_SControl));
|
|
#endif
|
|
switch (sstatus & SStatus_DET_mask) {
|
|
case SStatus_DET_NODEV:
|
|
/* No device; be silent. */
|
|
break;
|
|
|
|
case SStatus_DET_DEV_NE:
|
|
printf("%s: port %d: device connected, but "
|
|
"communication not established\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, chp->channel);
|
|
break;
|
|
|
|
case SStatus_DET_OFFLINE:
|
|
printf("%s: port %d: PHY offline\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, chp->channel);
|
|
break;
|
|
|
|
case SStatus_DET_DEV:
|
|
/*
|
|
* XXX ATAPI detection doesn't currently work. Don't
|
|
* XXX know why. But, it's not like the standard method
|
|
* XXX can detect an ATAPI device connected via a SATA/PATA
|
|
* XXX bridge, so at least this is no worse. --thorpej
|
|
*/
|
|
if (chp->_vtbl != NULL)
|
|
CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (0 << 4));
|
|
else
|
|
bus_space_write_1(chp->cmd_iot, chp->cmd_ioh,
|
|
wdr_sdh & _WDC_REGMASK, WDSD_IBM | (0 << 4));
|
|
delay(10); /* 400ns delay */
|
|
/* Save register contents. */
|
|
if (chp->_vtbl != NULL) {
|
|
scnt = CHP_READ_REG(chp, wdr_seccnt);
|
|
sn = CHP_READ_REG(chp, wdr_sector);
|
|
cl = CHP_READ_REG(chp, wdr_cyl_lo);
|
|
ch = CHP_READ_REG(chp, wdr_cyl_hi);
|
|
} else {
|
|
scnt = bus_space_read_1(chp->cmd_iot,
|
|
chp->cmd_ioh, wdr_seccnt & _WDC_REGMASK);
|
|
sn = bus_space_read_1(chp->cmd_iot,
|
|
chp->cmd_ioh, wdr_sector & _WDC_REGMASK);
|
|
cl = bus_space_read_1(chp->cmd_iot,
|
|
chp->cmd_ioh, wdr_cyl_lo & _WDC_REGMASK);
|
|
ch = bus_space_read_1(chp->cmd_iot,
|
|
chp->cmd_ioh, wdr_cyl_hi & _WDC_REGMASK);
|
|
}
|
|
#if 0
|
|
printf("%s: port %d: scnt=0x%x sn=0x%x cl=0x%x ch=0x%x\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, chp->channel,
|
|
scnt, sn, cl, ch);
|
|
#endif
|
|
/*
|
|
* scnt and sn are supposed to be 0x1 for ATAPI, but in some
|
|
* cases we get wrong values here, so ignore it.
|
|
*/
|
|
s = splbio();
|
|
if (cl == 0x14 && ch == 0xeb)
|
|
chp->ch_drive[0].drive_flags |= DRIVE_ATAPI;
|
|
else
|
|
chp->ch_drive[0].drive_flags |= DRIVE_ATA;
|
|
splx(s);
|
|
|
|
printf("%s: port %d",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, chp->channel);
|
|
switch ((sstatus & SStatus_SPD_mask) >> SStatus_SPD_shift) {
|
|
case 1:
|
|
printf(": 1.5Gb/s");
|
|
break;
|
|
case 2:
|
|
printf(": 3.0Gb/s");
|
|
break;
|
|
}
|
|
printf("\n");
|
|
break;
|
|
|
|
default:
|
|
printf("%s: port %d: unknown SStatus: 0x%08x\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, chp->channel, sstatus);
|
|
}
|
|
}
|
|
|
|
void
|
|
sii3114_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_channel *cp;
|
|
pcireg_t scs_cmd;
|
|
pci_intr_handle_t intrhandle;
|
|
const char *intrstr;
|
|
int channel;
|
|
struct pciide_satalink *sl;
|
|
|
|
/* Allocate memory for private data */
|
|
sc->sc_cookielen = sizeof(*sl);
|
|
sc->sc_cookie = malloc(sc->sc_cookielen, M_DEVBUF, M_NOWAIT | M_ZERO);
|
|
sl = sc->sc_cookie;
|
|
|
|
#define SII3114_RESET_BITS \
|
|
(SCS_CMD_PBM_RESET | SCS_CMD_ARB_RESET | \
|
|
SCS_CMD_FF1_RESET | SCS_CMD_FF0_RESET | \
|
|
SCS_CMD_FF3_RESET | SCS_CMD_FF2_RESET | \
|
|
SCS_CMD_IDE1_RESET | SCS_CMD_IDE0_RESET | \
|
|
SCS_CMD_IDE3_RESET | SCS_CMD_IDE2_RESET)
|
|
|
|
/*
|
|
* Reset everything and then unblock all of the interrupts.
|
|
*/
|
|
scs_cmd = pci_conf_read(pa->pa_pc, pa->pa_tag, SII3112_SCS_CMD);
|
|
pci_conf_write(pa->pa_pc, pa->pa_tag, SII3112_SCS_CMD,
|
|
scs_cmd | SII3114_RESET_BITS);
|
|
delay(50 * 1000);
|
|
pci_conf_write(pa->pa_pc, pa->pa_tag, SII3112_SCS_CMD,
|
|
scs_cmd & SCS_CMD_M66EN);
|
|
delay(50 * 1000);
|
|
|
|
/*
|
|
* On the 3114, the BA5 register space is always enabled. In
|
|
* order to use the 3114 in any sane way, we must use this BA5
|
|
* register space, and so we consider it an error if we cannot
|
|
* map it.
|
|
*
|
|
* As a consequence of using BA5, our register mapping is different
|
|
* from a normal PCI IDE controller's, and so we are unable to use
|
|
* most of the common PCI IDE register mapping functions.
|
|
*/
|
|
if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x14,
|
|
PCI_MAPREG_TYPE_MEM |
|
|
PCI_MAPREG_MEM_TYPE_32BIT, 0,
|
|
&sl->ba5_st, &sl->ba5_sh,
|
|
NULL, NULL, 0) != 0) {
|
|
printf(": unable to map BA5 register space\n");
|
|
return;
|
|
}
|
|
sl->ba5_en = 1;
|
|
|
|
/*
|
|
* Set the Interrupt Steering bit in the IDEDMA_CMD register of
|
|
* channel 2. This is required at all times for proper operation
|
|
* when using the BA5 register space (otherwise interrupts from
|
|
* all 4 channels won't work).
|
|
*/
|
|
BA5_WRITE_4(sc, 2, ba5_IDEDMA_CMD, IDEDMA_CMD_INT_STEER);
|
|
|
|
printf(": DMA");
|
|
sii3114_mapreg_dma(sc, pa);
|
|
printf("\n");
|
|
|
|
sii_fixup_cacheline(sc, pa);
|
|
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32;
|
|
sc->sc_wdcdev.PIO_cap = 4;
|
|
if (sc->sc_dma_ok) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_UDMA;
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_IRQACK;
|
|
sc->sc_wdcdev.irqack = pciide_irqack;
|
|
sc->sc_wdcdev.DMA_cap = 2;
|
|
sc->sc_wdcdev.UDMA_cap = 6;
|
|
}
|
|
sc->sc_wdcdev.set_modes = sii3112_setup_channel;
|
|
|
|
/* We can use SControl and SStatus to probe for drives. */
|
|
sc->sc_wdcdev.drv_probe = sii3112_drv_probe;
|
|
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
sc->sc_wdcdev.nchannels = 4;
|
|
|
|
/* Map and establish the interrupt handler. */
|
|
if (pci_intr_map(pa, &intrhandle) != 0) {
|
|
printf("%s: couldn't map native-PCI interrupt\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname);
|
|
return;
|
|
}
|
|
intrstr = pci_intr_string(pa->pa_pc, intrhandle);
|
|
sc->sc_pci_ih = pci_intr_establish(pa->pa_pc, intrhandle, IPL_BIO,
|
|
/* XXX */
|
|
pciide_pci_intr, sc,
|
|
sc->sc_wdcdev.sc_dev.dv_xname);
|
|
if (sc->sc_pci_ih != NULL) {
|
|
printf("%s: using %s for native-PCI interrupt\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname,
|
|
intrstr ? intrstr : "unknown interrupt");
|
|
} else {
|
|
printf("%s: couldn't establish native-PCI interrupt",
|
|
sc->sc_wdcdev.sc_dev.dv_xname);
|
|
if (intrstr != NULL)
|
|
printf(" at %s", intrstr);
|
|
printf("\n");
|
|
return;
|
|
}
|
|
|
|
for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
|
|
cp = &sc->pciide_channels[channel];
|
|
if (sii3114_chansetup(sc, channel) == 0)
|
|
continue;
|
|
sii3114_mapchan(cp);
|
|
if (cp->hw_ok == 0)
|
|
continue;
|
|
sc->sc_wdcdev.set_modes(&cp->wdc_channel);
|
|
}
|
|
}
|
|
|
|
void
|
|
sii3114_mapreg_dma(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
int chan, reg;
|
|
bus_size_t size;
|
|
struct pciide_satalink *sl = sc->sc_cookie;
|
|
|
|
sc->sc_wdcdev.dma_arg = sc;
|
|
sc->sc_wdcdev.dma_init = pciide_dma_init;
|
|
sc->sc_wdcdev.dma_start = pciide_dma_start;
|
|
sc->sc_wdcdev.dma_finish = pciide_dma_finish;
|
|
|
|
/*
|
|
* Slice off a subregion of BA5 for each of the channel's DMA
|
|
* registers.
|
|
*/
|
|
|
|
sc->sc_dma_iot = sl->ba5_st;
|
|
for (chan = 0; chan < 4; chan++) {
|
|
for (reg = 0; reg < IDEDMA_NREGS; reg++) {
|
|
size = 4;
|
|
if (size > (IDEDMA_SCH_OFFSET - reg))
|
|
size = IDEDMA_SCH_OFFSET - reg;
|
|
if (bus_space_subregion(sl->ba5_st,
|
|
sl->ba5_sh,
|
|
satalink_ba5_regmap[chan].ba5_IDEDMA_CMD + reg,
|
|
size, &sl->regs[chan].dma_iohs[reg]) != 0) {
|
|
sc->sc_dma_ok = 0;
|
|
printf(": can't subregion offset "
|
|
"%lu size %lu",
|
|
(u_long) satalink_ba5_regmap[
|
|
chan].ba5_IDEDMA_CMD + reg,
|
|
(u_long) size);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
sc->sc_dmacmd_read = sii3114_dmacmd_read;
|
|
sc->sc_dmacmd_write = sii3114_dmacmd_write;
|
|
sc->sc_dmactl_read = sii3114_dmactl_read;
|
|
sc->sc_dmactl_write = sii3114_dmactl_write;
|
|
sc->sc_dmatbl_write = sii3114_dmatbl_write;
|
|
|
|
/* DMA registers all set up! */
|
|
sc->sc_dmat = pa->pa_dmat;
|
|
sc->sc_dma_ok = 1;
|
|
}
|
|
|
|
int
|
|
sii3114_chansetup(struct pciide_softc *sc, int channel)
|
|
{
|
|
static const char *channel_names[] = {
|
|
"port 0",
|
|
"port 1",
|
|
"port 2",
|
|
"port 3",
|
|
};
|
|
struct pciide_channel *cp = &sc->pciide_channels[channel];
|
|
|
|
sc->wdc_chanarray[channel] = &cp->wdc_channel;
|
|
|
|
/*
|
|
* We must always keep the Interrupt Steering bit set in channel 2's
|
|
* IDEDMA_CMD register.
|
|
*/
|
|
if (channel == 2)
|
|
cp->idedma_cmd = IDEDMA_CMD_INT_STEER;
|
|
|
|
cp->name = channel_names[channel];
|
|
cp->wdc_channel.channel = channel;
|
|
cp->wdc_channel.wdc = &sc->sc_wdcdev;
|
|
cp->wdc_channel.ch_queue = wdc_alloc_queue();
|
|
if (cp->wdc_channel.ch_queue == NULL) {
|
|
printf("%s %s channel: "
|
|
"cannot allocate channel queue",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
|
|
return (0);
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
void
|
|
sii3114_mapchan(struct pciide_channel *cp)
|
|
{
|
|
struct channel_softc *wdc_cp = &cp->wdc_channel;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
struct pciide_satalink *sl = sc->sc_cookie;
|
|
int chan = wdc_cp->channel;
|
|
int i;
|
|
|
|
cp->hw_ok = 0;
|
|
cp->compat = 0;
|
|
cp->ih = sc->sc_pci_ih;
|
|
|
|
sl->regs[chan].cmd_iot = sl->ba5_st;
|
|
if (bus_space_subregion(sl->ba5_st, sl->ba5_sh,
|
|
satalink_ba5_regmap[chan].ba5_IDE_TF0,
|
|
9, &sl->regs[chan].cmd_baseioh) != 0) {
|
|
printf("%s: couldn't subregion %s cmd base\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
|
|
return;
|
|
}
|
|
|
|
sl->regs[chan].ctl_iot = sl->ba5_st;
|
|
if (bus_space_subregion(sl->ba5_st, sl->ba5_sh,
|
|
satalink_ba5_regmap[chan].ba5_IDE_TF8,
|
|
1, &cp->ctl_baseioh) != 0) {
|
|
printf("%s: couldn't subregion %s ctl base\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
|
|
return;
|
|
}
|
|
sl->regs[chan].ctl_ioh = cp->ctl_baseioh;
|
|
|
|
for (i = 0; i < WDC_NREG; i++) {
|
|
if (bus_space_subregion(sl->regs[chan].cmd_iot,
|
|
sl->regs[chan].cmd_baseioh,
|
|
i, i == 0 ? 4 : 1,
|
|
&sl->regs[chan].cmd_iohs[i]) != 0) {
|
|
printf("%s: couldn't subregion %s channel "
|
|
"cmd regs\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
|
|
return;
|
|
}
|
|
}
|
|
sl->regs[chan].cmd_iohs[wdr_status & _WDC_REGMASK] =
|
|
sl->regs[chan].cmd_iohs[wdr_command & _WDC_REGMASK];
|
|
sl->regs[chan].cmd_iohs[wdr_features & _WDC_REGMASK] =
|
|
sl->regs[chan].cmd_iohs[wdr_error & _WDC_REGMASK];
|
|
wdc_cp->data32iot = wdc_cp->cmd_iot = sl->regs[chan].cmd_iot;
|
|
wdc_cp->data32ioh = wdc_cp->cmd_ioh = sl->regs[chan].cmd_iohs[0];
|
|
wdc_cp->_vtbl = &wdc_sii3114_vtbl;
|
|
wdcattach(wdc_cp);
|
|
cp->hw_ok = 1;
|
|
}
|
|
|
|
u_int8_t
|
|
sii3114_read_reg(struct channel_softc *chp, enum wdc_regs reg)
|
|
{
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
struct pciide_satalink *sl = sc->sc_cookie;
|
|
|
|
if (reg & _WDC_AUX)
|
|
return (bus_space_read_1(sl->regs[chp->channel].ctl_iot,
|
|
sl->regs[chp->channel].ctl_ioh, reg & _WDC_REGMASK));
|
|
else
|
|
return (bus_space_read_1(sl->regs[chp->channel].cmd_iot,
|
|
sl->regs[chp->channel].cmd_iohs[reg & _WDC_REGMASK], 0));
|
|
}
|
|
|
|
void
|
|
sii3114_write_reg(struct channel_softc *chp, enum wdc_regs reg, u_int8_t val)
|
|
{
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
struct pciide_satalink *sl = sc->sc_cookie;
|
|
|
|
if (reg & _WDC_AUX)
|
|
bus_space_write_1(sl->regs[chp->channel].ctl_iot,
|
|
sl->regs[chp->channel].ctl_ioh, reg & _WDC_REGMASK, val);
|
|
else
|
|
bus_space_write_1(sl->regs[chp->channel].cmd_iot,
|
|
sl->regs[chp->channel].cmd_iohs[reg & _WDC_REGMASK],
|
|
0, val);
|
|
}
|
|
|
|
u_int8_t
|
|
sii3114_dmacmd_read(struct pciide_softc *sc, int chan)
|
|
{
|
|
struct pciide_satalink *sl = sc->sc_cookie;
|
|
|
|
return (bus_space_read_1(sc->sc_dma_iot,
|
|
sl->regs[chan].dma_iohs[IDEDMA_CMD(0)], 0));
|
|
}
|
|
|
|
void
|
|
sii3114_dmacmd_write(struct pciide_softc *sc, int chan, u_int8_t val)
|
|
{
|
|
struct pciide_satalink *sl = sc->sc_cookie;
|
|
|
|
bus_space_write_1(sc->sc_dma_iot,
|
|
sl->regs[chan].dma_iohs[IDEDMA_CMD(0)], 0, val);
|
|
}
|
|
|
|
u_int8_t
|
|
sii3114_dmactl_read(struct pciide_softc *sc, int chan)
|
|
{
|
|
struct pciide_satalink *sl = sc->sc_cookie;
|
|
|
|
return (bus_space_read_1(sc->sc_dma_iot,
|
|
sl->regs[chan].dma_iohs[IDEDMA_CTL(0)], 0));
|
|
}
|
|
|
|
void
|
|
sii3114_dmactl_write(struct pciide_softc *sc, int chan, u_int8_t val)
|
|
{
|
|
struct pciide_satalink *sl = sc->sc_cookie;
|
|
|
|
bus_space_write_1(sc->sc_dma_iot,
|
|
sl->regs[chan].dma_iohs[IDEDMA_CTL(0)], 0, val);
|
|
}
|
|
|
|
void
|
|
sii3114_dmatbl_write(struct pciide_softc *sc, int chan, u_int32_t val)
|
|
{
|
|
struct pciide_satalink *sl = sc->sc_cookie;
|
|
|
|
bus_space_write_4(sc->sc_dma_iot,
|
|
sl->regs[chan].dma_iohs[IDEDMA_TBL(0)], 0, val);
|
|
}
|
|
|
|
void
|
|
cy693_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_channel *cp;
|
|
pcireg_t interface = PCI_INTERFACE(pa->pa_class);
|
|
bus_size_t cmdsize, ctlsize;
|
|
struct pciide_cy *cy;
|
|
|
|
/* Allocate memory for private data */
|
|
sc->sc_cookielen = sizeof(*cy);
|
|
sc->sc_cookie = malloc(sc->sc_cookielen, M_DEVBUF, M_NOWAIT | M_ZERO);
|
|
cy = sc->sc_cookie;
|
|
|
|
/*
|
|
* this chip has 2 PCI IDE functions, one for primary and one for
|
|
* secondary. So we need to call pciide_mapregs_compat() with
|
|
* the real channel
|
|
*/
|
|
if (pa->pa_function == 1) {
|
|
cy->cy_compatchan = 0;
|
|
} else if (pa->pa_function == 2) {
|
|
cy->cy_compatchan = 1;
|
|
} else {
|
|
printf(": unexpected PCI function %d\n", pa->pa_function);
|
|
return;
|
|
}
|
|
|
|
if (interface & PCIIDE_INTERFACE_BUS_MASTER_DMA) {
|
|
printf(": DMA");
|
|
pciide_mapreg_dma(sc, pa);
|
|
} else {
|
|
printf(": no DMA");
|
|
sc->sc_dma_ok = 0;
|
|
}
|
|
|
|
cy->cy_handle = cy82c693_init(pa->pa_iot);
|
|
if (cy->cy_handle == NULL) {
|
|
printf(", (unable to map ctl registers)");
|
|
sc->sc_dma_ok = 0;
|
|
}
|
|
|
|
sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
|
|
WDC_CAPABILITY_MODE;
|
|
if (sc->sc_dma_ok) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_IRQACK;
|
|
sc->sc_wdcdev.irqack = pciide_irqack;
|
|
}
|
|
sc->sc_wdcdev.PIO_cap = 4;
|
|
sc->sc_wdcdev.DMA_cap = 2;
|
|
sc->sc_wdcdev.set_modes = cy693_setup_channel;
|
|
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
sc->sc_wdcdev.nchannels = 1;
|
|
|
|
/* Only one channel for this chip; if we are here it's enabled */
|
|
cp = &sc->pciide_channels[0];
|
|
sc->wdc_chanarray[0] = &cp->wdc_channel;
|
|
cp->name = PCIIDE_CHANNEL_NAME(0);
|
|
cp->wdc_channel.channel = 0;
|
|
cp->wdc_channel.wdc = &sc->sc_wdcdev;
|
|
cp->wdc_channel.ch_queue = wdc_alloc_queue();
|
|
if (cp->wdc_channel.ch_queue == NULL) {
|
|
printf(": cannot allocate channel queue\n");
|
|
return;
|
|
}
|
|
printf(", %s %s to ", PCIIDE_CHANNEL_NAME(0),
|
|
(interface & PCIIDE_INTERFACE_SETTABLE(0)) ?
|
|
"configured" : "wired");
|
|
if (interface & PCIIDE_INTERFACE_PCI(0)) {
|
|
printf("native-PCI\n");
|
|
cp->hw_ok = pciide_mapregs_native(pa, cp, &cmdsize, &ctlsize,
|
|
pciide_pci_intr);
|
|
} else {
|
|
printf("compatibility\n");
|
|
cp->hw_ok = pciide_mapregs_compat(pa, cp, cy->cy_compatchan,
|
|
&cmdsize, &ctlsize);
|
|
}
|
|
|
|
cp->wdc_channel.data32iot = cp->wdc_channel.cmd_iot;
|
|
cp->wdc_channel.data32ioh = cp->wdc_channel.cmd_ioh;
|
|
pciide_map_compat_intr(pa, cp, cy->cy_compatchan, interface);
|
|
if (cp->hw_ok == 0)
|
|
return;
|
|
wdcattach(&cp->wdc_channel);
|
|
if (pciide_chan_candisable(cp)) {
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag,
|
|
PCI_COMMAND_STATUS_REG, 0);
|
|
}
|
|
if (cp->hw_ok == 0) {
|
|
pciide_unmap_compat_intr(pa, cp, cy->cy_compatchan,
|
|
interface);
|
|
return;
|
|
}
|
|
|
|
WDCDEBUG_PRINT(("cy693_chip_map: old timings reg 0x%x\n",
|
|
pci_conf_read(sc->sc_pc, sc->sc_tag, CY_CMD_CTRL)), DEBUG_PROBE);
|
|
cy693_setup_channel(&cp->wdc_channel);
|
|
WDCDEBUG_PRINT(("cy693_chip_map: new timings reg 0x%x\n",
|
|
pci_conf_read(sc->sc_pc, sc->sc_tag, CY_CMD_CTRL)), DEBUG_PROBE);
|
|
}
|
|
|
|
void
|
|
cy693_setup_channel(struct channel_softc *chp)
|
|
{
|
|
struct ata_drive_datas *drvp;
|
|
int drive;
|
|
u_int32_t cy_cmd_ctrl;
|
|
u_int32_t idedma_ctl;
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
int dma_mode = -1;
|
|
struct pciide_cy *cy = sc->sc_cookie;
|
|
|
|
cy_cmd_ctrl = idedma_ctl = 0;
|
|
|
|
/* setup DMA if needed */
|
|
pciide_channel_dma_setup(cp);
|
|
|
|
for (drive = 0; drive < 2; drive++) {
|
|
drvp = &chp->ch_drive[drive];
|
|
/* If no drive, skip */
|
|
if ((drvp->drive_flags & DRIVE) == 0)
|
|
continue;
|
|
/* add timing values, setup DMA if needed */
|
|
if (drvp->drive_flags & DRIVE_DMA) {
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
/* use Multiword DMA */
|
|
if (dma_mode == -1 || dma_mode > drvp->DMA_mode)
|
|
dma_mode = drvp->DMA_mode;
|
|
}
|
|
cy_cmd_ctrl |= (cy_pio_pulse[drvp->PIO_mode] <<
|
|
CY_CMD_CTRL_IOW_PULSE_OFF(drive));
|
|
cy_cmd_ctrl |= (cy_pio_rec[drvp->PIO_mode] <<
|
|
CY_CMD_CTRL_IOW_REC_OFF(drive));
|
|
cy_cmd_ctrl |= (cy_pio_pulse[drvp->PIO_mode] <<
|
|
CY_CMD_CTRL_IOR_PULSE_OFF(drive));
|
|
cy_cmd_ctrl |= (cy_pio_rec[drvp->PIO_mode] <<
|
|
CY_CMD_CTRL_IOR_REC_OFF(drive));
|
|
}
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, CY_CMD_CTRL, cy_cmd_ctrl);
|
|
chp->ch_drive[0].DMA_mode = dma_mode;
|
|
chp->ch_drive[1].DMA_mode = dma_mode;
|
|
|
|
if (dma_mode == -1)
|
|
dma_mode = 0;
|
|
|
|
if (cy->cy_handle != NULL) {
|
|
/* Note: `multiple' is implied. */
|
|
cy82c693_write(cy->cy_handle,
|
|
(cy->cy_compatchan == 0) ?
|
|
CY_DMA_IDX_PRIMARY : CY_DMA_IDX_SECONDARY, dma_mode);
|
|
}
|
|
|
|
pciide_print_modes(cp);
|
|
|
|
if (idedma_ctl != 0) {
|
|
/* Add software bits in status register */
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(chp->channel), idedma_ctl);
|
|
}
|
|
}
|
|
|
|
static struct sis_hostbr_type {
|
|
u_int16_t id;
|
|
u_int8_t rev;
|
|
u_int8_t udma_mode;
|
|
char *name;
|
|
u_int8_t type;
|
|
#define SIS_TYPE_NOUDMA 0
|
|
#define SIS_TYPE_66 1
|
|
#define SIS_TYPE_100OLD 2
|
|
#define SIS_TYPE_100NEW 3
|
|
#define SIS_TYPE_133OLD 4
|
|
#define SIS_TYPE_133NEW 5
|
|
#define SIS_TYPE_SOUTH 6
|
|
} sis_hostbr_type[] = {
|
|
/* Most infos here are from sos@freebsd.org */
|
|
{PCI_PRODUCT_SIS_530, 0x00, 4, "530", SIS_TYPE_66},
|
|
#if 0
|
|
/*
|
|
* controllers associated to a rev 0x2 530 Host to PCI Bridge
|
|
* have problems with UDMA (info provided by Christos)
|
|
*/
|
|
{PCI_PRODUCT_SIS_530, 0x02, 0, "530 (buggy)", SIS_TYPE_NOUDMA},
|
|
#endif
|
|
{PCI_PRODUCT_SIS_540, 0x00, 4, "540", SIS_TYPE_66},
|
|
{PCI_PRODUCT_SIS_550, 0x00, 4, "550", SIS_TYPE_66},
|
|
{PCI_PRODUCT_SIS_620, 0x00, 4, "620", SIS_TYPE_66},
|
|
{PCI_PRODUCT_SIS_630, 0x00, 4, "630", SIS_TYPE_66},
|
|
{PCI_PRODUCT_SIS_630, 0x30, 5, "630S", SIS_TYPE_100NEW},
|
|
{PCI_PRODUCT_SIS_633, 0x00, 5, "633", SIS_TYPE_100NEW},
|
|
{PCI_PRODUCT_SIS_635, 0x00, 5, "635", SIS_TYPE_100NEW},
|
|
{PCI_PRODUCT_SIS_640, 0x00, 4, "640", SIS_TYPE_SOUTH},
|
|
{PCI_PRODUCT_SIS_645, 0x00, 6, "645", SIS_TYPE_SOUTH},
|
|
{PCI_PRODUCT_SIS_646, 0x00, 6, "645DX", SIS_TYPE_SOUTH},
|
|
{PCI_PRODUCT_SIS_648, 0x00, 6, "648", SIS_TYPE_SOUTH},
|
|
{PCI_PRODUCT_SIS_650, 0x00, 6, "650", SIS_TYPE_SOUTH},
|
|
{PCI_PRODUCT_SIS_651, 0x00, 6, "651", SIS_TYPE_SOUTH},
|
|
{PCI_PRODUCT_SIS_652, 0x00, 6, "652", SIS_TYPE_SOUTH},
|
|
{PCI_PRODUCT_SIS_655, 0x00, 6, "655", SIS_TYPE_SOUTH},
|
|
{PCI_PRODUCT_SIS_658, 0x00, 6, "658", SIS_TYPE_SOUTH},
|
|
{PCI_PRODUCT_SIS_661, 0x00, 6, "661", SIS_TYPE_SOUTH},
|
|
{PCI_PRODUCT_SIS_730, 0x00, 5, "730", SIS_TYPE_100OLD},
|
|
{PCI_PRODUCT_SIS_733, 0x00, 5, "733", SIS_TYPE_100NEW},
|
|
{PCI_PRODUCT_SIS_735, 0x00, 5, "735", SIS_TYPE_100NEW},
|
|
{PCI_PRODUCT_SIS_740, 0x00, 5, "740", SIS_TYPE_SOUTH},
|
|
{PCI_PRODUCT_SIS_741, 0x00, 6, "741", SIS_TYPE_SOUTH},
|
|
{PCI_PRODUCT_SIS_745, 0x00, 5, "745", SIS_TYPE_100NEW},
|
|
{PCI_PRODUCT_SIS_746, 0x00, 6, "746", SIS_TYPE_SOUTH},
|
|
{PCI_PRODUCT_SIS_748, 0x00, 6, "748", SIS_TYPE_SOUTH},
|
|
{PCI_PRODUCT_SIS_750, 0x00, 6, "750", SIS_TYPE_SOUTH},
|
|
{PCI_PRODUCT_SIS_751, 0x00, 6, "751", SIS_TYPE_SOUTH},
|
|
{PCI_PRODUCT_SIS_752, 0x00, 6, "752", SIS_TYPE_SOUTH},
|
|
{PCI_PRODUCT_SIS_755, 0x00, 6, "755", SIS_TYPE_SOUTH},
|
|
{PCI_PRODUCT_SIS_760, 0x00, 6, "760", SIS_TYPE_SOUTH},
|
|
/*
|
|
* From sos@freebsd.org: the 0x961 ID will never be found in real world
|
|
* {PCI_PRODUCT_SIS_961, 0x00, 6, "961", SIS_TYPE_133NEW},
|
|
*/
|
|
{PCI_PRODUCT_SIS_962, 0x00, 6, "962", SIS_TYPE_133NEW},
|
|
{PCI_PRODUCT_SIS_963, 0x00, 6, "963", SIS_TYPE_133NEW},
|
|
{PCI_PRODUCT_SIS_964, 0x00, 6, "964", SIS_TYPE_133NEW},
|
|
{PCI_PRODUCT_SIS_965, 0x00, 6, "965", SIS_TYPE_133NEW},
|
|
{PCI_PRODUCT_SIS_966, 0x00, 6, "966", SIS_TYPE_133NEW},
|
|
{PCI_PRODUCT_SIS_968, 0x00, 6, "968", SIS_TYPE_133NEW}
|
|
};
|
|
|
|
static struct sis_hostbr_type *sis_hostbr_type_match;
|
|
|
|
int
|
|
sis_hostbr_match(struct pci_attach_args *pa)
|
|
{
|
|
int i;
|
|
|
|
if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_SIS)
|
|
return (0);
|
|
sis_hostbr_type_match = NULL;
|
|
for (i = 0;
|
|
i < sizeof(sis_hostbr_type) / sizeof(sis_hostbr_type[0]);
|
|
i++) {
|
|
if (PCI_PRODUCT(pa->pa_id) == sis_hostbr_type[i].id &&
|
|
PCI_REVISION(pa->pa_class) >= sis_hostbr_type[i].rev)
|
|
sis_hostbr_type_match = &sis_hostbr_type[i];
|
|
}
|
|
return (sis_hostbr_type_match != NULL);
|
|
}
|
|
|
|
int
|
|
sis_south_match(struct pci_attach_args *pa)
|
|
{
|
|
return(PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SIS &&
|
|
PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SIS_85C503 &&
|
|
PCI_REVISION(pa->pa_class) >= 0x10);
|
|
}
|
|
|
|
void
|
|
sis_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_channel *cp;
|
|
int channel;
|
|
u_int8_t sis_ctr0 = pciide_pci_read(sc->sc_pc, sc->sc_tag, SIS_CTRL0);
|
|
pcireg_t interface = PCI_INTERFACE(pa->pa_class);
|
|
int rev = sc->sc_rev;
|
|
bus_size_t cmdsize, ctlsize;
|
|
struct pciide_sis *sis;
|
|
|
|
/* Allocate memory for private data */
|
|
sc->sc_cookielen = sizeof(*sis);
|
|
sc->sc_cookie = malloc(sc->sc_cookielen, M_DEVBUF, M_NOWAIT | M_ZERO);
|
|
sis = sc->sc_cookie;
|
|
|
|
pci_find_device(NULL, sis_hostbr_match);
|
|
|
|
if (sis_hostbr_type_match) {
|
|
if (sis_hostbr_type_match->type == SIS_TYPE_SOUTH) {
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag, SIS_REG_57,
|
|
pciide_pci_read(sc->sc_pc, sc->sc_tag,
|
|
SIS_REG_57) & 0x7f);
|
|
if (sc->sc_pp->ide_product == SIS_PRODUCT_5518) {
|
|
sis->sis_type = SIS_TYPE_133NEW;
|
|
sc->sc_wdcdev.UDMA_cap =
|
|
sis_hostbr_type_match->udma_mode;
|
|
} else {
|
|
if (pci_find_device(NULL, sis_south_match)) {
|
|
sis->sis_type = SIS_TYPE_133OLD;
|
|
sc->sc_wdcdev.UDMA_cap =
|
|
sis_hostbr_type_match->udma_mode;
|
|
} else {
|
|
sis->sis_type = SIS_TYPE_100NEW;
|
|
sc->sc_wdcdev.UDMA_cap =
|
|
sis_hostbr_type_match->udma_mode;
|
|
}
|
|
}
|
|
} else {
|
|
sis->sis_type = sis_hostbr_type_match->type;
|
|
sc->sc_wdcdev.UDMA_cap =
|
|
sis_hostbr_type_match->udma_mode;
|
|
}
|
|
printf(": %s", sis_hostbr_type_match->name);
|
|
} else {
|
|
printf(": 5597/5598");
|
|
if (rev >= 0xd0) {
|
|
sc->sc_wdcdev.UDMA_cap = 2;
|
|
sis->sis_type = SIS_TYPE_66;
|
|
} else {
|
|
sc->sc_wdcdev.UDMA_cap = 0;
|
|
sis->sis_type = SIS_TYPE_NOUDMA;
|
|
}
|
|
}
|
|
|
|
printf(": DMA");
|
|
pciide_mapreg_dma(sc, pa);
|
|
|
|
sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
|
|
WDC_CAPABILITY_MODE;
|
|
if (sc->sc_dma_ok) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_IRQACK;
|
|
sc->sc_wdcdev.irqack = pciide_irqack;
|
|
if (sis->sis_type >= SIS_TYPE_66)
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_UDMA;
|
|
}
|
|
|
|
sc->sc_wdcdev.PIO_cap = 4;
|
|
sc->sc_wdcdev.DMA_cap = 2;
|
|
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
|
|
switch (sis->sis_type) {
|
|
case SIS_TYPE_NOUDMA:
|
|
case SIS_TYPE_66:
|
|
case SIS_TYPE_100OLD:
|
|
sc->sc_wdcdev.set_modes = sis_setup_channel;
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag, SIS_MISC,
|
|
pciide_pci_read(sc->sc_pc, sc->sc_tag, SIS_MISC) |
|
|
SIS_MISC_TIM_SEL | SIS_MISC_FIFO_SIZE | SIS_MISC_GTC);
|
|
break;
|
|
case SIS_TYPE_100NEW:
|
|
case SIS_TYPE_133OLD:
|
|
sc->sc_wdcdev.set_modes = sis_setup_channel;
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag, SIS_REG_49,
|
|
pciide_pci_read(sc->sc_pc, sc->sc_tag, SIS_REG_49) | 0x01);
|
|
break;
|
|
case SIS_TYPE_133NEW:
|
|
sc->sc_wdcdev.set_modes = sis96x_setup_channel;
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag, SIS_REG_50,
|
|
pciide_pci_read(sc->sc_pc, sc->sc_tag, SIS_REG_50) & 0xf7);
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag, SIS_REG_52,
|
|
pciide_pci_read(sc->sc_pc, sc->sc_tag, SIS_REG_52) & 0xf7);
|
|
break;
|
|
}
|
|
|
|
pciide_print_channels(sc->sc_wdcdev.nchannels, interface);
|
|
|
|
for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
|
|
cp = &sc->pciide_channels[channel];
|
|
if (pciide_chansetup(sc, channel, interface) == 0)
|
|
continue;
|
|
if ((channel == 0 && (sis_ctr0 & SIS_CTRL0_CHAN0_EN) == 0) ||
|
|
(channel == 1 && (sis_ctr0 & SIS_CTRL0_CHAN1_EN) == 0)) {
|
|
printf("%s: %s ignored (disabled)\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
|
|
cp->hw_ok = 0;
|
|
continue;
|
|
}
|
|
pciide_map_compat_intr(pa, cp, channel, interface);
|
|
if (cp->hw_ok == 0)
|
|
continue;
|
|
pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
|
|
pciide_pci_intr);
|
|
if (cp->hw_ok == 0) {
|
|
pciide_unmap_compat_intr(pa, cp, channel, interface);
|
|
continue;
|
|
}
|
|
if (pciide_chan_candisable(cp)) {
|
|
if (channel == 0)
|
|
sis_ctr0 &= ~SIS_CTRL0_CHAN0_EN;
|
|
else
|
|
sis_ctr0 &= ~SIS_CTRL0_CHAN1_EN;
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag, SIS_CTRL0,
|
|
sis_ctr0);
|
|
}
|
|
if (cp->hw_ok == 0) {
|
|
pciide_unmap_compat_intr(pa, cp, channel, interface);
|
|
continue;
|
|
}
|
|
sc->sc_wdcdev.set_modes(&cp->wdc_channel);
|
|
}
|
|
}
|
|
|
|
void
|
|
sis96x_setup_channel(struct channel_softc *chp)
|
|
{
|
|
struct ata_drive_datas *drvp;
|
|
int drive;
|
|
u_int32_t sis_tim;
|
|
u_int32_t idedma_ctl;
|
|
int regtim;
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
|
|
sis_tim = 0;
|
|
idedma_ctl = 0;
|
|
/* setup DMA if needed */
|
|
pciide_channel_dma_setup(cp);
|
|
|
|
for (drive = 0; drive < 2; drive++) {
|
|
regtim = SIS_TIM133(
|
|
pciide_pci_read(sc->sc_pc, sc->sc_tag, SIS_REG_57),
|
|
chp->channel, drive);
|
|
drvp = &chp->ch_drive[drive];
|
|
/* If no drive, skip */
|
|
if ((drvp->drive_flags & DRIVE) == 0)
|
|
continue;
|
|
/* add timing values, setup DMA if needed */
|
|
if (drvp->drive_flags & DRIVE_UDMA) {
|
|
/* use Ultra/DMA */
|
|
drvp->drive_flags &= ~DRIVE_DMA;
|
|
if (pciide_pci_read(sc->sc_pc, sc->sc_tag,
|
|
SIS96x_REG_CBL(chp->channel)) & SIS96x_REG_CBL_33) {
|
|
if (drvp->UDMA_mode > 2)
|
|
drvp->UDMA_mode = 2;
|
|
}
|
|
sis_tim |= sis_udma133new_tim[drvp->UDMA_mode];
|
|
sis_tim |= sis_pio133new_tim[drvp->PIO_mode];
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
} else if (drvp->drive_flags & DRIVE_DMA) {
|
|
/*
|
|
* use Multiword DMA
|
|
* Timings will be used for both PIO and DMA,
|
|
* so adjust DMA mode if needed
|
|
*/
|
|
if (drvp->PIO_mode > (drvp->DMA_mode + 2))
|
|
drvp->PIO_mode = drvp->DMA_mode + 2;
|
|
if (drvp->DMA_mode + 2 > (drvp->PIO_mode))
|
|
drvp->DMA_mode = (drvp->PIO_mode > 2) ?
|
|
drvp->PIO_mode - 2 : 0;
|
|
sis_tim |= sis_dma133new_tim[drvp->DMA_mode];
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
} else {
|
|
sis_tim |= sis_pio133new_tim[drvp->PIO_mode];
|
|
}
|
|
WDCDEBUG_PRINT(("sis96x_setup_channel: new timings reg for "
|
|
"channel %d drive %d: 0x%x (reg 0x%x)\n",
|
|
chp->channel, drive, sis_tim, regtim), DEBUG_PROBE);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, regtim, sis_tim);
|
|
}
|
|
if (idedma_ctl != 0) {
|
|
/* Add software bits in status register */
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(chp->channel), idedma_ctl);
|
|
}
|
|
pciide_print_modes(cp);
|
|
}
|
|
|
|
void
|
|
sis_setup_channel(struct channel_softc *chp)
|
|
{
|
|
struct ata_drive_datas *drvp;
|
|
int drive;
|
|
u_int32_t sis_tim;
|
|
u_int32_t idedma_ctl;
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
struct pciide_sis *sis = sc->sc_cookie;
|
|
|
|
WDCDEBUG_PRINT(("sis_setup_channel: old timings reg for "
|
|
"channel %d 0x%x\n", chp->channel,
|
|
pci_conf_read(sc->sc_pc, sc->sc_tag, SIS_TIM(chp->channel))),
|
|
DEBUG_PROBE);
|
|
sis_tim = 0;
|
|
idedma_ctl = 0;
|
|
/* setup DMA if needed */
|
|
pciide_channel_dma_setup(cp);
|
|
|
|
for (drive = 0; drive < 2; drive++) {
|
|
drvp = &chp->ch_drive[drive];
|
|
/* If no drive, skip */
|
|
if ((drvp->drive_flags & DRIVE) == 0)
|
|
continue;
|
|
/* add timing values, setup DMA if needed */
|
|
if ((drvp->drive_flags & DRIVE_DMA) == 0 &&
|
|
(drvp->drive_flags & DRIVE_UDMA) == 0)
|
|
goto pio;
|
|
|
|
if (drvp->drive_flags & DRIVE_UDMA) {
|
|
/* use Ultra/DMA */
|
|
drvp->drive_flags &= ~DRIVE_DMA;
|
|
if (pciide_pci_read(sc->sc_pc, sc->sc_tag,
|
|
SIS_REG_CBL) & SIS_REG_CBL_33(chp->channel)) {
|
|
if (drvp->UDMA_mode > 2)
|
|
drvp->UDMA_mode = 2;
|
|
}
|
|
switch (sis->sis_type) {
|
|
case SIS_TYPE_66:
|
|
case SIS_TYPE_100OLD:
|
|
sis_tim |= sis_udma66_tim[drvp->UDMA_mode] <<
|
|
SIS_TIM66_UDMA_TIME_OFF(drive);
|
|
break;
|
|
case SIS_TYPE_100NEW:
|
|
sis_tim |=
|
|
sis_udma100new_tim[drvp->UDMA_mode] <<
|
|
SIS_TIM100_UDMA_TIME_OFF(drive);
|
|
break;
|
|
case SIS_TYPE_133OLD:
|
|
sis_tim |=
|
|
sis_udma133old_tim[drvp->UDMA_mode] <<
|
|
SIS_TIM100_UDMA_TIME_OFF(drive);
|
|
break;
|
|
default:
|
|
printf("unknown SiS IDE type %d\n",
|
|
sis->sis_type);
|
|
}
|
|
} else {
|
|
/*
|
|
* use Multiword DMA
|
|
* Timings will be used for both PIO and DMA,
|
|
* so adjust DMA mode if needed
|
|
*/
|
|
if (drvp->PIO_mode > (drvp->DMA_mode + 2))
|
|
drvp->PIO_mode = drvp->DMA_mode + 2;
|
|
if (drvp->DMA_mode + 2 > (drvp->PIO_mode))
|
|
drvp->DMA_mode = (drvp->PIO_mode > 2) ?
|
|
drvp->PIO_mode - 2 : 0;
|
|
if (drvp->DMA_mode == 0)
|
|
drvp->PIO_mode = 0;
|
|
}
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
pio: switch (sis->sis_type) {
|
|
case SIS_TYPE_NOUDMA:
|
|
case SIS_TYPE_66:
|
|
case SIS_TYPE_100OLD:
|
|
sis_tim |= sis_pio_act[drvp->PIO_mode] <<
|
|
SIS_TIM66_ACT_OFF(drive);
|
|
sis_tim |= sis_pio_rec[drvp->PIO_mode] <<
|
|
SIS_TIM66_REC_OFF(drive);
|
|
break;
|
|
case SIS_TYPE_100NEW:
|
|
case SIS_TYPE_133OLD:
|
|
sis_tim |= sis_pio_act[drvp->PIO_mode] <<
|
|
SIS_TIM100_ACT_OFF(drive);
|
|
sis_tim |= sis_pio_rec[drvp->PIO_mode] <<
|
|
SIS_TIM100_REC_OFF(drive);
|
|
break;
|
|
default:
|
|
printf("unknown SiS IDE type %d\n",
|
|
sis->sis_type);
|
|
}
|
|
}
|
|
WDCDEBUG_PRINT(("sis_setup_channel: new timings reg for "
|
|
"channel %d 0x%x\n", chp->channel, sis_tim), DEBUG_PROBE);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, SIS_TIM(chp->channel), sis_tim);
|
|
if (idedma_ctl != 0) {
|
|
/* Add software bits in status register */
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(chp->channel), idedma_ctl);
|
|
}
|
|
pciide_print_modes(cp);
|
|
}
|
|
|
|
void
|
|
natsemi_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_channel *cp;
|
|
int channel;
|
|
pcireg_t interface, ctl;
|
|
bus_size_t cmdsize, ctlsize;
|
|
|
|
printf(": DMA");
|
|
pciide_mapreg_dma(sc, pa);
|
|
sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16;
|
|
|
|
if (sc->sc_dma_ok) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_IRQACK;
|
|
sc->sc_wdcdev.irqack = natsemi_irqack;
|
|
}
|
|
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag, NATSEMI_CCBT, 0xb7);
|
|
|
|
/*
|
|
* Mask off interrupts from both channels, appropriate channel(s)
|
|
* will be unmasked later.
|
|
*/
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag, NATSEMI_CTRL2,
|
|
pciide_pci_read(sc->sc_pc, sc->sc_tag, NATSEMI_CTRL2) |
|
|
NATSEMI_CHMASK(0) | NATSEMI_CHMASK(1));
|
|
|
|
sc->sc_wdcdev.PIO_cap = 4;
|
|
sc->sc_wdcdev.DMA_cap = 2;
|
|
sc->sc_wdcdev.set_modes = natsemi_setup_channel;
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
|
|
|
|
interface = PCI_INTERFACE(pci_conf_read(sc->sc_pc, sc->sc_tag,
|
|
PCI_CLASS_REG));
|
|
interface &= ~PCIIDE_CHANSTATUS_EN; /* Reserved on PC87415 */
|
|
pciide_print_channels(sc->sc_wdcdev.nchannels, interface);
|
|
|
|
/* If we're in PCIIDE mode, unmask INTA, otherwise mask it. */
|
|
ctl = pciide_pci_read(sc->sc_pc, sc->sc_tag, NATSEMI_CTRL1);
|
|
if (interface & (PCIIDE_INTERFACE_PCI(0) | PCIIDE_INTERFACE_PCI(1)))
|
|
ctl &= ~NATSEMI_CTRL1_INTAMASK;
|
|
else
|
|
ctl |= NATSEMI_CTRL1_INTAMASK;
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag, NATSEMI_CTRL1, ctl);
|
|
|
|
for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
|
|
cp = &sc->pciide_channels[channel];
|
|
if (pciide_chansetup(sc, channel, interface) == 0)
|
|
continue;
|
|
|
|
pciide_map_compat_intr(pa, cp, channel, interface);
|
|
if (cp->hw_ok == 0)
|
|
continue;
|
|
|
|
pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
|
|
natsemi_pci_intr);
|
|
if (cp->hw_ok == 0) {
|
|
pciide_unmap_compat_intr(pa, cp, channel, interface);
|
|
continue;
|
|
}
|
|
natsemi_setup_channel(&cp->wdc_channel);
|
|
}
|
|
}
|
|
|
|
void
|
|
natsemi_setup_channel(struct channel_softc *chp)
|
|
{
|
|
struct ata_drive_datas *drvp;
|
|
int drive, ndrives = 0;
|
|
u_int32_t idedma_ctl = 0;
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
u_int8_t tim;
|
|
|
|
/* setup DMA if needed */
|
|
pciide_channel_dma_setup(cp);
|
|
|
|
for (drive = 0; drive < 2; drive++) {
|
|
drvp = &chp->ch_drive[drive];
|
|
/* If no drive, skip */
|
|
if ((drvp->drive_flags & DRIVE) == 0)
|
|
continue;
|
|
|
|
ndrives++;
|
|
/* add timing values, setup DMA if needed */
|
|
if ((drvp->drive_flags & DRIVE_DMA) == 0) {
|
|
tim = natsemi_pio_pulse[drvp->PIO_mode] |
|
|
(natsemi_pio_recover[drvp->PIO_mode] << 4);
|
|
} else {
|
|
/*
|
|
* use Multiword DMA
|
|
* Timings will be used for both PIO and DMA,
|
|
* so adjust DMA mode if needed
|
|
*/
|
|
if (drvp->PIO_mode >= 3 &&
|
|
(drvp->DMA_mode + 2) > drvp->PIO_mode) {
|
|
drvp->DMA_mode = drvp->PIO_mode - 2;
|
|
}
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
tim = natsemi_dma_pulse[drvp->DMA_mode] |
|
|
(natsemi_dma_recover[drvp->DMA_mode] << 4);
|
|
}
|
|
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag,
|
|
NATSEMI_RTREG(chp->channel, drive), tim);
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag,
|
|
NATSEMI_WTREG(chp->channel, drive), tim);
|
|
}
|
|
if (idedma_ctl != 0) {
|
|
/* Add software bits in status register */
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(chp->channel), idedma_ctl);
|
|
}
|
|
if (ndrives > 0) {
|
|
/* Unmask the channel if at least one drive is found */
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag, NATSEMI_CTRL2,
|
|
pciide_pci_read(sc->sc_pc, sc->sc_tag, NATSEMI_CTRL2) &
|
|
~(NATSEMI_CHMASK(chp->channel)));
|
|
}
|
|
|
|
pciide_print_modes(cp);
|
|
|
|
/* Go ahead and ack interrupts generated during probe. */
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(chp->channel),
|
|
bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(chp->channel)));
|
|
}
|
|
|
|
void
|
|
natsemi_irqack(struct channel_softc *chp)
|
|
{
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
u_int8_t clr;
|
|
|
|
/* The "clear" bits are in the wrong register *sigh* */
|
|
clr = bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CMD(chp->channel));
|
|
clr |= bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(chp->channel)) &
|
|
(IDEDMA_CTL_ERR | IDEDMA_CTL_INTR);
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CMD(chp->channel), clr);
|
|
}
|
|
|
|
int
|
|
natsemi_pci_intr(void *arg)
|
|
{
|
|
struct pciide_softc *sc = arg;
|
|
struct pciide_channel *cp;
|
|
struct channel_softc *wdc_cp;
|
|
int i, rv, crv;
|
|
u_int8_t msk;
|
|
|
|
rv = 0;
|
|
msk = pciide_pci_read(sc->sc_pc, sc->sc_tag, NATSEMI_CTRL2);
|
|
for (i = 0; i < sc->sc_wdcdev.nchannels; i++) {
|
|
cp = &sc->pciide_channels[i];
|
|
wdc_cp = &cp->wdc_channel;
|
|
|
|
/* If a compat channel skip. */
|
|
if (cp->compat)
|
|
continue;
|
|
|
|
/* If this channel is masked, skip it. */
|
|
if (msk & NATSEMI_CHMASK(i))
|
|
continue;
|
|
|
|
if (pciide_intr_flag(cp) == 0)
|
|
continue;
|
|
|
|
crv = wdcintr(wdc_cp);
|
|
if (crv == 0)
|
|
; /* leave rv alone */
|
|
else if (crv == 1)
|
|
rv = 1; /* claim the intr */
|
|
else if (rv == 0) /* crv should be -1 in this case */
|
|
rv = crv; /* if we've done no better, take it */
|
|
}
|
|
return (rv);
|
|
}
|
|
|
|
void
|
|
ns_scx200_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_channel *cp;
|
|
int channel;
|
|
pcireg_t interface = PCI_INTERFACE(pa->pa_class);
|
|
bus_size_t cmdsize, ctlsize;
|
|
|
|
printf(": DMA");
|
|
pciide_mapreg_dma(sc, pa);
|
|
|
|
sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
|
|
WDC_CAPABILITY_MODE;
|
|
if (sc->sc_dma_ok) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_UDMA;
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_IRQACK;
|
|
sc->sc_wdcdev.irqack = pciide_irqack;
|
|
}
|
|
sc->sc_wdcdev.PIO_cap = 4;
|
|
sc->sc_wdcdev.DMA_cap = 2;
|
|
sc->sc_wdcdev.UDMA_cap = 2;
|
|
|
|
sc->sc_wdcdev.set_modes = ns_scx200_setup_channel;
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
|
|
|
|
/*
|
|
* Soekris net4801 errata 0003:
|
|
*
|
|
* The SC1100 built in busmaster IDE controller is pretty standard,
|
|
* but have two bugs: data transfers need to be dword aligned and
|
|
* it cannot do an exact 64Kbyte data transfer.
|
|
*
|
|
* Assume that reducing maximum segment size by one page
|
|
* will be enough, and restrict boundary too for extra certainty.
|
|
*/
|
|
if (sc->sc_pp->ide_product == PCI_PRODUCT_NS_SCX200_IDE) {
|
|
sc->sc_dma_maxsegsz = IDEDMA_BYTE_COUNT_MAX - PAGE_SIZE;
|
|
sc->sc_dma_boundary = IDEDMA_BYTE_COUNT_MAX - PAGE_SIZE;
|
|
}
|
|
|
|
/*
|
|
* This chip seems to be unable to do one-sector transfers
|
|
* using DMA.
|
|
*/
|
|
sc->sc_wdcdev.quirks = WDC_QUIRK_NOSHORTDMA;
|
|
|
|
pciide_print_channels(sc->sc_wdcdev.nchannels, interface);
|
|
|
|
for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
|
|
cp = &sc->pciide_channels[channel];
|
|
if (pciide_chansetup(sc, channel, interface) == 0)
|
|
continue;
|
|
pciide_map_compat_intr(pa, cp, channel, interface);
|
|
if (cp->hw_ok == 0)
|
|
continue;
|
|
pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
|
|
pciide_pci_intr);
|
|
if (cp->hw_ok == 0) {
|
|
pciide_unmap_compat_intr(pa, cp, channel, interface);
|
|
continue;
|
|
}
|
|
sc->sc_wdcdev.set_modes(&cp->wdc_channel);
|
|
}
|
|
}
|
|
|
|
void
|
|
ns_scx200_setup_channel(struct channel_softc *chp)
|
|
{
|
|
struct ata_drive_datas *drvp;
|
|
int drive, mode;
|
|
u_int32_t idedma_ctl;
|
|
struct pciide_channel *cp = (struct pciide_channel*)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
int channel = chp->channel;
|
|
int pioformat;
|
|
pcireg_t piotim, dmatim;
|
|
|
|
/* Setup DMA if needed */
|
|
pciide_channel_dma_setup(cp);
|
|
|
|
idedma_ctl = 0;
|
|
|
|
pioformat = (pci_conf_read(sc->sc_pc, sc->sc_tag,
|
|
SCx200_TIM_DMA(0, 0)) >> SCx200_PIOFORMAT_SHIFT) & 0x01;
|
|
WDCDEBUG_PRINT(("%s: pio format %d\n", __func__, pioformat),
|
|
DEBUG_PROBE);
|
|
|
|
/* Per channel settings */
|
|
for (drive = 0; drive < 2; drive++) {
|
|
drvp = &chp->ch_drive[drive];
|
|
|
|
/* If no drive, skip */
|
|
if ((drvp->drive_flags & DRIVE) == 0)
|
|
continue;
|
|
|
|
piotim = pci_conf_read(sc->sc_pc, sc->sc_tag,
|
|
SCx200_TIM_PIO(channel, drive));
|
|
dmatim = pci_conf_read(sc->sc_pc, sc->sc_tag,
|
|
SCx200_TIM_DMA(channel, drive));
|
|
WDCDEBUG_PRINT(("%s:%d:%d: piotim=0x%x, dmatim=0x%x\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, channel, drive,
|
|
piotim, dmatim), DEBUG_PROBE);
|
|
|
|
if ((chp->wdc->cap & WDC_CAPABILITY_UDMA) != 0 &&
|
|
(drvp->drive_flags & DRIVE_UDMA) != 0) {
|
|
/* Setup UltraDMA mode */
|
|
drvp->drive_flags &= ~DRIVE_DMA;
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
dmatim = scx200_udma33[drvp->UDMA_mode];
|
|
mode = drvp->PIO_mode;
|
|
} else if ((chp->wdc->cap & WDC_CAPABILITY_DMA) != 0 &&
|
|
(drvp->drive_flags & DRIVE_DMA) != 0) {
|
|
/* Setup multiword DMA mode */
|
|
drvp->drive_flags &= ~DRIVE_UDMA;
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
dmatim = scx200_dma33[drvp->DMA_mode];
|
|
|
|
/* mode = min(pio, dma + 2) */
|
|
if (drvp->PIO_mode <= (drvp->DMA_mode + 2))
|
|
mode = drvp->PIO_mode;
|
|
else
|
|
mode = drvp->DMA_mode + 2;
|
|
} else {
|
|
mode = drvp->PIO_mode;
|
|
}
|
|
|
|
/* Setup PIO mode */
|
|
drvp->PIO_mode = mode;
|
|
if (mode < 2)
|
|
drvp->DMA_mode = 0;
|
|
else
|
|
drvp->DMA_mode = mode - 2;
|
|
|
|
piotim = scx200_pio33[pioformat][drvp->PIO_mode];
|
|
|
|
WDCDEBUG_PRINT(("%s:%d:%d: new piotim=0x%x, dmatim=0x%x\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, channel, drive,
|
|
piotim, dmatim), DEBUG_PROBE);
|
|
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag,
|
|
SCx200_TIM_PIO(channel, drive), piotim);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag,
|
|
SCx200_TIM_DMA(channel, drive), dmatim);
|
|
}
|
|
|
|
if (idedma_ctl != 0) {
|
|
/* Add software bits in status register */
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(channel), idedma_ctl);
|
|
}
|
|
|
|
pciide_print_modes(cp);
|
|
}
|
|
|
|
void
|
|
acer_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_channel *cp;
|
|
int channel;
|
|
pcireg_t cr, interface;
|
|
bus_size_t cmdsize, ctlsize;
|
|
int rev = sc->sc_rev;
|
|
|
|
printf(": DMA");
|
|
pciide_mapreg_dma(sc, pa);
|
|
sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
|
|
WDC_CAPABILITY_MODE;
|
|
|
|
if (sc->sc_dma_ok) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA;
|
|
if (rev >= 0x20) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_UDMA;
|
|
if (rev >= 0xC4)
|
|
sc->sc_wdcdev.UDMA_cap = 5;
|
|
else if (rev >= 0xC2)
|
|
sc->sc_wdcdev.UDMA_cap = 4;
|
|
else
|
|
sc->sc_wdcdev.UDMA_cap = 2;
|
|
}
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_IRQACK;
|
|
sc->sc_wdcdev.irqack = pciide_irqack;
|
|
if (rev <= 0xC4)
|
|
sc->sc_wdcdev.dma_init = acer_dma_init;
|
|
}
|
|
|
|
sc->sc_wdcdev.PIO_cap = 4;
|
|
sc->sc_wdcdev.DMA_cap = 2;
|
|
sc->sc_wdcdev.set_modes = acer_setup_channel;
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
|
|
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag, ACER_CDRC,
|
|
(pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_CDRC) |
|
|
ACER_CDRC_DMA_EN) & ~ACER_CDRC_FIFO_DISABLE);
|
|
|
|
/* Enable "microsoft register bits" R/W. */
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag, ACER_CCAR3,
|
|
pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_CCAR3) | ACER_CCAR3_PI);
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag, ACER_CCAR1,
|
|
pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_CCAR1) &
|
|
~(ACER_CHANSTATUS_RO|PCIIDE_CHAN_RO(0)|PCIIDE_CHAN_RO(1)));
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag, ACER_CCAR2,
|
|
pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_CCAR2) &
|
|
~ACER_CHANSTATUSREGS_RO);
|
|
cr = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_CLASS_REG);
|
|
cr |= (PCIIDE_CHANSTATUS_EN << PCI_INTERFACE_SHIFT);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_CLASS_REG, cr);
|
|
/* Don't use cr, re-read the real register content instead */
|
|
interface = PCI_INTERFACE(pci_conf_read(sc->sc_pc, sc->sc_tag,
|
|
PCI_CLASS_REG));
|
|
|
|
pciide_print_channels(sc->sc_wdcdev.nchannels, interface);
|
|
|
|
/* From linux: enable "Cable Detection" */
|
|
if (rev >= 0xC2)
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag, ACER_0x4B,
|
|
pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_0x4B)
|
|
| ACER_0x4B_CDETECT);
|
|
|
|
for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
|
|
cp = &sc->pciide_channels[channel];
|
|
if (pciide_chansetup(sc, channel, interface) == 0)
|
|
continue;
|
|
if ((interface & PCIIDE_CHAN_EN(channel)) == 0) {
|
|
printf("%s: %s ignored (disabled)\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
|
|
cp->hw_ok = 0;
|
|
continue;
|
|
}
|
|
pciide_map_compat_intr(pa, cp, channel, interface);
|
|
if (cp->hw_ok == 0)
|
|
continue;
|
|
pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
|
|
(rev >= 0xC2) ? pciide_pci_intr : acer_pci_intr);
|
|
if (cp->hw_ok == 0) {
|
|
pciide_unmap_compat_intr(pa, cp, channel, interface);
|
|
continue;
|
|
}
|
|
if (pciide_chan_candisable(cp)) {
|
|
cr &= ~(PCIIDE_CHAN_EN(channel) << PCI_INTERFACE_SHIFT);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag,
|
|
PCI_CLASS_REG, cr);
|
|
}
|
|
if (cp->hw_ok == 0) {
|
|
pciide_unmap_compat_intr(pa, cp, channel, interface);
|
|
continue;
|
|
}
|
|
acer_setup_channel(&cp->wdc_channel);
|
|
}
|
|
}
|
|
|
|
void
|
|
acer_setup_channel(struct channel_softc *chp)
|
|
{
|
|
struct ata_drive_datas *drvp;
|
|
int drive;
|
|
u_int32_t acer_fifo_udma;
|
|
u_int32_t idedma_ctl;
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
|
|
idedma_ctl = 0;
|
|
acer_fifo_udma = pci_conf_read(sc->sc_pc, sc->sc_tag, ACER_FTH_UDMA);
|
|
WDCDEBUG_PRINT(("acer_setup_channel: old fifo/udma reg 0x%x\n",
|
|
acer_fifo_udma), DEBUG_PROBE);
|
|
/* setup DMA if needed */
|
|
pciide_channel_dma_setup(cp);
|
|
|
|
if ((chp->ch_drive[0].drive_flags | chp->ch_drive[1].drive_flags) &
|
|
DRIVE_UDMA) { /* check 80 pins cable */
|
|
if (pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_0x4A) &
|
|
ACER_0x4A_80PIN(chp->channel)) {
|
|
WDCDEBUG_PRINT(("%s:%d: 80-wire cable not detected\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, chp->channel),
|
|
DEBUG_PROBE);
|
|
if (chp->ch_drive[0].UDMA_mode > 2)
|
|
chp->ch_drive[0].UDMA_mode = 2;
|
|
if (chp->ch_drive[1].UDMA_mode > 2)
|
|
chp->ch_drive[1].UDMA_mode = 2;
|
|
}
|
|
}
|
|
|
|
for (drive = 0; drive < 2; drive++) {
|
|
drvp = &chp->ch_drive[drive];
|
|
/* If no drive, skip */
|
|
if ((drvp->drive_flags & DRIVE) == 0)
|
|
continue;
|
|
WDCDEBUG_PRINT(("acer_setup_channel: old timings reg for "
|
|
"channel %d drive %d 0x%x\n", chp->channel, drive,
|
|
pciide_pci_read(sc->sc_pc, sc->sc_tag,
|
|
ACER_IDETIM(chp->channel, drive))), DEBUG_PROBE);
|
|
/* clear FIFO/DMA mode */
|
|
acer_fifo_udma &= ~(ACER_FTH_OPL(chp->channel, drive, 0x3) |
|
|
ACER_UDMA_EN(chp->channel, drive) |
|
|
ACER_UDMA_TIM(chp->channel, drive, 0x7));
|
|
|
|
/* add timing values, setup DMA if needed */
|
|
if ((drvp->drive_flags & DRIVE_DMA) == 0 &&
|
|
(drvp->drive_flags & DRIVE_UDMA) == 0) {
|
|
acer_fifo_udma |=
|
|
ACER_FTH_OPL(chp->channel, drive, 0x1);
|
|
goto pio;
|
|
}
|
|
|
|
acer_fifo_udma |= ACER_FTH_OPL(chp->channel, drive, 0x2);
|
|
if (drvp->drive_flags & DRIVE_UDMA) {
|
|
/* use Ultra/DMA */
|
|
drvp->drive_flags &= ~DRIVE_DMA;
|
|
acer_fifo_udma |= ACER_UDMA_EN(chp->channel, drive);
|
|
acer_fifo_udma |=
|
|
ACER_UDMA_TIM(chp->channel, drive,
|
|
acer_udma[drvp->UDMA_mode]);
|
|
/* XXX disable if one drive < UDMA3 ? */
|
|
if (drvp->UDMA_mode >= 3) {
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag,
|
|
ACER_0x4B,
|
|
pciide_pci_read(sc->sc_pc, sc->sc_tag,
|
|
ACER_0x4B) | ACER_0x4B_UDMA66);
|
|
}
|
|
} else {
|
|
/*
|
|
* use Multiword DMA
|
|
* Timings will be used for both PIO and DMA,
|
|
* so adjust DMA mode if needed
|
|
*/
|
|
if (drvp->PIO_mode > (drvp->DMA_mode + 2))
|
|
drvp->PIO_mode = drvp->DMA_mode + 2;
|
|
if (drvp->DMA_mode + 2 > (drvp->PIO_mode))
|
|
drvp->DMA_mode = (drvp->PIO_mode > 2) ?
|
|
drvp->PIO_mode - 2 : 0;
|
|
if (drvp->DMA_mode == 0)
|
|
drvp->PIO_mode = 0;
|
|
}
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
pio: pciide_pci_write(sc->sc_pc, sc->sc_tag,
|
|
ACER_IDETIM(chp->channel, drive),
|
|
acer_pio[drvp->PIO_mode]);
|
|
}
|
|
WDCDEBUG_PRINT(("acer_setup_channel: new fifo/udma reg 0x%x\n",
|
|
acer_fifo_udma), DEBUG_PROBE);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, ACER_FTH_UDMA, acer_fifo_udma);
|
|
if (idedma_ctl != 0) {
|
|
/* Add software bits in status register */
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(chp->channel), idedma_ctl);
|
|
}
|
|
pciide_print_modes(cp);
|
|
}
|
|
|
|
int
|
|
acer_pci_intr(void *arg)
|
|
{
|
|
struct pciide_softc *sc = arg;
|
|
struct pciide_channel *cp;
|
|
struct channel_softc *wdc_cp;
|
|
int i, rv, crv;
|
|
u_int32_t chids;
|
|
|
|
rv = 0;
|
|
chids = pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_CHIDS);
|
|
for (i = 0; i < sc->sc_wdcdev.nchannels; i++) {
|
|
cp = &sc->pciide_channels[i];
|
|
wdc_cp = &cp->wdc_channel;
|
|
/* If a compat channel skip. */
|
|
if (cp->compat)
|
|
continue;
|
|
if (chids & ACER_CHIDS_INT(i)) {
|
|
crv = wdcintr(wdc_cp);
|
|
if (crv == 0)
|
|
printf("%s:%d: bogus intr\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, i);
|
|
else
|
|
rv = 1;
|
|
}
|
|
}
|
|
return (rv);
|
|
}
|
|
|
|
int
|
|
acer_dma_init(void *v, int channel, int drive, void *databuf,
|
|
size_t datalen, int flags)
|
|
{
|
|
/* Use PIO for LBA48 transfers. */
|
|
if (flags & WDC_DMA_LBA48)
|
|
return (EINVAL);
|
|
|
|
return (pciide_dma_init(v, channel, drive, databuf, datalen, flags));
|
|
}
|
|
|
|
void
|
|
hpt_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_channel *cp;
|
|
int i, compatchan, revision;
|
|
pcireg_t interface;
|
|
bus_size_t cmdsize, ctlsize;
|
|
|
|
revision = sc->sc_rev;
|
|
|
|
/*
|
|
* when the chip is in native mode it identifies itself as a
|
|
* 'misc mass storage'. Fake interface in this case.
|
|
*/
|
|
if (PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_IDE) {
|
|
interface = PCI_INTERFACE(pa->pa_class);
|
|
} else {
|
|
interface = PCIIDE_INTERFACE_BUS_MASTER_DMA |
|
|
PCIIDE_INTERFACE_PCI(0);
|
|
if ((sc->sc_pp->ide_product == PCI_PRODUCT_TRIONES_HPT366 &&
|
|
(revision == HPT370_REV || revision == HPT370A_REV ||
|
|
revision == HPT372_REV)) ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_TRIONES_HPT372A ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_TRIONES_HPT302 ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_TRIONES_HPT371 ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_TRIONES_HPT374)
|
|
interface |= PCIIDE_INTERFACE_PCI(1);
|
|
}
|
|
|
|
printf(": DMA");
|
|
pciide_mapreg_dma(sc, pa);
|
|
printf("\n");
|
|
sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
|
|
WDC_CAPABILITY_MODE;
|
|
if (sc->sc_dma_ok) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_UDMA;
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_IRQACK;
|
|
sc->sc_wdcdev.irqack = pciide_irqack;
|
|
}
|
|
sc->sc_wdcdev.PIO_cap = 4;
|
|
sc->sc_wdcdev.DMA_cap = 2;
|
|
|
|
sc->sc_wdcdev.set_modes = hpt_setup_channel;
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
if (sc->sc_pp->ide_product == PCI_PRODUCT_TRIONES_HPT366 &&
|
|
revision == HPT366_REV) {
|
|
sc->sc_wdcdev.UDMA_cap = 4;
|
|
/*
|
|
* The 366 has 2 PCI IDE functions, one for primary and one
|
|
* for secondary. So we need to call pciide_mapregs_compat()
|
|
* with the real channel
|
|
*/
|
|
if (pa->pa_function == 0) {
|
|
compatchan = 0;
|
|
} else if (pa->pa_function == 1) {
|
|
compatchan = 1;
|
|
} else {
|
|
printf("%s: unexpected PCI function %d\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, pa->pa_function);
|
|
return;
|
|
}
|
|
sc->sc_wdcdev.nchannels = 1;
|
|
} else {
|
|
sc->sc_wdcdev.nchannels = 2;
|
|
if (sc->sc_pp->ide_product == PCI_PRODUCT_TRIONES_HPT372A ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_TRIONES_HPT302 ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_TRIONES_HPT371 ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_TRIONES_HPT374)
|
|
sc->sc_wdcdev.UDMA_cap = 6;
|
|
else if (sc->sc_pp->ide_product == PCI_PRODUCT_TRIONES_HPT366) {
|
|
if (revision == HPT372_REV)
|
|
sc->sc_wdcdev.UDMA_cap = 6;
|
|
else
|
|
sc->sc_wdcdev.UDMA_cap = 5;
|
|
}
|
|
}
|
|
for (i = 0; i < sc->sc_wdcdev.nchannels; i++) {
|
|
cp = &sc->pciide_channels[i];
|
|
compatchan = 0;
|
|
if (sc->sc_wdcdev.nchannels > 1) {
|
|
compatchan = i;
|
|
if((pciide_pci_read(sc->sc_pc, sc->sc_tag,
|
|
HPT370_CTRL1(i)) & HPT370_CTRL1_EN) == 0) {
|
|
printf("%s: %s ignored (disabled)\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
|
|
cp->hw_ok = 0;
|
|
continue;
|
|
}
|
|
}
|
|
if (pciide_chansetup(sc, i, interface) == 0)
|
|
continue;
|
|
if (interface & PCIIDE_INTERFACE_PCI(i)) {
|
|
cp->hw_ok = pciide_mapregs_native(pa, cp, &cmdsize,
|
|
&ctlsize, hpt_pci_intr);
|
|
} else {
|
|
cp->hw_ok = pciide_mapregs_compat(pa, cp, compatchan,
|
|
&cmdsize, &ctlsize);
|
|
}
|
|
if (cp->hw_ok == 0)
|
|
return;
|
|
cp->wdc_channel.data32iot = cp->wdc_channel.cmd_iot;
|
|
cp->wdc_channel.data32ioh = cp->wdc_channel.cmd_ioh;
|
|
wdcattach(&cp->wdc_channel);
|
|
hpt_setup_channel(&cp->wdc_channel);
|
|
}
|
|
if ((sc->sc_pp->ide_product == PCI_PRODUCT_TRIONES_HPT366 &&
|
|
(revision == HPT370_REV || revision == HPT370A_REV ||
|
|
revision == HPT372_REV)) ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_TRIONES_HPT372A ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_TRIONES_HPT302 ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_TRIONES_HPT371 ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_TRIONES_HPT374) {
|
|
/*
|
|
* Turn off fast interrupts
|
|
*/
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag, HPT370_CTRL2(0),
|
|
pciide_pci_read(sc->sc_pc, sc->sc_tag, HPT370_CTRL2(0)) &
|
|
~(HPT370_CTRL2_FASTIRQ | HPT370_CTRL2_HIRQ));
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag, HPT370_CTRL2(1),
|
|
pciide_pci_read(sc->sc_pc, sc->sc_tag, HPT370_CTRL2(1)) &
|
|
~(HPT370_CTRL2_FASTIRQ | HPT370_CTRL2_HIRQ));
|
|
|
|
/*
|
|
* HPT370 and higher has a bit to disable interrupts,
|
|
* make sure to clear it
|
|
*/
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag, HPT_CSEL,
|
|
pciide_pci_read(sc->sc_pc, sc->sc_tag, HPT_CSEL) &
|
|
~HPT_CSEL_IRQDIS);
|
|
}
|
|
/* set clocks, etc (mandatory on 372/4, optional otherwise) */
|
|
if (sc->sc_pp->ide_product == PCI_PRODUCT_TRIONES_HPT372A ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_TRIONES_HPT302 ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_TRIONES_HPT371 ||
|
|
sc->sc_pp->ide_product == PCI_PRODUCT_TRIONES_HPT374 ||
|
|
(sc->sc_pp->ide_product == PCI_PRODUCT_TRIONES_HPT366 &&
|
|
revision == HPT372_REV))
|
|
pciide_pci_write(sc->sc_pc, sc->sc_tag, HPT_SC2,
|
|
(pciide_pci_read(sc->sc_pc, sc->sc_tag, HPT_SC2) &
|
|
HPT_SC2_MAEN) | HPT_SC2_OSC_EN);
|
|
|
|
return;
|
|
}
|
|
|
|
void
|
|
hpt_setup_channel(struct channel_softc *chp)
|
|
{
|
|
struct ata_drive_datas *drvp;
|
|
int drive;
|
|
int cable;
|
|
u_int32_t before, after;
|
|
u_int32_t idedma_ctl;
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
int revision = sc->sc_rev;
|
|
u_int32_t *tim_pio, *tim_dma, *tim_udma;
|
|
|
|
cable = pciide_pci_read(sc->sc_pc, sc->sc_tag, HPT_CSEL);
|
|
|
|
/* setup DMA if needed */
|
|
pciide_channel_dma_setup(cp);
|
|
|
|
idedma_ctl = 0;
|
|
|
|
switch (sc->sc_pp->ide_product) {
|
|
case PCI_PRODUCT_TRIONES_HPT366:
|
|
if (revision == HPT370_REV ||
|
|
revision == HPT370A_REV) {
|
|
tim_pio = hpt370_pio;
|
|
tim_dma = hpt370_dma;
|
|
tim_udma = hpt370_udma;
|
|
} else if (revision == HPT372_REV) {
|
|
tim_pio = hpt372_pio;
|
|
tim_dma = hpt372_dma;
|
|
tim_udma = hpt372_udma;
|
|
} else {
|
|
tim_pio = hpt366_pio;
|
|
tim_dma = hpt366_dma;
|
|
tim_udma = hpt366_udma;
|
|
}
|
|
break;
|
|
case PCI_PRODUCT_TRIONES_HPT372A:
|
|
case PCI_PRODUCT_TRIONES_HPT302:
|
|
case PCI_PRODUCT_TRIONES_HPT371:
|
|
tim_pio = hpt372_pio;
|
|
tim_dma = hpt372_dma;
|
|
tim_udma = hpt372_udma;
|
|
break;
|
|
case PCI_PRODUCT_TRIONES_HPT374:
|
|
tim_pio = hpt374_pio;
|
|
tim_dma = hpt374_dma;
|
|
tim_udma = hpt374_udma;
|
|
break;
|
|
default:
|
|
printf("%s: no known timing values\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname);
|
|
goto end;
|
|
}
|
|
|
|
/* Per drive settings */
|
|
for (drive = 0; drive < 2; drive++) {
|
|
drvp = &chp->ch_drive[drive];
|
|
/* If no drive, skip */
|
|
if ((drvp->drive_flags & DRIVE) == 0)
|
|
continue;
|
|
before = pci_conf_read(sc->sc_pc, sc->sc_tag,
|
|
HPT_IDETIM(chp->channel, drive));
|
|
|
|
/* add timing values, setup DMA if needed */
|
|
if (drvp->drive_flags & DRIVE_UDMA) {
|
|
/* use Ultra/DMA */
|
|
drvp->drive_flags &= ~DRIVE_DMA;
|
|
if ((cable & HPT_CSEL_CBLID(chp->channel)) != 0 &&
|
|
drvp->UDMA_mode > 2) {
|
|
WDCDEBUG_PRINT(("%s(%s:%d:%d): 80-wire "
|
|
"cable not detected\n", drvp->drive_name,
|
|
sc->sc_wdcdev.sc_dev.dv_xname,
|
|
chp->channel, drive), DEBUG_PROBE);
|
|
drvp->UDMA_mode = 2;
|
|
}
|
|
after = tim_udma[drvp->UDMA_mode];
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
} else if (drvp->drive_flags & DRIVE_DMA) {
|
|
/*
|
|
* use Multiword DMA.
|
|
* Timings will be used for both PIO and DMA, so adjust
|
|
* DMA mode if needed
|
|
*/
|
|
if (drvp->PIO_mode >= 3 &&
|
|
(drvp->DMA_mode + 2) > drvp->PIO_mode) {
|
|
drvp->DMA_mode = drvp->PIO_mode - 2;
|
|
}
|
|
after = tim_dma[drvp->DMA_mode];
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
} else {
|
|
/* PIO only */
|
|
after = tim_pio[drvp->PIO_mode];
|
|
}
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag,
|
|
HPT_IDETIM(chp->channel, drive), after);
|
|
WDCDEBUG_PRINT(("%s: bus speed register set to 0x%08x "
|
|
"(BIOS 0x%08x)\n", sc->sc_wdcdev.sc_dev.dv_xname,
|
|
after, before), DEBUG_PROBE);
|
|
}
|
|
end:
|
|
if (idedma_ctl != 0) {
|
|
/* Add software bits in status register */
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(chp->channel), idedma_ctl);
|
|
}
|
|
pciide_print_modes(cp);
|
|
}
|
|
|
|
int
|
|
hpt_pci_intr(void *arg)
|
|
{
|
|
struct pciide_softc *sc = arg;
|
|
struct pciide_channel *cp;
|
|
struct channel_softc *wdc_cp;
|
|
int rv = 0;
|
|
int dmastat, i, crv;
|
|
|
|
for (i = 0; i < sc->sc_wdcdev.nchannels; i++) {
|
|
dmastat = bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(i));
|
|
if((dmastat & (IDEDMA_CTL_ACT | IDEDMA_CTL_INTR)) !=
|
|
IDEDMA_CTL_INTR)
|
|
continue;
|
|
cp = &sc->pciide_channels[i];
|
|
wdc_cp = &cp->wdc_channel;
|
|
crv = wdcintr(wdc_cp);
|
|
if (crv == 0) {
|
|
printf("%s:%d: bogus intr\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, i);
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(i), dmastat);
|
|
} else
|
|
rv = 1;
|
|
}
|
|
return (rv);
|
|
}
|
|
|
|
/* Macros to test product */
|
|
#define PDC_IS_262(sc) \
|
|
((sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_PDC20262 || \
|
|
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_PDC20265 || \
|
|
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_PDC20267)
|
|
#define PDC_IS_265(sc) \
|
|
((sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_PDC20265 || \
|
|
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_PDC20267 || \
|
|
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_PDC20268 || \
|
|
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_PDC20268R || \
|
|
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_PDC20269 || \
|
|
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_PDC20271 || \
|
|
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_PDC20275 || \
|
|
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_PDC20276 || \
|
|
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_PDC20277)
|
|
#define PDC_IS_268(sc) \
|
|
((sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_PDC20268 || \
|
|
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_PDC20268R || \
|
|
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_PDC20269 || \
|
|
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_PDC20271 || \
|
|
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_PDC20275 || \
|
|
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_PDC20276 || \
|
|
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_PDC20277)
|
|
#define PDC_IS_269(sc) \
|
|
((sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_PDC20269 || \
|
|
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_PDC20271 || \
|
|
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_PDC20275 || \
|
|
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_PDC20276 || \
|
|
(sc)->sc_pp->ide_product == PCI_PRODUCT_PROMISE_PDC20277)
|
|
|
|
u_int8_t
|
|
pdc268_config_read(struct channel_softc *chp, int index)
|
|
{
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
int channel = chp->channel;
|
|
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
PDC268_INDEX(channel), index);
|
|
return (bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
PDC268_DATA(channel)));
|
|
}
|
|
|
|
void
|
|
pdc202xx_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_channel *cp;
|
|
int channel;
|
|
pcireg_t interface, st, mode;
|
|
bus_size_t cmdsize, ctlsize;
|
|
|
|
if (!PDC_IS_268(sc)) {
|
|
st = pci_conf_read(sc->sc_pc, sc->sc_tag, PDC2xx_STATE);
|
|
WDCDEBUG_PRINT(("pdc202xx_setup_chip: controller state 0x%x\n",
|
|
st), DEBUG_PROBE);
|
|
}
|
|
|
|
/* turn off RAID mode */
|
|
if (!PDC_IS_268(sc))
|
|
st &= ~PDC2xx_STATE_IDERAID;
|
|
|
|
/*
|
|
* can't rely on the PCI_CLASS_REG content if the chip was in raid
|
|
* mode. We have to fake interface
|
|
*/
|
|
interface = PCIIDE_INTERFACE_SETTABLE(0) | PCIIDE_INTERFACE_SETTABLE(1);
|
|
if (PDC_IS_268(sc) || (st & PDC2xx_STATE_NATIVE))
|
|
interface |= PCIIDE_INTERFACE_PCI(0) | PCIIDE_INTERFACE_PCI(1);
|
|
|
|
printf(": DMA");
|
|
pciide_mapreg_dma(sc, pa);
|
|
|
|
sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
|
|
WDC_CAPABILITY_MODE;
|
|
if (sc->sc_pp->ide_product == PCI_PRODUCT_PROMISE_PDC20246 ||
|
|
PDC_IS_262(sc))
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_NO_ATAPI_DMA;
|
|
if (sc->sc_dma_ok) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_UDMA;
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_IRQACK;
|
|
sc->sc_wdcdev.irqack = pciide_irqack;
|
|
}
|
|
sc->sc_wdcdev.PIO_cap = 4;
|
|
sc->sc_wdcdev.DMA_cap = 2;
|
|
if (PDC_IS_269(sc))
|
|
sc->sc_wdcdev.UDMA_cap = 6;
|
|
else if (PDC_IS_265(sc))
|
|
sc->sc_wdcdev.UDMA_cap = 5;
|
|
else if (PDC_IS_262(sc))
|
|
sc->sc_wdcdev.UDMA_cap = 4;
|
|
else
|
|
sc->sc_wdcdev.UDMA_cap = 2;
|
|
sc->sc_wdcdev.set_modes = PDC_IS_268(sc) ?
|
|
pdc20268_setup_channel : pdc202xx_setup_channel;
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
|
|
|
|
if (PDC_IS_262(sc)) {
|
|
sc->sc_wdcdev.dma_start = pdc20262_dma_start;
|
|
sc->sc_wdcdev.dma_finish = pdc20262_dma_finish;
|
|
}
|
|
|
|
pciide_print_channels(sc->sc_wdcdev.nchannels, interface);
|
|
if (!PDC_IS_268(sc)) {
|
|
/* setup failsafe defaults */
|
|
mode = 0;
|
|
mode = PDC2xx_TIM_SET_PA(mode, pdc2xx_pa[0]);
|
|
mode = PDC2xx_TIM_SET_PB(mode, pdc2xx_pb[0]);
|
|
mode = PDC2xx_TIM_SET_MB(mode, pdc2xx_dma_mb[0]);
|
|
mode = PDC2xx_TIM_SET_MC(mode, pdc2xx_dma_mc[0]);
|
|
for (channel = 0;
|
|
channel < sc->sc_wdcdev.nchannels;
|
|
channel++) {
|
|
WDCDEBUG_PRINT(("pdc202xx_setup_chip: channel %d "
|
|
"drive 0 initial timings 0x%x, now 0x%x\n",
|
|
channel, pci_conf_read(sc->sc_pc, sc->sc_tag,
|
|
PDC2xx_TIM(channel, 0)), mode | PDC2xx_TIM_IORDYp),
|
|
DEBUG_PROBE);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag,
|
|
PDC2xx_TIM(channel, 0), mode | PDC2xx_TIM_IORDYp);
|
|
WDCDEBUG_PRINT(("pdc202xx_setup_chip: channel %d "
|
|
"drive 1 initial timings 0x%x, now 0x%x\n",
|
|
channel, pci_conf_read(sc->sc_pc, sc->sc_tag,
|
|
PDC2xx_TIM(channel, 1)), mode), DEBUG_PROBE);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag,
|
|
PDC2xx_TIM(channel, 1), mode);
|
|
}
|
|
|
|
mode = PDC2xx_SCR_DMA;
|
|
if (PDC_IS_262(sc)) {
|
|
mode = PDC2xx_SCR_SET_GEN(mode, PDC262_SCR_GEN_LAT);
|
|
} else {
|
|
/* the BIOS set it up this way */
|
|
mode = PDC2xx_SCR_SET_GEN(mode, 0x1);
|
|
}
|
|
mode = PDC2xx_SCR_SET_I2C(mode, 0x3); /* ditto */
|
|
mode = PDC2xx_SCR_SET_POLL(mode, 0x1); /* ditto */
|
|
WDCDEBUG_PRINT(("pdc202xx_setup_chip: initial SCR 0x%x, "
|
|
"now 0x%x\n",
|
|
bus_space_read_4(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
PDC2xx_SCR),
|
|
mode), DEBUG_PROBE);
|
|
bus_space_write_4(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
PDC2xx_SCR, mode);
|
|
|
|
/* controller initial state register is OK even without BIOS */
|
|
/* Set DMA mode to IDE DMA compatibility */
|
|
mode =
|
|
bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh, PDC2xx_PM);
|
|
WDCDEBUG_PRINT(("pdc202xx_setup_chip: primary mode 0x%x", mode),
|
|
DEBUG_PROBE);
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh, PDC2xx_PM,
|
|
mode | 0x1);
|
|
mode =
|
|
bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh, PDC2xx_SM);
|
|
WDCDEBUG_PRINT((", secondary mode 0x%x\n", mode ), DEBUG_PROBE);
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh, PDC2xx_SM,
|
|
mode | 0x1);
|
|
}
|
|
|
|
for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
|
|
cp = &sc->pciide_channels[channel];
|
|
if (pciide_chansetup(sc, channel, interface) == 0)
|
|
continue;
|
|
if (!PDC_IS_268(sc) && (st & (PDC_IS_262(sc) ?
|
|
PDC262_STATE_EN(channel):PDC246_STATE_EN(channel))) == 0) {
|
|
printf("%s: %s ignored (disabled)\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
|
|
cp->hw_ok = 0;
|
|
continue;
|
|
}
|
|
pciide_map_compat_intr(pa, cp, channel, interface);
|
|
if (cp->hw_ok == 0)
|
|
continue;
|
|
if (PDC_IS_265(sc))
|
|
pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
|
|
pdc20265_pci_intr);
|
|
else
|
|
pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
|
|
pdc202xx_pci_intr);
|
|
if (cp->hw_ok == 0) {
|
|
pciide_unmap_compat_intr(pa, cp, channel, interface);
|
|
continue;
|
|
}
|
|
if (!PDC_IS_268(sc) && pciide_chan_candisable(cp)) {
|
|
st &= ~(PDC_IS_262(sc) ?
|
|
PDC262_STATE_EN(channel):PDC246_STATE_EN(channel));
|
|
pciide_unmap_compat_intr(pa, cp, channel, interface);
|
|
}
|
|
if (PDC_IS_268(sc))
|
|
pdc20268_setup_channel(&cp->wdc_channel);
|
|
else
|
|
pdc202xx_setup_channel(&cp->wdc_channel);
|
|
}
|
|
if (!PDC_IS_268(sc)) {
|
|
WDCDEBUG_PRINT(("pdc202xx_setup_chip: new controller state "
|
|
"0x%x\n", st), DEBUG_PROBE);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, PDC2xx_STATE, st);
|
|
}
|
|
return;
|
|
}
|
|
|
|
void
|
|
pdc202xx_setup_channel(struct channel_softc *chp)
|
|
{
|
|
struct ata_drive_datas *drvp;
|
|
int drive;
|
|
pcireg_t mode, st;
|
|
u_int32_t idedma_ctl, scr, atapi;
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
int channel = chp->channel;
|
|
|
|
/* setup DMA if needed */
|
|
pciide_channel_dma_setup(cp);
|
|
|
|
idedma_ctl = 0;
|
|
WDCDEBUG_PRINT(("pdc202xx_setup_channel %s: scr 0x%x\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname,
|
|
bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh, PDC262_U66)),
|
|
DEBUG_PROBE);
|
|
|
|
/* Per channel settings */
|
|
if (PDC_IS_262(sc)) {
|
|
scr = bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
PDC262_U66);
|
|
st = pci_conf_read(sc->sc_pc, sc->sc_tag, PDC2xx_STATE);
|
|
/* Check cable */
|
|
if ((st & PDC262_STATE_80P(channel)) != 0 &&
|
|
((chp->ch_drive[0].drive_flags & DRIVE_UDMA &&
|
|
chp->ch_drive[0].UDMA_mode > 2) ||
|
|
(chp->ch_drive[1].drive_flags & DRIVE_UDMA &&
|
|
chp->ch_drive[1].UDMA_mode > 2))) {
|
|
WDCDEBUG_PRINT(("%s:%d: 80-wire cable not detected\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, channel),
|
|
DEBUG_PROBE);
|
|
if (chp->ch_drive[0].UDMA_mode > 2)
|
|
chp->ch_drive[0].UDMA_mode = 2;
|
|
if (chp->ch_drive[1].UDMA_mode > 2)
|
|
chp->ch_drive[1].UDMA_mode = 2;
|
|
}
|
|
/* Trim UDMA mode */
|
|
if ((chp->ch_drive[0].drive_flags & DRIVE_UDMA &&
|
|
chp->ch_drive[0].UDMA_mode <= 2) ||
|
|
(chp->ch_drive[1].drive_flags & DRIVE_UDMA &&
|
|
chp->ch_drive[1].UDMA_mode <= 2)) {
|
|
if (chp->ch_drive[0].UDMA_mode > 2)
|
|
chp->ch_drive[0].UDMA_mode = 2;
|
|
if (chp->ch_drive[1].UDMA_mode > 2)
|
|
chp->ch_drive[1].UDMA_mode = 2;
|
|
}
|
|
/* Set U66 if needed */
|
|
if ((chp->ch_drive[0].drive_flags & DRIVE_UDMA &&
|
|
chp->ch_drive[0].UDMA_mode > 2) ||
|
|
(chp->ch_drive[1].drive_flags & DRIVE_UDMA &&
|
|
chp->ch_drive[1].UDMA_mode > 2))
|
|
scr |= PDC262_U66_EN(channel);
|
|
else
|
|
scr &= ~PDC262_U66_EN(channel);
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
PDC262_U66, scr);
|
|
WDCDEBUG_PRINT(("pdc202xx_setup_channel %s:%d: ATAPI 0x%x\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, channel,
|
|
bus_space_read_4(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
PDC262_ATAPI(channel))), DEBUG_PROBE);
|
|
if (chp->ch_drive[0].drive_flags & DRIVE_ATAPI ||
|
|
chp->ch_drive[1].drive_flags & DRIVE_ATAPI) {
|
|
if (((chp->ch_drive[0].drive_flags & DRIVE_UDMA) &&
|
|
!(chp->ch_drive[1].drive_flags & DRIVE_UDMA) &&
|
|
(chp->ch_drive[1].drive_flags & DRIVE_DMA)) ||
|
|
((chp->ch_drive[1].drive_flags & DRIVE_UDMA) &&
|
|
!(chp->ch_drive[0].drive_flags & DRIVE_UDMA) &&
|
|
(chp->ch_drive[0].drive_flags & DRIVE_DMA)))
|
|
atapi = 0;
|
|
else
|
|
atapi = PDC262_ATAPI_UDMA;
|
|
bus_space_write_4(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
PDC262_ATAPI(channel), atapi);
|
|
}
|
|
}
|
|
for (drive = 0; drive < 2; drive++) {
|
|
drvp = &chp->ch_drive[drive];
|
|
/* If no drive, skip */
|
|
if ((drvp->drive_flags & DRIVE) == 0)
|
|
continue;
|
|
mode = 0;
|
|
if (drvp->drive_flags & DRIVE_UDMA) {
|
|
/* use Ultra/DMA */
|
|
drvp->drive_flags &= ~DRIVE_DMA;
|
|
mode = PDC2xx_TIM_SET_MB(mode,
|
|
pdc2xx_udma_mb[drvp->UDMA_mode]);
|
|
mode = PDC2xx_TIM_SET_MC(mode,
|
|
pdc2xx_udma_mc[drvp->UDMA_mode]);
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
} else if (drvp->drive_flags & DRIVE_DMA) {
|
|
mode = PDC2xx_TIM_SET_MB(mode,
|
|
pdc2xx_dma_mb[drvp->DMA_mode]);
|
|
mode = PDC2xx_TIM_SET_MC(mode,
|
|
pdc2xx_dma_mc[drvp->DMA_mode]);
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
} else {
|
|
mode = PDC2xx_TIM_SET_MB(mode,
|
|
pdc2xx_dma_mb[0]);
|
|
mode = PDC2xx_TIM_SET_MC(mode,
|
|
pdc2xx_dma_mc[0]);
|
|
}
|
|
mode = PDC2xx_TIM_SET_PA(mode, pdc2xx_pa[drvp->PIO_mode]);
|
|
mode = PDC2xx_TIM_SET_PB(mode, pdc2xx_pb[drvp->PIO_mode]);
|
|
if (drvp->drive_flags & DRIVE_ATA)
|
|
mode |= PDC2xx_TIM_PRE;
|
|
mode |= PDC2xx_TIM_SYNC | PDC2xx_TIM_ERRDY;
|
|
if (drvp->PIO_mode >= 3) {
|
|
mode |= PDC2xx_TIM_IORDY;
|
|
if (drive == 0)
|
|
mode |= PDC2xx_TIM_IORDYp;
|
|
}
|
|
WDCDEBUG_PRINT(("pdc202xx_setup_channel: %s:%d:%d "
|
|
"timings 0x%x\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname,
|
|
chp->channel, drive, mode), DEBUG_PROBE);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag,
|
|
PDC2xx_TIM(chp->channel, drive), mode);
|
|
}
|
|
if (idedma_ctl != 0) {
|
|
/* Add software bits in status register */
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(channel), idedma_ctl);
|
|
}
|
|
pciide_print_modes(cp);
|
|
}
|
|
|
|
void
|
|
pdc20268_setup_channel(struct channel_softc *chp)
|
|
{
|
|
struct ata_drive_datas *drvp;
|
|
int drive, cable;
|
|
u_int32_t idedma_ctl;
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
int channel = chp->channel;
|
|
|
|
/* check 80 pins cable */
|
|
cable = pdc268_config_read(chp, 0x0b) & PDC268_CABLE;
|
|
|
|
/* setup DMA if needed */
|
|
pciide_channel_dma_setup(cp);
|
|
|
|
idedma_ctl = 0;
|
|
|
|
for (drive = 0; drive < 2; drive++) {
|
|
drvp = &chp->ch_drive[drive];
|
|
/* If no drive, skip */
|
|
if ((drvp->drive_flags & DRIVE) == 0)
|
|
continue;
|
|
if (drvp->drive_flags & DRIVE_UDMA) {
|
|
/* use Ultra/DMA */
|
|
drvp->drive_flags &= ~DRIVE_DMA;
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
if (cable && drvp->UDMA_mode > 2) {
|
|
WDCDEBUG_PRINT(("%s(%s:%d:%d): 80-wire "
|
|
"cable not detected\n", drvp->drive_name,
|
|
sc->sc_wdcdev.sc_dev.dv_xname,
|
|
channel, drive), DEBUG_PROBE);
|
|
drvp->UDMA_mode = 2;
|
|
}
|
|
} else if (drvp->drive_flags & DRIVE_DMA) {
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
}
|
|
}
|
|
/* nothing to do to setup modes, the controller snoop SET_FEATURE cmd */
|
|
if (idedma_ctl != 0) {
|
|
/* Add software bits in status register */
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(channel), idedma_ctl);
|
|
}
|
|
pciide_print_modes(cp);
|
|
}
|
|
|
|
int
|
|
pdc202xx_pci_intr(void *arg)
|
|
{
|
|
struct pciide_softc *sc = arg;
|
|
struct pciide_channel *cp;
|
|
struct channel_softc *wdc_cp;
|
|
int i, rv, crv;
|
|
u_int32_t scr;
|
|
|
|
rv = 0;
|
|
scr = bus_space_read_4(sc->sc_dma_iot, sc->sc_dma_ioh, PDC2xx_SCR);
|
|
for (i = 0; i < sc->sc_wdcdev.nchannels; i++) {
|
|
cp = &sc->pciide_channels[i];
|
|
wdc_cp = &cp->wdc_channel;
|
|
/* If a compat channel skip. */
|
|
if (cp->compat)
|
|
continue;
|
|
if (scr & PDC2xx_SCR_INT(i)) {
|
|
crv = wdcintr(wdc_cp);
|
|
if (crv == 0)
|
|
printf("%s:%d: bogus intr (reg 0x%x)\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, i, scr);
|
|
else
|
|
rv = 1;
|
|
}
|
|
}
|
|
return (rv);
|
|
}
|
|
|
|
int
|
|
pdc20265_pci_intr(void *arg)
|
|
{
|
|
struct pciide_softc *sc = arg;
|
|
struct pciide_channel *cp;
|
|
struct channel_softc *wdc_cp;
|
|
int i, rv, crv;
|
|
u_int32_t dmastat;
|
|
|
|
rv = 0;
|
|
for (i = 0; i < sc->sc_wdcdev.nchannels; i++) {
|
|
cp = &sc->pciide_channels[i];
|
|
wdc_cp = &cp->wdc_channel;
|
|
/* If a compat channel skip. */
|
|
if (cp->compat)
|
|
continue;
|
|
|
|
/*
|
|
* In case of shared IRQ check that the interrupt
|
|
* was actually generated by this channel.
|
|
* Only check the channel that is enabled.
|
|
*/
|
|
if (cp->hw_ok && PDC_IS_268(sc)) {
|
|
if ((pdc268_config_read(wdc_cp,
|
|
0x0b) & PDC268_INTR) == 0)
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* The Ultra/100 seems to assert PDC2xx_SCR_INT * spuriously,
|
|
* however it asserts INT in IDEDMA_CTL even for non-DMA ops.
|
|
* So use it instead (requires 2 reg reads instead of 1,
|
|
* but we can't do it another way).
|
|
*/
|
|
dmastat = bus_space_read_1(sc->sc_dma_iot,
|
|
sc->sc_dma_ioh, IDEDMA_CTL(i));
|
|
if ((dmastat & IDEDMA_CTL_INTR) == 0)
|
|
continue;
|
|
|
|
crv = wdcintr(wdc_cp);
|
|
if (crv == 0)
|
|
printf("%s:%d: bogus intr\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, i);
|
|
else
|
|
rv = 1;
|
|
}
|
|
return (rv);
|
|
}
|
|
|
|
void
|
|
pdc20262_dma_start(void *v, int channel, int drive)
|
|
{
|
|
struct pciide_softc *sc = v;
|
|
struct pciide_dma_maps *dma_maps =
|
|
&sc->pciide_channels[channel].dma_maps[drive];
|
|
u_int8_t clock;
|
|
u_int32_t count;
|
|
|
|
if (dma_maps->dma_flags & WDC_DMA_LBA48) {
|
|
clock = bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
PDC262_U66);
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
PDC262_U66, clock | PDC262_U66_EN(channel));
|
|
count = dma_maps->dmamap_xfer->dm_mapsize >> 1;
|
|
count |= dma_maps->dma_flags & WDC_DMA_READ ?
|
|
PDC262_ATAPI_LBA48_READ : PDC262_ATAPI_LBA48_WRITE;
|
|
bus_space_write_4(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
PDC262_ATAPI(channel), count);
|
|
}
|
|
|
|
pciide_dma_start(v, channel, drive);
|
|
}
|
|
|
|
int
|
|
pdc20262_dma_finish(void *v, int channel, int drive, int force)
|
|
{
|
|
struct pciide_softc *sc = v;
|
|
struct pciide_dma_maps *dma_maps =
|
|
&sc->pciide_channels[channel].dma_maps[drive];
|
|
u_int8_t clock;
|
|
|
|
if (dma_maps->dma_flags & WDC_DMA_LBA48) {
|
|
clock = bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
PDC262_U66);
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
PDC262_U66, clock & ~PDC262_U66_EN(channel));
|
|
bus_space_write_4(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
PDC262_ATAPI(channel), 0);
|
|
}
|
|
|
|
return (pciide_dma_finish(v, channel, drive, force));
|
|
}
|
|
|
|
void
|
|
pdcsata_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_channel *cp;
|
|
struct channel_softc *wdc_cp;
|
|
struct pciide_pdcsata *ps;
|
|
int channel, i;
|
|
bus_size_t dmasize;
|
|
pci_intr_handle_t intrhandle;
|
|
const char *intrstr;
|
|
|
|
/* Allocate memory for private data */
|
|
sc->sc_cookielen = sizeof(*ps);
|
|
sc->sc_cookie = malloc(sc->sc_cookielen, M_DEVBUF, M_NOWAIT | M_ZERO);
|
|
ps = sc->sc_cookie;
|
|
|
|
/*
|
|
* Promise SATA controllers have 3 or 4 channels,
|
|
* the usual IDE registers are mapped in I/O space, with offsets.
|
|
*/
|
|
if (pci_intr_map(pa, &intrhandle) != 0) {
|
|
printf(": couldn't map interrupt\n");
|
|
return;
|
|
}
|
|
intrstr = pci_intr_string(pa->pa_pc, intrhandle);
|
|
|
|
switch (sc->sc_pp->ide_product) {
|
|
case PCI_PRODUCT_PROMISE_PDC20318:
|
|
case PCI_PRODUCT_PROMISE_PDC20319:
|
|
case PCI_PRODUCT_PROMISE_PDC20371:
|
|
case PCI_PRODUCT_PROMISE_PDC20375:
|
|
case PCI_PRODUCT_PROMISE_PDC20376:
|
|
case PCI_PRODUCT_PROMISE_PDC20377:
|
|
case PCI_PRODUCT_PROMISE_PDC20378:
|
|
case PCI_PRODUCT_PROMISE_PDC20379:
|
|
default:
|
|
sc->sc_pci_ih = pci_intr_establish(pa->pa_pc,
|
|
intrhandle, IPL_BIO, pdc203xx_pci_intr, sc,
|
|
sc->sc_wdcdev.sc_dev.dv_xname);
|
|
break;
|
|
|
|
case PCI_PRODUCT_PROMISE_PDC40518:
|
|
case PCI_PRODUCT_PROMISE_PDC40519:
|
|
case PCI_PRODUCT_PROMISE_PDC40718:
|
|
case PCI_PRODUCT_PROMISE_PDC40719:
|
|
case PCI_PRODUCT_PROMISE_PDC40779:
|
|
case PCI_PRODUCT_PROMISE_PDC20571:
|
|
case PCI_PRODUCT_PROMISE_PDC20575:
|
|
case PCI_PRODUCT_PROMISE_PDC20579:
|
|
case PCI_PRODUCT_PROMISE_PDC20771:
|
|
case PCI_PRODUCT_PROMISE_PDC20775:
|
|
sc->sc_pci_ih = pci_intr_establish(pa->pa_pc,
|
|
intrhandle, IPL_BIO, pdc205xx_pci_intr, sc,
|
|
sc->sc_wdcdev.sc_dev.dv_xname);
|
|
break;
|
|
}
|
|
|
|
if (sc->sc_pci_ih == NULL) {
|
|
printf(": couldn't establish native-PCI interrupt");
|
|
if (intrstr != NULL)
|
|
printf(" at %s", intrstr);
|
|
printf("\n");
|
|
return;
|
|
}
|
|
|
|
sc->sc_dma_ok = (pci_mapreg_map(pa, PCIIDE_REG_BUS_MASTER_DMA,
|
|
PCI_MAPREG_MEM_TYPE_32BIT, 0, &sc->sc_dma_iot,
|
|
&sc->sc_dma_ioh, NULL, &dmasize, 0) == 0);
|
|
if (!sc->sc_dma_ok) {
|
|
printf(": couldn't map bus-master DMA registers\n");
|
|
pci_intr_disestablish(pa->pa_pc, sc->sc_pci_ih);
|
|
return;
|
|
}
|
|
|
|
sc->sc_dmat = pa->pa_dmat;
|
|
|
|
if (pci_mapreg_map(pa, PDC203xx_BAR_IDEREGS,
|
|
PCI_MAPREG_MEM_TYPE_32BIT, 0, &ps->ba5_st,
|
|
&ps->ba5_sh, NULL, NULL, 0) != 0) {
|
|
printf(": couldn't map IDE registers\n");
|
|
bus_space_unmap(sc->sc_dma_iot, sc->sc_dma_ioh, dmasize);
|
|
pci_intr_disestablish(pa->pa_pc, sc->sc_pci_ih);
|
|
return;
|
|
}
|
|
|
|
printf(": DMA\n");
|
|
|
|
sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16;
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_UDMA;
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_IRQACK;
|
|
sc->sc_wdcdev.irqack = pdc203xx_irqack;
|
|
sc->sc_wdcdev.PIO_cap = 4;
|
|
sc->sc_wdcdev.DMA_cap = 2;
|
|
sc->sc_wdcdev.UDMA_cap = 6;
|
|
sc->sc_wdcdev.set_modes = pdc203xx_setup_channel;
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
|
|
switch (sc->sc_pp->ide_product) {
|
|
case PCI_PRODUCT_PROMISE_PDC20318:
|
|
case PCI_PRODUCT_PROMISE_PDC20319:
|
|
case PCI_PRODUCT_PROMISE_PDC20371:
|
|
case PCI_PRODUCT_PROMISE_PDC20375:
|
|
case PCI_PRODUCT_PROMISE_PDC20376:
|
|
case PCI_PRODUCT_PROMISE_PDC20377:
|
|
case PCI_PRODUCT_PROMISE_PDC20378:
|
|
case PCI_PRODUCT_PROMISE_PDC20379:
|
|
default:
|
|
bus_space_write_4(ps->ba5_st, ps->ba5_sh, 0x06c, 0x00ff0033);
|
|
sc->sc_wdcdev.nchannels =
|
|
(bus_space_read_4(ps->ba5_st, ps->ba5_sh, 0x48) & 0x02) ?
|
|
PDC203xx_NCHANNELS : 3;
|
|
break;
|
|
|
|
case PCI_PRODUCT_PROMISE_PDC40518:
|
|
case PCI_PRODUCT_PROMISE_PDC40519:
|
|
case PCI_PRODUCT_PROMISE_PDC40718:
|
|
case PCI_PRODUCT_PROMISE_PDC40719:
|
|
case PCI_PRODUCT_PROMISE_PDC40779:
|
|
case PCI_PRODUCT_PROMISE_PDC20571:
|
|
bus_space_write_4(ps->ba5_st, ps->ba5_sh, 0x60, 0x00ff00ff);
|
|
sc->sc_wdcdev.nchannels = PDC40718_NCHANNELS;
|
|
|
|
sc->sc_wdcdev.reset = pdc205xx_do_reset;
|
|
sc->sc_wdcdev.drv_probe = pdc205xx_drv_probe;
|
|
|
|
break;
|
|
case PCI_PRODUCT_PROMISE_PDC20575:
|
|
case PCI_PRODUCT_PROMISE_PDC20579:
|
|
case PCI_PRODUCT_PROMISE_PDC20771:
|
|
case PCI_PRODUCT_PROMISE_PDC20775:
|
|
bus_space_write_4(ps->ba5_st, ps->ba5_sh, 0x60, 0x00ff00ff);
|
|
sc->sc_wdcdev.nchannels = PDC20575_NCHANNELS;
|
|
|
|
sc->sc_wdcdev.reset = pdc205xx_do_reset;
|
|
sc->sc_wdcdev.drv_probe = pdc205xx_drv_probe;
|
|
|
|
break;
|
|
}
|
|
|
|
sc->sc_wdcdev.dma_arg = sc;
|
|
sc->sc_wdcdev.dma_init = pciide_dma_init;
|
|
sc->sc_wdcdev.dma_start = pdc203xx_dma_start;
|
|
sc->sc_wdcdev.dma_finish = pdc203xx_dma_finish;
|
|
|
|
for (channel = 0; channel < sc->sc_wdcdev.nchannels;
|
|
channel++) {
|
|
cp = &sc->pciide_channels[channel];
|
|
sc->wdc_chanarray[channel] = &cp->wdc_channel;
|
|
|
|
cp->ih = sc->sc_pci_ih;
|
|
cp->name = NULL;
|
|
cp->wdc_channel.channel = channel;
|
|
cp->wdc_channel.wdc = &sc->sc_wdcdev;
|
|
cp->wdc_channel.ch_queue = wdc_alloc_queue();
|
|
if (cp->wdc_channel.ch_queue == NULL) {
|
|
printf("%s: channel %d: "
|
|
"cannot allocate channel queue\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, channel);
|
|
continue;
|
|
}
|
|
wdc_cp = &cp->wdc_channel;
|
|
|
|
ps->regs[channel].ctl_iot = ps->ba5_st;
|
|
ps->regs[channel].cmd_iot = ps->ba5_st;
|
|
|
|
if (bus_space_subregion(ps->ba5_st, ps->ba5_sh,
|
|
0x0238 + (channel << 7), 1,
|
|
&ps->regs[channel].ctl_ioh) != 0) {
|
|
printf("%s: couldn't map channel %d ctl regs\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname,
|
|
channel);
|
|
continue;
|
|
}
|
|
for (i = 0; i < WDC_NREG; i++) {
|
|
if (bus_space_subregion(ps->ba5_st, ps->ba5_sh,
|
|
0x0200 + (i << 2) + (channel << 7), i == 0 ? 4 : 1,
|
|
&ps->regs[channel].cmd_iohs[i]) != 0) {
|
|
printf("%s: couldn't map channel %d cmd "
|
|
"regs\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname,
|
|
channel);
|
|
goto loop_end;
|
|
}
|
|
}
|
|
ps->regs[channel].cmd_iohs[wdr_status & _WDC_REGMASK] =
|
|
ps->regs[channel].cmd_iohs[wdr_command & _WDC_REGMASK];
|
|
ps->regs[channel].cmd_iohs[wdr_features & _WDC_REGMASK] =
|
|
ps->regs[channel].cmd_iohs[wdr_error & _WDC_REGMASK];
|
|
wdc_cp->data32iot = wdc_cp->cmd_iot =
|
|
ps->regs[channel].cmd_iot;
|
|
wdc_cp->data32ioh = wdc_cp->cmd_ioh =
|
|
ps->regs[channel].cmd_iohs[0];
|
|
wdc_cp->_vtbl = &wdc_pdc203xx_vtbl;
|
|
|
|
/*
|
|
* Subregion de busmaster registers. They're spread all over
|
|
* the controller's register space :(. They are also 4 bytes
|
|
* sized, with some specific extensions in the extra bits.
|
|
* It also seems that the IDEDMA_CTL register isn't available.
|
|
*/
|
|
if (bus_space_subregion(ps->ba5_st, ps->ba5_sh,
|
|
0x260 + (channel << 7), 1,
|
|
&ps->regs[channel].dma_iohs[IDEDMA_CMD(0)]) != 0) {
|
|
printf("%s channel %d: can't subregion DMA "
|
|
"registers\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, channel);
|
|
continue;
|
|
}
|
|
if (bus_space_subregion(ps->ba5_st, ps->ba5_sh,
|
|
0x244 + (channel << 7), 4,
|
|
&ps->regs[channel].dma_iohs[IDEDMA_TBL(0)]) != 0) {
|
|
printf("%s channel %d: can't subregion DMA "
|
|
"registers\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, channel);
|
|
continue;
|
|
}
|
|
|
|
wdcattach(wdc_cp);
|
|
bus_space_write_4(sc->sc_dma_iot,
|
|
ps->regs[channel].dma_iohs[IDEDMA_CMD(0)], 0,
|
|
(bus_space_read_4(sc->sc_dma_iot,
|
|
ps->regs[channel].dma_iohs[IDEDMA_CMD(0)],
|
|
0) & ~0x00003f9f) | (channel + 1));
|
|
bus_space_write_4(ps->ba5_st, ps->ba5_sh,
|
|
(channel + 1) << 2, 0x00000001);
|
|
|
|
pdc203xx_setup_channel(&cp->wdc_channel);
|
|
|
|
loop_end: ;
|
|
}
|
|
|
|
printf("%s: using %s for native-PCI interrupt\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname,
|
|
intrstr ? intrstr : "unknown interrupt");
|
|
}
|
|
|
|
void
|
|
pdc203xx_setup_channel(struct channel_softc *chp)
|
|
{
|
|
struct ata_drive_datas *drvp;
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
int drive, s;
|
|
|
|
pciide_channel_dma_setup(cp);
|
|
|
|
for (drive = 0; drive < 2; drive++) {
|
|
drvp = &chp->ch_drive[drive];
|
|
if ((drvp->drive_flags & DRIVE) == 0)
|
|
continue;
|
|
if (drvp->drive_flags & DRIVE_UDMA) {
|
|
s = splbio();
|
|
drvp->drive_flags &= ~DRIVE_DMA;
|
|
splx(s);
|
|
}
|
|
}
|
|
pciide_print_modes(cp);
|
|
}
|
|
|
|
int
|
|
pdc203xx_pci_intr(void *arg)
|
|
{
|
|
struct pciide_softc *sc = arg;
|
|
struct pciide_channel *cp;
|
|
struct channel_softc *wdc_cp;
|
|
struct pciide_pdcsata *ps = sc->sc_cookie;
|
|
int i, rv, crv;
|
|
u_int32_t scr;
|
|
|
|
rv = 0;
|
|
scr = bus_space_read_4(ps->ba5_st, ps->ba5_sh, 0x00040);
|
|
|
|
for (i = 0; i < sc->sc_wdcdev.nchannels; i++) {
|
|
cp = &sc->pciide_channels[i];
|
|
wdc_cp = &cp->wdc_channel;
|
|
if (scr & (1 << (i + 1))) {
|
|
crv = wdcintr(wdc_cp);
|
|
if (crv == 0) {
|
|
printf("%s:%d: bogus intr (reg 0x%x)\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname,
|
|
i, scr);
|
|
} else
|
|
rv = 1;
|
|
}
|
|
}
|
|
|
|
return (rv);
|
|
}
|
|
|
|
int
|
|
pdc205xx_pci_intr(void *arg)
|
|
{
|
|
struct pciide_softc *sc = arg;
|
|
struct pciide_channel *cp;
|
|
struct channel_softc *wdc_cp;
|
|
struct pciide_pdcsata *ps = sc->sc_cookie;
|
|
int i, rv, crv;
|
|
u_int32_t scr, status;
|
|
|
|
rv = 0;
|
|
scr = bus_space_read_4(ps->ba5_st, ps->ba5_sh, 0x40);
|
|
bus_space_write_4(ps->ba5_st, ps->ba5_sh, 0x40, scr & 0x0000ffff);
|
|
|
|
status = bus_space_read_4(ps->ba5_st, ps->ba5_sh, 0x60);
|
|
bus_space_write_4(ps->ba5_st, ps->ba5_sh, 0x60, status & 0x000000ff);
|
|
|
|
for (i = 0; i < sc->sc_wdcdev.nchannels; i++) {
|
|
cp = &sc->pciide_channels[i];
|
|
wdc_cp = &cp->wdc_channel;
|
|
if (scr & (1 << (i + 1))) {
|
|
crv = wdcintr(wdc_cp);
|
|
if (crv == 0) {
|
|
printf("%s:%d: bogus intr (reg 0x%x)\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname,
|
|
i, scr);
|
|
} else
|
|
rv = 1;
|
|
}
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
void
|
|
pdc203xx_irqack(struct channel_softc *chp)
|
|
{
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
struct pciide_pdcsata *ps = sc->sc_cookie;
|
|
int chan = chp->channel;
|
|
|
|
bus_space_write_4(sc->sc_dma_iot,
|
|
ps->regs[chan].dma_iohs[IDEDMA_CMD(0)], 0,
|
|
(bus_space_read_4(sc->sc_dma_iot,
|
|
ps->regs[chan].dma_iohs[IDEDMA_CMD(0)],
|
|
0) & ~0x00003f9f) | (chan + 1));
|
|
bus_space_write_4(ps->ba5_st, ps->ba5_sh,
|
|
(chan + 1) << 2, 0x00000001);
|
|
}
|
|
|
|
void
|
|
pdc203xx_dma_start(void *v, int channel, int drive)
|
|
{
|
|
struct pciide_softc *sc = v;
|
|
struct pciide_channel *cp = &sc->pciide_channels[channel];
|
|
struct pciide_dma_maps *dma_maps = &cp->dma_maps[drive];
|
|
struct pciide_pdcsata *ps = sc->sc_cookie;
|
|
|
|
/* Write table address */
|
|
bus_space_write_4(sc->sc_dma_iot,
|
|
ps->regs[channel].dma_iohs[IDEDMA_TBL(0)], 0,
|
|
dma_maps->dmamap_table->dm_segs[0].ds_addr);
|
|
|
|
/* Start DMA engine */
|
|
bus_space_write_4(sc->sc_dma_iot,
|
|
ps->regs[channel].dma_iohs[IDEDMA_CMD(0)], 0,
|
|
(bus_space_read_4(sc->sc_dma_iot,
|
|
ps->regs[channel].dma_iohs[IDEDMA_CMD(0)],
|
|
0) & ~0xc0) | ((dma_maps->dma_flags & WDC_DMA_READ) ? 0x80 : 0xc0));
|
|
}
|
|
|
|
int
|
|
pdc203xx_dma_finish(void *v, int channel, int drive, int force)
|
|
{
|
|
struct pciide_softc *sc = v;
|
|
struct pciide_channel *cp = &sc->pciide_channels[channel];
|
|
struct pciide_dma_maps *dma_maps = &cp->dma_maps[drive];
|
|
struct pciide_pdcsata *ps = sc->sc_cookie;
|
|
|
|
/* Stop DMA channel */
|
|
bus_space_write_4(sc->sc_dma_iot,
|
|
ps->regs[channel].dma_iohs[IDEDMA_CMD(0)], 0,
|
|
(bus_space_read_4(sc->sc_dma_iot,
|
|
ps->regs[channel].dma_iohs[IDEDMA_CMD(0)],
|
|
0) & ~0x80));
|
|
|
|
/* Unload the map of the data buffer */
|
|
bus_dmamap_sync(sc->sc_dmat, dma_maps->dmamap_xfer, 0,
|
|
dma_maps->dmamap_xfer->dm_mapsize,
|
|
(dma_maps->dma_flags & WDC_DMA_READ) ?
|
|
BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
|
|
bus_dmamap_unload(sc->sc_dmat, dma_maps->dmamap_xfer);
|
|
|
|
return (0);
|
|
}
|
|
|
|
u_int8_t
|
|
pdc203xx_read_reg(struct channel_softc *chp, enum wdc_regs reg)
|
|
{
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
struct pciide_pdcsata *ps = sc->sc_cookie;
|
|
u_int8_t val;
|
|
|
|
if (reg & _WDC_AUX) {
|
|
return (bus_space_read_1(ps->regs[chp->channel].ctl_iot,
|
|
ps->regs[chp->channel].ctl_ioh, reg & _WDC_REGMASK));
|
|
} else {
|
|
val = bus_space_read_1(ps->regs[chp->channel].cmd_iot,
|
|
ps->regs[chp->channel].cmd_iohs[reg & _WDC_REGMASK], 0);
|
|
return (val);
|
|
}
|
|
}
|
|
|
|
void
|
|
pdc203xx_write_reg(struct channel_softc *chp, enum wdc_regs reg, u_int8_t val)
|
|
{
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
struct pciide_pdcsata *ps = sc->sc_cookie;
|
|
|
|
if (reg & _WDC_AUX)
|
|
bus_space_write_1(ps->regs[chp->channel].ctl_iot,
|
|
ps->regs[chp->channel].ctl_ioh, reg & _WDC_REGMASK, val);
|
|
else
|
|
bus_space_write_1(ps->regs[chp->channel].cmd_iot,
|
|
ps->regs[chp->channel].cmd_iohs[reg & _WDC_REGMASK],
|
|
0, val);
|
|
}
|
|
|
|
void
|
|
pdc205xx_do_reset(struct channel_softc *chp)
|
|
{
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
struct pciide_pdcsata *ps = sc->sc_cookie;
|
|
u_int32_t scontrol;
|
|
|
|
wdc_do_reset(chp);
|
|
|
|
/* reset SATA */
|
|
scontrol = SControl_DET_INIT | SControl_SPD_ANY | SControl_IPM_NONE;
|
|
SCONTROL_WRITE(ps, chp->channel, scontrol);
|
|
delay(50*1000);
|
|
|
|
scontrol &= ~SControl_DET_INIT;
|
|
SCONTROL_WRITE(ps, chp->channel, scontrol);
|
|
delay(50*1000);
|
|
}
|
|
|
|
void
|
|
pdc205xx_drv_probe(struct channel_softc *chp)
|
|
{
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
struct pciide_pdcsata *ps = sc->sc_cookie;
|
|
bus_space_handle_t *iohs;
|
|
u_int32_t scontrol, sstatus;
|
|
u_int16_t scnt, sn, cl, ch;
|
|
int s;
|
|
|
|
SCONTROL_WRITE(ps, chp->channel, 0);
|
|
delay(50*1000);
|
|
|
|
scontrol = SControl_DET_INIT | SControl_SPD_ANY | SControl_IPM_NONE;
|
|
SCONTROL_WRITE(ps,chp->channel,scontrol);
|
|
delay(50*1000);
|
|
|
|
scontrol &= ~SControl_DET_INIT;
|
|
SCONTROL_WRITE(ps,chp->channel,scontrol);
|
|
delay(50*1000);
|
|
|
|
sstatus = SSTATUS_READ(ps,chp->channel);
|
|
|
|
switch (sstatus & SStatus_DET_mask) {
|
|
case SStatus_DET_NODEV:
|
|
/* No Device; be silent. */
|
|
break;
|
|
|
|
case SStatus_DET_DEV_NE:
|
|
printf("%s: port %d: device connected, but "
|
|
"communication not established\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, chp->channel);
|
|
break;
|
|
|
|
case SStatus_DET_OFFLINE:
|
|
printf("%s: port %d: PHY offline\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, chp->channel);
|
|
break;
|
|
|
|
case SStatus_DET_DEV:
|
|
iohs = ps->regs[chp->channel].cmd_iohs;
|
|
bus_space_write_1(chp->cmd_iot, iohs[wdr_sdh], 0,
|
|
WDSD_IBM);
|
|
delay(10); /* 400ns delay */
|
|
scnt = bus_space_read_2(chp->cmd_iot, iohs[wdr_seccnt], 0);
|
|
sn = bus_space_read_2(chp->cmd_iot, iohs[wdr_sector], 0);
|
|
cl = bus_space_read_2(chp->cmd_iot, iohs[wdr_cyl_lo], 0);
|
|
ch = bus_space_read_2(chp->cmd_iot, iohs[wdr_cyl_hi], 0);
|
|
#if 0
|
|
printf("%s: port %d: scnt=0x%x sn=0x%x cl=0x%x ch=0x%x\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, chp->channel,
|
|
scnt, sn, cl, ch);
|
|
#endif
|
|
/*
|
|
* scnt and sn are supposed to be 0x1 for ATAPI, but in some
|
|
* cases we get wrong values here, so ignore it.
|
|
*/
|
|
s = splbio();
|
|
if (cl == 0x14 && ch == 0xeb)
|
|
chp->ch_drive[0].drive_flags |= DRIVE_ATAPI;
|
|
else
|
|
chp->ch_drive[0].drive_flags |= DRIVE_ATA;
|
|
splx(s);
|
|
#if 0
|
|
printf("%s: port %d",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, chp->channel);
|
|
switch ((sstatus & SStatus_SPD_mask) >> SStatus_SPD_shift) {
|
|
case 1:
|
|
printf(": 1.5Gb/s");
|
|
break;
|
|
case 2:
|
|
printf(": 3.0Gb/s");
|
|
break;
|
|
}
|
|
printf("\n");
|
|
#endif
|
|
break;
|
|
|
|
default:
|
|
printf("%s: port %d: unknown SStatus: 0x%08x\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, chp->channel, sstatus);
|
|
}
|
|
}
|
|
|
|
void
|
|
serverworks_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_channel *cp;
|
|
pcireg_t interface = PCI_INTERFACE(pa->pa_class);
|
|
pcitag_t pcib_tag;
|
|
int channel;
|
|
bus_size_t cmdsize, ctlsize;
|
|
|
|
printf(": DMA");
|
|
pciide_mapreg_dma(sc, pa);
|
|
printf("\n");
|
|
sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
|
|
WDC_CAPABILITY_MODE;
|
|
|
|
if (sc->sc_dma_ok) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_UDMA;
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_IRQACK;
|
|
sc->sc_wdcdev.irqack = pciide_irqack;
|
|
}
|
|
sc->sc_wdcdev.PIO_cap = 4;
|
|
sc->sc_wdcdev.DMA_cap = 2;
|
|
switch (sc->sc_pp->ide_product) {
|
|
case PCI_PRODUCT_RCC_OSB4_IDE:
|
|
sc->sc_wdcdev.UDMA_cap = 2;
|
|
break;
|
|
case PCI_PRODUCT_RCC_CSB5_IDE:
|
|
if (sc->sc_rev < 0x92)
|
|
sc->sc_wdcdev.UDMA_cap = 4;
|
|
else
|
|
sc->sc_wdcdev.UDMA_cap = 5;
|
|
break;
|
|
case PCI_PRODUCT_RCC_CSB6_IDE:
|
|
sc->sc_wdcdev.UDMA_cap = 4;
|
|
break;
|
|
case PCI_PRODUCT_RCC_CSB6_RAID_IDE:
|
|
case PCI_PRODUCT_RCC_HT_1000_IDE:
|
|
sc->sc_wdcdev.UDMA_cap = 5;
|
|
break;
|
|
}
|
|
|
|
sc->sc_wdcdev.set_modes = serverworks_setup_channel;
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
sc->sc_wdcdev.nchannels =
|
|
(sc->sc_pp->ide_product == PCI_PRODUCT_RCC_CSB6_IDE ? 1 : 2);
|
|
|
|
for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
|
|
cp = &sc->pciide_channels[channel];
|
|
if (pciide_chansetup(sc, channel, interface) == 0)
|
|
continue;
|
|
pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
|
|
serverworks_pci_intr);
|
|
if (cp->hw_ok == 0)
|
|
return;
|
|
pciide_map_compat_intr(pa, cp, channel, interface);
|
|
if (cp->hw_ok == 0)
|
|
return;
|
|
serverworks_setup_channel(&cp->wdc_channel);
|
|
}
|
|
|
|
pcib_tag = pci_make_tag(pa->pa_pc, pa->pa_bus, pa->pa_device, 0);
|
|
pci_conf_write(pa->pa_pc, pcib_tag, 0x64,
|
|
(pci_conf_read(pa->pa_pc, pcib_tag, 0x64) & ~0x2000) | 0x4000);
|
|
}
|
|
|
|
void
|
|
serverworks_setup_channel(struct channel_softc *chp)
|
|
{
|
|
struct ata_drive_datas *drvp;
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
int channel = chp->channel;
|
|
int drive, unit;
|
|
u_int32_t pio_time, dma_time, pio_mode, udma_mode;
|
|
u_int32_t idedma_ctl;
|
|
static const u_int8_t pio_modes[5] = {0x5d, 0x47, 0x34, 0x22, 0x20};
|
|
static const u_int8_t dma_modes[3] = {0x77, 0x21, 0x20};
|
|
|
|
/* setup DMA if needed */
|
|
pciide_channel_dma_setup(cp);
|
|
|
|
pio_time = pci_conf_read(sc->sc_pc, sc->sc_tag, 0x40);
|
|
dma_time = pci_conf_read(sc->sc_pc, sc->sc_tag, 0x44);
|
|
pio_mode = pci_conf_read(sc->sc_pc, sc->sc_tag, 0x48);
|
|
udma_mode = pci_conf_read(sc->sc_pc, sc->sc_tag, 0x54);
|
|
|
|
pio_time &= ~(0xffff << (16 * channel));
|
|
dma_time &= ~(0xffff << (16 * channel));
|
|
pio_mode &= ~(0xff << (8 * channel + 16));
|
|
udma_mode &= ~(0xff << (8 * channel + 16));
|
|
udma_mode &= ~(3 << (2 * channel));
|
|
|
|
idedma_ctl = 0;
|
|
|
|
/* Per drive settings */
|
|
for (drive = 0; drive < 2; drive++) {
|
|
drvp = &chp->ch_drive[drive];
|
|
/* If no drive, skip */
|
|
if ((drvp->drive_flags & DRIVE) == 0)
|
|
continue;
|
|
unit = drive + 2 * channel;
|
|
/* add timing values, setup DMA if needed */
|
|
pio_time |= pio_modes[drvp->PIO_mode] << (8 * (unit^1));
|
|
pio_mode |= drvp->PIO_mode << (4 * unit + 16);
|
|
if ((chp->wdc->cap & WDC_CAPABILITY_UDMA) &&
|
|
(drvp->drive_flags & DRIVE_UDMA)) {
|
|
/* use Ultra/DMA, check for 80-pin cable */
|
|
if (sc->sc_rev <= 0x92 && drvp->UDMA_mode > 2 &&
|
|
(PCI_PRODUCT(pci_conf_read(sc->sc_pc, sc->sc_tag,
|
|
PCI_SUBSYS_ID_REG)) &
|
|
(1 << (14 + channel))) == 0) {
|
|
WDCDEBUG_PRINT(("%s(%s:%d:%d): 80-wire "
|
|
"cable not detected\n", drvp->drive_name,
|
|
sc->sc_wdcdev.sc_dev.dv_xname,
|
|
channel, drive), DEBUG_PROBE);
|
|
drvp->UDMA_mode = 2;
|
|
}
|
|
dma_time |= dma_modes[drvp->DMA_mode] << (8 * (unit^1));
|
|
udma_mode |= drvp->UDMA_mode << (4 * unit + 16);
|
|
udma_mode |= 1 << unit;
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
} else if ((chp->wdc->cap & WDC_CAPABILITY_DMA) &&
|
|
(drvp->drive_flags & DRIVE_DMA)) {
|
|
/* use Multiword DMA */
|
|
drvp->drive_flags &= ~DRIVE_UDMA;
|
|
dma_time |= dma_modes[drvp->DMA_mode] << (8 * (unit^1));
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
} else {
|
|
/* PIO only */
|
|
drvp->drive_flags &= ~(DRIVE_UDMA | DRIVE_DMA);
|
|
}
|
|
}
|
|
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, 0x40, pio_time);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, 0x44, dma_time);
|
|
if (sc->sc_pp->ide_product != PCI_PRODUCT_RCC_OSB4_IDE)
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, 0x48, pio_mode);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, 0x54, udma_mode);
|
|
|
|
if (idedma_ctl != 0) {
|
|
/* Add software bits in status register */
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(channel), idedma_ctl);
|
|
}
|
|
pciide_print_modes(cp);
|
|
}
|
|
|
|
int
|
|
serverworks_pci_intr(void *arg)
|
|
{
|
|
struct pciide_softc *sc = arg;
|
|
struct pciide_channel *cp;
|
|
struct channel_softc *wdc_cp;
|
|
int rv = 0;
|
|
int dmastat, i, crv;
|
|
|
|
for (i = 0; i < sc->sc_wdcdev.nchannels; i++) {
|
|
dmastat = bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(i));
|
|
if ((dmastat & (IDEDMA_CTL_ACT | IDEDMA_CTL_INTR)) !=
|
|
IDEDMA_CTL_INTR)
|
|
continue;
|
|
cp = &sc->pciide_channels[i];
|
|
wdc_cp = &cp->wdc_channel;
|
|
crv = wdcintr(wdc_cp);
|
|
if (crv == 0) {
|
|
printf("%s:%d: bogus intr\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, i);
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(i), dmastat);
|
|
} else
|
|
rv = 1;
|
|
}
|
|
return (rv);
|
|
}
|
|
|
|
void
|
|
svwsata_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_channel *cp;
|
|
pci_intr_handle_t intrhandle;
|
|
const char *intrstr;
|
|
int channel;
|
|
struct pciide_svwsata *ss;
|
|
|
|
/* Allocate memory for private data */
|
|
sc->sc_cookielen = sizeof(*ss);
|
|
sc->sc_cookie = malloc(sc->sc_cookielen, M_DEVBUF, M_NOWAIT | M_ZERO);
|
|
ss = sc->sc_cookie;
|
|
|
|
/* The 4-port version has a dummy second function. */
|
|
if (pci_conf_read(sc->sc_pc, sc->sc_tag,
|
|
PCI_MAPREG_START + 0x14) == 0) {
|
|
printf("\n");
|
|
return;
|
|
}
|
|
|
|
if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x14,
|
|
PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0,
|
|
&ss->ba5_st, &ss->ba5_sh, NULL, NULL, 0) != 0) {
|
|
printf(": unable to map BA5 register space\n");
|
|
return;
|
|
}
|
|
|
|
printf(": DMA");
|
|
svwsata_mapreg_dma(sc, pa);
|
|
printf("\n");
|
|
|
|
if (sc->sc_dma_ok) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_UDMA |
|
|
WDC_CAPABILITY_DMA | WDC_CAPABILITY_IRQACK;
|
|
sc->sc_wdcdev.irqack = pciide_irqack;
|
|
}
|
|
sc->sc_wdcdev.PIO_cap = 4;
|
|
sc->sc_wdcdev.DMA_cap = 2;
|
|
sc->sc_wdcdev.UDMA_cap = 6;
|
|
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
sc->sc_wdcdev.nchannels = 4;
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
|
|
WDC_CAPABILITY_MODE | WDC_CAPABILITY_SATA;
|
|
sc->sc_wdcdev.set_modes = sata_setup_channel;
|
|
|
|
/* We can use SControl and SStatus to probe for drives. */
|
|
sc->sc_wdcdev.drv_probe = svwsata_drv_probe;
|
|
|
|
/* Map and establish the interrupt handler. */
|
|
if(pci_intr_map(pa, &intrhandle) != 0) {
|
|
printf("%s: couldn't map native-PCI interrupt\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname);
|
|
return;
|
|
}
|
|
intrstr = pci_intr_string(pa->pa_pc, intrhandle);
|
|
sc->sc_pci_ih = pci_intr_establish(pa->pa_pc, intrhandle, IPL_BIO,
|
|
pciide_pci_intr, sc, sc->sc_wdcdev.sc_dev.dv_xname);
|
|
if (sc->sc_pci_ih != NULL) {
|
|
printf("%s: using %s for native-PCI interrupt\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname,
|
|
intrstr ? intrstr : "unknown interrupt");
|
|
} else {
|
|
printf("%s: couldn't establish native-PCI interrupt",
|
|
sc->sc_wdcdev.sc_dev.dv_xname);
|
|
if (intrstr != NULL)
|
|
printf(" at %s", intrstr);
|
|
printf("\n");
|
|
return;
|
|
}
|
|
|
|
switch (sc->sc_pp->ide_product) {
|
|
case PCI_PRODUCT_RCC_K2_SATA:
|
|
bus_space_write_4(ss->ba5_st, ss->ba5_sh, SVWSATA_SICR1,
|
|
bus_space_read_4(ss->ba5_st, ss->ba5_sh, SVWSATA_SICR1)
|
|
& ~0x00040000);
|
|
bus_space_write_4(ss->ba5_st, ss->ba5_sh,
|
|
SVWSATA_SIM, 0);
|
|
break;
|
|
}
|
|
|
|
for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
|
|
cp = &sc->pciide_channels[channel];
|
|
if (pciide_chansetup(sc, channel, 0) == 0)
|
|
continue;
|
|
svwsata_mapchan(cp);
|
|
sata_setup_channel(&cp->wdc_channel);
|
|
}
|
|
}
|
|
|
|
void
|
|
svwsata_mapreg_dma(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_svwsata *ss = sc->sc_cookie;
|
|
|
|
sc->sc_wdcdev.dma_arg = sc;
|
|
sc->sc_wdcdev.dma_init = pciide_dma_init;
|
|
sc->sc_wdcdev.dma_start = pciide_dma_start;
|
|
sc->sc_wdcdev.dma_finish = pciide_dma_finish;
|
|
|
|
/* XXX */
|
|
sc->sc_dma_iot = ss->ba5_st;
|
|
sc->sc_dma_ioh = ss->ba5_sh;
|
|
|
|
sc->sc_dmacmd_read = svwsata_dmacmd_read;
|
|
sc->sc_dmacmd_write = svwsata_dmacmd_write;
|
|
sc->sc_dmactl_read = svwsata_dmactl_read;
|
|
sc->sc_dmactl_write = svwsata_dmactl_write;
|
|
sc->sc_dmatbl_write = svwsata_dmatbl_write;
|
|
|
|
/* DMA registers all set up! */
|
|
sc->sc_dmat = pa->pa_dmat;
|
|
sc->sc_dma_ok = 1;
|
|
}
|
|
|
|
u_int8_t
|
|
svwsata_dmacmd_read(struct pciide_softc *sc, int chan)
|
|
{
|
|
return (bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
(chan << 8) + SVWSATA_DMA + IDEDMA_CMD(0)));
|
|
}
|
|
|
|
void
|
|
svwsata_dmacmd_write(struct pciide_softc *sc, int chan, u_int8_t val)
|
|
{
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
(chan << 8) + SVWSATA_DMA + IDEDMA_CMD(0), val);
|
|
}
|
|
|
|
u_int8_t
|
|
svwsata_dmactl_read(struct pciide_softc *sc, int chan)
|
|
{
|
|
return (bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
(chan << 8) + SVWSATA_DMA + IDEDMA_CTL(0)));
|
|
}
|
|
|
|
void
|
|
svwsata_dmactl_write(struct pciide_softc *sc, int chan, u_int8_t val)
|
|
{
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
(chan << 8) + SVWSATA_DMA + IDEDMA_CTL(0), val);
|
|
}
|
|
|
|
void
|
|
svwsata_dmatbl_write(struct pciide_softc *sc, int chan, u_int32_t val)
|
|
{
|
|
bus_space_write_4(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
(chan << 8) + SVWSATA_DMA + IDEDMA_TBL(0), val);
|
|
}
|
|
|
|
void
|
|
svwsata_mapchan(struct pciide_channel *cp)
|
|
{
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
struct channel_softc *wdc_cp = &cp->wdc_channel;
|
|
struct pciide_svwsata *ss = sc->sc_cookie;
|
|
|
|
cp->compat = 0;
|
|
cp->ih = sc->sc_pci_ih;
|
|
|
|
if (bus_space_subregion(ss->ba5_st, ss->ba5_sh,
|
|
(wdc_cp->channel << 8) + SVWSATA_TF0,
|
|
SVWSATA_TF8 - SVWSATA_TF0, &wdc_cp->cmd_ioh) != 0) {
|
|
printf("%s: couldn't map %s cmd regs\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
|
|
return;
|
|
}
|
|
if (bus_space_subregion(ss->ba5_st, ss->ba5_sh,
|
|
(wdc_cp->channel << 8) + SVWSATA_TF8, 4,
|
|
&wdc_cp->ctl_ioh) != 0) {
|
|
printf("%s: couldn't map %s ctl regs\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
|
|
return;
|
|
}
|
|
wdc_cp->cmd_iot = wdc_cp->ctl_iot = ss->ba5_st;
|
|
wdc_cp->_vtbl = &wdc_svwsata_vtbl;
|
|
wdc_cp->ch_flags |= WDCF_DMA_BEFORE_CMD;
|
|
wdcattach(wdc_cp);
|
|
}
|
|
|
|
void
|
|
svwsata_drv_probe(struct channel_softc *chp)
|
|
{
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
struct pciide_svwsata *ss = sc->sc_cookie;
|
|
int channel = chp->channel;
|
|
uint32_t scontrol, sstatus;
|
|
uint8_t scnt, sn, cl, ch;
|
|
int s;
|
|
|
|
/*
|
|
* Request communication initialization sequence, any speed.
|
|
* Performing this is the equivalent of an ATA Reset.
|
|
*/
|
|
scontrol = SControl_DET_INIT | SControl_SPD_ANY;
|
|
|
|
/*
|
|
* XXX We don't yet support SATA power management; disable all
|
|
* power management state transitions.
|
|
*/
|
|
scontrol |= SControl_IPM_NONE;
|
|
|
|
bus_space_write_4(ss->ba5_st, ss->ba5_sh,
|
|
(channel << 8) + SVWSATA_SCONTROL, scontrol);
|
|
delay(50 * 1000);
|
|
scontrol &= ~SControl_DET_INIT;
|
|
bus_space_write_4(ss->ba5_st, ss->ba5_sh,
|
|
(channel << 8) + SVWSATA_SCONTROL, scontrol);
|
|
delay(100 * 1000);
|
|
|
|
sstatus = bus_space_read_4(ss->ba5_st, ss->ba5_sh,
|
|
(channel << 8) + SVWSATA_SSTATUS);
|
|
#if 0
|
|
printf("%s: port %d: SStatus=0x%08x, SControl=0x%08x\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, chp->channel, sstatus,
|
|
bus_space_read_4(ss->ba5_st, ss->ba5_sh,
|
|
(channel << 8) + SVWSATA_SSTATUS));
|
|
#endif
|
|
switch (sstatus & SStatus_DET_mask) {
|
|
case SStatus_DET_NODEV:
|
|
/* No device; be silent. */
|
|
break;
|
|
|
|
case SStatus_DET_DEV_NE:
|
|
printf("%s: port %d: device connected, but "
|
|
"communication not established\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, chp->channel);
|
|
break;
|
|
|
|
case SStatus_DET_OFFLINE:
|
|
printf("%s: port %d: PHY offline\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, chp->channel);
|
|
break;
|
|
|
|
case SStatus_DET_DEV:
|
|
/*
|
|
* XXX ATAPI detection doesn't currently work. Don't
|
|
* XXX know why. But, it's not like the standard method
|
|
* XXX can detect an ATAPI device connected via a SATA/PATA
|
|
* XXX bridge, so at least this is no worse. --thorpej
|
|
*/
|
|
if (chp->_vtbl != NULL)
|
|
CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM | (0 << 4));
|
|
else
|
|
bus_space_write_1(chp->cmd_iot, chp->cmd_ioh,
|
|
wdr_sdh & _WDC_REGMASK, WDSD_IBM | (0 << 4));
|
|
delay(10); /* 400ns delay */
|
|
/* Save register contents. */
|
|
if (chp->_vtbl != NULL) {
|
|
scnt = CHP_READ_REG(chp, wdr_seccnt);
|
|
sn = CHP_READ_REG(chp, wdr_sector);
|
|
cl = CHP_READ_REG(chp, wdr_cyl_lo);
|
|
ch = CHP_READ_REG(chp, wdr_cyl_hi);
|
|
} else {
|
|
scnt = bus_space_read_1(chp->cmd_iot,
|
|
chp->cmd_ioh, wdr_seccnt & _WDC_REGMASK);
|
|
sn = bus_space_read_1(chp->cmd_iot,
|
|
chp->cmd_ioh, wdr_sector & _WDC_REGMASK);
|
|
cl = bus_space_read_1(chp->cmd_iot,
|
|
chp->cmd_ioh, wdr_cyl_lo & _WDC_REGMASK);
|
|
ch = bus_space_read_1(chp->cmd_iot,
|
|
chp->cmd_ioh, wdr_cyl_hi & _WDC_REGMASK);
|
|
}
|
|
#if 0
|
|
printf("%s: port %d: scnt=0x%x sn=0x%x cl=0x%x ch=0x%x\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, chp->channel,
|
|
scnt, sn, cl, ch);
|
|
#endif
|
|
/*
|
|
* scnt and sn are supposed to be 0x1 for ATAPI, but in some
|
|
* cases we get wrong values here, so ignore it.
|
|
*/
|
|
s = splbio();
|
|
if (cl == 0x14 && ch == 0xeb)
|
|
chp->ch_drive[0].drive_flags |= DRIVE_ATAPI;
|
|
else
|
|
chp->ch_drive[0].drive_flags |= DRIVE_ATA;
|
|
splx(s);
|
|
|
|
printf("%s: port %d",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, chp->channel);
|
|
switch ((sstatus & SStatus_SPD_mask) >> SStatus_SPD_shift) {
|
|
case 1:
|
|
printf(": 1.5Gb/s");
|
|
break;
|
|
case 2:
|
|
printf(": 3.0Gb/s");
|
|
break;
|
|
}
|
|
printf("\n");
|
|
break;
|
|
|
|
default:
|
|
printf("%s: port %d: unknown SStatus: 0x%08x\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, chp->channel, sstatus);
|
|
}
|
|
}
|
|
|
|
u_int8_t
|
|
svwsata_read_reg(struct channel_softc *chp, enum wdc_regs reg)
|
|
{
|
|
if (reg & _WDC_AUX) {
|
|
return (bus_space_read_4(chp->ctl_iot, chp->ctl_ioh,
|
|
(reg & _WDC_REGMASK) << 2));
|
|
} else {
|
|
return (bus_space_read_4(chp->cmd_iot, chp->cmd_ioh,
|
|
(reg & _WDC_REGMASK) << 2));
|
|
}
|
|
}
|
|
|
|
void
|
|
svwsata_write_reg(struct channel_softc *chp, enum wdc_regs reg, u_int8_t val)
|
|
{
|
|
if (reg & _WDC_AUX) {
|
|
bus_space_write_4(chp->ctl_iot, chp->ctl_ioh,
|
|
(reg & _WDC_REGMASK) << 2, val);
|
|
} else {
|
|
bus_space_write_4(chp->cmd_iot, chp->cmd_ioh,
|
|
(reg & _WDC_REGMASK) << 2, val);
|
|
}
|
|
}
|
|
|
|
void
|
|
svwsata_lba48_write_reg(struct channel_softc *chp, enum wdc_regs reg, u_int16_t val)
|
|
{
|
|
if (reg & _WDC_AUX) {
|
|
bus_space_write_4(chp->ctl_iot, chp->ctl_ioh,
|
|
(reg & _WDC_REGMASK) << 2, val);
|
|
} else {
|
|
bus_space_write_4(chp->cmd_iot, chp->cmd_ioh,
|
|
(reg & _WDC_REGMASK) << 2, val);
|
|
}
|
|
}
|
|
|
|
#define ACARD_IS_850(sc) \
|
|
((sc)->sc_pp->ide_product == PCI_PRODUCT_ACARD_ATP850U)
|
|
|
|
void
|
|
acard_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_channel *cp;
|
|
int i;
|
|
pcireg_t interface;
|
|
bus_size_t cmdsize, ctlsize;
|
|
|
|
/*
|
|
* when the chip is in native mode it identifies itself as a
|
|
* 'misc mass storage'. Fake interface in this case.
|
|
*/
|
|
if (PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_IDE) {
|
|
interface = PCI_INTERFACE(pa->pa_class);
|
|
} else {
|
|
interface = PCIIDE_INTERFACE_BUS_MASTER_DMA |
|
|
PCIIDE_INTERFACE_PCI(0) | PCIIDE_INTERFACE_PCI(1);
|
|
}
|
|
|
|
printf(": DMA");
|
|
pciide_mapreg_dma(sc, pa);
|
|
printf("\n");
|
|
sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
|
|
WDC_CAPABILITY_MODE;
|
|
|
|
if (sc->sc_dma_ok) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_UDMA;
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_IRQACK;
|
|
sc->sc_wdcdev.irqack = pciide_irqack;
|
|
}
|
|
sc->sc_wdcdev.PIO_cap = 4;
|
|
sc->sc_wdcdev.DMA_cap = 2;
|
|
switch (sc->sc_pp->ide_product) {
|
|
case PCI_PRODUCT_ACARD_ATP850U:
|
|
sc->sc_wdcdev.UDMA_cap = 2;
|
|
break;
|
|
case PCI_PRODUCT_ACARD_ATP860:
|
|
case PCI_PRODUCT_ACARD_ATP860A:
|
|
sc->sc_wdcdev.UDMA_cap = 4;
|
|
break;
|
|
case PCI_PRODUCT_ACARD_ATP865A:
|
|
case PCI_PRODUCT_ACARD_ATP865R:
|
|
sc->sc_wdcdev.UDMA_cap = 6;
|
|
break;
|
|
}
|
|
|
|
sc->sc_wdcdev.set_modes = acard_setup_channel;
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
sc->sc_wdcdev.nchannels = 2;
|
|
|
|
for (i = 0; i < sc->sc_wdcdev.nchannels; i++) {
|
|
cp = &sc->pciide_channels[i];
|
|
if (pciide_chansetup(sc, i, interface) == 0)
|
|
continue;
|
|
if (interface & PCIIDE_INTERFACE_PCI(i)) {
|
|
cp->hw_ok = pciide_mapregs_native(pa, cp, &cmdsize,
|
|
&ctlsize, pciide_pci_intr);
|
|
} else {
|
|
cp->hw_ok = pciide_mapregs_compat(pa, cp, i,
|
|
&cmdsize, &ctlsize);
|
|
}
|
|
if (cp->hw_ok == 0)
|
|
return;
|
|
cp->wdc_channel.data32iot = cp->wdc_channel.cmd_iot;
|
|
cp->wdc_channel.data32ioh = cp->wdc_channel.cmd_ioh;
|
|
wdcattach(&cp->wdc_channel);
|
|
acard_setup_channel(&cp->wdc_channel);
|
|
}
|
|
if (!ACARD_IS_850(sc)) {
|
|
u_int32_t reg;
|
|
reg = pci_conf_read(sc->sc_pc, sc->sc_tag, ATP8x0_CTRL);
|
|
reg &= ~ATP860_CTRL_INT;
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, ATP8x0_CTRL, reg);
|
|
}
|
|
}
|
|
|
|
void
|
|
acard_setup_channel(struct channel_softc *chp)
|
|
{
|
|
struct ata_drive_datas *drvp;
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
int channel = chp->channel;
|
|
int drive;
|
|
u_int32_t idetime, udma_mode;
|
|
u_int32_t idedma_ctl;
|
|
|
|
/* setup DMA if needed */
|
|
pciide_channel_dma_setup(cp);
|
|
|
|
if (ACARD_IS_850(sc)) {
|
|
idetime = 0;
|
|
udma_mode = pci_conf_read(sc->sc_pc, sc->sc_tag, ATP850_UDMA);
|
|
udma_mode &= ~ATP850_UDMA_MASK(channel);
|
|
} else {
|
|
idetime = pci_conf_read(sc->sc_pc, sc->sc_tag, ATP860_IDETIME);
|
|
idetime &= ~ATP860_SETTIME_MASK(channel);
|
|
udma_mode = pci_conf_read(sc->sc_pc, sc->sc_tag, ATP860_UDMA);
|
|
udma_mode &= ~ATP860_UDMA_MASK(channel);
|
|
}
|
|
|
|
idedma_ctl = 0;
|
|
|
|
/* Per drive settings */
|
|
for (drive = 0; drive < 2; drive++) {
|
|
drvp = &chp->ch_drive[drive];
|
|
/* If no drive, skip */
|
|
if ((drvp->drive_flags & DRIVE) == 0)
|
|
continue;
|
|
/* add timing values, setup DMA if needed */
|
|
if ((chp->wdc->cap & WDC_CAPABILITY_UDMA) &&
|
|
(drvp->drive_flags & DRIVE_UDMA)) {
|
|
/* use Ultra/DMA */
|
|
if (ACARD_IS_850(sc)) {
|
|
idetime |= ATP850_SETTIME(drive,
|
|
acard_act_udma[drvp->UDMA_mode],
|
|
acard_rec_udma[drvp->UDMA_mode]);
|
|
udma_mode |= ATP850_UDMA_MODE(channel, drive,
|
|
acard_udma_conf[drvp->UDMA_mode]);
|
|
} else {
|
|
idetime |= ATP860_SETTIME(channel, drive,
|
|
acard_act_udma[drvp->UDMA_mode],
|
|
acard_rec_udma[drvp->UDMA_mode]);
|
|
udma_mode |= ATP860_UDMA_MODE(channel, drive,
|
|
acard_udma_conf[drvp->UDMA_mode]);
|
|
}
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
} else if ((chp->wdc->cap & WDC_CAPABILITY_DMA) &&
|
|
(drvp->drive_flags & DRIVE_DMA)) {
|
|
/* use Multiword DMA */
|
|
drvp->drive_flags &= ~DRIVE_UDMA;
|
|
if (ACARD_IS_850(sc)) {
|
|
idetime |= ATP850_SETTIME(drive,
|
|
acard_act_dma[drvp->DMA_mode],
|
|
acard_rec_dma[drvp->DMA_mode]);
|
|
} else {
|
|
idetime |= ATP860_SETTIME(channel, drive,
|
|
acard_act_dma[drvp->DMA_mode],
|
|
acard_rec_dma[drvp->DMA_mode]);
|
|
}
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
} else {
|
|
/* PIO only */
|
|
drvp->drive_flags &= ~(DRIVE_UDMA | DRIVE_DMA);
|
|
if (ACARD_IS_850(sc)) {
|
|
idetime |= ATP850_SETTIME(drive,
|
|
acard_act_pio[drvp->PIO_mode],
|
|
acard_rec_pio[drvp->PIO_mode]);
|
|
} else {
|
|
idetime |= ATP860_SETTIME(channel, drive,
|
|
acard_act_pio[drvp->PIO_mode],
|
|
acard_rec_pio[drvp->PIO_mode]);
|
|
}
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, ATP8x0_CTRL,
|
|
pci_conf_read(sc->sc_pc, sc->sc_tag, ATP8x0_CTRL)
|
|
| ATP8x0_CTRL_EN(channel));
|
|
}
|
|
}
|
|
|
|
if (idedma_ctl != 0) {
|
|
/* Add software bits in status register */
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(channel), idedma_ctl);
|
|
}
|
|
pciide_print_modes(cp);
|
|
|
|
if (ACARD_IS_850(sc)) {
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag,
|
|
ATP850_IDETIME(channel), idetime);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, ATP850_UDMA, udma_mode);
|
|
} else {
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, ATP860_IDETIME, idetime);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, ATP860_UDMA, udma_mode);
|
|
}
|
|
}
|
|
|
|
void
|
|
nforce_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_channel *cp;
|
|
int channel;
|
|
pcireg_t interface = PCI_INTERFACE(pa->pa_class);
|
|
bus_size_t cmdsize, ctlsize;
|
|
u_int32_t conf;
|
|
|
|
conf = pci_conf_read(sc->sc_pc, sc->sc_tag, NFORCE_CONF);
|
|
WDCDEBUG_PRINT(("%s: conf register 0x%x\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, conf), DEBUG_PROBE);
|
|
|
|
printf(": DMA");
|
|
pciide_mapreg_dma(sc, pa);
|
|
|
|
sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
|
|
WDC_CAPABILITY_MODE;
|
|
if (sc->sc_dma_ok) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_UDMA;
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_IRQACK;
|
|
sc->sc_wdcdev.irqack = pciide_irqack;
|
|
}
|
|
sc->sc_wdcdev.PIO_cap = 4;
|
|
sc->sc_wdcdev.DMA_cap = 2;
|
|
switch (sc->sc_pp->ide_product) {
|
|
case PCI_PRODUCT_NVIDIA_NFORCE_IDE:
|
|
sc->sc_wdcdev.UDMA_cap = 5;
|
|
break;
|
|
default:
|
|
sc->sc_wdcdev.UDMA_cap = 6;
|
|
}
|
|
sc->sc_wdcdev.set_modes = nforce_setup_channel;
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
|
|
|
|
pciide_print_channels(sc->sc_wdcdev.nchannels, interface);
|
|
|
|
for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
|
|
cp = &sc->pciide_channels[channel];
|
|
|
|
if (pciide_chansetup(sc, channel, interface) == 0)
|
|
continue;
|
|
|
|
if ((conf & NFORCE_CHAN_EN(channel)) == 0) {
|
|
printf("%s: %s ignored (disabled)\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
|
|
cp->hw_ok = 0;
|
|
continue;
|
|
}
|
|
|
|
pciide_map_compat_intr(pa, cp, channel, interface);
|
|
if (cp->hw_ok == 0)
|
|
continue;
|
|
pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
|
|
nforce_pci_intr);
|
|
if (cp->hw_ok == 0) {
|
|
pciide_unmap_compat_intr(pa, cp, channel, interface);
|
|
continue;
|
|
}
|
|
|
|
if (pciide_chan_candisable(cp)) {
|
|
conf &= ~NFORCE_CHAN_EN(channel);
|
|
pciide_unmap_compat_intr(pa, cp, channel, interface);
|
|
continue;
|
|
}
|
|
|
|
sc->sc_wdcdev.set_modes(&cp->wdc_channel);
|
|
}
|
|
WDCDEBUG_PRINT(("%s: new conf register 0x%x\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, conf), DEBUG_PROBE);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, NFORCE_CONF, conf);
|
|
}
|
|
|
|
void
|
|
nforce_setup_channel(struct channel_softc *chp)
|
|
{
|
|
struct ata_drive_datas *drvp;
|
|
int drive, mode;
|
|
u_int32_t idedma_ctl;
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
int channel = chp->channel;
|
|
u_int32_t conf, piodmatim, piotim, udmatim;
|
|
|
|
conf = pci_conf_read(sc->sc_pc, sc->sc_tag, NFORCE_CONF);
|
|
piodmatim = pci_conf_read(sc->sc_pc, sc->sc_tag, NFORCE_PIODMATIM);
|
|
piotim = pci_conf_read(sc->sc_pc, sc->sc_tag, NFORCE_PIOTIM);
|
|
udmatim = pci_conf_read(sc->sc_pc, sc->sc_tag, NFORCE_UDMATIM);
|
|
WDCDEBUG_PRINT(("%s: %s old timing values: piodmatim=0x%x, "
|
|
"piotim=0x%x, udmatim=0x%x\n", sc->sc_wdcdev.sc_dev.dv_xname,
|
|
cp->name, piodmatim, piotim, udmatim), DEBUG_PROBE);
|
|
|
|
/* Setup DMA if needed */
|
|
pciide_channel_dma_setup(cp);
|
|
|
|
/* Clear all bits for this channel */
|
|
idedma_ctl = 0;
|
|
piodmatim &= ~NFORCE_PIODMATIM_MASK(channel);
|
|
udmatim &= ~NFORCE_UDMATIM_MASK(channel);
|
|
|
|
/* Per channel settings */
|
|
for (drive = 0; drive < 2; drive++) {
|
|
drvp = &chp->ch_drive[drive];
|
|
|
|
/* If no drive, skip */
|
|
if ((drvp->drive_flags & DRIVE) == 0)
|
|
continue;
|
|
|
|
if ((chp->wdc->cap & WDC_CAPABILITY_UDMA) != 0 &&
|
|
(drvp->drive_flags & DRIVE_UDMA) != 0) {
|
|
/* Setup UltraDMA mode */
|
|
drvp->drive_flags &= ~DRIVE_DMA;
|
|
|
|
udmatim |= NFORCE_UDMATIM_SET(channel, drive,
|
|
nforce_udma[drvp->UDMA_mode]) |
|
|
NFORCE_UDMA_EN(channel, drive) |
|
|
NFORCE_UDMA_ENM(channel, drive);
|
|
|
|
mode = drvp->PIO_mode;
|
|
} else if ((chp->wdc->cap & WDC_CAPABILITY_DMA) != 0 &&
|
|
(drvp->drive_flags & DRIVE_DMA) != 0) {
|
|
/* Setup multiword DMA mode */
|
|
drvp->drive_flags &= ~DRIVE_UDMA;
|
|
|
|
/* mode = min(pio, dma + 2) */
|
|
if (drvp->PIO_mode <= (drvp->DMA_mode + 2))
|
|
mode = drvp->PIO_mode;
|
|
else
|
|
mode = drvp->DMA_mode + 2;
|
|
} else {
|
|
mode = drvp->PIO_mode;
|
|
goto pio;
|
|
}
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
|
|
pio:
|
|
/* Setup PIO mode */
|
|
if (mode <= 2) {
|
|
drvp->DMA_mode = 0;
|
|
drvp->PIO_mode = 0;
|
|
mode = 0;
|
|
} else {
|
|
drvp->PIO_mode = mode;
|
|
drvp->DMA_mode = mode - 2;
|
|
}
|
|
piodmatim |= NFORCE_PIODMATIM_SET(channel, drive,
|
|
nforce_pio[mode]);
|
|
}
|
|
|
|
if (idedma_ctl != 0) {
|
|
/* Add software bits in status register */
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(channel), idedma_ctl);
|
|
}
|
|
|
|
WDCDEBUG_PRINT(("%s: %s new timing values: piodmatim=0x%x, "
|
|
"piotim=0x%x, udmatim=0x%x\n", sc->sc_wdcdev.sc_dev.dv_xname,
|
|
cp->name, piodmatim, piotim, udmatim), DEBUG_PROBE);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, NFORCE_PIODMATIM, piodmatim);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, NFORCE_UDMATIM, udmatim);
|
|
|
|
pciide_print_modes(cp);
|
|
}
|
|
|
|
int
|
|
nforce_pci_intr(void *arg)
|
|
{
|
|
struct pciide_softc *sc = arg;
|
|
struct pciide_channel *cp;
|
|
struct channel_softc *wdc_cp;
|
|
int i, rv, crv;
|
|
u_int32_t dmastat;
|
|
|
|
rv = 0;
|
|
for (i = 0; i < sc->sc_wdcdev.nchannels; i++) {
|
|
cp = &sc->pciide_channels[i];
|
|
wdc_cp = &cp->wdc_channel;
|
|
|
|
/* Skip compat channel */
|
|
if (cp->compat)
|
|
continue;
|
|
|
|
dmastat = bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(i));
|
|
if ((dmastat & IDEDMA_CTL_INTR) == 0)
|
|
continue;
|
|
|
|
crv = wdcintr(wdc_cp);
|
|
if (crv == 0)
|
|
printf("%s:%d: bogus intr\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, i);
|
|
else
|
|
rv = 1;
|
|
}
|
|
return (rv);
|
|
}
|
|
|
|
void
|
|
artisea_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_channel *cp;
|
|
bus_size_t cmdsize, ctlsize;
|
|
pcireg_t interface;
|
|
int channel;
|
|
|
|
printf(": DMA");
|
|
#ifdef PCIIDE_I31244_DISABLEDMA
|
|
if (sc->sc_rev == 0) {
|
|
printf(" disabled due to rev. 0");
|
|
sc->sc_dma_ok = 0;
|
|
} else
|
|
#endif
|
|
pciide_mapreg_dma(sc, pa);
|
|
printf("\n");
|
|
|
|
/*
|
|
* XXX Configure LEDs to show activity.
|
|
*/
|
|
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
|
|
WDC_CAPABILITY_MODE | WDC_CAPABILITY_SATA;
|
|
sc->sc_wdcdev.PIO_cap = 4;
|
|
if (sc->sc_dma_ok) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_UDMA;
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_IRQACK;
|
|
sc->sc_wdcdev.irqack = pciide_irqack;
|
|
sc->sc_wdcdev.DMA_cap = 2;
|
|
sc->sc_wdcdev.UDMA_cap = 6;
|
|
}
|
|
sc->sc_wdcdev.set_modes = sata_setup_channel;
|
|
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
|
|
|
|
interface = PCI_INTERFACE(pa->pa_class);
|
|
|
|
for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
|
|
cp = &sc->pciide_channels[channel];
|
|
if (pciide_chansetup(sc, channel, interface) == 0)
|
|
continue;
|
|
pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
|
|
pciide_pci_intr);
|
|
if (cp->hw_ok == 0)
|
|
continue;
|
|
pciide_map_compat_intr(pa, cp, channel, interface);
|
|
sata_setup_channel(&cp->wdc_channel);
|
|
}
|
|
}
|
|
|
|
void
|
|
ite_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_channel *cp;
|
|
int channel;
|
|
pcireg_t interface;
|
|
bus_size_t cmdsize, ctlsize;
|
|
pcireg_t cfg, modectl;
|
|
|
|
/*
|
|
* Fake interface since IT8212F is claimed to be a ``RAID'' device.
|
|
*/
|
|
interface = PCIIDE_INTERFACE_BUS_MASTER_DMA |
|
|
PCIIDE_INTERFACE_PCI(0) | PCIIDE_INTERFACE_PCI(1);
|
|
|
|
cfg = pci_conf_read(sc->sc_pc, sc->sc_tag, IT_CFG);
|
|
modectl = pci_conf_read(sc->sc_pc, sc->sc_tag, IT_MODE);
|
|
WDCDEBUG_PRINT(("%s: cfg=0x%x, modectl=0x%x\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cfg & IT_CFG_MASK,
|
|
modectl & IT_MODE_MASK), DEBUG_PROBE);
|
|
|
|
printf(": DMA");
|
|
pciide_mapreg_dma(sc, pa);
|
|
|
|
sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
|
|
WDC_CAPABILITY_MODE;
|
|
if (sc->sc_dma_ok) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_UDMA;
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_IRQACK;
|
|
sc->sc_wdcdev.irqack = pciide_irqack;
|
|
}
|
|
sc->sc_wdcdev.PIO_cap = 4;
|
|
sc->sc_wdcdev.DMA_cap = 2;
|
|
sc->sc_wdcdev.UDMA_cap = 6;
|
|
|
|
sc->sc_wdcdev.set_modes = ite_setup_channel;
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
|
|
|
|
pciide_print_channels(sc->sc_wdcdev.nchannels, interface);
|
|
|
|
/* Disable RAID */
|
|
modectl &= ~IT_MODE_RAID1;
|
|
/* Disable CPU firmware mode */
|
|
modectl &= ~IT_MODE_CPU;
|
|
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, IT_MODE, modectl);
|
|
|
|
for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
|
|
cp = &sc->pciide_channels[channel];
|
|
|
|
if (pciide_chansetup(sc, channel, interface) == 0)
|
|
continue;
|
|
pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
|
|
pciide_pci_intr);
|
|
sc->sc_wdcdev.set_modes(&cp->wdc_channel);
|
|
}
|
|
|
|
/* Re-read configuration registers after channels setup */
|
|
cfg = pci_conf_read(sc->sc_pc, sc->sc_tag, IT_CFG);
|
|
modectl = pci_conf_read(sc->sc_pc, sc->sc_tag, IT_MODE);
|
|
WDCDEBUG_PRINT(("%s: cfg=0x%x, modectl=0x%x\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cfg & IT_CFG_MASK,
|
|
modectl & IT_MODE_MASK), DEBUG_PROBE);
|
|
}
|
|
|
|
void
|
|
ite_setup_channel(struct channel_softc *chp)
|
|
{
|
|
struct ata_drive_datas *drvp;
|
|
int drive, mode;
|
|
u_int32_t idedma_ctl;
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
int channel = chp->channel;
|
|
pcireg_t cfg, modectl;
|
|
pcireg_t tim;
|
|
|
|
cfg = pci_conf_read(sc->sc_pc, sc->sc_tag, IT_CFG);
|
|
modectl = pci_conf_read(sc->sc_pc, sc->sc_tag, IT_MODE);
|
|
tim = pci_conf_read(sc->sc_pc, sc->sc_tag, IT_TIM(channel));
|
|
WDCDEBUG_PRINT(("%s:%d: tim=0x%x\n", sc->sc_wdcdev.sc_dev.dv_xname,
|
|
channel, tim), DEBUG_PROBE);
|
|
|
|
/* Setup DMA if needed */
|
|
pciide_channel_dma_setup(cp);
|
|
|
|
/* Clear all bits for this channel */
|
|
idedma_ctl = 0;
|
|
|
|
/* Per channel settings */
|
|
for (drive = 0; drive < 2; drive++) {
|
|
drvp = &chp->ch_drive[drive];
|
|
|
|
/* If no drive, skip */
|
|
if ((drvp->drive_flags & DRIVE) == 0)
|
|
continue;
|
|
|
|
if ((chp->wdc->cap & WDC_CAPABILITY_UDMA) != 0 &&
|
|
(drvp->drive_flags & DRIVE_UDMA) != 0) {
|
|
/* Setup UltraDMA mode */
|
|
drvp->drive_flags &= ~DRIVE_DMA;
|
|
modectl &= ~IT_MODE_DMA(channel, drive);
|
|
|
|
#if 0
|
|
/* Check cable, works only in CPU firmware mode */
|
|
if (drvp->UDMA_mode > 2 &&
|
|
(cfg & IT_CFG_CABLE(channel, drive)) == 0) {
|
|
WDCDEBUG_PRINT(("%s(%s:%d:%d): "
|
|
"80-wire cable not detected\n",
|
|
drvp->drive_name,
|
|
sc->sc_wdcdev.sc_dev.dv_xname,
|
|
channel, drive), DEBUG_PROBE);
|
|
drvp->UDMA_mode = 2;
|
|
}
|
|
#endif
|
|
|
|
if (drvp->UDMA_mode >= 5)
|
|
tim |= IT_TIM_UDMA5(drive);
|
|
else
|
|
tim &= ~IT_TIM_UDMA5(drive);
|
|
|
|
mode = drvp->PIO_mode;
|
|
} else if ((chp->wdc->cap & WDC_CAPABILITY_DMA) != 0 &&
|
|
(drvp->drive_flags & DRIVE_DMA) != 0) {
|
|
/* Setup multiword DMA mode */
|
|
drvp->drive_flags &= ~DRIVE_UDMA;
|
|
modectl |= IT_MODE_DMA(channel, drive);
|
|
|
|
/* mode = min(pio, dma + 2) */
|
|
if (drvp->PIO_mode <= (drvp->DMA_mode + 2))
|
|
mode = drvp->PIO_mode;
|
|
else
|
|
mode = drvp->DMA_mode + 2;
|
|
} else {
|
|
mode = drvp->PIO_mode;
|
|
goto pio;
|
|
}
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
|
|
pio:
|
|
/* Setup PIO mode */
|
|
if (mode <= 2) {
|
|
drvp->DMA_mode = 0;
|
|
drvp->PIO_mode = 0;
|
|
mode = 0;
|
|
} else {
|
|
drvp->PIO_mode = mode;
|
|
drvp->DMA_mode = mode - 2;
|
|
}
|
|
|
|
/* Enable IORDY if PIO mode >= 3 */
|
|
if (drvp->PIO_mode >= 3)
|
|
cfg |= IT_CFG_IORDY(channel);
|
|
}
|
|
|
|
WDCDEBUG_PRINT(("%s: tim=0x%x\n", sc->sc_wdcdev.sc_dev.dv_xname,
|
|
tim), DEBUG_PROBE);
|
|
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, IT_CFG, cfg);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, IT_MODE, modectl);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, IT_TIM(channel), tim);
|
|
|
|
if (idedma_ctl != 0) {
|
|
/* Add software bits in status register */
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(channel), idedma_ctl);
|
|
}
|
|
|
|
pciide_print_modes(cp);
|
|
}
|
|
|
|
void
|
|
ixp_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_channel *cp;
|
|
int channel;
|
|
pcireg_t interface = PCI_INTERFACE(pa->pa_class);
|
|
bus_size_t cmdsize, ctlsize;
|
|
|
|
printf(": DMA");
|
|
pciide_mapreg_dma(sc, pa);
|
|
|
|
sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
|
|
WDC_CAPABILITY_MODE;
|
|
if (sc->sc_dma_ok) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_UDMA;
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_IRQACK;
|
|
sc->sc_wdcdev.irqack = pciide_irqack;
|
|
}
|
|
sc->sc_wdcdev.PIO_cap = 4;
|
|
sc->sc_wdcdev.DMA_cap = 2;
|
|
sc->sc_wdcdev.UDMA_cap = 6;
|
|
|
|
sc->sc_wdcdev.set_modes = ixp_setup_channel;
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
|
|
|
|
pciide_print_channels(sc->sc_wdcdev.nchannels, interface);
|
|
|
|
for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
|
|
cp = &sc->pciide_channels[channel];
|
|
if (pciide_chansetup(sc, channel, interface) == 0)
|
|
continue;
|
|
pciide_map_compat_intr(pa, cp, channel, interface);
|
|
if (cp->hw_ok == 0)
|
|
continue;
|
|
pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
|
|
pciide_pci_intr);
|
|
if (cp->hw_ok == 0) {
|
|
pciide_unmap_compat_intr(pa, cp, channel, interface);
|
|
continue;
|
|
}
|
|
sc->sc_wdcdev.set_modes(&cp->wdc_channel);
|
|
}
|
|
}
|
|
|
|
void
|
|
ixp_setup_channel(struct channel_softc *chp)
|
|
{
|
|
struct ata_drive_datas *drvp;
|
|
int drive, mode;
|
|
u_int32_t idedma_ctl;
|
|
struct pciide_channel *cp = (struct pciide_channel*)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
int channel = chp->channel;
|
|
pcireg_t udma, mdma_timing, pio, pio_timing;
|
|
|
|
pio_timing = pci_conf_read(sc->sc_pc, sc->sc_tag, IXP_PIO_TIMING);
|
|
pio = pci_conf_read(sc->sc_pc, sc->sc_tag, IXP_PIO_CTL);
|
|
mdma_timing = pci_conf_read(sc->sc_pc, sc->sc_tag, IXP_MDMA_TIMING);
|
|
udma = pci_conf_read(sc->sc_pc, sc->sc_tag, IXP_UDMA_CTL);
|
|
|
|
/* Setup DMA if needed */
|
|
pciide_channel_dma_setup(cp);
|
|
|
|
idedma_ctl = 0;
|
|
|
|
/* Per channel settings */
|
|
for (drive = 0; drive < 2; drive++) {
|
|
drvp = &chp->ch_drive[drive];
|
|
|
|
/* If no drive, skip */
|
|
if ((drvp->drive_flags & DRIVE) == 0)
|
|
continue;
|
|
if ((chp->wdc->cap & WDC_CAPABILITY_UDMA) != 0 &&
|
|
(drvp->drive_flags & DRIVE_UDMA) != 0) {
|
|
/* Setup UltraDMA mode */
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
IXP_UDMA_ENABLE(udma, chp->channel, drive);
|
|
IXP_SET_MODE(udma, chp->channel, drive,
|
|
drvp->UDMA_mode);
|
|
mode = drvp->PIO_mode;
|
|
} else if ((chp->wdc->cap & WDC_CAPABILITY_DMA) != 0 &&
|
|
(drvp->drive_flags & DRIVE_DMA) != 0) {
|
|
/* Setup multiword DMA mode */
|
|
drvp->drive_flags &= ~DRIVE_UDMA;
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
IXP_UDMA_DISABLE(udma, chp->channel, drive);
|
|
IXP_SET_TIMING(mdma_timing, chp->channel, drive,
|
|
ixp_mdma_timings[drvp->DMA_mode]);
|
|
|
|
/* mode = min(pio, dma + 2) */
|
|
if (drvp->PIO_mode <= (drvp->DMA_mode + 2))
|
|
mode = drvp->PIO_mode;
|
|
else
|
|
mode = drvp->DMA_mode + 2;
|
|
} else {
|
|
mode = drvp->PIO_mode;
|
|
}
|
|
|
|
/* Setup PIO mode */
|
|
drvp->PIO_mode = mode;
|
|
if (mode < 2)
|
|
drvp->DMA_mode = 0;
|
|
else
|
|
drvp->DMA_mode = mode - 2;
|
|
/*
|
|
* Set PIO mode and timings
|
|
* Linux driver avoids PIO mode 1, let's do it too.
|
|
*/
|
|
if (drvp->PIO_mode == 1)
|
|
drvp->PIO_mode = 0;
|
|
|
|
IXP_SET_MODE(pio, chp->channel, drive, drvp->PIO_mode);
|
|
IXP_SET_TIMING(pio_timing, chp->channel, drive,
|
|
ixp_pio_timings[drvp->PIO_mode]);
|
|
}
|
|
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, IXP_UDMA_CTL, udma);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, IXP_MDMA_TIMING, mdma_timing);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, IXP_PIO_CTL, pio);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, IXP_PIO_TIMING, pio_timing);
|
|
|
|
if (idedma_ctl != 0) {
|
|
/* Add software bits in status register */
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(channel), idedma_ctl);
|
|
}
|
|
|
|
pciide_print_modes(cp);
|
|
}
|
|
|
|
void
|
|
jmicron_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_channel *cp;
|
|
int channel;
|
|
pcireg_t interface = PCI_INTERFACE(pa->pa_class);
|
|
bus_size_t cmdsize, ctlsize;
|
|
u_int32_t conf;
|
|
|
|
conf = pci_conf_read(sc->sc_pc, sc->sc_tag, JMICRON_CONF);
|
|
WDCDEBUG_PRINT(("%s: conf register 0x%x\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, conf), DEBUG_PROBE);
|
|
|
|
printf(": DMA");
|
|
pciide_mapreg_dma(sc, pa);
|
|
|
|
sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
|
|
WDC_CAPABILITY_MODE;
|
|
if (sc->sc_dma_ok) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_UDMA;
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_IRQACK;
|
|
sc->sc_wdcdev.irqack = pciide_irqack;
|
|
}
|
|
sc->sc_wdcdev.PIO_cap = 4;
|
|
sc->sc_wdcdev.DMA_cap = 2;
|
|
sc->sc_wdcdev.UDMA_cap = 6;
|
|
sc->sc_wdcdev.set_modes = jmicron_setup_channel;
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
|
|
|
|
pciide_print_channels(sc->sc_wdcdev.nchannels, interface);
|
|
|
|
for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
|
|
cp = &sc->pciide_channels[channel];
|
|
|
|
if (pciide_chansetup(sc, channel, interface) == 0)
|
|
continue;
|
|
|
|
#if 0
|
|
if ((conf & JMICRON_CHAN_EN(channel)) == 0) {
|
|
printf("%s: %s ignored (disabled)\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
|
|
cp->hw_ok = 0;
|
|
continue;
|
|
}
|
|
#endif
|
|
|
|
pciide_map_compat_intr(pa, cp, channel, interface);
|
|
if (cp->hw_ok == 0)
|
|
continue;
|
|
pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
|
|
pciide_pci_intr);
|
|
if (cp->hw_ok == 0) {
|
|
pciide_unmap_compat_intr(pa, cp, channel, interface);
|
|
continue;
|
|
}
|
|
|
|
if (pciide_chan_candisable(cp)) {
|
|
conf &= ~JMICRON_CHAN_EN(channel);
|
|
pciide_unmap_compat_intr(pa, cp, channel, interface);
|
|
continue;
|
|
}
|
|
|
|
sc->sc_wdcdev.set_modes(&cp->wdc_channel);
|
|
}
|
|
WDCDEBUG_PRINT(("%s: new conf register 0x%x\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, conf), DEBUG_PROBE);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, JMICRON_CONF, conf);
|
|
}
|
|
|
|
void
|
|
jmicron_setup_channel(struct channel_softc *chp)
|
|
{
|
|
struct ata_drive_datas *drvp;
|
|
int drive, mode;
|
|
u_int32_t idedma_ctl;
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
int channel = chp->channel;
|
|
u_int32_t conf;
|
|
|
|
conf = pci_conf_read(sc->sc_pc, sc->sc_tag, JMICRON_CONF);
|
|
|
|
/* Setup DMA if needed */
|
|
pciide_channel_dma_setup(cp);
|
|
|
|
/* Clear all bits for this channel */
|
|
idedma_ctl = 0;
|
|
|
|
/* Per channel settings */
|
|
for (drive = 0; drive < 2; drive++) {
|
|
drvp = &chp->ch_drive[drive];
|
|
|
|
/* If no drive, skip */
|
|
if ((drvp->drive_flags & DRIVE) == 0)
|
|
continue;
|
|
|
|
if ((chp->wdc->cap & WDC_CAPABILITY_UDMA) != 0 &&
|
|
(drvp->drive_flags & DRIVE_UDMA) != 0) {
|
|
/* Setup UltraDMA mode */
|
|
drvp->drive_flags &= ~DRIVE_DMA;
|
|
|
|
/* see if cable is up to scratch */
|
|
if ((conf & JMICRON_CONF_40PIN) &&
|
|
(drvp->UDMA_mode > 2))
|
|
drvp->UDMA_mode = 2;
|
|
|
|
mode = drvp->PIO_mode;
|
|
} else if ((chp->wdc->cap & WDC_CAPABILITY_DMA) != 0 &&
|
|
(drvp->drive_flags & DRIVE_DMA) != 0) {
|
|
/* Setup multiword DMA mode */
|
|
drvp->drive_flags &= ~DRIVE_UDMA;
|
|
|
|
/* mode = min(pio, dma + 2) */
|
|
if (drvp->PIO_mode <= (drvp->DMA_mode + 2))
|
|
mode = drvp->PIO_mode;
|
|
else
|
|
mode = drvp->DMA_mode + 2;
|
|
} else {
|
|
mode = drvp->PIO_mode;
|
|
goto pio;
|
|
}
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
|
|
pio:
|
|
/* Setup PIO mode */
|
|
if (mode <= 2) {
|
|
drvp->DMA_mode = 0;
|
|
drvp->PIO_mode = 0;
|
|
} else {
|
|
drvp->PIO_mode = mode;
|
|
drvp->DMA_mode = mode - 2;
|
|
}
|
|
}
|
|
|
|
if (idedma_ctl != 0) {
|
|
/* Add software bits in status register */
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(channel), idedma_ctl);
|
|
}
|
|
|
|
pciide_print_modes(cp);
|
|
}
|
|
|
|
void
|
|
phison_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_channel *cp;
|
|
int channel;
|
|
pcireg_t interface = PCI_INTERFACE(pa->pa_class);
|
|
bus_size_t cmdsize, ctlsize;
|
|
|
|
sc->chip_unmap = default_chip_unmap;
|
|
|
|
printf(": DMA");
|
|
pciide_mapreg_dma(sc, pa);
|
|
|
|
sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
|
|
WDC_CAPABILITY_MODE;
|
|
if (sc->sc_dma_ok) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_UDMA;
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_IRQACK;
|
|
sc->sc_wdcdev.irqack = pciide_irqack;
|
|
}
|
|
sc->sc_wdcdev.PIO_cap = 4;
|
|
sc->sc_wdcdev.DMA_cap = 2;
|
|
sc->sc_wdcdev.UDMA_cap = 5;
|
|
sc->sc_wdcdev.set_modes = phison_setup_channel;
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
sc->sc_wdcdev.nchannels = 1;
|
|
|
|
pciide_print_channels(sc->sc_wdcdev.nchannels, interface);
|
|
|
|
for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
|
|
cp = &sc->pciide_channels[channel];
|
|
|
|
if (pciide_chansetup(sc, channel, interface) == 0)
|
|
continue;
|
|
|
|
pciide_map_compat_intr(pa, cp, channel, interface);
|
|
if (cp->hw_ok == 0)
|
|
continue;
|
|
pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
|
|
pciide_pci_intr);
|
|
if (cp->hw_ok == 0) {
|
|
pciide_unmap_compat_intr(pa, cp, channel, interface);
|
|
continue;
|
|
}
|
|
|
|
sc->sc_wdcdev.set_modes(&cp->wdc_channel);
|
|
}
|
|
}
|
|
|
|
void
|
|
phison_setup_channel(struct channel_softc *chp)
|
|
{
|
|
struct ata_drive_datas *drvp;
|
|
int drive, mode;
|
|
u_int32_t idedma_ctl;
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
int channel = chp->channel;
|
|
|
|
/* Setup DMA if needed */
|
|
pciide_channel_dma_setup(cp);
|
|
|
|
/* Clear all bits for this channel */
|
|
idedma_ctl = 0;
|
|
|
|
/* Per channel settings */
|
|
for (drive = 0; drive < 2; drive++) {
|
|
drvp = &chp->ch_drive[drive];
|
|
|
|
/* If no drive, skip */
|
|
if ((drvp->drive_flags & DRIVE) == 0)
|
|
continue;
|
|
|
|
if ((chp->wdc->cap & WDC_CAPABILITY_UDMA) != 0 &&
|
|
(drvp->drive_flags & DRIVE_UDMA) != 0) {
|
|
/* Setup UltraDMA mode */
|
|
drvp->drive_flags &= ~DRIVE_DMA;
|
|
mode = drvp->PIO_mode;
|
|
} else if ((chp->wdc->cap & WDC_CAPABILITY_DMA) != 0 &&
|
|
(drvp->drive_flags & DRIVE_DMA) != 0) {
|
|
/* Setup multiword DMA mode */
|
|
drvp->drive_flags &= ~DRIVE_UDMA;
|
|
|
|
/* mode = min(pio, dma + 2) */
|
|
if (drvp->PIO_mode <= (drvp->DMA_mode + 2))
|
|
mode = drvp->PIO_mode;
|
|
else
|
|
mode = drvp->DMA_mode + 2;
|
|
} else {
|
|
mode = drvp->PIO_mode;
|
|
goto pio;
|
|
}
|
|
idedma_ctl |= IDEDMA_CTL_DRV_DMA(drive);
|
|
|
|
pio:
|
|
/* Setup PIO mode */
|
|
if (mode <= 2) {
|
|
drvp->DMA_mode = 0;
|
|
drvp->PIO_mode = 0;
|
|
} else {
|
|
drvp->PIO_mode = mode;
|
|
drvp->DMA_mode = mode - 2;
|
|
}
|
|
}
|
|
|
|
if (idedma_ctl != 0) {
|
|
/* Add software bits in status register */
|
|
bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
|
|
IDEDMA_CTL(channel), idedma_ctl);
|
|
}
|
|
|
|
pciide_print_modes(cp);
|
|
}
|
|
|
|
void
|
|
sch_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_channel *cp;
|
|
int channel;
|
|
pcireg_t interface = PCI_INTERFACE(pa->pa_class);
|
|
bus_size_t cmdsize, ctlsize;
|
|
|
|
printf(": DMA");
|
|
pciide_mapreg_dma(sc, pa);
|
|
|
|
sc->sc_wdcdev.cap = WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32 |
|
|
WDC_CAPABILITY_MODE;
|
|
if (sc->sc_dma_ok) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA | WDC_CAPABILITY_UDMA;
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_IRQACK;
|
|
sc->sc_wdcdev.irqack = pciide_irqack;
|
|
}
|
|
sc->sc_wdcdev.PIO_cap = 4;
|
|
sc->sc_wdcdev.DMA_cap = 2;
|
|
sc->sc_wdcdev.UDMA_cap = 5;
|
|
sc->sc_wdcdev.set_modes = sch_setup_channel;
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
sc->sc_wdcdev.nchannels = 1;
|
|
|
|
pciide_print_channels(sc->sc_wdcdev.nchannels, interface);
|
|
|
|
for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
|
|
cp = &sc->pciide_channels[channel];
|
|
|
|
if (pciide_chansetup(sc, channel, interface) == 0)
|
|
continue;
|
|
|
|
pciide_map_compat_intr(pa, cp, channel, interface);
|
|
if (cp->hw_ok == 0)
|
|
continue;
|
|
pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
|
|
pciide_pci_intr);
|
|
if (cp->hw_ok == 0) {
|
|
pciide_unmap_compat_intr(pa, cp, channel, interface);
|
|
continue;
|
|
}
|
|
|
|
sc->sc_wdcdev.set_modes(&cp->wdc_channel);
|
|
}
|
|
}
|
|
|
|
void
|
|
sch_setup_channel(struct channel_softc *chp)
|
|
{
|
|
struct ata_drive_datas *drvp;
|
|
int drive, mode;
|
|
u_int32_t tim, timaddr;
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
|
|
/* Setup DMA if needed */
|
|
pciide_channel_dma_setup(cp);
|
|
|
|
/* Per channel settings */
|
|
for (drive = 0; drive < 2; drive++) {
|
|
drvp = &chp->ch_drive[drive];
|
|
|
|
/* If no drive, skip */
|
|
if ((drvp->drive_flags & DRIVE) == 0)
|
|
continue;
|
|
|
|
timaddr = (drive == 0) ? SCH_D0TIM : SCH_D1TIM;
|
|
tim = pci_conf_read(sc->sc_pc, sc->sc_tag, timaddr);
|
|
tim &= ~SCH_TIM_MASK;
|
|
|
|
if ((chp->wdc->cap & WDC_CAPABILITY_UDMA) != 0 &&
|
|
(drvp->drive_flags & DRIVE_UDMA) != 0) {
|
|
/* Setup UltraDMA mode */
|
|
drvp->drive_flags &= ~DRIVE_DMA;
|
|
|
|
mode = drvp->PIO_mode;
|
|
tim |= (drvp->UDMA_mode << 16) | SCH_TIM_SYNCDMA;
|
|
} else if ((chp->wdc->cap & WDC_CAPABILITY_DMA) != 0 &&
|
|
(drvp->drive_flags & DRIVE_DMA) != 0) {
|
|
/* Setup multiword DMA mode */
|
|
drvp->drive_flags &= ~DRIVE_UDMA;
|
|
|
|
tim &= ~SCH_TIM_SYNCDMA;
|
|
|
|
/* mode = min(pio, dma + 2) */
|
|
if (drvp->PIO_mode <= (drvp->DMA_mode + 2))
|
|
mode = drvp->PIO_mode;
|
|
else
|
|
mode = drvp->DMA_mode + 2;
|
|
} else {
|
|
mode = drvp->PIO_mode;
|
|
goto pio;
|
|
}
|
|
|
|
pio:
|
|
/* Setup PIO mode */
|
|
if (mode <= 2) {
|
|
drvp->DMA_mode = 0;
|
|
drvp->PIO_mode = 0;
|
|
} else {
|
|
drvp->PIO_mode = mode;
|
|
drvp->DMA_mode = mode - 2;
|
|
}
|
|
tim |= (drvp->DMA_mode << 8) | (drvp->PIO_mode);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, timaddr, tim);
|
|
}
|
|
|
|
pciide_print_modes(cp);
|
|
}
|
|
|
|
void
|
|
rdc_chip_map(struct pciide_softc *sc, struct pci_attach_args *pa)
|
|
{
|
|
struct pciide_channel *cp;
|
|
int channel;
|
|
u_int32_t patr;
|
|
pcireg_t interface = PCI_INTERFACE(pa->pa_class);
|
|
bus_size_t cmdsize, ctlsize;
|
|
|
|
printf(": DMA");
|
|
pciide_mapreg_dma(sc, pa);
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32;
|
|
if (sc->sc_dma_ok) {
|
|
sc->sc_wdcdev.cap |= WDC_CAPABILITY_UDMA |
|
|
WDC_CAPABILITY_DMA | WDC_CAPABILITY_IRQACK;
|
|
sc->sc_wdcdev.irqack = pciide_irqack;
|
|
sc->sc_wdcdev.dma_init = pciide_dma_init;
|
|
}
|
|
sc->sc_wdcdev.PIO_cap = 4;
|
|
sc->sc_wdcdev.DMA_cap = 2;
|
|
sc->sc_wdcdev.UDMA_cap = 5;
|
|
sc->sc_wdcdev.set_modes = rdc_setup_channel;
|
|
sc->sc_wdcdev.channels = sc->wdc_chanarray;
|
|
sc->sc_wdcdev.nchannels = PCIIDE_NUM_CHANNELS;
|
|
|
|
pciide_print_channels(sc->sc_wdcdev.nchannels, interface);
|
|
|
|
WDCDEBUG_PRINT(("rdc_chip_map: old PATR=0x%x, "
|
|
"PSD1ATR=0x%x, UDCCR=0x%x, IIOCR=0x%x\n",
|
|
pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_PATR),
|
|
pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_PSD1ATR),
|
|
pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_UDCCR),
|
|
pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_IIOCR)),
|
|
DEBUG_PROBE);
|
|
|
|
for (channel = 0; channel < sc->sc_wdcdev.nchannels; channel++) {
|
|
cp = &sc->pciide_channels[channel];
|
|
|
|
if (pciide_chansetup(sc, channel, interface) == 0)
|
|
continue;
|
|
patr = pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_PATR);
|
|
if ((patr & RDCIDE_PATR_EN(channel)) == 0) {
|
|
printf("%s: %s ignored (disabled)\n",
|
|
sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
|
|
cp->hw_ok = 0;
|
|
continue;
|
|
}
|
|
pciide_map_compat_intr(pa, cp, channel, interface);
|
|
if (cp->hw_ok == 0)
|
|
continue;
|
|
pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
|
|
pciide_pci_intr);
|
|
if (cp->hw_ok == 0)
|
|
goto next;
|
|
if (pciide_chan_candisable(cp)) {
|
|
patr &= ~RDCIDE_PATR_EN(channel);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, RDCIDE_PATR,
|
|
patr);
|
|
}
|
|
if (cp->hw_ok == 0)
|
|
goto next;
|
|
sc->sc_wdcdev.set_modes(&cp->wdc_channel);
|
|
next:
|
|
if (cp->hw_ok == 0)
|
|
pciide_unmap_compat_intr(pa, cp, channel, interface);
|
|
}
|
|
|
|
WDCDEBUG_PRINT(("rdc_chip_map: PATR=0x%x, "
|
|
"PSD1ATR=0x%x, UDCCR=0x%x, IIOCR=0x%x\n",
|
|
pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_PATR),
|
|
pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_PSD1ATR),
|
|
pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_UDCCR),
|
|
pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_IIOCR)),
|
|
DEBUG_PROBE);
|
|
}
|
|
|
|
void
|
|
rdc_setup_channel(struct channel_softc *chp)
|
|
{
|
|
u_int8_t drive;
|
|
u_int32_t patr, psd1atr, udccr, iiocr;
|
|
struct pciide_channel *cp = (struct pciide_channel *)chp;
|
|
struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
|
|
struct ata_drive_datas *drvp;
|
|
|
|
patr = pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_PATR);
|
|
psd1atr = pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_PSD1ATR);
|
|
udccr = pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_UDCCR);
|
|
iiocr = pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_IIOCR);
|
|
|
|
/* setup DMA */
|
|
pciide_channel_dma_setup(cp);
|
|
|
|
/* clear modes */
|
|
patr = patr & (RDCIDE_PATR_EN(0) | RDCIDE_PATR_EN(1));
|
|
psd1atr &= ~RDCIDE_PSD1ATR_SETUP_MASK(chp->channel);
|
|
psd1atr &= ~RDCIDE_PSD1ATR_HOLD_MASK(chp->channel);
|
|
for (drive = 0; drive < 2; drive++) {
|
|
udccr &= ~RDCIDE_UDCCR_EN(chp->channel, drive);
|
|
udccr &= ~RDCIDE_UDCCR_TIM_MASK(chp->channel, drive);
|
|
iiocr &= ~RDCIDE_IIOCR_CLK_MASK(chp->channel, drive);
|
|
}
|
|
/* now setup modes */
|
|
for (drive = 0; drive < 2; drive++) {
|
|
drvp = &cp->wdc_channel.ch_drive[drive];
|
|
if ((drvp->drive_flags & DRIVE) == 0)
|
|
continue;
|
|
if (drvp->drive_flags & DRIVE_ATAPI)
|
|
patr |= RDCIDE_PATR_ATA(chp->channel, drive);
|
|
if (drive == 0) {
|
|
patr |= RDCIDE_PATR_SETUP(rdcide_setup[drvp->PIO_mode],
|
|
chp->channel);
|
|
patr |= RDCIDE_PATR_HOLD(rdcide_hold[drvp->PIO_mode],
|
|
chp->channel);
|
|
} else {
|
|
patr |= RDCIDE_PATR_DEV1_TEN(chp->channel);
|
|
psd1atr |= RDCIDE_PSD1ATR_SETUP(
|
|
rdcide_setup[drvp->PIO_mode],
|
|
chp->channel);
|
|
psd1atr |= RDCIDE_PSD1ATR_HOLD(
|
|
rdcide_hold[drvp->PIO_mode],
|
|
chp->channel);
|
|
}
|
|
if (drvp->PIO_mode > 0) {
|
|
patr |= RDCIDE_PATR_FTIM(chp->channel, drive);
|
|
patr |= RDCIDE_PATR_IORDY(chp->channel, drive);
|
|
}
|
|
if (drvp->drive_flags & DRIVE_DMA)
|
|
patr |= RDCIDE_PATR_DMAEN(chp->channel, drive);
|
|
if ((drvp->drive_flags & DRIVE_UDMA) == 0)
|
|
continue;
|
|
|
|
if ((iiocr & RDCIDE_IIOCR_CABLE(chp->channel, drive)) == 0
|
|
&& drvp->UDMA_mode > 2)
|
|
drvp->UDMA_mode = 2;
|
|
udccr |= RDCIDE_UDCCR_EN(chp->channel, drive);
|
|
udccr |= RDCIDE_UDCCR_TIM(rdcide_udmatim[drvp->UDMA_mode],
|
|
chp->channel, drive);
|
|
iiocr |= RDCIDE_IIOCR_CLK(rdcide_udmaclk[drvp->UDMA_mode],
|
|
chp->channel, drive);
|
|
}
|
|
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, RDCIDE_PATR, patr);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, RDCIDE_PSD1ATR, psd1atr);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, RDCIDE_UDCCR, udccr);
|
|
pci_conf_write(sc->sc_pc, sc->sc_tag, RDCIDE_IIOCR, iiocr);
|
|
}
|