From 0b6198f8a859700e3816254222e31466014ea553 Mon Sep 17 00:00:00 2001 From: Amaury Pouly Date: Tue, 18 Jun 2013 16:39:11 +0200 Subject: [PATCH] imx233: add basic ATA driver The current driver only works in PIO mode. Change-Id: I1cf2eaedcce0172a254c3bab0e1257886226d3a0 --- firmware/SOURCES | 3 + firmware/target/arm/imx233/ata-imx233.c | 232 ++++++++++++++++++++++++ firmware/target/arm/imx233/ata-target.h | 78 ++++++++ 3 files changed, 313 insertions(+) create mode 100644 firmware/target/arm/imx233/ata-imx233.c create mode 100644 firmware/target/arm/imx233/ata-target.h diff --git a/firmware/SOURCES b/firmware/SOURCES index 83389482f3..40e0f36773 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -521,6 +521,9 @@ target/arm/imx233/kernel-imx233.c # if (CONFIG_STORAGE & (STORAGE_SD | STORAGE_MMC)) target/arm/imx233/sdmmc-imx233.c # endif +# if (CONFIG_STORAGE & (STORAGE_ATA)) +target/arm/imx233/ata-imx233.c +# endif target/arm/imx233/partitions-imx233.c target/arm/imx233/ssp-imx233.c target/arm/imx233/dma-imx233.c diff --git a/firmware/target/arm/imx233/ata-imx233.c b/firmware/target/arm/imx233/ata-imx233.c new file mode 100644 index 0000000000..da546ab2a1 --- /dev/null +++ b/firmware/target/arm/imx233/ata-imx233.c @@ -0,0 +1,232 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2013 Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef ATA_IMX233_H +#define ATA_IMX233_H + +#include "config.h" +#include "system.h" +#include "pinctrl-imx233.h" +#include "clkctrl-imx233.h" +#include "ata-target.h" +#include "ata-defines.h" + +#include "regs/regs-gpmi.h" + +struct pio_timing_t +{ + /** all values are in ns */ + int addr_setup; /* "Address valid to DIOR-/DIOW-setup" */ + int data_hold; /* "DIOR-/DIOW-recovery time" */ + int data_setup; /* "DIOR-/DIOW-" */ +}; + +static struct pio_timing_t pio_timing[] = +{ + /* FIXME: OF uses 290, 290, 290, 80, 70 for data_setup */ + {70, 100, 165}, + {50, 100, 125}, + {30, 100, 100}, + {30, 70, 80}, + {25, 25, 70}, +}; + +static void imx233_ata_wait_ready(void) +{ + while(BF_RD(GPMI_CTRL0, RUN)) + yield(); +} + +static uint16_t imx233_ata_read_reg(unsigned reg) +{ + /* wait ready */ + imx233_ata_wait_ready(); + + /* setup command */ + HW_GPMI_CTRL0 = BF_OR6(GPMI_CTRL0, RUN(1), + COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__READ), + WORD_LENGTH(BV_GPMI_CTRL0_WORD_LENGTH__16_BIT), + CS(IMX233_ATA_REG_CS(reg)), ADDRESS(IMX233_ATA_REG_ADDR(reg)), + XFER_COUNT(1)); + + /* wait for completion */ + while(BF_RD(GPMI_STAT, FIFO_EMPTY)); + + /* get data */ + return HW_GPMI_DATA & 0xffff; +} + +static void imx233_ata_write_reg(unsigned reg, uint16_t data) +{ + /* wait ready */ + imx233_ata_wait_ready(); + + /* setup command */ + HW_GPMI_CTRL0 = BF_OR6(GPMI_CTRL0, RUN(1), + COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__WRITE), + WORD_LENGTH(BV_GPMI_CTRL0_WORD_LENGTH__16_BIT), + CS(IMX233_ATA_REG_CS(reg)), ADDRESS(IMX233_ATA_REG_ADDR(reg)), + XFER_COUNT(1)); + + /* send data */ + HW_GPMI_DATA = data; +} + +uint8_t imx233_ata_inb(unsigned reg) +{ + return imx233_ata_read_reg(reg) & 0xff; +} + +uint16_t imx233_ata_inw(unsigned reg) +{ + return imx233_ata_read_reg(reg); +} + +void imx233_ata_outb(unsigned reg, uint8_t v) +{ + imx233_ata_write_reg(reg, v); +} + +void imx233_ata_outw(unsigned reg, uint16_t v) +{ + imx233_ata_write_reg(reg, v); +} + +void ata_set_pio_timings(int mode) +{ + /* load timing */ + struct pio_timing_t t = pio_timing[mode > 3 ? 3 : mode]; + /* adjust to the clock */ + unsigned clock_freq = 80 * 1000; +#define adjust_to_clock(val) \ + val = (val * clock_freq) / 1000 / 1000 + + adjust_to_clock(t.addr_setup); + adjust_to_clock(t.data_hold); + adjust_to_clock(t.data_setup); + /* write */ + imx233_ata_wait_ready(); + HW_GPMI_TIMING0 = BF_OR3(GPMI_TIMING0, ADDRESS_SETUP(t.addr_setup), + DATA_HOLD(t.data_hold), DATA_SETUP(t.data_setup)); +} + +void ata_reset(void) +{ + /* reset device */ + BF_WR_V(GPMI_CTRL1, DEV_RESET, ENABLED); + sleep(HZ / 10); + BF_WR_V(GPMI_CTRL1, DEV_RESET, DISABLED); +} + +void ata_enable(bool on) +{ +} + +bool ata_is_coldstart(void) +{ + return false; +} + +#ifdef HAVE_ATA_DMA +void ata_dma_set_mode(unsigned char mode); +bool ata_dma_setup(void *addr, unsigned long bytes, bool write); +bool ata_dma_finish(void); +#endif + +static int ata_wait_status(unsigned status, unsigned mask, int timeout) +{ + long end_tick = current_tick + timeout; + + while(TIME_BEFORE(current_tick, end_tick)) + { + if((ATA_IN8(ATA_STATUS) & mask) == status) + return 1; + sleep(0); + } + + return 0; +} + +int ata_wait_for_bsy(void) +{ + /* BSY = 0 */ + return ata_wait_status(0, STATUS_BSY, HZ); +} + +int ata_wait_for_rdy(void) +{ + /* RDY = 1 && BSY = 0 */ + return ata_wait_status(STATUS_RDY, STATUS_RDY | STATUS_BSY, HZ); +} + +void ata_device_init(void) +{ + /* reset block */ + imx233_reset_block(&HW_GPMI_CTRL0); + /* setup pins */ + imx233_pinctrl_setup_vpin(VPIN_GPMI_D0, "ata d0", PINCTRL_DRIVE_4mA, false); + imx233_pinctrl_setup_vpin(VPIN_GPMI_D1, "ata d1", PINCTRL_DRIVE_4mA, false); + imx233_pinctrl_setup_vpin(VPIN_GPMI_D2, "ata d2", PINCTRL_DRIVE_4mA, false); + imx233_pinctrl_setup_vpin(VPIN_GPMI_D3, "ata d3", PINCTRL_DRIVE_4mA, false); + imx233_pinctrl_setup_vpin(VPIN_GPMI_D4, "ata d4", PINCTRL_DRIVE_4mA, false); + imx233_pinctrl_setup_vpin(VPIN_GPMI_D5, "ata d5", PINCTRL_DRIVE_4mA, false); + imx233_pinctrl_setup_vpin(VPIN_GPMI_D6, "ata d6", PINCTRL_DRIVE_4mA, false); + imx233_pinctrl_setup_vpin(VPIN_GPMI_D7, "ata d7", PINCTRL_DRIVE_4mA, false); + imx233_pinctrl_setup_vpin(VPIN_GPMI_D8, "ata d8", PINCTRL_DRIVE_4mA, false); + imx233_pinctrl_setup_vpin(VPIN_GPMI_D9, "ata d9", PINCTRL_DRIVE_4mA, false); + imx233_pinctrl_setup_vpin(VPIN_GPMI_D10, "ata d10", PINCTRL_DRIVE_4mA, false); + imx233_pinctrl_setup_vpin(VPIN_GPMI_D11, "ata d11", PINCTRL_DRIVE_4mA, false); + imx233_pinctrl_setup_vpin(VPIN_GPMI_D12, "ata d12", PINCTRL_DRIVE_4mA, false); + imx233_pinctrl_setup_vpin(VPIN_GPMI_D13, "ata d13", PINCTRL_DRIVE_4mA, false); + imx233_pinctrl_setup_vpin(VPIN_GPMI_D14, "ata d14", PINCTRL_DRIVE_4mA, false); + imx233_pinctrl_setup_vpin(VPIN_GPMI_D15, "ata d15", PINCTRL_DRIVE_4mA, false); + imx233_pinctrl_setup_vpin(VPIN_GPMI_D15, "ata d15", PINCTRL_DRIVE_4mA, false); + imx233_pinctrl_setup_vpin(VPIN_GPMI_CE0n, "ata cs0", PINCTRL_DRIVE_4mA, false); + imx233_pinctrl_setup_vpin(VPIN_GPMI_CE1n, "ata cs1", PINCTRL_DRIVE_4mA, false); + imx233_pinctrl_setup_vpin(VPIN_GPMI_A0, "ata a0", PINCTRL_DRIVE_4mA, false); + imx233_pinctrl_setup_vpin(VPIN_GPMI_A1, "ata a1", PINCTRL_DRIVE_4mA, false); + imx233_pinctrl_setup_vpin(VPIN_GPMI_A2, "ata a2", PINCTRL_DRIVE_4mA, false); + imx233_pinctrl_setup_vpin(VPIN_GPMI_IRQ, "ata irq", PINCTRL_DRIVE_4mA, false); + imx233_pinctrl_setup_vpin(VPIN_GPMI_RDY, "ata rdy", PINCTRL_DRIVE_4mA, false); +#ifdef HAVE_ATA_DMA + imx233_pinctrl_setup_vpin(VPIN_GPMI_RDY2, "ata dmack", PINCTRL_DRIVE_4mA, false); + imx233_pinctrl_setup_vpin(VPIN_GPMI_RDY3, "ata dmarq", PINCTRL_DRIVE_4mA, false); +#endif + imx233_pinctrl_setup_vpin(VPIN_GPMI_RDn, "ata rd", PINCTRL_DRIVE_4mA, false); + imx233_pinctrl_setup_vpin(VPIN_GPMI_WRn, "ata wr", PINCTRL_DRIVE_4mA, false); + /* setup ata mode */ + BF_WR_V(GPMI_CTRL1, GPMI_MODE, ATA); + /* reset device */ + ata_reset(); + ata_enable(true); + + /* setup mode 0 for all until identification */ + ata_set_pio_timings(0); + +#ifdef HAVE_ATA_DMA + ata_set_mdma_timings(0); + ata_set_udma_timings(0); +#endif +} + +#endif /* ATA_IMX233_H */ + + + diff --git a/firmware/target/arm/imx233/ata-target.h b/firmware/target/arm/imx233/ata-target.h new file mode 100644 index 0000000000..a95ea03247 --- /dev/null +++ b/firmware/target/arm/imx233/ata-target.h @@ -0,0 +1,78 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2013 Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef ATA_TARGET_H +#define ATA_TARGET_H + +#include "config.h" + +#ifdef BOOTLOADER +#define ATA_DRIVER_CLOSE +#endif + +#ifdef HAVE_ATA_DMA +/* FIXME does this chips does MWDMA ? */ +#define ATA_MAX_MWDMA 2 +#define ATA_MAX_UDMA 4 +#endif + +uint8_t imx233_ata_inb(unsigned reg); +uint16_t imx233_ata_inw(unsigned reg); +void imx233_ata_outb(unsigned reg, uint8_t v); +void imx233_ata_outw(unsigned reg, uint16_t v); + +#define IMX233_ATA_REG(cs,addr) ((cs) << 3 | (addr)) +#define IMX233_ATA_REG_CS(reg) ((reg) >> 3) +#define IMX233_ATA_REG_ADDR(reg) ((reg) & 0x7) +/* use register address (see ATA spec) */ +#define ATA_DATA IMX233_ATA_REG(0, 0) +#define ATA_ERROR IMX233_ATA_REG(0, 1) +#define ATA_NSECTOR IMX233_ATA_REG(0, 2) +#define ATA_SECTOR IMX233_ATA_REG(0, 3) +#define ATA_LCYL IMX233_ATA_REG(0, 4) +#define ATA_HCYL IMX233_ATA_REG(0, 5) +#define ATA_SELECT IMX233_ATA_REG(0, 6) +#define ATA_COMMAND IMX233_ATA_REG(0, 7) +#define ATA_CONTROL IMX233_ATA_REG(1, 6) + +/* keep consistent with definition of IMX233_ATA_REG */ +#define ATA_OUT8(reg, data) imx233_ata_outb(reg, data) +#define ATA_OUT16(reg, data) imx233_ata_outw(reg, data) +#define ATA_IN8(reg) imx233_ata_inb(reg) +#define ATA_IN16(reg) imx233_ata_inw(reg) + +#define ATA_SET_PIO_TIMING + +#define ATA_TARGET_POLLING + +void ata_set_pio_timings(int mode); +void ata_reset(void); +void ata_enable(bool on); +bool ata_is_coldstart(void); +#ifdef HAVE_ATA_DMA +void ata_dma_set_mode(unsigned char mode); +bool ata_dma_setup(void *addr, unsigned long bytes, bool write); +bool ata_dma_finish(void); +#endif +int ata_wait_for_bsy(void); +int ata_wait_for_rdy(void); +void ata_device_init(void); + +#endif /* ATA_TARGET_H */