All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] mv-ahci: add set-mode, cable id functions
@ 2009-04-19 13:09 Jeff Garzik
  0 siblings, 0 replies; only message in thread
From: Jeff Garzik @ 2009-04-19 13:09 UTC (permalink / raw)
  To: linux-ide


I just checked this into the 'libahci' branch of libata-dev.git...



diff --git a/drivers/ata/mv-ahci.c b/drivers/ata/mv-ahci.c
index a19b979..02b35c5 100644
--- a/drivers/ata/mv-ahci.c
+++ b/drivers/ata/mv-ahci.c
@@ -55,7 +55,28 @@ enum {
 	board_ahci_mv		= 0,
 };
 
-enum mvp_specific_registers {
+enum mvp_host_registers {
+	MVP_HOST_PATA_MODE0	= 0xA0,		/* DMA/PIO mode, drive 0 */
+	MVP_HOST_PATA_MODE1	= 0xA4,		/* DMA/PIO mode, drive 1 */
+
+	MVP_ENABLE_MDMA		= 0x100,	/* Enable MDMA? */
+
+	MVP_MASK_PIO		= 0x38,		/* PIO mode: bits 5:3 */
+	MVP_SHIFT_PIO		= 3,
+	MVP_MASK_MDMA		= 0xC0,		/* MDMA mode: bits 7:6 */
+	MVP_SHIFT_MDMA		= 6,
+	MVP_MASK_UDMA		= 0x7,		/* UDMA mode: bits 2:0 */
+	MVP_SHIFT_UDMA		= 0,
+
+	MVP_MASK_DMA		= MVP_MASK_MDMA | MVP_MASK_UDMA |
+				  MVP_ENABLE_MDMA,
+
+	MVP_CBLID_BAR		= 4,
+	MVP_CBLID_REG		= 0x01,
+	MVP_CBLID		= (1 << 0),
+};
+
+enum mvp_port_registers {
 	MVP_D0_TF0		= 0x20,		/* dev0 taskfile part 1 */
 	MVP_D0_TF1		= 0x24,		/* dev0 taskfile part 2 */
 	MVP_D0_TF2		= 0x28,		/* dev0 taskfile part 3 */
@@ -117,6 +138,9 @@ static int mvp_hardreset(struct ata_link *link, unsigned int *class,
 static int mvp_softreset(struct ata_link *link, unsigned int *class,
 			 unsigned long deadline);
 static int mvp_port_start(struct ata_port *ap);
+static void mvp_set_piomode(struct ata_port *ap, struct ata_device *adev);
+static void mvp_set_dmamode(struct ata_port *ap, struct ata_device *adev);
+static int mvp_cable_id(struct ata_port *ap);
 
 static struct device_attribute *mv_ahci_shost_attrs[] = {
 	&dev_attr_link_power_management_policy,
@@ -182,6 +206,10 @@ static struct ata_port_operations mv_pata_ops = {
 	.qc_prep		= mvp_qc_prep,
 	.qc_issue		= ahci_qc_issue,
 
+	.cable_detect		= mvp_cable_id,
+	.set_piomode		= mvp_set_piomode,
+	.set_dmamode		= mvp_set_dmamode,
+
 	.freeze			= ahci_freeze,
 	.thaw			= ahci_thaw,
 	.hardreset		= mvp_hardreset,
@@ -329,6 +357,77 @@ static void mv_ahci_dump_port(struct ata_port *ap)
 	}
 }
 
+static int mvp_cable_id(struct ata_port *ap)
+{
+	void __iomem *mmio = ap->host->iomap[MVP_CBLID_BAR];
+	u8 tmp;
+
+	tmp = ioread8(mmio + MVP_CBLID_REG);
+	if (tmp & MVP_CBLID) {
+		DPRINTK("detected 40-pin PATA cable\n");
+		return ATA_CBL_PATA40;
+	}
+
+	DPRINTK("detected 80-pin PATA cable\n");
+	return ATA_CBL_PATA80;
+}
+
+static void mvp_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+	unsigned int pio = adev->pio_mode - XFER_PIO_0;
+	bool is_slave = (adev->devno != 0);
+	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
+	u32 tmp, new_tmp;
+
+	/* TODO?  early chip revs stored this info in PCI BAR4, not BAR5 */
+
+	if (!is_slave)
+		mmio += MVP_HOST_PATA_MODE0;
+	else
+		mmio += MVP_HOST_PATA_MODE1;
+
+	tmp = readl(mmio);
+	new_tmp = tmp & ~MVP_MASK_PIO;
+	new_tmp |= (pio << MVP_SHIFT_PIO);
+
+	if (new_tmp != tmp) {
+		writel(new_tmp, mmio);
+		readl(mmio);	/* flush */
+	}
+}
+
+static void mvp_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+	bool is_slave = (adev->devno != 0);
+	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
+	u32 tmp, new_tmp;
+
+	/* TODO?  early chip revs stored this info in PCI BAR4, not BAR5 */
+
+	if (!is_slave)
+		mmio += MVP_HOST_PATA_MODE0;
+	else
+		mmio += MVP_HOST_PATA_MODE1;
+
+	tmp = readl(mmio);
+	new_tmp = tmp & ~MVP_MASK_DMA;
+
+	if (adev->dma_mode >= XFER_UDMA_0) {
+		unsigned int udma = adev->dma_mode - XFER_UDMA_0;
+
+		new_tmp |= (udma << MVP_SHIFT_UDMA);
+	} else {
+		unsigned int mwdma = adev->dma_mode - XFER_MW_DMA_0;
+
+		new_tmp |= (mwdma << MVP_SHIFT_MDMA) | MVP_ENABLE_MDMA;
+	}
+
+	if (new_tmp != tmp) {
+		writel(new_tmp, mmio);
+		readl(mmio);	/* flush */
+	}
+}
+
 /* WARNING: the following doesn't clear the interrupt, it's
  * a read-only view of the device's ATA shadow registers
  */
@@ -946,7 +1045,9 @@ static int mv_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *en
 	/* AHCI controllers often implement SFF compatible interface.
 	 * Grab all PCI BARs just in case.
 	 */
-	rc = pcim_iomap_regions_request_all(pdev, 1 << AHCI_PCI_BAR, DRV_NAME);
+	rc = pcim_iomap_regions_request_all(pdev,
+			(1 << AHCI_PCI_BAR) | (1 << MVP_CBLID_BAR),
+			DRV_NAME);
 	if (rc == -EBUSY)
 		pcim_pin_device(pdev);
 	if (rc)

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2009-04-19 13:09 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-04-19 13:09 [PATCH] mv-ahci: add set-mode, cable id functions Jeff Garzik

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.