/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id: ata-meg-fx.c 27935 2010-08-28 23:12:11Z funman $ * * Copyright (C) 2011 by Michael Sparmann * * 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. * ****************************************************************************/ #include "config.h" #include "cpu.h" #include "kernel.h" #include "thread.h" #include "system.h" #include "power.h" #include "panic.h" #include "pmu-target.h" #include "ata.h" #include "ata-target.h" #include "s5l8702.h" static struct wakeup ata_wakeup; #ifdef HAVE_ATA_DMA static uint32_t ata_dma_flags; #endif void ata_reset(void) { ATA_SWRST = 1; sleep(HZ / 100); ATA_SWRST = 0; sleep(HZ / 10); } void ata_enable(bool on) { if (on) { PWRCON(0) &= ~(1 << 5); ATA_CFG = 0x41; sleep(HZ / 100); ATA_CFG = 0x40; sleep(HZ / 20); ata_reset(); ATA_CCONTROL = 1; sleep(HZ / 5); ATA_PIO_TIME = 0x191f7; *ATA_HCYL = 0; while (!(ATA_PIO_READY & 2)) yield(); } else { ATA_CCONTROL = 0; while (!(ATA_CCONTROL & 2)) yield(); PWRCON(1) |= 1 << 5; } } bool ata_is_coldstart(void) { return false; } void ata_device_init(void) { VIC0INTENABLE = 1 << IRQ_ATA; } uint16_t ata_read_cbr(uint32_t volatile* reg) { while (!(ATA_PIO_READY & 2)); volatile uint32_t __attribute__((unused)) dummy = *reg; while (!(ATA_PIO_READY & 1)); return ATA_PIO_RDATA; } void ata_write_cbr(uint32_t volatile* reg, uint16_t data) { while (!(ATA_PIO_READY & 2)); *reg = data; } void ata_set_pio_timings(int mode) { if (mode >= 4) ATA_PIO_TIME = 0x7083; if (mode >= 3) ATA_PIO_TIME = 0x2072; else ATA_PIO_TIME = 0x11f3; } #ifdef HAVE_ATA_DMA static void ata_set_mdma_timings(unsigned int mode) { if (mode >= 2) ATA_MDMA_TIME = 0x5072; if (mode >= 1) ATA_MDMA_TIME = 0x7083; else ATA_MDMA_TIME = 0x1c175; } static void ata_set_udma_timings(unsigned int mode) { if (mode >= 4) ATA_UDMA_TIME = 0x2010a52; if (mode >= 3) ATA_UDMA_TIME = 0x2020a52; if (mode >= 2) ATA_UDMA_TIME = 0x3030a52; if (mode >= 1) ATA_UDMA_TIME = 0x3050a52; else ATA_UDMA_TIME = 0x5071152; } void ata_dma_set_mode(unsigned char mode) { unsigned int modeidx = mode & 0x07; unsigned int dmamode = mode & 0xf8; if (dmamode == 0x40 && modeidx <= ATA_MAX_UDMA) { /* Using Ultra DMA */ ata_set_udma_timings(dmamode); ata_dma_flags = 0x60c; } else if (dmamode == 0x20 && modeidx <= ATA_MAX_MWDMA) { /* Using Multiword DMA */ ata_set_mdma_timings(dmamode); ata_dma_flags = 0x408; } else { /* Don't understand this - force PIO. */ ata_dma_flags = 0; } } bool ata_dma_setup(void *addr, unsigned long bytes, bool write) { if ((((int)addr) & 0xf) || (((int)bytes) & 0xf) || !ata_dma_flags) return false; if (write) clean_dcache(); else invalidate_dcache(); ATA_CCOMMAND = 2; if (write) { ATA_SBUF_START = addr; ATA_SBUF_SIZE = bytes; ATA_CFG |= 0x10; } else { ATA_TBUF_START = addr; ATA_TBUF_SIZE = bytes; ATA_CFG &= ~0x10; } ATA_XFR_NUM = bytes - 1; return true; } bool ata_dma_finish(void) { ATA_CFG |= ata_dma_flags; ATA_CFG &= ~0x180; wakeup_wait(&ata_wakeup, TIMEOUT_NOBLOCK); ATA_IRQ = 0x1f; ATA_IRQ_MASK = 1; ATA_CCOMMAND = 1; if (wakeup_wait(&ata_wakeup, HZ / 2) != OBJ_WAIT_SUCCEEDED) { ATA_CCOMMAND = 2; ATA_CFG &= ~0x100c; return false; } ATA_CCOMMAND = 2; ATA_CFG &= ~0x100c; return true; } #endif /* HAVE_ATA_DMA */ void INT_ATA(void) { uint32_t ata_irq = ATA_IRQ; ATA_IRQ = ata_irq; if (ata_irq & ATA_IRQ_MASK) wakeup_signal(&ata_wakeup); ATA_IRQ_MASK = 0; }