struct device_node* node;
struct macio_dev *mdev;
u32 timings[4];
+ volatile u32 __iomem * *kauai_fcr;
#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
/* Those fields are duplicating what is in hwif. We currently
* can't use the hwif ones because of some assumptions that are
controller_kl_ata3, /* KeyLargo ATA-3 */
controller_kl_ata4, /* KeyLargo ATA-4 */
controller_un_ata6, /* UniNorth2 ATA-6 */
- controller_k2_ata6 /* K2 ATA-6 */
+ controller_k2_ata6, /* K2 ATA-6 */
+ controller_sh_ata6, /* Shasta ATA-6 */
};
static const char* model_name[] = {
"KeyLargo ATA-4", /* KeyLargo ATA-4 (UDMA/66) */
"UniNorth ATA-6", /* UniNorth2 ATA-6 (UDMA/100) */
"K2 ATA-6", /* K2 ATA-6 (UDMA/100) */
+ "Shasta ATA-6", /* Shasta ATA-6 (UDMA/133) */
};
/*
#define IDE_SYSCLK_NS 30 /* 33Mhz cell */
#define IDE_SYSCLK_66_NS 15 /* 66Mhz cell */
+/* 133Mhz cell, found in shasta.
+ * See comments about 100 Mhz Uninorth 2...
+ * Note that PIO_MASK and MDMA_MASK seem to overlap
+ */
+#define TR_133_PIOREG_PIO_MASK 0xff000fff
+#define TR_133_PIOREG_MDMA_MASK 0x00fff800
+#define TR_133_UDMAREG_UDMA_MASK 0x0003ffff
+#define TR_133_UDMAREG_UDMA_EN 0x00000001
+
/* 100Mhz cell, found in Uninorth 2. I don't have much infos about
* this one yet, it appears as a pci device (106b/0033) on uninorth
* internal PCI bus and it's clock is controlled like gem or fw. It
#define IDE_INTR_DMA 0x80000000
#define IDE_INTR_DEVICE 0x40000000
+/*
+ * FCR Register on Kauai. Not sure what bit 0x4 is ...
+ */
+#define KAUAI_FCR_UATA_MAGIC 0x00000004
+#define KAUAI_FCR_UATA_RESET_N 0x00000002
+#define KAUAI_FCR_UATA_ENABLE 0x00000001
+
#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
/* Rounded Multiword DMA timings
{ 0 , 0 },
};
+static struct kauai_timing shasta_pio_timings[] __pmacdata =
+{
+ { 930 , 0x08000fff },
+ { 600 , 0x0A000c97 },
+ { 383 , 0x07000712 },
+ { 360 , 0x040003cd },
+ { 330 , 0x040003cd },
+ { 300 , 0x040003cd },
+ { 270 , 0x040003cd },
+ { 240 , 0x040003cd },
+ { 239 , 0x040003cd },
+ { 180 , 0x0400028b },
+ { 120 , 0x0400010a }
+};
+
+static struct kauai_timing shasta_mdma_timings[] __pmacdata =
+{
+ { 1260 , 0x00fff000 },
+ { 480 , 0x00820800 },
+ { 360 , 0x00820800 },
+ { 270 , 0x00820800 },
+ { 240 , 0x00820800 },
+ { 210 , 0x00820800 },
+ { 180 , 0x00820800 },
+ { 150 , 0x0028b000 },
+ { 120 , 0x001ca000 },
+ { 0 , 0 },
+};
+
+static struct kauai_timing shasta_udma133_timings[] __pmacdata =
+{
+ { 120 , 0x00035901, },
+ { 90 , 0x000348b1, },
+ { 60 , 0x00033881, },
+ { 45 , 0x00033861, },
+ { 30 , 0x00033841, },
+ { 20 , 0x00033031, },
+ { 15 , 0x00033021, },
+ { 0 , 0 },
+};
+
+
static inline u32
kauai_lookup_timing(struct kauai_timing* table, int cycle_time)
{
if (pmif == NULL)
return;
- if (pmif->kind == controller_un_ata6 || pmif->kind == controller_k2_ata6)
+ if (pmif->kind == controller_sh_ata6 ||
+ pmif->kind == controller_un_ata6 ||
+ pmif->kind == controller_k2_ata6)
pmac_ide_kauai_selectproc(drive);
else
pmac_ide_selectproc(drive);
pio = ide_get_best_pio_mode(drive, pio, 4, &d);
switch (pmif->kind) {
+ case controller_sh_ata6: {
+ /* 133Mhz cell */
+ u32 tr = kauai_lookup_timing(shasta_pio_timings, d.cycle_time);
+ if (tr == 0)
+ return;
+ *timings = ((*timings) & ~TR_133_PIOREG_PIO_MASK) | tr;
+ break;
+ }
case controller_un_ata6:
case controller_k2_ata6: {
/* 100Mhz cell */
return 0;
}
+/*
+ * Calculate Shasta ATA/133 UDMA timings
+ */
+static int __pmac
+set_timings_udma_shasta(u32 *pio_timings, u32 *ultra_timings, u8 speed)
+{
+ struct ide_timing *t = ide_timing_find_mode(speed);
+ u32 tr;
+
+ if (speed > XFER_UDMA_6 || t == NULL)
+ return 1;
+ tr = kauai_lookup_timing(shasta_udma133_timings, (int)t->udma);
+ if (tr == 0)
+ return 1;
+ *ultra_timings = ((*ultra_timings) & ~TR_133_UDMAREG_UDMA_MASK) | tr;
+ *ultra_timings = (*ultra_timings) | TR_133_UDMAREG_UDMA_EN;
+
+ return 0;
+}
+
/*
* Calculate MDMA timings for all cells
*/
cycleTime = 150;
/* Get the proper timing array for this controller */
switch(intf_type) {
+ case controller_sh_ata6:
case controller_un_ata6:
case controller_k2_ata6:
break;
#endif
}
switch(intf_type) {
+ case controller_sh_ata6: {
+ /* 133Mhz cell */
+ u32 tr = kauai_lookup_timing(shasta_mdma_timings, cycleTime);
+ if (tr == 0)
+ return 1;
+ *timings = ((*timings) & ~TR_133_PIOREG_MDMA_MASK) | tr;
+ *timings2 = (*timings2) & ~TR_133_UDMAREG_UDMA_EN;
+ }
case controller_un_ata6:
case controller_k2_ata6: {
/* 100Mhz cell */
switch(speed) {
#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+ case XFER_UDMA_6:
+ if (pmif->kind != controller_sh_ata6)
+ return 1;
case XFER_UDMA_5:
if (pmif->kind != controller_un_ata6 &&
- pmif->kind != controller_k2_ata6)
+ pmif->kind != controller_k2_ata6 &&
+ pmif->kind != controller_sh_ata6)
return 1;
case XFER_UDMA_4:
case XFER_UDMA_3:
else if (pmif->kind == controller_un_ata6
|| pmif->kind == controller_k2_ata6)
ret = set_timings_udma_ata6(timings, timings2, speed);
+ else if (pmif->kind == controller_sh_ata6)
+ ret = set_timings_udma_shasta(timings, timings2, speed);
else
ret = 1;
break;
unsigned int value, value2 = 0;
switch(pmif->kind) {
+ case controller_sh_ata6:
+ value = 0x0a820c97;
+ value2 = 0x00033031;
+ break;
case controller_un_ata6:
case controller_k2_ata6:
value = 0x08618a92;
}
#endif /* CONFIG_BLK_DEV_IDE_PMAC_BLINK */
+ disable_irq(pmif->irq);
+
/* The media bay will handle itself just fine */
if (pmif->mediabay)
return 0;
- /* Disable the bus */
- ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, pmif->node, pmif->aapl_bus_id, 0);
+ /* Kauai has bus control FCRs directly here */
+ if (pmif->kauai_fcr) {
+ u32 fcr = readl(pmif->kauai_fcr);
+ fcr &= ~(KAUAI_FCR_UATA_RESET_N | KAUAI_FCR_UATA_ENABLE);
+ writel(fcr, pmif->kauai_fcr);
+ }
+
+ /* Disable the bus on older machines and the cell on kauai */
+ ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, pmif->node, pmif->aapl_bus_id,
+ 0);
return 0;
}
ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, pmif->node, pmif->aapl_bus_id, 1);
msleep(10);
ppc_md.feature_call(PMAC_FTR_IDE_RESET, pmif->node, pmif->aapl_bus_id, 0);
+
+ /* Kauai has it different */
+ if (pmif->kauai_fcr) {
+ u32 fcr = readl(pmif->kauai_fcr);
+ fcr |= KAUAI_FCR_UATA_RESET_N | KAUAI_FCR_UATA_ENABLE;
+ writel(fcr, pmif->kauai_fcr);
+ }
+
msleep(jiffies_to_msecs(IDE_WAKEUP_DELAY));
}
/* Sanitize drive timings */
sanitize_timings(pmif);
+ enable_irq(pmif->irq);
+
return 0;
}
pmif->cable_80 = 0;
pmif->broken_dma = pmif->broken_dma_warn = 0;
- if (device_is_compatible(np, "kauai-ata"))
+ if (device_is_compatible(np, "shasta-ata"))
+ pmif->kind = controller_sh_ata6;
+ else if (device_is_compatible(np, "kauai-ata"))
pmif->kind = controller_un_ata6;
else if (device_is_compatible(np, "K2-UATA"))
pmif->kind = controller_k2_ata6;
/* Get cable type from device-tree */
if (pmif->kind == controller_kl_ata4 || pmif->kind == controller_un_ata6
- || pmif->kind == controller_k2_ata6) {
+ || pmif->kind == controller_k2_ata6
+ || pmif->kind == controller_sh_ata6) {
char* cable = get_property(np, "cable-type", NULL);
if (cable && !strncmp(cable, "80-", 3))
pmif->cable_80 = 1;
}
+ /* G5's seem to have incorrect cable type in device-tree. Let's assume
+ * they have a 80 conductor cable, this seem to be always the case unless
+ * the user mucked around
+ */
+ if (device_is_compatible(np, "K2-UATA") ||
+ device_is_compatible(np, "shasta-ata"))
+ pmif->cable_80 = 1;
+
+ /* On Kauai-type controllers, we make sure the FCR is correct */
+ if (pmif->kauai_fcr)
+ writel(KAUAI_FCR_UATA_MAGIC |
+ KAUAI_FCR_UATA_RESET_N |
+ KAUAI_FCR_UATA_ENABLE, pmif->kauai_fcr);
pmif->mediabay = 0;
hwif->drives[0].unmask = 1;
hwif->drives[1].unmask = 1;
hwif->tuneproc = pmac_ide_tuneproc;
- if (pmif->kind == controller_un_ata6 || pmif->kind == controller_k2_ata6)
+ if (pmif->kind == controller_un_ata6
+ || pmif->kind == controller_k2_ata6
+ || pmif->kind == controller_sh_ata6)
hwif->selectproc = pmac_ide_kauai_selectproc;
else
hwif->selectproc = pmac_ide_selectproc;
pmif->node = mdev->ofdev.node;
pmif->regbase = regbase;
pmif->irq = irq;
+ pmif->kauai_fcr = NULL;
#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
if (macio_resource_count(mdev) >= 2) {
if (macio_request_resource(mdev, 1, "ide-pmac (dma)"))
pmif->regbase = (unsigned long) base + 0x2000;
#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
pmif->dma_regs = base + 0x1000;
-#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
-
- /* We use the OF node irq mapping */
- if (np->n_intrs == 0)
- pmif->irq = pdev->irq;
- else
- pmif->irq = np->intrs[0].line;
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+ pmif->kauai_fcr = base;
+ pmif->irq = pdev->irq;
pci_set_drvdata(pdev, hwif);
{ PCI_VENDOR_ID_APPLE, PCI_DEVIEC_ID_APPLE_UNI_N_ATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_IPID_ATA100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_K2_ATA100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_SH_ATA,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
};
static struct pci_driver pmac_ide_pci_driver = {
.suspend = pmac_ide_pci_suspend,
.resume = pmac_ide_pci_resume,
};
+MODULE_DEVICE_TABLE(pci, pmac_ide_pci_match);
void __init
pmac_ide_probe(void)
timing_local[1] = *timings2;
/* Calculate timings for interface */
- if (pmif->kind == controller_un_ata6 || pmif->kind == controller_k2_ata6)
+ if (pmif->kind == controller_un_ata6
+ || pmif->kind == controller_k2_ata6)
ret = set_timings_udma_ata6( &timing_local[0],
&timing_local[1],
mode);
+ else if (pmif->kind == controller_sh_ata6)
+ ret = set_timings_udma_shasta( &timing_local[0],
+ &timing_local[1],
+ mode);
else
ret = set_timings_udma_ata4(&timing_local[0], mode);
if (ret)
short mode;
map = XFER_MWDMA;
- if (pmif->kind == controller_kl_ata4 || pmif->kind == controller_un_ata6
- || pmif->kind == controller_k2_ata6) {
+ if (pmif->kind == controller_kl_ata4
+ || pmif->kind == controller_un_ata6
+ || pmif->kind == controller_k2_ata6
+ || pmif->kind == controller_sh_ata6) {
map |= XFER_UDMA;
if (pmif->cable_80) {
map |= XFER_UDMA_66;
if (pmif->kind == controller_un_ata6 ||
- pmif->kind == controller_k2_ata6)
+ pmif->kind == controller_k2_ata6 ||
+ pmif->kind == controller_sh_ata6)
map |= XFER_UDMA_100;
+ if (pmif->kind == controller_sh_ata6)
+ map |= XFER_UDMA_133;
}
}
mode = ide_find_best_mode(drive, map);
hwif->atapi_dma = 1;
switch(pmif->kind) {
+ case controller_sh_ata6:
+ hwif->ultra_mask = pmif->cable_80 ? 0x7f : 0x07;
+ hwif->mwdma_mask = 0x07;
+ hwif->swdma_mask = 0x00;
+ break;
case controller_un_ata6:
case controller_k2_ata6:
hwif->ultra_mask = pmif->cable_80 ? 0x3f : 0x07;