summaryrefslogtreecommitdiffstats
path: root/firmware/target/arm/imx233/ata-imx233.c
blob: b8f3268bdd21801fcfac7693cf91b60d54a33dcd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
/***************************************************************************
 *             __________               __   ___.
 *   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 "kernel.h"

#include "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 */
    BF_WR_ALL(GPMI_CTRL0, RUN(1), COMMAND_MODE_V(READ), WORD_LENGTH_V(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 */
    BF_WR_ALL(GPMI_CTRL0, RUN(1), COMMAND_MODE_V(WRITE), WORD_LENGTH_V(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();
    BF_WR_ALL(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(GPMI_CTRL1, DEV_RESET_V(ENABLED));
    sleep(HZ / 10);
    BF_WR(GPMI_CTRL1, DEV_RESET_V(DISABLED));
}

void ata_enable(bool on)
{
    (void)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(GPMI_CTRL1, GPMI_MODE_V(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 */