rockbox/firmware/target/arm/imx233/ata-imx233.c
Amaury Pouly 0b6198f8a8 imx233: add basic ATA driver
The current driver only works in PIO mode.

Change-Id: I1cf2eaedcce0172a254c3bab0e1257886226d3a0
2013-06-18 16:41:13 +02:00

232 lines
7.1 KiB
C

/***************************************************************************
* __________ __ ___.
* 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 */