]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/devs/disk/v85x/edb_v850/v2_0/src/v85x_edb_v850_disk.c
Initial revision
[karo-tx-redboot.git] / packages / devs / disk / v85x / edb_v850 / v2_0 / src / v85x_edb_v850_disk.c
1 //==========================================================================
2 //
3 //      v85x_edb_v850_disk.c
4 //
5 //      Elatec v850 development board disk driver 
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 2003 Savin Zlobec.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // -------------------------------------------
37 //####ECOSGPLCOPYRIGHTEND####
38 //==========================================================================
39 //#####DESCRIPTIONBEGIN####
40 //
41 // Author(s):    savin
42 // Contributors: 
43 // Date:         2003-08-21
44 //
45 //####DESCRIPTIONEND####
46 //
47 //==========================================================================
48
49 #include <pkgconf/devs_disk_v85x_edb_v850.h>
50
51 #include <cyg/infra/cyg_type.h>
52 #include <cyg/infra/cyg_ass.h>
53 #include <cyg/infra/diag.h>
54 #include <cyg/hal/hal_arch.h>
55 #include <cyg/hal/hal_io.h>
56 #include <cyg/hal/drv_api.h>
57 #include <cyg/io/io.h>
58 #include <cyg/io/devtab.h>
59 #include <cyg/io/disk.h>
60
61 #include <cf_ata.h>
62
63 // ----------------------------------------------------------------------------
64
65 //#define DEBUG 1
66
67 #ifdef DEBUG
68 # define D(_args_) diag_printf _args_
69 #else
70 # define D(_args_)
71 #endif
72
73 // ----------------------------------------------------------------------------
74
75 #include <cyg/hal/v850_common.h>
76
77 static volatile unsigned char* P10  = (volatile unsigned char*)V850_REG_P10;
78 static volatile unsigned char* PM10 = (volatile unsigned char*)V850_REG_PM10;
79 static volatile unsigned char* PU10 = (volatile unsigned char*)V850_REG_PU10;
80
81 #define CF_BASE 0x00380000
82
83 #define CF_HW_INIT()                  \
84     do {                              \
85         *PU10 |= (1<<4);              \
86         *PM10 |= (1<<4);              \
87         *PM10 &= ~2;                  \
88     } while (0)
89
90 #define CF_HW_RESET()                   \
91     do {                                \
92         int i;                          \
93         *P10 |=  2;                     \
94         for (i = 0; i < 500000; i++);   \
95         *P10 &= ~2;                     \
96         for (i = 0; i < 500000; i++);   \
97     } while (0)
98
99 #define CF_HW_BUSY_WAIT()               \
100     do {                                \
101         while (0 == (*P10 & (1<<4)));   \
102     } while (0)
103
104 // ----------------------------------------------------------------------------
105
106 typedef struct {
107     volatile cyg_uint16 *base;
108 } cf_disk_info_t;
109
110 // ----------------------------------------------------------------------------
111
112 static cyg_bool cf_disk_init(struct cyg_devtab_entry *tab);
113
114 static Cyg_ErrNo cf_disk_read(disk_channel *chan, 
115                               void         *buf,
116                               cyg_uint32    len, 
117                               cyg_uint32    block_num); 
118         
119
120 static Cyg_ErrNo cf_disk_write(disk_channel *chan, 
121                                const void   *buf,
122                                cyg_uint32    len, 
123                                cyg_uint32    block_num); 
124  
125 static Cyg_ErrNo cf_disk_get_config(disk_channel *chan, 
126                                     cyg_uint32    key,
127                                     const void   *xbuf, 
128                                     cyg_uint32   *len);
129
130 static Cyg_ErrNo cf_disk_set_config(disk_channel *chan, 
131                                     cyg_uint32    key,
132                                     const void   *xbuf, 
133                                     cyg_uint32   *len);
134
135 static Cyg_ErrNo cf_disk_lookup(struct cyg_devtab_entry **tab,
136                                 struct cyg_devtab_entry  *sub_tab,
137                                 const char               *name);
138
139 static DISK_FUNS(cf_disk_funs, 
140                  cf_disk_read, 
141                  cf_disk_write, 
142                  cf_disk_get_config,
143                  cf_disk_set_config
144 );
145
146 // ----------------------------------------------------------------------------
147
148 #define CF_DISK_INSTANCE(_number_,_base_,_mbr_supp_,_name_)           \
149 static cf_disk_info_t cf_disk_info##_number_ = {                      \
150     base: (volatile cyg_uint16 *)_base_,                              \
151 };                                                                    \
152 DISK_CHANNEL(cf_disk_channel##_number_,                               \
153              cf_disk_funs,                                            \
154              cf_disk_info##_number_,                                  \
155              _mbr_supp_,                                              \
156              4                                                        \
157 );                                                                    \
158 BLOCK_DEVTAB_ENTRY(cf_disk_io##_number_,                              \
159                    _name_,                                            \
160                    0,                                                 \
161                    &cyg_io_disk_devio,                                \
162                    cf_disk_init,                                      \
163                    cf_disk_lookup,                                    \
164                    &cf_disk_channel##_number_                         \
165 );
166
167 // ----------------------------------------------------------------------------
168
169 #ifdef CYGVAR_DEVS_DISK_V85X_EDB_V850_DISK0
170 CF_DISK_INSTANCE(0, CF_BASE, true, CYGDAT_IO_DISK_V85X_EDB_V850_DISK0_NAME);
171 #endif
172
173 // ----------------------------------------------------------------------------
174
175 static __inline__ cyg_uint8
176 get_status(volatile cyg_uint16 *base)
177 {
178     cyg_uint16 val;
179     HAL_READ_UINT16(base + 7, val);
180     return (val & 0x00FF);
181 }
182
183 static __inline__ cyg_uint8
184 get_error(volatile cyg_uint16 *base)
185 {
186     cyg_uint16 val;
187     HAL_READ_UINT16(base + 6, val);
188     return ((val >> 8) & 0x00FF);
189 }
190
191 static __inline__ void
192 set_dctrl(volatile cyg_uint16 *base, cyg_uint8 dbits)
193 {
194     cyg_uint16 val = dbits;
195     HAL_WRITE_UINT16(base + 7, val);
196 }
197
198 static cyg_bool 
199 exe_cmd(volatile cyg_uint16 *base,
200         cyg_uint8            cmd,
201         cyg_uint8            drive,
202         cyg_uint32           lba_addr,
203         cyg_uint8            sec_cnt)
204 {
205     cyg_uint8  lba0_7;
206     cyg_uint16 lba8_23;
207     cyg_uint8  lba24_27;
208     cyg_uint8  drv;
209
210     lba0_7   = lba_addr & 0xFF;
211     lba8_23  = (lba_addr >> 8)  & 0xFFFF;
212     lba24_27 = (lba_addr >> 24) & 0x0F;
213
214     // drive and LBA addressing mode flag
215     if (0 == drive) drv = 0x40;
216     else            drv = 0x50;
217      
218     CF_HW_BUSY_WAIT();
219
220     HAL_WRITE_UINT16(base + 1, sec_cnt | (lba0_7 << 8));
221     HAL_WRITE_UINT16(base + 2, lba8_23);
222     HAL_WRITE_UINT16(base + 3, lba24_27 | drv | (cmd << 8));
223
224     CF_HW_BUSY_WAIT();
225     
226     return (0 == (get_status(base) & CF_SREG_ERR));
227 }
228
229 static void
230 read_data(volatile cyg_uint16 *base,
231           void                *buf,
232           cyg_uint16           len)
233 {
234     cyg_uint16 *bufp = (cyg_uint16 *)buf;
235     int i;
236
237     CF_HW_BUSY_WAIT();
238
239     for (i = 0; i < 512; i += 2)
240     {
241         cyg_uint16 data;
242         HAL_READ_UINT16(base + 4, data);
243         if (i < len) *bufp++ = data;
244     }
245
246     CF_HW_BUSY_WAIT();
247 }
248
249 static void
250 write_data(volatile cyg_uint16 *base,
251            const void          *buf,
252            cyg_uint16           len)
253 {
254     cyg_uint16 *bufp = (cyg_uint16 * const)buf;
255     int i;
256
257     CF_HW_BUSY_WAIT();
258
259     for (i = 0; i < 512; i += 2)
260     {
261         cyg_uint16 data;
262
263         if (i < len) data = *bufp++;
264         else         data = 0x0000;
265
266         HAL_WRITE_UINT16(base + 4, data);
267     }
268     
269     CF_HW_BUSY_WAIT();
270 }
271
272 static void
273 id_strcpy(char *dest, cyg_uint16 *src, cyg_uint16 size)
274 {
275     int i;
276
277     for (i = 0; i < size; i+=2)
278     {
279         *dest++ = (char)(*src >> 8);
280         *dest++ = (char)(*src & 0x00FF);
281         src++;
282     }
283     *dest = '\0';
284 }
285
286 // ----------------------------------------------------------------------------
287
288 static cyg_bool 
289 cf_disk_init(struct cyg_devtab_entry *tab)
290 {
291     disk_channel           *chan = (disk_channel *) tab->priv;
292     cf_disk_info_t         *info = (cf_disk_info_t *) chan->dev_priv;
293     cf_ata_identify_data_t *ata_id;
294     cyg_uint8               id_buf[sizeof(cf_ata_identify_data_t)];
295     cyg_disk_identify_t     ident;
296     
297     if (chan->init) 
298         return true;
299
300     D(("CF(%p) hw init\n", info->base));
301
302     CF_HW_INIT();
303     CF_HW_RESET();
304     
305     D(("CF(%p) identify drive\n", info->base));
306
307     if (!exe_cmd(info->base, CF_ATA_IDENTIFY_DRIVE_CMD, 0, 0, 0))
308     {
309         D(("CF(%p) error (%x)\n", info->base, get_error(info->base)));
310         return false; 
311     }
312     read_data(info->base, id_buf, sizeof(cf_ata_identify_data_t));
313    
314     ata_id = (cf_ata_identify_data_t *)id_buf;
315
316     D(("CF(%p) general conf = %x\n", info->base, ata_id->general_conf));
317             
318     if (0x848A != ata_id->general_conf)
319         return false;
320     
321     id_strcpy(ident.serial,       ata_id->serial,       20);
322     id_strcpy(ident.firmware_rev, ata_id->firmware_rev, 8);
323     id_strcpy(ident.model_num,    ata_id->model_num,    40);
324     
325     ident.cylinders_num   = ata_id->num_cylinders;
326     ident.heads_num       = ata_id->num_heads;
327     ident.sectors_num     = ata_id->num_sectors;
328     ident.lba_sectors_num = ata_id->lba_total_sectors[1] << 16 | 
329                             ata_id->lba_total_sectors[0];
330     
331     if (!(chan->callbacks->disk_init)(tab))
332         return false;
333
334     if (ENOERR != (chan->callbacks->disk_connected)(tab, &ident))
335         return false;
336
337     return true;
338 }
339
340 static Cyg_ErrNo 
341 cf_disk_lookup(struct cyg_devtab_entry **tab, 
342                struct cyg_devtab_entry  *sub_tab,
343                const char *name)
344 {
345     disk_channel *chan = (disk_channel *) (*tab)->priv;
346     return (chan->callbacks->disk_lookup)(tab, sub_tab, name);
347 }
348
349 static Cyg_ErrNo 
350 cf_disk_read(disk_channel *chan, 
351              void         *buf,
352              cyg_uint32    len, 
353              cyg_uint32    block_num)
354 {
355     cf_disk_info_t *info = (cf_disk_info_t *)chan->dev_priv;
356
357     D(("CF(%p) read block %d\n", info->base, block_num));
358
359     if (!exe_cmd(info->base, CF_ATA_READ_SECTORS_CMD, 0, block_num, 1))
360     {
361         D(("CF(%p) error (%x)\n", info->base, get_error(info->base)));
362         return -EIO; 
363     }
364     read_data(info->base, buf, len);
365         
366     return ENOERR;
367 }
368
369 static Cyg_ErrNo 
370 cf_disk_write(disk_channel *chan, 
371               const void   *buf,
372               cyg_uint32    len, 
373               cyg_uint32    block_num)
374 {
375     cf_disk_info_t *info = (cf_disk_info_t *)chan->dev_priv;
376
377     D(("CF(%p) write block %d\n", info->base, block_num));
378  
379     if (!exe_cmd(info->base, CF_ATA_WRITE_SECTORS_CMD, 0, block_num, 1))
380     {
381         D(("CF(%p) error (%x)\n", info->base, get_error(info->base)));
382         return -EIO; 
383     }
384     write_data(info->base, buf, len);
385         
386     return ENOERR;
387 }
388
389 static Cyg_ErrNo
390 cf_disk_get_config(disk_channel *chan, 
391                    cyg_uint32    key,
392                    const void   *xbuf, 
393                    cyg_uint32   *len)
394 {
395     return -EINVAL;
396 }
397
398 static Cyg_ErrNo
399 cf_disk_set_config(disk_channel *chan, 
400                    cyg_uint32    key,
401                    const void   *xbuf, 
402                    cyg_uint32   *len)
403 {
404     return -EINVAL;
405 }
406
407 // ----------------------------------------------------------------------------
408 // EOF v85x_edb_v850_disk.c