diff options
Diffstat (limited to 'drivers/ata/pata_imx.c')
-rw-r--r-- | drivers/ata/pata_imx.c | 82 |
1 files changed, 57 insertions, 25 deletions
diff --git a/drivers/ata/pata_imx.c b/drivers/ata/pata_imx.c index 139d20778b29..d4caa23f5a88 100644 --- a/drivers/ata/pata_imx.c +++ b/drivers/ata/pata_imx.c @@ -11,19 +11,26 @@ * * TODO: * - dmaengine support - * - check if timing stuff needed */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/blkdev.h> -#include <scsi/scsi_host.h> + #include <linux/ata.h> +#include <linux/clk.h> #include <linux/libata.h> +#include <linux/module.h> #include <linux/platform_device.h> -#include <linux/clk.h> #define DRV_NAME "pata_imx" +#define PATA_IMX_ATA_TIME_OFF 0x00 +#define PATA_IMX_ATA_TIME_ON 0x01 +#define PATA_IMX_ATA_TIME_1 0x02 +#define PATA_IMX_ATA_TIME_2W 0x03 +#define PATA_IMX_ATA_TIME_2R 0x04 +#define PATA_IMX_ATA_TIME_AX 0x05 +#define PATA_IMX_ATA_TIME_PIO_RDX 0x06 +#define PATA_IMX_ATA_TIME_4 0x07 +#define PATA_IMX_ATA_TIME_9 0x08 + #define PATA_IMX_ATA_CONTROL 0x24 #define PATA_IMX_ATA_CTRL_FIFO_RST_B (1<<7) #define PATA_IMX_ATA_CTRL_ATA_RST_B (1<<6) @@ -33,6 +40,10 @@ #define PATA_IMX_DRIVE_DATA 0xA0 #define PATA_IMX_DRIVE_CONTROL 0xD8 +static u32 pio_t4[] = { 30, 20, 15, 10, 10 }; +static u32 pio_t9[] = { 20, 15, 10, 10, 10 }; +static u32 pio_tA[] = { 35, 35, 35, 35, 35 }; + struct pata_imx_priv { struct clk *clk; /* timings/interrupt/control regs */ @@ -40,28 +51,49 @@ struct pata_imx_priv { u32 ata_ctl; }; -static int pata_imx_set_mode(struct ata_link *link, struct ata_device **unused) +static void pata_imx_set_timing(struct ata_device *adev, + struct pata_imx_priv *priv) +{ + struct ata_timing timing; + unsigned long clkrate; + u32 T, mode; + + clkrate = clk_get_rate(priv->clk); + + if (adev->pio_mode < XFER_PIO_0 || adev->pio_mode > XFER_PIO_4 || + !clkrate) + return; + + T = 1000000000 / clkrate; + ata_timing_compute(adev, adev->pio_mode, &timing, T * 1000, 0); + + mode = adev->pio_mode - XFER_PIO_0; + + writeb(3, priv->host_regs + PATA_IMX_ATA_TIME_OFF); + writeb(3, priv->host_regs + PATA_IMX_ATA_TIME_ON); + writeb(timing.setup, priv->host_regs + PATA_IMX_ATA_TIME_1); + writeb(timing.act8b, priv->host_regs + PATA_IMX_ATA_TIME_2W); + writeb(timing.act8b, priv->host_regs + PATA_IMX_ATA_TIME_2R); + writeb(1, priv->host_regs + PATA_IMX_ATA_TIME_PIO_RDX); + + writeb(pio_t4[mode] / T + 1, priv->host_regs + PATA_IMX_ATA_TIME_4); + writeb(pio_t9[mode] / T + 1, priv->host_regs + PATA_IMX_ATA_TIME_9); + writeb(pio_tA[mode] / T + 1, priv->host_regs + PATA_IMX_ATA_TIME_AX); +} + +static void pata_imx_set_piomode(struct ata_port *ap, struct ata_device *adev) { - struct ata_device *dev; - struct ata_port *ap = link->ap; struct pata_imx_priv *priv = ap->host->private_data; u32 val; - ata_for_each_dev(dev, link, ENABLED) { - dev->pio_mode = dev->xfer_mode = XFER_PIO_0; - dev->xfer_shift = ATA_SHIFT_PIO; - dev->flags |= ATA_DFLAG_PIO; - - val = __raw_readl(priv->host_regs + PATA_IMX_ATA_CONTROL); - if (ata_pio_need_iordy(dev)) - val |= PATA_IMX_ATA_CTRL_IORDY_EN; - else - val &= ~PATA_IMX_ATA_CTRL_IORDY_EN; - __raw_writel(val, priv->host_regs + PATA_IMX_ATA_CONTROL); + pata_imx_set_timing(adev, priv); - ata_dev_info(dev, "configured for PIO\n"); - } - return 0; + val = __raw_readl(priv->host_regs + PATA_IMX_ATA_CONTROL); + if (ata_pio_need_iordy(adev)) + val |= PATA_IMX_ATA_CTRL_IORDY_EN; + else + val &= ~PATA_IMX_ATA_CTRL_IORDY_EN; + __raw_writel(val, priv->host_regs + PATA_IMX_ATA_CONTROL); } static struct scsi_host_template pata_imx_sht = { @@ -72,7 +104,7 @@ static struct ata_port_operations pata_imx_port_ops = { .inherits = &ata_sff_port_ops, .sff_data_xfer = ata_sff_data_xfer_noirq, .cable_detect = ata_cable_unknown, - .set_mode = pata_imx_set_mode, + .set_piomode = pata_imx_set_piomode, }; static void pata_imx_setup_port(struct ata_ioports *ioaddr) @@ -128,7 +160,7 @@ static int pata_imx_probe(struct platform_device *pdev) ap = host->ports[0]; ap->ops = &pata_imx_port_ops; - ap->pio_mask = ATA_PIO0; + ap->pio_mask = ATA_PIO4; ap->flags |= ATA_FLAG_SLAVE_POSS; io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |