]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/devs/disk/ide/v2_0/src/ide_disk.c
620d414d9d9472f5de1522a504f47a1434d0defb
[karo-tx-redboot.git] / packages / devs / disk / ide / v2_0 / src / ide_disk.c
1 //==========================================================================
2 //
3 //      ide_disk.c
4 //
5 //      IDE polled mode disk driver 
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Red Hat, Inc.
12 // Copyright (C) 2004 eCosCentric, Ltd.
13 //
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
17 //
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21 // for more details.
22 //
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 //
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
33 //
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
36 //
37 // -------------------------------------------
38 //####ECOSGPLCOPYRIGHTEND####
39 //==========================================================================
40 //#####DESCRIPTIONBEGIN####
41 //
42 // Author(s):    iz
43 // Contributors: 
44 // Date:         2004-10-16
45 //
46 //####DESCRIPTIONEND####
47 //
48 //==========================================================================
49
50 #include <pkgconf/devs_disk_ide.h>
51
52 #include <cyg/infra/cyg_type.h>
53 #include <cyg/infra/cyg_ass.h>
54 #include <cyg/infra/diag.h>
55 #include <cyg/hal/hal_arch.h>
56 #include <cyg/hal/hal_io.h>
57 #include <cyg/hal/hal_if.h>             // delays
58 #include <cyg/hal/drv_api.h>
59 #include <cyg/io/io.h>
60 #include <cyg/io/devtab.h>
61 #include <cyg/io/disk.h>
62
63 #include "ide_disk.h"
64
65 // ----------------------------------------------------------------------------
66
67 //#define DEBUG 1
68
69 #ifdef DEBUG
70 # define D(fmt,args...) diag_printf(fmt, ## args)
71 #else
72 # define D(fmt,args...)
73 #endif
74
75 // ----------------------------------------------------------------------------
76
77 #ifdef CYGVAR_DEVS_DISK_IDE_DISK0
78 IDE_DISK_INSTANCE(0, 0, 0, true, CYGDAT_IO_DISK_IDE_DISK0_NAME);
79 #endif
80
81 #ifdef CYGVAR_DEVS_DISK_IDE_DISK1
82 IDE_DISK_INSTANCE(1, 0, 1, true, CYGDAT_IO_DISK_IDE_DISK1_NAME);
83 #endif
84
85 #ifdef CYGVAR_DEVS_DISK_IDE_DISK2
86 IDE_DISK_INSTANCE(2, 1, 0, true, CYGDAT_IO_DISK_IDE_DISK2_NAME);
87 #endif
88
89 #ifdef CYGVAR_DEVS_DISK_IDE_DISK3
90 IDE_DISK_INSTANCE(3, 1, 1, true, CYGDAT_IO_DISK_IDE_DISK3_NAME);
91 #endif
92
93 // ----------------------------------------------------------------------------
94
95 static void
96 id_strcpy(char *dest, cyg_uint16 *src, cyg_uint16 size)
97 {
98     int i;
99
100     for (i = 0; i < size; i+=2)
101     {
102         *dest++ = (char)(*src >> 8);
103         *dest++ = (char)(*src & 0x00FF);
104         src++;
105     }
106     *dest = '\0';
107 }
108
109 // ----------------------------------------------------------------------------
110
111 static inline void
112 __wait_for_ready(int ctlr)
113 {
114     cyg_uint8 status;
115     do {
116          HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
117     } while (status & (IDE_STAT_BSY | IDE_STAT_DRQ));
118 }
119
120 // Wait while the device is busy with the last command
121 static inline int
122 __wait_busy(int ctlr)
123 {
124     cyg_uint8 status;
125     cyg_ucount32 tries;
126     
127     for (tries=0; tries < 1000000; tries++) {
128          CYGACC_CALL_IF_DELAY_US(10);
129          HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
130          if ((status & IDE_STAT_BSY) == 0)
131               return 1;
132     }
133     return 0;   
134 }
135
136 static inline int
137 __wait_for_drq(int ctlr)
138 {
139     cyg_uint8 status;
140     cyg_ucount32 tries;
141
142     for (tries=0; tries<1000000; tries++) {
143         CYGACC_CALL_IF_DELAY_US(10);
144         HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
145         if (!(status & IDE_STAT_BSY)) {
146             if (status & IDE_STAT_DRQ)
147                 return 1;
148             else
149                 return 0;
150         }
151     }
152     return 0;
153 }
154
155 // Return true if any devices attached to controller
156 static int
157 ide_presence_detect(int ctlr)
158 {
159     cyg_uint8 sel, val;
160     int i;
161
162     for (i = 0; i < 2; i++) {
163         sel = (i << 4) | 0xA0;
164         CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000);
165         HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, sel);
166         CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000);
167         HAL_IDE_READ_UINT8(ctlr, IDE_REG_DEVICE, val);
168         if (val == sel) {
169 #ifndef CYGSEM_DEVS_DISK_IDE_VMWARE
170             if (i)
171                 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, 0);
172 #endif
173             return 1;
174         }
175     }
176     return 0;
177 }
178
179 static int
180 ide_reset(int ctlr)
181 {
182     cyg_uint8 status;
183     int delay;
184 //
185 // VMware note:
186 // VMware virtual IDE device handler obviously expects that
187 // the reset and setup functions were already done
188 // by it's bios and complains if one uses reset here...
189 //
190 #ifndef CYGSEM_DEVS_DISK_IDE_VMWARE
191     HAL_IDE_WRITE_CONTROL(ctlr, 6);    // polled mode, reset asserted
192     CYGACC_CALL_IF_DELAY_US(5000);
193     HAL_IDE_WRITE_CONTROL(ctlr, 2);   // polled mode, reset cleared
194     CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000);
195 #endif
196
197     // wait 30 seconds max for not busy and drive ready
198     for (delay = 0; delay < 300; ++delay) {
199         CYGACC_CALL_IF_DELAY_US((cyg_uint32)100000);
200         HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
201             if (!(status & IDE_STAT_BSY)) {
202                 if (status & IDE_STAT_DRDY) {
203                     return 1;
204                 }
205             }
206     }
207     return 0;
208 }
209
210 static int
211 ide_ident(int ctlr, int dev, cyg_uint16 *buf)
212 {
213     int i;
214
215     if (!__wait_busy(ctlr)) {
216          return 0;
217     }
218     
219     HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, dev << 4);
220     HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, 0xEC);
221     CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000);
222
223     if (!__wait_for_drq(ctlr)) {
224          return 0;
225     }
226     
227     for (i = 0; i < (CYGDAT_DEVS_DISK_IDE_SECTOR_SIZE / sizeof(cyg_uint16));
228          i++, buf++)
229         HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *buf);
230
231     return 1;
232 }
233
234 static int
235 ide_read_sector(int ctlr, int dev, cyg_uint32 start, 
236                 cyg_uint8 *buf, cyg_uint32 len)
237 {
238     int j, c;
239     cyg_uint16 p;
240     cyg_uint8 * b=buf;
241
242     if(!__wait_busy(ctlr)) {
243          return 0;
244     }
245     
246     HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COUNT, 1);    // count =1
247     HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBALOW, start & 0xff);
248     HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAMID, (start >>  8) & 0xff);
249     HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAHI,  (start >> 16) & 0xff);
250     HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE,
251           ((start >> 24) & 0xf) | (dev << 4) | 0x40);
252     HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, 0x20);
253
254     if (!__wait_for_drq(ctlr))
255         return 0;
256     // 
257     // It would be fine if all buffers were word aligned,
258     // but who knows
259     //
260     for (j = 0, c=0 ; j < (CYGDAT_DEVS_DISK_IDE_SECTOR_SIZE / sizeof(cyg_uint16));
261          j++) {
262         HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, p);
263         if (c++<len) *b++=p&0xff;
264         if (c++<len) *b++=(p>>8)&0xff;
265     }
266     return 1;
267 }
268
269 static int
270 ide_write_sector(int ctlr, int dev, cyg_uint32 start, 
271                 cyg_uint8 *buf, cyg_uint32 len)
272 {
273     int j, c;
274     cyg_uint16 p;
275     cyg_uint8 * b=buf;
276
277     if(!__wait_busy(ctlr)) {
278          return 0;
279     }
280     
281     HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COUNT, 1);    // count =1
282     HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBALOW, start & 0xff);
283     HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAMID, (start >>  8) & 0xff);
284     HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAHI,  (start >> 16) & 0xff);
285     HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE,
286           ((start >> 24) & 0xf) | (dev << 4) | 0x40);
287     HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, 0x30);
288
289     if (!__wait_for_drq(ctlr))
290         return 0;
291     // 
292     // It would be fine if all buffers were word aligned,
293     // but who knows
294     //
295     for (j = 0, c=0 ; j < (CYGDAT_DEVS_DISK_IDE_SECTOR_SIZE / sizeof(cyg_uint16));
296          j++) {
297         p = (c++<len) ? *b++ : 0;
298         p |= (c++<len) ? (*b++<<8) : 0; 
299         HAL_IDE_WRITE_UINT16(ctlr, IDE_REG_DATA, p);
300     }
301     return 1;
302 }
303
304 // ----------------------------------------------------------------------------
305
306 static cyg_bool 
307 ide_disk_init(struct cyg_devtab_entry *tab)
308 {
309     disk_channel *chan = (disk_channel *) tab->priv;
310     ide_disk_info_t *info = (ide_disk_info_t *) chan->dev_priv;
311     cyg_uint32 id_buf[CYGDAT_DEVS_DISK_IDE_SECTOR_SIZE/sizeof(cyg_uint32)];
312     static int num_controllers;
313     static int ide_present[4], ide_reset_done[4];
314     cyg_disk_identify_t ident;
315     ide_identify_data_t *ide_idData=(ide_identify_data_t*)id_buf;
316     
317     if (chan->init) 
318         return true;
319
320     D("IDE(%d:%d) hw init\n", info->port, info->chan);
321     
322     if (!num_controllers) num_controllers=HAL_IDE_INIT();
323     if (info->chan>=num_controllers) {
324         D("No IDE controller for channel %d:%d\n", info->port, info->chan);
325         return false;
326     }
327     if (!ide_present[info->port]) {
328         ide_present[info->port]=ide_presence_detect(info->port);
329         if (!ide_present[info->port]) {
330             diag_printf("No devices on IDE controller #%d\n",info->port);
331             return false;
332         }
333     }
334     if (!ide_reset_done[info->port]) {
335         ide_reset_done[info->port]=ide_reset(info->port);
336         if (!ide_reset_done[info->port]) {
337             D("Controller #%d reset failure\n",info->port);
338             return false;
339         }
340     }
341     
342     D("IDE %d:%d identify drive\n", info->port, info->chan);
343     
344     if (!ide_ident(info->port, info->chan, (cyg_uint16 *)id_buf)) {
345         diag_printf("IDE %d:%d ident DRQ error\n", info->port, info->chan);
346         return false;
347     }
348
349     id_strcpy(ident.serial, ide_idData->serial,       20);
350     id_strcpy(ident.firmware_rev, ide_idData->firmware_rev, 8);
351     id_strcpy(ident.model_num, ide_idData->model_num,    40);
352     
353     ident.cylinders_num  = ide_idData->num_cylinders;
354     ident.heads_num = ide_idData->num_heads;
355     ident.sectors_num = ide_idData->num_sectors;
356     ident.lba_sectors_num = ide_idData->lba_total_sectors[1] << 16 | 
357                             ide_idData->lba_total_sectors[0];
358     
359     D("\tSerial : %s\n", ident.serial);
360     D("\tFirmware rev. : %s\n", ident.firmware_rev);
361     D("\tModel : %s\n", ident.model_num);
362     D("\tC/H/S : %d/%d/%d\n", ident.cylinders_num, 
363                               ident.heads_num, ident.sectors_num);
364     D("\tKind : %x\n", (ide_idData->general_conf>>8)&0x1f);
365
366     if (((ide_idData->general_conf>>8)&0x1f)!=2) {
367         diag_printf("IDE device %d:%d is not a hard disk!\n",
368                     info->port, info->chan);
369         return false;
370     }
371     if (!(chan->callbacks->disk_init)(tab))
372         return false;
373
374     if (ENOERR != (chan->callbacks->disk_connected)(tab, &ident))
375         return false;
376
377     return true;
378 }
379
380 // ----------------------------------------------------------------------------
381
382 static Cyg_ErrNo 
383 ide_disk_lookup(struct cyg_devtab_entry **tab, 
384                 struct cyg_devtab_entry  *sub_tab,
385                 const char *name)
386 {
387     disk_channel *chan = (disk_channel *) (*tab)->priv;
388     return (chan->callbacks->disk_lookup)(tab, sub_tab, name);
389 }
390
391 // ----------------------------------------------------------------------------
392
393 static Cyg_ErrNo 
394 ide_disk_read(disk_channel *chan, 
395               void         *buf,
396               cyg_uint32    len, 
397               cyg_uint32    block_num)
398 {
399     ide_disk_info_t *info = (ide_disk_info_t *)chan->dev_priv;
400
401     D("IDE %d:%d read block %d\n", info->port, info->chan, block_num);
402
403     if (!ide_read_sector(info->port, info->chan, block_num, 
404                          (cyg_uint8 *)buf, len)) {
405         diag_printf("IDE %d:%d read DRQ error\n", info->port, info->chan);
406         return -EIO; 
407     }
408
409     return ENOERR;
410 }
411
412 // ----------------------------------------------------------------------------
413
414 static Cyg_ErrNo 
415 ide_disk_write(disk_channel *chan, 
416                const void   *buf,
417                cyg_uint32    len, 
418                cyg_uint32    block_num)
419 {
420     ide_disk_info_t *info = (ide_disk_info_t *)chan->dev_priv;
421
422     D("IDE %d:%d write block %d\n", info->port, info->chan, block_num);
423
424     if (!ide_write_sector(info->port, info->chan, block_num, 
425                          (cyg_uint8 *)buf, len)) {
426         diag_printf("IDE %d:%d read DRQ error\n", info->port, info->chan);
427         return -EIO; 
428     }
429         
430     return ENOERR;
431 }
432
433 // ----------------------------------------------------------------------------
434
435 static Cyg_ErrNo
436 ide_disk_get_config(disk_channel *chan, 
437                     cyg_uint32    key,
438                     const void   *xbuf, 
439                     cyg_uint32   *len)
440 {
441     return -EINVAL;
442 }
443
444 // ----------------------------------------------------------------------------
445
446 static Cyg_ErrNo
447 ide_disk_set_config(disk_channel *chan, 
448                     cyg_uint32    key,
449                     const void   *xbuf, 
450                     cyg_uint32   *len)
451 {
452     return -EINVAL;
453 }
454
455 //EOF ide_disk.c