summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsos <sos@FreeBSD.org>2003-05-01 06:20:50 +0000
committersos <sos@FreeBSD.org>2003-05-01 06:20:50 +0000
commit9f4de55ff28048fc5c191cc9f226a1aa7043c9ad (patch)
tree046aabd61b28e6cf578849bad8b69717d3e8140c
parent4cf0da39d0a5409f3df27e4bbc17e5f3b36f5d7b (diff)
downloadFreeBSD-src-9f4de55ff28048fc5c191cc9f226a1aa7043c9ad.zip
FreeBSD-src-9f4de55ff28048fc5c191cc9f226a1aa7043c9ad.tar.gz
I'm pleased to announce that Promise is now supporting the FreeBSD
project by providing documentation (under NDA) and hardware for testing. This commit is the first result of the cooperation, and adds support for several of their new controllers that we didn't support before (and probably newer would have without this arrangement). Add support for the Promise SATA150 TX2/TX4 and the Promise TX4000 controllers. This also adds support for various motherboard fitted Promise SATA/ATA chips. Note that this code uses memory mapped registers to minimize overhead. I belive FreeBSD has made another first in the Open Source world by being able to release support for this :)
-rw-r--r--sys/dev/ata/ata-chipset.c151
-rw-r--r--sys/dev/ata/ata-pci.h19
2 files changed, 161 insertions, 9 deletions
diff --git a/sys/dev/ata/ata-chipset.c b/sys/dev/ata/ata-chipset.c
index dd71819..edcc905 100644
--- a/sys/dev/ata/ata-chipset.c
+++ b/sys/dev/ata/ata-chipset.c
@@ -79,12 +79,17 @@ static int ata_via_chipinit(device_t);
static void ata_via_family_setmode(struct ata_device *, int);
static void ata_via_southbridge_fixup(device_t);
static int ata_promise_chipinit(device_t);
+static int ata_promise_mio_allocate(device_t, struct ata_channel *);
static void ata_promise_old_intr(void *);
static void ata_promise_tx2_intr(void *);
+static void ata_promise_mio_intr(void *);
static void ata_promise_setmode(struct ata_device *, int);
static int ata_promise_old_dmainit(struct ata_channel *);
static int ata_promise_old_dmastart(struct ata_channel *, caddr_t, int32_t,int);
static int ata_promise_old_dmastop(struct ata_channel *);
+static int ata_promise_mio_dmainit(struct ata_channel *);
+static int ata_promise_mio_dmastart(struct ata_channel *, caddr_t, int32_t,int);
+static int ata_promise_mio_dmastop(struct ata_channel *);
static int ata_serverworks_chipinit(device_t);
static void ata_serverworks_setmode(struct ata_device *, int);
static int ata_sii_chipinit(device_t);
@@ -939,6 +944,18 @@ ata_promise_ident(device_t dev)
{ ATA_PDC20275, 0, PRTX, 0x00, ATA_UDMA6, "Promise PDC20275" },
{ ATA_PDC20276, 0, PRTX, PRSX6K, ATA_UDMA6, "Promise PDC20276" },
{ ATA_PDC20277, 0, PRTX, 0x00, ATA_UDMA6, "Promise PDC20277" },
+ { ATA_PDC20318, 0, PRMIO, PRSATA, ATA_UDMA6, "Promise PDC20318" },
+ { ATA_PDC20319, 0, PRMIO, PRSATA, ATA_UDMA6, "Promise PDC20319" },
+ { ATA_PDC20371, 0, PRMIO, PRSATA, ATA_UDMA6, "Promise PDC20371" },
+ { ATA_PDC20375, 0, PRMIO, PRSATA, ATA_UDMA6, "Promise PDC20375" },
+ { ATA_PDC20376, 0, PRMIO, PRSATA, ATA_UDMA6, "Promise PDC20376" },
+ { ATA_PDC20377, 0, PRMIO, PRSATA, ATA_UDMA6, "Promise PDC20377" },
+ { ATA_PDC20378, 0, PRMIO, PRSATA, ATA_UDMA6, "Promise PDC20378" },
+ { ATA_PDC20379, 0, PRMIO, PRSATA, ATA_UDMA6, "Promise PDC20379" },
+ { ATA_PDC20617, 0, PRMIO, PRDUAL, ATA_UDMA6, "Promise PDC20617" },
+ { ATA_PDC20618, 0, PRMIO, PRDUAL, ATA_UDMA6, "Promise PDC20618" },
+ { ATA_PDC20619, 0, PRMIO, PRDUAL, ATA_UDMA6, "Promise PDC20619" },
+ { ATA_PDC20620, 0, PRMIO, PRDUAL, ATA_UDMA6, "Promise PDC20620" },
{ 0, 0, 0, 0, 0, 0}};
char *desc, buffer[64];
uintptr_t devid = 0;
@@ -1015,11 +1032,67 @@ ata_promise_chipinit(device_t dev)
return ENXIO;
}
break;
+
+ case PRMIO:
+ rid = 0x1c;
+ if (!(ctlr->r_io2 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
+ 0, ~0, 1, RF_ACTIVE)))
+ return ENXIO;
+
+ ctlr->dmainit = ata_promise_mio_dmainit;
+ ctlr->allocate = ata_promise_mio_allocate;
+
+ if (ctlr->chip->cfg2 & PRDUAL) {
+ ctlr->channels = ((ATA_INL(ctlr->r_io2, 0x48) & 0x01) > 0) +
+ ((ATA_INL(ctlr->r_io2, 0x48) & 0x02) > 0) + 2;
+ }
+ else if (ctlr->chip->cfg2 & PRSATA) {
+ ATA_OUTL(ctlr->r_io2, 0x06c, 0x00ff0033);
+ ctlr->channels = ((ATA_INL(ctlr->r_io2, 0x48) & 0x02) > 0) + 3;
+ }
+ else
+ ctlr->channels = 4;
+
+ if ((bus_setup_intr(dev, ctlr->r_irq, INTR_TYPE_BIO | INTR_ENTROPY,
+ ata_promise_mio_intr, ctlr, &ctlr->handle))) {
+ device_printf(dev, "unable to setup interrupt\n");
+ return ENXIO;
+ }
+ break;
}
ctlr->setmode = ata_promise_setmode;
return 0;
}
+static int
+ata_promise_mio_allocate(device_t dev, struct ata_channel *ch)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
+ int i;
+
+ for (i = ATA_DATA; i <= ATA_STATUS; i++) {
+ ch->r_io[i].res = ctlr->r_io2;
+ ch->r_io[i].offset = 0x200 + (i << 2) + (ch->unit << 7);
+ }
+ ch->r_io[ATA_ALTSTAT].res = ctlr->r_io2;
+ ch->r_io[ATA_ALTSTAT].offset = 0x238 + (ch->unit << 7);
+ ch->r_io[ATA_BMCTL_PORT].res = ctlr->r_io2;
+ ch->r_io[ATA_BMCTL_PORT].offset = 0x260 + (ch->unit << 7);
+ ch->r_io[ATA_BMDTP_PORT].res = ctlr->r_io2;
+ ch->r_io[ATA_BMDTP_PORT].offset = 0x244 + (ch->unit << 7);
+ ch->r_io[ATA_BMDEVSPEC_0].res = ctlr->r_io2;
+ ch->r_io[ATA_BMDEVSPEC_0].offset = (ch->unit << 2);
+ ch->r_io[ATA_IDX_ADDR].res = ctlr->r_io2;
+
+ ATA_IDX_OUTL(ch, ATA_BMCMD_PORT,
+ (ATA_IDX_INL(ch, ATA_BMCMD_PORT) & ~0x00000f8f) | ch->unit);
+ ATA_IDX_OUTL(ch, ATA_BMDEVSPEC_0, 0x00000001);
+
+ ch->flags |= ATA_NO_SLAVE;
+ ctlr->dmainit(ch);
+ return 0;
+}
+
static void
ata_promise_old_intr(void *data)
{
@@ -1072,6 +1145,24 @@ ata_promise_tx2_intr(void *data)
}
static void
+ata_promise_mio_intr(void *data)
+{
+ struct ata_pci_controller *ctlr = data;
+ struct ata_channel *ch;
+ u_int32_t irq_vector;
+ int unit;
+
+ irq_vector = ATA_INL(ctlr->r_io2, 0x0040);
+ for (unit = 0; unit < ctlr->channels; unit++) {
+ if (irq_vector & (1 << unit)) {
+ if ((ch = ctlr->interrupt[unit].argument))
+ ctlr->interrupt[unit].function(ch);
+ ATA_IDX_OUTL(ch, ATA_BMDEVSPEC_0, 0x00000001);
+ }
+ }
+}
+
+static void
ata_promise_setmode(struct ata_device *atadev, int mode)
{
device_t parent = device_get_parent(atadev->channel->dev);
@@ -1098,8 +1189,19 @@ ata_promise_setmode(struct ata_device *atadev, int mode)
mode = ata_limit_mode(atadev, mode, ctlr->chip->max_dma);
- /* is this a TX2 or later chip ? */
switch (ctlr->chip->cfg1) {
+ case PROLD:
+ case PRNEW:
+ if (mode > ATA_UDMA2 && (pci_read_config(parent, 0x50, 2) &
+ (atadev->channel->unit ? 1 << 11 : 1 << 10))) {
+ ata_prtdev(atadev,
+ "DMA limited to UDMA33, non-ATA66 cable or device\n");
+ mode = ATA_UDMA2;
+ }
+ if (ATAPI_DEVICE(atadev) && mode > ATA_PIO_MAX)
+ mode = ata_limit_mode(atadev, mode, ATA_PIO_MAX);
+ break;
+
case PRTX:
ATA_IDX_OUTB(atadev->channel, ATA_BMDEVSPEC_0, 0x0b);
if (mode > ATA_UDMA2 &&
@@ -1110,16 +1212,14 @@ ata_promise_setmode(struct ata_device *atadev, int mode)
}
break;
- case PROLD:
- case PRNEW:
- if (mode > ATA_UDMA2 && (pci_read_config(parent, 0x50, 2) &
- (atadev->channel->unit ? 1 << 11 : 1 << 10))) {
+ case PRMIO:
+ if (mode > ATA_UDMA2 &&
+ (ATA_IDX_INL(atadev->channel, ATA_BMCTL_PORT) & 0x01000000)) {
ata_prtdev(atadev,
"DMA limited to UDMA33, non-ATA66 cable or device\n");
mode = ATA_UDMA2;
}
- if (ATAPI_DEVICE(atadev) && mode > ATA_PIO_MAX)
- mode = ata_limit_mode(atadev, mode, ATA_PIO_MAX);
+ break;
}
error = ata_command(atadev, ATA_C_SETFEATURES, 0, mode,
@@ -1196,6 +1296,43 @@ ata_promise_old_dmastop(struct ata_channel *ch)
return error;
}
+static int
+ata_promise_mio_dmainit(struct ata_channel *ch)
+{
+ int error;
+
+ if ((error = ata_dmainit(ch)))
+ return error;
+
+ ch->dma->start = ata_promise_mio_dmastart;
+ ch->dma->stop = ata_promise_mio_dmastop;
+ return 0;
+}
+
+static int
+ata_promise_mio_dmastart(struct ata_channel *ch,
+ caddr_t data, int32_t count, int dir)
+{
+ int error;
+
+ if ((error = ata_dmastart(ch, data, count, dir)))
+ return error;
+
+ ATA_IDX_OUTL(ch, ATA_BMDTP_PORT, ch->dma->mdmatab);
+ ATA_IDX_OUTL(ch, ATA_BMCTL_PORT,
+ (ATA_IDX_INL(ch, ATA_BMCTL_PORT) & ~0x000000c0) |
+ ((dir) ? 0x00000080 : 0x000000c0));
+ return error;
+}
+
+static int
+ata_promise_mio_dmastop(struct ata_channel *ch)
+{
+ ATA_IDX_OUTL(ch, ATA_BMCTL_PORT,
+ ATA_IDX_INL(ch, ATA_BMCTL_PORT) & ~0x00000080);
+ return ata_dmastop(ch);
+}
+
/*
* ServerWorks chipset support functions
*/
diff --git a/sys/dev/ata/ata-pci.h b/sys/dev/ata/ata-pci.h
index 0e8b49b..ebaa280 100644
--- a/sys/dev/ata/ata-pci.h
+++ b/sys/dev/ata/ata-pci.h
@@ -129,7 +129,18 @@ struct ata_pci_controller {
#define ATA_PDC20275 0x1275105a
#define ATA_PDC20276 0x5275105a
#define ATA_PDC20277 0x7275105a
+#define ATA_PDC20318 0x3318105a
+#define ATA_PDC20319 0x3319105a
+#define ATA_PDC20371 0x3371105a
+#define ATA_PDC20375 0x3375105a
#define ATA_PDC20376 0x3376105a
+#define ATA_PDC20377 0x3377105a
+#define ATA_PDC20378 0x3373105a
+#define ATA_PDC20379 0x3372105a
+#define ATA_PDC20617 0x6617105a
+#define ATA_PDC20618 0x6626105a
+#define ATA_PDC20619 0x6629105a
+#define ATA_PDC20620 0x6620105a
#define ATA_PDC20621 0x6621105a
#define ATA_SERVERWORKS_ID 0x1166
@@ -216,9 +227,13 @@ struct ata_pci_controller {
#define PROLD 0
#define PRNEW 1
#define PRTX 2
-#define PRMEM 3
+#define PRMIO 3
+#define PRIDX 4
#define PRTX4 0x01
-#define PRSX6K 0x02
+#define PRSX4K 0x02
+#define PRSX6K 0x04
+#define PRSATA 0x08
+#define PRDUAL 0x10
#define SWKS33 0
#define SWKS66 1
OpenPOWER on IntegriCloud