]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/block/ftide020.c
Merge branch 'master' of git://git.denx.de/u-boot-mpc83xx
[karo-tx-uboot.git] / drivers / block / ftide020.c
1 /*
2  * Faraday FTIDE020 ATA Controller (AHB)
3  *
4  * (C) Copyright 2011 Andes Technology
5  * Greentime Hu <greentime@andestech.com>
6  * Macpaul Lin <macpaul@andestech.com>
7  * Kuo-Wei Chou <kwchou@andestech.com>
8  *
9  * See file CREDITS for list of people who contributed to this
10  * project.
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License as
14  * published by the Free Software Foundation; either version 2 of
15  * the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
25  * MA 02111-1307 USA
26  *
27  */
28 /* ftide020.c - ide support functions for the FTIDE020_S controller */
29
30 #include <config.h>
31 #include <common.h>
32 #include <ata.h>
33 #include <ide.h>
34 #include <asm/io.h>
35 #include <api_public.h>
36
37 #include "ftide020.h"
38
39 /* base address */
40 #define FTIDE_BASE      CONFIG_SYS_ATA_BASE_ADDR
41
42 /*
43  * data address - The CMD and DATA use the same FIFO in FTIDE020_S
44  *   FTIDE_DATA = CONFIG_SYS_ATA_BASE_ADDR + CONFIG_SYS_ATA_DATA_OFFSET
45  *              = &ftide020->rw_fifo
46  */
47 #define FTIDE_DATA      (&ftide020->rw_fifo)
48
49 /* command and data I/O macros */
50 /* 0x0 - DATA FIFO */
51 #define WRITE_DATA(x)   outl((x), &ftide020->rw_fifo)   /* 0x00 */
52 #define READ_DATA()     inl(&ftide020->rw_fifo)         /* 0x00 */
53 /* 0x04 - R: Status Reg, W: CMD_FIFO */
54 #define WRITE_CMD(x)    outl((x), &ftide020->cmd_fifo)  /* 0x04 */
55 #define READ_STATUS()   inl(&ftide020->cmd_fifo)        /* 0x04 */
56
57 void ftide_set_device(int cx8, int dev)
58 {
59         static struct ftide020_s *ftide020 = (struct ftide020_s *) FTIDE_BASE;
60
61         WRITE_CMD(SET_DEV_CMD | IDE_SET_CX8(cx8) | dev);
62 }
63
64 unsigned char ide_read_register(int dev, unsigned int port)
65 {
66         static struct ftide020_s *ftide020 = (struct ftide020_s *) FTIDE_BASE;
67
68         ftide_set_device(0, dev);
69         WRITE_CMD(READ_REG_CMD | IDE_REG_CS_READ(CONFIG_IDE_REG_CS) |
70                 IDE_REG_DA_WRITE(port));
71
72         return READ_DATA() & 0xff;
73 }
74
75 void ide_write_register(int dev, unsigned int port, unsigned char val)
76 {
77         static struct ftide020_s *ftide020 = (struct ftide020_s *) FTIDE_BASE;
78
79         ftide_set_device(0, dev);
80         WRITE_CMD(WRITE_REG_CMD | IDE_REG_CS_WRITE(CONFIG_IDE_REG_CS) |
81                 IDE_REG_DA_WRITE(port) | val);
82 }
83
84 void ide_write_data(int dev, ulong *sect_buf, int words)
85 {
86         static struct ftide020_s *ftide020 = (struct ftide020_s *) FTIDE_BASE;
87
88         ftide_set_device(0, dev);
89         WRITE_CMD(WRITE_DATA_CMD | ((words << 2) - 1));
90
91         /* block write */
92         outsl(FTIDE_DATA, sect_buf, words);
93 }
94
95 void ide_read_data(int dev, ulong *sect_buf, int words)
96 {
97         static struct ftide020_s *ftide020 = (struct ftide020_s *) FTIDE_BASE;
98
99         ftide_set_device(0, dev);
100         WRITE_CMD(READ_DATA_CMD | ((words << 2) - 1));
101
102         /* block read */
103         insl(FTIDE_DATA, sect_buf, words);
104 }
105
106 void ftide_dfifo_ready(ulong *time)
107 {
108         static struct ftide020_s *ftide020 = (struct ftide020_s *) FTIDE_BASE;
109
110         while (!(READ_STATUS() & STATUS_RFE)) {
111                 if (*time-- == 0)
112                         break;
113
114                 udelay(100);
115         }
116 }
117
118 extern ulong ide_bus_offset[CONFIG_SYS_IDE_MAXBUS];
119
120 /* Reset_IDE_controller */
121 static void reset_ide_controller(void)
122 {
123         static struct ftide020_s *ftide020 = (struct ftide020_s *) FTIDE_BASE;
124         unsigned int val;
125
126         val = inl(&ftide020->cr);
127
128         val |= CONTROL_RST;
129         outl(val, &ftide020->cr);
130
131         /* wait until reset OK, this is poor HW design */
132         mdelay(50);
133         val &= ~(CONTROL_RST);
134         outl(val, &ftide020->cr);
135
136         mdelay(50);
137         val |= CONTROL_SRST;
138         outl(val, &ftide020->cr);
139
140         /* wait until reset OK, this is poor HW design */
141         mdelay(50);
142         val &= ~(CONTROL_SRST);
143         outl(val, &ftide020->cr);
144
145         /* IORDY enable for PIO, for 2 device */
146         val |= (CONTROL_IRE0 | CONTROL_IRE1);
147         outl(val, &ftide020->cr);
148 }
149
150 /* IDE clock frequence */
151 uint ftide_clock_freq(void)
152 {
153         /*
154          * todo: To aquire dynamic system frequency is dependend on the power
155          * management unit which the ftide020 is connected to. In current,
156          * there are only few PMU supports in u-boot.
157          * So this function is wait for future enhancement.
158          */
159         return 100;
160 }
161
162 /* Calculate Timing Registers */
163 static unsigned int timing_cal(u16 t0, u16 t1, u16 t2, u16 t4)
164 {
165         unsigned int val, ahb_ns = 8;
166         u8 TEOC, T1, T2, T4;
167
168         T1 = (u8) (t1 / ahb_ns);
169         if ((T1 * ahb_ns) == t1)
170                 T1--;
171
172         T2 = (u8) (t2 / ahb_ns);
173         if ((T2 * ahb_ns) == t2)
174                 T2--;
175
176         T4 = (u8) (t4 / ahb_ns);
177         if ((T4 * ahb_ns) == t4)
178                 T4--;
179
180         TEOC = (u8) (t0 / ahb_ns);
181         if ((TEOC * ahb_ns) == t0)
182                 TEOC--;
183
184         TEOC = ((TEOC > (T1 + T2 + T4)) ? (TEOC - (T1 + T2 + T4)) : 0);
185
186         /*
187          * Here the fields in data timing registers in PIO mode
188          * is accessed the same way as command timing registers.
189          */
190         val =   DT_REG_PIO_T1(T1)       |
191                 DT_REG_PIO_T2(T2)       |
192                 DT_REG_PIO_T4(T4)       |
193                 DT_REG_PIO_TEOC(TEOC);
194
195         return val;
196 }
197
198 /* Set Timing Register */
199 static unsigned int set_mode_timing(u8 dev, u8 id, u8 mode)
200 {
201         static struct ftide020_s *ftide020 = (struct ftide020_s *) FTIDE_BASE;
202         u16 t0, t1, t2, t4;
203         u8 tcyc, tcvs, tmli, tenv, tack, trp;
204         unsigned int val, sysclk = 8;
205
206         if (id >= TATOL_TIMING)
207                 return 0;
208
209         sysclk = ftide_clock_freq();
210         switch (id) {
211         case CMD_TIMING:
212                 if (mode < REG_MODE) {
213                         t0 = REG_ACCESS_TIMING[REG_T0][mode];
214                         t1 = REG_ACCESS_TIMING[REG_T1][mode];
215                         t2 = REG_ACCESS_TIMING[REG_T2][mode];
216                         t4 = REG_ACCESS_TIMING[REG_T4][mode];
217
218                         val = timing_cal(t0, t1, t2, t4);
219                         outl(val, (dev ? &ftide020->ctrd1 : &ftide020->ctrd0));
220                         return 1;
221                 } else
222                         return 0;
223         case PIO_TIMING:
224                 if (mode < PIO_MODE) {
225                         t0 = PIO_ACCESS_TIMING[PIO_T0][mode];
226                         t1 = PIO_ACCESS_TIMING[PIO_T1][mode];
227                         t2 = PIO_ACCESS_TIMING[PIO_T2][mode];
228                         t4 = PIO_ACCESS_TIMING[PIO_T4][mode];
229
230                         val = timing_cal(t0, t1, t2, t4);
231
232                         outl(val, (dev ? &ftide020->dtrd1 : &ftide020->dtrd0));
233                         return 1;
234                 } else
235                         return 0;
236         case DMA_TIMING:
237                 if (mode < UDMA_MODE) {
238                         /*
239                          * 0.999 is ceiling
240                          * for tcyc, tcvs, tmli, tenv, trp, tack
241                          */
242                         tcyc = (u8) (((UDMA_ACCESS_TIMING[UDMA_TCYC][mode] \
243                                                 * sysclk) + 9990) / 10000);
244                         tcvs = (u8) (((UDMA_ACCESS_TIMING[UDMA_TCVS][mode] \
245                                                 * sysclk) + 9990) / 10000);
246                         tmli = (u8) (((UDMA_ACCESS_TIMING[UDMA_TMLI][mode] \
247                                                 * sysclk) + 9990) / 10000);
248                         tenv = (u8) (((UDMA_ACCESS_TIMING[UDMA_TENV][mode] \
249                                                 * sysclk) + 9990) / 10000);
250                         trp  = (u8) (((UDMA_ACCESS_TIMING[UDMA_TRP][mode] \
251                                                 * sysclk) + 9990) / 10000);
252                         tack = (u8) (((UDMA_ACCESS_TIMING[UDMA_TACK][mode] \
253                                                  * sysclk) + 9990) / 10000);
254
255                         val  =  DT_REG_UDMA_TENV((tenv > 0) ? (tenv - 1) : 0) |
256                                 DT_REG_UDMA_TMLI((tmli > 0) ? (tmli - 1) : 0) |
257                                 DT_REG_UDMA_TCYC((tcyc > 0) ? (tcyc - 1) : 0) |
258                                 DT_REG_UDMA_TACK((tack > 0) ? (tack - 1) : 0) |
259                                 DT_REG_UDMA_TCVS((tcvs > 0) ? (tcvs - 1) : 0) |
260                                 DT_REG_UDMA_TRP((trp > 0) ? (trp - 1) : 0);
261
262                         outl(val, (dev ? &ftide020->dtrd1 : &ftide020->dtrd0));
263                         return 1;
264                 } else
265                         return 0;
266         default:
267                 return 0;
268         }
269 }
270
271 static void ftide_read_hwrev(void)
272 {
273         static struct ftide020_s *ftide020 = (struct ftide020_s *) FTIDE_BASE;
274         unsigned int rev;
275
276         rev = inl(&ftide020->revision);
277 }
278
279 static int ftide_controller_probe(void)
280 {
281         static struct ftide020_s *ftide020 = (struct ftide020_s *) FTIDE_BASE;
282         unsigned int bak;
283
284         bak = inl(&ftide020->ctrd1);
285
286         /* probing by using shorter setup time */
287         outl(CONFIG_CTRD1_PROBE_T1, &ftide020->ctrd1);
288         if ((inl(&ftide020->ctrd1) & 0xff) != CONFIG_CTRD1_PROBE_T1) {
289                 outl(bak, &ftide020->ctrd1);
290                 return 0;
291         }
292
293         /* probing by using longer setup time */
294         outl(CONFIG_CTRD1_PROBE_T2, &ftide020->ctrd1);
295         if ((inl(&ftide020->ctrd1) & 0xff) != CONFIG_CTRD1_PROBE_T2) {
296                 outl(bak, &ftide020->ctrd1);
297                 return 0;
298         }
299
300         outl(bak, &ftide020->ctrd1);
301
302         return 1;
303 }
304
305 /* ide_preinit() was migrated from linux driver ide_probe_for_ftide() */
306 int ide_preinit(void)
307 {
308         static struct ftide020_s *ftide020 = (struct ftide020_s *) FTIDE_BASE;
309         int status;
310         unsigned int val;
311         int i;
312
313         status = 1;
314         for (i = 0; i < CONFIG_SYS_IDE_MAXBUS; i++)
315                 ide_bus_offset[i] = -ATA_STATUS;
316
317         /* auto-detect IDE controller */
318         if (ftide_controller_probe()) {
319                 printf("FTIDE020_S\n");
320         } else {
321                 printf("FTIDE020_S ATA controller not found.\n");
322                 return API_ENODEV;
323         }
324
325         /* check HW IP revision */
326         ftide_read_hwrev();
327
328         /* set FIFO threshold */
329         outl(((WRITE_FIFO - RX_THRESH) << 16) | RX_THRESH, &ftide020->dmatirr);
330
331         /* set Device_0 PIO_4 timing */
332         set_mode_timing(0, CMD_TIMING, REG_MODE4);
333         set_mode_timing(0, PIO_TIMING, PIO_MODE4);
334
335         /* set Device_1 PIO_4 timing */
336         set_mode_timing(1, CMD_TIMING, REG_MODE4);
337         set_mode_timing(1, PIO_TIMING, PIO_MODE4);
338
339         /* from E-bios */
340         /* little endian */
341         outl(0x0, &ftide020->cr);
342         mdelay(10);
343
344         outl(0x0fff0fff, &ftide020->ahbtr);
345         mdelay(10);
346
347         /* Enable controller Interrupt */
348         val = inl(&ftide020->cr);
349
350         /* Enable: IDE IRQ, IDE Terminate ERROR IRQ, AHB Timeout error IRQ */
351         val |= (CONTROL_IIE | CONTROL_TERIE | CONTROL_AERIE);
352         outl(val, &ftide020->cr);
353
354         status = 0;
355
356         return status;
357 }
358
359 void ide_set_reset(int flag)
360 {
361         debug("ide_set_reset()\n");
362         reset_ide_controller();
363         return;
364 }