Author: oxygene
Date: 2009-03-12 18:00:30 +0100 (Thu, 12 Mar 2009)
New Revision: 87

Modified:
   trunk/filo/drivers/ide_new.c
   trunk/filo/drivers/ide_new.h
Log:
Use PCI BARs for I/O ports in new IDE driver. Port from
old IDE driver.


Modified: trunk/filo/drivers/ide_new.c
===================================================================
--- trunk/filo/drivers/ide_new.c        2009-03-11 03:07:08 UTC (rev 86)
+++ trunk/filo/drivers/ide_new.c        2009-03-12 17:00:30 UTC (rev 87)
@@ -29,6 +29,10 @@
 #include "ide_new.h"
 #include "hdreg.h"
 
+#ifdef CONFIG_SUPPORT_PCI
+#include <pci.h>
+#endif
+
 #if 0
 #define dprintf printf
 #else
@@ -44,6 +48,7 @@
 #define IDE_NUM_CHANNELS CONFIG_IDE_NUM_CHANNELS
 #endif
 #define IDE_MAX_CHANNELS 4
+#define IDE_MAX_DRIVES (IDE_MAX_CHANNELS * 2)
 
 static struct ide_channel ob_ide_channels[IDE_MAX_CHANNELS];
 
@@ -1150,21 +1155,198 @@
        return(drive->bs);
 }
 
+#ifdef CONFIG_SUPPORT_PCI
+static int pci_find_ata_device_on_bus(int bus, pcidev_t * dev, int *index, int 
sata, int pata)
+{
+       int slot, func;
+       u32 val;
+       unsigned char hdr;
+       u32 class;
+
+        for (slot = 0; slot < 0x20; slot++) {
+               for (func = 0; func < 8; func++) {
+                       pcidev_t currdev = PCI_DEV(bus, slot, func);
+
+                       val = pci_read_config32(currdev, REG_VENDOR_ID);
+
+                       if (val == 0xffffffff || val == 0x00000000 ||
+                           val == 0x0000ffff || val == 0xffff0000)
+                               continue;
+
+                       class = pci_read_config16(currdev, 0x0a);
+                       debug("%02x:%02x.%02x [%04x:%04x] class %04x\n",
+                               bus, slot, func, val & 0xffff, val >> 16, 
class);
+
+                       if ((sata && class == 0x180) || (pata && class == 
0x101)) {
+                               if (*index == 0) {
+                                       *dev = currdev;
+                                       return 1;
+                               }
+                               (*index)--;
+                       }
+
+                       hdr = pci_read_config8(currdev, REG_HEADER_TYPE) & 0x7f;
+
+                       if (hdr == HEADER_TYPE_BRIDGE || hdr == 
HEADER_TYPE_CARDBUS) {
+                               unsigned int new_bus;
+                               new_bus = (pci_read_config32(currdev, 
REG_PRIMARY_BUS) >> 8) & 0xff;
+                               if (new_bus == 0) {
+                                       debug("Misconfigured bridge at 
%02x:%02x.%02x skipped.\n",
+                                               bus, slot, func);
+                                       continue;
+                               }
+                               if (pci_find_ata_device_on_bus(new_bus, dev, 
index, sata, pata))
+                                       return 1;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+int pci_find_ata_device(pcidev_t *dev, int *index, int sata, int pata)
+{
+       debug(" Scanning for:%s%s\n", sata?" SATA":"", pata?" PATA":"");
+       return pci_find_ata_device_on_bus(0, dev, index, sata, pata);
+}
+#endif
+
+
+static void fixupregs(struct ide_channel *chan)
+{
+       int i;
+       for (i = 1; i < 8; i++)
+               chan->io_regs[i] = chan->io_regs[0] + i;
+       chan->io_regs[9] = chan->io_regs[8] + 1;
+}
+
+static int find_ide_controller_compat(struct ide_channel *chan, int index)
+{
+#ifdef CONFIG_SUPPORT_PCI
+       int skip, i, pci_index = index / 2;
+       pcidev_t dev;
+#else
+       if (index >= IDE_MAX_CHANNELS)
+               return -1;
+#endif
+#ifdef CONFIG_PCMCIA_CF
+       if (index == 2) {
+               chan->io_regs[0] = 0x1e0;
+               chan->io_regs[8] = 0x1ec;
+               fixupregs(chan);
+               return 0;
+       }
+#endif
+#ifdef CONFIG_SUPPORT_PCI
+       /* skip any SATA and PATA PCI controllers in native mode */
+       for (skip = i = 0; i < pci_index && index; i++) {
+               int devidx = i;
+               /* look for i:th ata (IDE/other storage really) device */
+               if(!pci_find_ata_device(&dev, &devidx, 1, 1))
+                       break;
+               /* only IDE can be in compat mode so skip all others */
+               if (pci_read_config16(dev, 0xa) != 0x0101) {
+                       /* other storage (SATA) always has two channels */
+                       skip += 2;
+                       continue;
+               }
+               /* primary in native mode? then skip it. */
+               if (1 == (pci_read_config8(dev, 0x09) & 1))
+                       skip++;
+               /* secondary in native mode? then skip it. */
+               if (index && 4 == (pci_read_config8(dev, 0x09)  & 4))
+                       skip++;
+       }
+       index = skip <= index ? index - skip : 0;
+       debug("skipping %d native PCI controllers, new index=%d\n", skip, 
index);
+       if (index >= IDE_MAX_CHANNELS)
+               return -1;
+#endif
+       chan->io_regs[0] = io_ports[index];
+       chan->io_regs[8] = ctl_ports[index];
+       fixupregs(chan);
+       return 0;
+}
+
+#ifdef CONFIG_SUPPORT_PCI
+static int find_ide_controller(struct ide_channel *chan, int chan_index)
+{
+       int pci_index;
+       pcidev_t dev;
+       unsigned int mask;
+       u8 prog_if;
+       u16 vendor, device, devclass;
+
+       /* A PCI IDE controller has two channels (pri, sec) */
+       pci_index = chan_index >> 1;
+
+       /* Find a IDE storage class device */
+
+       if (!pci_find_ata_device(&dev, &pci_index, 1, 0)) { // S-ATA first
+               pci_index = chan_index >> 1;
+               if (!pci_find_ata_device(&dev, &pci_index, 0, 1)) { // P-ATA 
second
+                       debug("PCI IDE #%d not found\n", chan_index >> 1);
+                       return -1;
+               }
+       }
+       
+       vendor = pci_read_config16(dev, 0);
+       device = pci_read_config16(dev, 2);
+       prog_if = pci_read_config8(dev, 9);
+       devclass = pci_read_config16(dev, 0x0a);
+
+       debug("found PCI IDE controller %04x:%04x prog_if=%#x\n",
+                       vendor, device, prog_if);
+
+       /* See how this controller is configured */
+       mask = (chan_index & 1) ? 4 : 1;
+       debug("%s channel: ", (chan_index & 1) ? "secondary" : "primary");
+       if ((prog_if & mask) || (devclass != 0x0101)) {
+               debug("native PCI mode\n");
+               if ((chan_index & 1) == 0) {
+                       /* Primary channel */
+                       chan->io_regs[0] = pci_read_resource(dev, 0); // io 
ports
+                       chan->io_regs[8] = pci_read_resource(dev, 1); // ctrl 
ports
+               } else {
+                       /* Secondary channel */
+                       chan->io_regs[0] = pci_read_resource(dev, 2); // io 
ports
+                       chan->io_regs[8] = pci_read_resource(dev, 3); // ctrl 
ports
+               }
+               chan->io_regs[0] &= ~3;
+               chan->io_regs[8] &= ~3;
+               fixupregs(chan);
+       } else {
+               debug("compatibility mode\n");
+               if (find_ide_controller_compat(chan, chan_index) != 0)
+                       return -1;
+       }
+       return 0;
+}
+#else /* !CONFIG_SUPPORT_PCI */
+# define find_ide_controller find_ide_controller_compat
+#endif
 //int ob_ide_init(int (*func)(struct ide_drive*))
-int ob_ide_init(void)
+int ob_ide_init(int drive)
 {
-       int i, j;
+       int j;
 
-       for (i = 0; i < IDE_NUM_CHANNELS; i++) {
-               struct ide_channel *chan = &ob_ide_channels[i];
+       struct ide_channel *chan;
+       int chan_index;
 
-               chan->mmio = 0;
+       if (drive >= IDE_MAX_DRIVES) {
+               printf("Unsupported drive number\n");
+               return -1;
+       }
 
-               for (j = 0; j < 8; j++)
-                       chan->io_regs[j] = io_ports[i] + j;
+       /* A controller has two drives (master, slave) */
+       chan_index = drive >> 1;
 
-               chan->io_regs[8] = ctl_ports[i];
-               chan->io_regs[9] = ctl_ports[i] + 1;
+       chan = &ob_ide_channels[chan_index];
+       if (chan->present == 0) {
+               if (find_ide_controller(chan, chan_index) != 0) {
+                       printf("IDE channel %d not found\n", chan_index);
+                       return -1;
+               }
 
                chan->obide_inb = ob_ide_inb;
                chan->obide_insw = ob_ide_insw;
@@ -1172,6 +1354,7 @@
                chan->obide_outsw = ob_ide_outsw;
 
                chan->selected = -1;
+               chan->mmio = 0;
 
                /*
                 * assume it's there, if not io port dead check will clear
@@ -1185,17 +1368,17 @@
                        /* init with a decent value */
                        chan->drives[j].bs = 512;
 
-                       chan->drives[j].nr = i * 2 + j;
+                       chan->drives[j].nr = chan_index * 2 + j;
                }
 
                ob_ide_probe(chan);
 
                if (!chan->present)
-                       continue;
+                       return -1;
 
                ob_ide_identify_drives(chan);
 
-               printf("ata-%d: [io ports 0x%x-0x%x,0x%x]\n", i,
+               printf("ata-%d: [io ports 0x%x-0x%x,0x%x]\n", chan_index,
                                chan->io_regs[0], chan->io_regs[0] + 7,
                                chan->io_regs[8]);
 
@@ -1232,10 +1415,7 @@
 int ide_probe(int drive)
 {
        struct ide_drive *curr_drive = & ob_ide_channels[drive / 
2].drives[drive % 2];
-       if (!inited) {
-               ob_ide_init();
-               inited = 1;
-       }
+       ob_ide_init(drive);
 
        if (!curr_drive->present)
                return -1;
@@ -1249,10 +1429,7 @@
        struct ide_drive *curr_drive = & ob_ide_channels[drive / 
2].drives[drive % 2];
        char *media = "UNKNOWN";
 
-       if (!inited) {
-               ob_ide_init();
-               inited = 1;
-       }
+       ob_ide_init(drive);
 
        if (!curr_drive->present) {
                return -1;
@@ -1300,3 +1477,4 @@
        }
        return 0;
 }
+

Modified: trunk/filo/drivers/ide_new.h
===================================================================
--- trunk/filo/drivers/ide_new.h        2009-03-11 03:07:08 UTC (rev 86)
+++ trunk/filo/drivers/ide_new.h        2009-03-12 17:00:30 UTC (rev 87)
@@ -218,7 +218,7 @@
 static int
 ob_ide_atapi_request_sense(struct ide_drive *drive);
 //int ob_ide_init(int (*func)(struct ide_drive*));
-int ob_ide_init(void);
+int ob_ide_init(int drive);
 
 
 /* FILO compat */


--
coreboot mailing list: [email protected]
http://www.coreboot.org/mailman/listinfo/coreboot

Reply via email to