| /*************************************************************************** |
| * __________ __ ___. |
| * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| * \/ \/ \/ \/ \/ |
| * $Id$ |
| * |
| * Copyright (C) 2007 by Will Robertson |
| * |
| * 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 "ata.h" |
| #include "ata-target.h" |
| #include "clkctl-imx31.h" |
| |
| static const struct ata_pio_timings |
| { |
| uint16_t time_2w; /* t2 during write */ |
| uint16_t time_2r; /* t2 during read */ |
| uint8_t time_1; /* t1 */ |
| uint8_t time_pio_rdx; /* trd */ |
| uint8_t time_4; /* t4 */ |
| uint8_t time_9; /* t9 */ |
| } pio_timings[5] = |
| { |
| [0] = /* PIO mode 0 */ |
| { |
| .time_1 = 70, |
| .time_2w = 290, |
| .time_2r = 290, |
| .time_4 = 30, |
| .time_9 = 20 |
| }, |
| [1] = /* PIO mode 1 */ |
| { |
| .time_1 = 50, |
| .time_2w = 290, |
| .time_2r = 290, |
| .time_4 = 20, |
| .time_9 = 15 |
| }, |
| [2] = /* PIO mode 2 */ |
| { |
| .time_1 = 30, |
| .time_2w = 290, |
| .time_2r = 290, |
| .time_4 = 15, |
| .time_9 = 10 |
| }, |
| [3] = /* PIO mode 3 */ |
| { |
| .time_1 = 30, |
| .time_2w = 80, |
| .time_2r = 80, |
| .time_4 = 10, |
| .time_9 = 10 |
| }, |
| [4] = /* PIO mode 4 */ |
| { |
| .time_1 = 25, |
| .time_2w = 70, |
| .time_2r = 70, |
| .time_4 = 10, |
| .time_9 = 10 |
| }, |
| }; |
| |
| static int pio_mode = 0; /* Setup mode 0 by default */ |
| |
| static void ata_wait_for_idle(void) |
| { |
| while (!(ATA_INTERRUPT_PENDING & ATA_CONTROLLER_IDLE)); |
| } |
| |
| /* Setup the timing for PIO mode */ |
| void ata_set_pio_timings(int mode) |
| { |
| ata_wait_for_idle(); |
| |
| const struct ata_pio_timings * const timings = &pio_timings[mode]; |
| /* T = period in nanoseconds */ |
| int T = 1000 * 1000 * 1000 / imx31_clkctl_get_ata_clk(); |
| |
| pio_mode = mode; |
| |
| ATA_TIME_OFF = 3; |
| ATA_TIME_ON = 3; |
| |
| ATA_TIME_1 = (timings->time_1 + T) / T; |
| ATA_TIME_2W = (timings->time_2w + T) / T; |
| ATA_TIME_2R = (timings->time_2r + T) / T; |
| ATA_TIME_AX = (35 + T) / T; /* tA */ |
| ATA_TIME_PIO_RDX = 1; |
| ATA_TIME_4 = (timings->time_4 + T) / T; |
| ATA_TIME_9 = (timings->time_9 + T) / T; |
| } |
| |
| void ata_reset(void) |
| { |
| /* Be sure we're not busy */ |
| ata_wait_for_idle(); |
| |
| ATA_INTF_CONTROL &= ~ATA_ATA_RST; |
| sleep(1); |
| ATA_INTF_CONTROL |= ATA_ATA_RST; |
| sleep(1); |
| |
| ata_wait_for_idle(); |
| } |
| |
| void ata_enable(bool on) |
| { |
| /* Unconditionally clock module before writing regs */ |
| imx31_clkctl_module_clock_gating(CG_ATA, CGM_ON_ALL); |
| |
| if (on) |
| { |
| ATA_INTF_CONTROL |= ATA_ATA_RST; |
| } |
| else |
| { |
| ata_wait_for_idle(); |
| |
| ATA_INTF_CONTROL &= ~ATA_ATA_RST; |
| |
| /* Disable off - unclock ATA module */ |
| imx31_clkctl_module_clock_gating(CG_ATA, CGM_OFF); |
| } |
| } |
| |
| bool ata_is_coldstart(void) |
| { |
| return true; |
| } |
| |
| void ata_device_init(void) |
| { |
| /* Make sure we're not in reset mode */ |
| ata_enable(true); |
| |
| /* mode may be switched later once identify info is ready in which |
| * case the main driver calls back */ |
| ata_set_pio_timings(pio_mode); |
| } |