diff options
Diffstat (limited to 'drivers/ata/pata_imx.c')
-rw-r--r-- | drivers/ata/pata_imx.c | 47 |
1 files changed, 46 insertions, 1 deletions
diff --git a/drivers/ata/pata_imx.c b/drivers/ata/pata_imx.c index 00df18b07fa6..8f13c9f27c8c 100644 --- a/drivers/ata/pata_imx.c +++ b/drivers/ata/pata_imx.c @@ -11,7 +11,6 @@ * * TODO: * - dmaengine support - * - check if timing stuff needed */ #include <linux/ata.h> @@ -22,6 +21,16 @@ #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) @@ -31,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 */ @@ -38,11 +51,43 @@ struct pata_imx_priv { u32 ata_ctl; }; +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 pata_imx_priv *priv = ap->host->private_data; u32 val; + pata_imx_set_timing(adev, priv); + val = __raw_readl(priv->host_regs + PATA_IMX_ATA_CONTROL); if (ata_pio_need_iordy(adev)) val |= PATA_IMX_ATA_CTRL_IORDY_EN; |