]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/devs/disk/v85x/edb_v850/v2_0/src/v85x_edb_v850_disk.c
Merge branch 'master' of git+ssh://git.kernelconcepts.de/karo-tx-redboot
[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 // Copyright (C) 2006 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):    savin
43 // Contributors: 
44 // Date:         2003-08-21
45 //
46 //####DESCRIPTIONEND####
47 //
48 //==========================================================================
49
50 #include <pkgconf/devs_disk_v85x_edb_v850.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/drv_api.h>
58 #include <cyg/io/io.h>
59 #include <cyg/io/devtab.h>
60 #include <cyg/io/disk.h>
61
62 #include <cf_ata.h>
63
64 // ----------------------------------------------------------------------------
65
66 //#define DEBUG 1
67
68 #ifdef DEBUG
69 # define D(_args_) diag_printf _args_
70 #else
71 # define D(_args_)
72 #endif
73
74 // ----------------------------------------------------------------------------
75
76 #include <cyg/hal/v850_common.h>
77
78 static volatile unsigned char* P10  = (volatile unsigned char*)V850_REG_P10;
79 static volatile unsigned char* PM10 = (volatile unsigned char*)V850_REG_PM10;
80 static volatile unsigned char* PU10 = (volatile unsigned char*)V850_REG_PU10;
81
82 #define CF_BASE 0x00380000
83
84 #define CF_HW_INIT()                  \
85     do {                              \
86         *PU10 |= (1<<4);              \
87         *PM10 |= (1<<4);              \
88         *PM10 &= ~2;                  \
89     } while (0)
90
91 #define CF_HW_RESET()                   \
92     do {                                \
93         int i;                          \
94         *P10 |=  2;                     \
95         for (i = 0; i < 500000; i++);   \
96         *P10 &= ~2;                     \
97         for (i = 0; i < 500000; i++);   \
98     } while (0)
99
100 #define CF_HW_BUSY_WAIT()               \
101     do {                                \
102         while (0 == (*P10 & (1<<4)));   \
103     } while (0)
104
105 // ----------------------------------------------------------------------------
106
107 typedef struct {
108     volatile cyg_uint16 *base;
109 } cf_disk_info_t;
110
111 // ----------------------------------------------------------------------------
112
113 static cyg_bool cf_disk_init(struct cyg_devtab_entry *tab);
114
115 static Cyg_ErrNo cf_disk_read(disk_channel *chan, 
116                               void         *buf,
117                               cyg_uint32    len, 
118                               cyg_uint32    block_num); 
119         
120
121 static Cyg_ErrNo cf_disk_write(disk_channel *chan, 
122                                const void   *buf,
123                                cyg_uint32    len, 
124                                cyg_uint32    block_num); 
125  
126 static Cyg_ErrNo cf_disk_get_config(disk_channel *chan, 
127                                     cyg_uint32    key,
128                                     const void   *xbuf, 
129                                     cyg_uint32   *len);
130
131 static Cyg_ErrNo cf_disk_set_config(disk_channel *chan, 
132                                     cyg_uint32    key,
133                                     const void   *xbuf, 
134                                     cyg_uint32   *len);
135
136 static Cyg_ErrNo cf_disk_lookup(struct cyg_devtab_entry **tab,
137                                 struct cyg_devtab_entry  *sub_tab,
138                                 const char               *name);
139
140 DISK_FUNS(cf_disk_funs, 
141           cf_disk_read, 
142           cf_disk_write, 
143           cf_disk_get_config,
144           cf_disk_set_config
145 );
146
147 // ----------------------------------------------------------------------------
148
149 // No h/w controller structure is needed, but the address of the
150 // second argument is taken anyway.
151 DISK_CONTROLLER(cf_disk_controller, cf_disk_controller);
152
153 #define CF_DISK_INSTANCE(_number_,_base_,_mbr_supp_,_name_)           \
154 static cf_disk_info_t cf_disk_info##_number_ = {                      \
155     base: (volatile cyg_uint16 *)_base_,                              \
156 };                                                                    \
157 DISK_CHANNEL(cf_disk_channel##_number_,                               \
158              cf_disk_funs,                                            \
159              cf_disk_info##_number_,                                  \
160              cf_disk_controller,                                      \
161              _mbr_supp_,                                              \
162              4                                                        \
163 );                                                                    \
164 BLOCK_DEVTAB_ENTRY(cf_disk_io##_number_,                              \
165                    _name_,                                            \
166                    0,                                                 \
167                    &cyg_io_disk_devio,                                \
168                    cf_disk_init,                                      \
169                    cf_disk_lookup,                                    \
170                    &cf_disk_channel##_number_                         \
171 );
172
173 // ----------------------------------------------------------------------------
174
175 #ifdef CYGVAR_DEVS_DISK_V85X_EDB_V850_DISK0
176 CF_DISK_INSTANCE(0, CF_BASE, true, CYGDAT_IO_DISK_V85X_EDB_V850_DISK0_NAME);
177 #endif
178
179 // ----------------------------------------------------------------------------
180
181 static __inline__ cyg_uint8
182 get_status(volatile cyg_uint16 *base)
183 {
184     cyg_uint16 val;
185     HAL_READ_UINT16(base + 7, val);
186     return (val & 0x00FF);
187 }
188
189 static __inline__ cyg_uint8
190 get_error(volatile cyg_uint16 *base)
191 {
192     cyg_uint16 val;
193     HAL_READ_UINT16(base + 6, val);
194     return ((val >> 8) & 0x00FF);
195 }
196
197 static __inline__ void
198 set_dctrl(volatile cyg_uint16 *base, cyg_uint8 dbits)
199 {
200     cyg_uint16 val = dbits;
201     HAL_WRITE_UINT16(base + 7, val);
202 }
203
204 static cyg_bool 
205 exe_cmd(volatile cyg_uint16 *base,
206         cyg_uint8            cmd,
207         cyg_uint8            drive,
208         cyg_uint32           lba_addr,
209         cyg_uint8            sec_cnt)
210 {
211     cyg_uint8  lba0_7;
212     cyg_uint16 lba8_23;
213     cyg_uint8  lba24_27;
214     cyg_uint8  drv;
215
216     lba0_7   = lba_addr & 0xFF;
217     lba8_23  = (lba_addr >> 8)  & 0xFFFF;
218     lba24_27 = (lba_addr >> 24) & 0x0F;
219
220     // drive and LBA addressing mode flag
221     if (0 == drive) drv = 0x40;
222     else            drv = 0x50;
223      
224     CF_HW_BUSY_WAIT();
225
226     HAL_WRITE_UINT16(base + 1, sec_cnt | (lba0_7 << 8));
227     HAL_WRITE_UINT16(base + 2, lba8_23);
228     HAL_WRITE_UINT16(base + 3, lba24_27 | drv | (cmd << 8));
229
230     CF_HW_BUSY_WAIT();
231     
232     return (0 == (get_status(base) & CF_SREG_ERR));
233 }
234
235 static void
236 read_data(volatile cyg_uint16 *base,
237           void                *buf,
238           cyg_uint16           len)
239 {
240     cyg_uint16 *bufp = (cyg_uint16 *)buf;
241     int i;
242
243     CF_HW_BUSY_WAIT();
244
245     for (i = 0; i < 512; i += 2)
246     {
247         cyg_uint16 data;
248         HAL_READ_UINT16(base + 4, data);
249         if (i < len) *bufp++ = data;
250     }
251
252     CF_HW_BUSY_WAIT();
253 }
254
255 static void
256 write_data(volatile cyg_uint16 *base,
257            const void          *buf,
258            cyg_uint16           len)
259 {
260     cyg_uint16 *bufp = (cyg_uint16 * const)buf;
261     int i;
262
263     CF_HW_BUSY_WAIT();
264
265     for (i = 0; i < 512; i += 2)
266     {
267         cyg_uint16 data;
268
269         if (i < len) data = *bufp++;
270         else         data = 0x0000;
271
272         HAL_WRITE_UINT16(base + 4, data);
273     }
274     
275     CF_HW_BUSY_WAIT();
276 }
277
278 static void
279 id_strcpy(char *dest, cyg_uint16 *src, cyg_uint16 size)
280 {
281     int i;
282
283     for (i = 0; i < size; i+=2)
284     {
285         *dest++ = (char)(*src >> 8);
286         *dest++ = (char)(*src & 0x00FF);
287         src++;
288     }
289     *dest = '\0';
290 }
291
292 // ----------------------------------------------------------------------------
293
294 static cyg_bool 
295 cf_disk_init(struct cyg_devtab_entry *tab)
296 {
297     disk_channel           *chan = (disk_channel *) tab->priv;
298     cf_disk_info_t         *info = (cf_disk_info_t *) chan->dev_priv;
299     cf_ata_identify_data_t *ata_id;
300     cyg_uint8               id_buf[sizeof(cf_ata_identify_data_t)];
301     cyg_disk_identify_t     ident;
302     
303     if (chan->init) 
304         return true;
305
306     D(("CF(%p) hw init\n", info->base));
307
308     CF_HW_INIT();
309     CF_HW_RESET();
310     
311     D(("CF(%p) identify drive\n", info->base));
312
313     if (!exe_cmd(info->base, CF_ATA_IDENTIFY_DRIVE_CMD, 0, 0, 0))
314     {
315         D(("CF(%p) error (%x)\n", info->base, get_error(info->base)));
316         return false; 
317     }
318     read_data(info->base, id_buf, sizeof(cf_ata_identify_data_t));
319    
320     ata_id = (cf_ata_identify_data_t *)id_buf;
321
322     D(("CF(%p) general conf = %x\n", info->base, ata_id->general_conf));
323             
324     if (0x848A != ata_id->general_conf)
325         return false;
326     
327     id_strcpy(ident.serial,       ata_id->serial,       20);
328     id_strcpy(ident.firmware_rev, ata_id->firmware_rev, 8);
329     id_strcpy(ident.model_num,    ata_id->model_num,    40);
330     
331     ident.cylinders_num   = ata_id->num_cylinders;
332     ident.heads_num       = ata_id->num_heads;
333     ident.sectors_num     = ata_id->num_sectors;
334     ident.lba_sectors_num = ata_id->lba_total_sectors[1] << 16 | 
335                             ata_id->lba_total_sectors[0];
336     ident.phys_block_size = 1;
337     ident.max_transfer    = 512;
338     if (!(chan->callbacks->disk_init)(tab))
339         return false;
340
341     if (ENOERR != (chan->callbacks->disk_connected)(tab, &ident))
342         return false;
343
344     return true;
345 }
346
347 static Cyg_ErrNo 
348 cf_disk_lookup(struct cyg_devtab_entry **tab, 
349                struct cyg_devtab_entry  *sub_tab,
350                const char *name)
351 {
352     disk_channel *chan = (disk_channel *) (*tab)->priv;
353     return (chan->callbacks->disk_lookup)(tab, sub_tab, name);
354 }
355
356 static Cyg_ErrNo 
357 cf_disk_read(disk_channel *chan, 
358              void         *buf,
359              cyg_uint32    len, 
360              cyg_uint32    block_num)
361 {
362     cf_disk_info_t *info = (cf_disk_info_t *)chan->dev_priv;
363
364     D(("CF(%p) read block %d\n", info->base, block_num));
365
366     if (!exe_cmd(info->base, CF_ATA_READ_SECTORS_CMD, 0, block_num, 1))
367     {
368         D(("CF(%p) error (%x)\n", info->base, get_error(info->base)));
369         return -EIO; 
370     }
371     read_data(info->base, buf, len);
372         
373     return ENOERR;
374 }
375
376 static Cyg_ErrNo 
377 cf_disk_write(disk_channel *chan, 
378               const void   *buf,
379               cyg_uint32    len, 
380               cyg_uint32    block_num)
381 {
382     cf_disk_info_t *info = (cf_disk_info_t *)chan->dev_priv;
383
384     D(("CF(%p) write block %d\n", info->base, block_num));
385  
386     if (!exe_cmd(info->base, CF_ATA_WRITE_SECTORS_CMD, 0, block_num, 1))
387     {
388         D(("CF(%p) error (%x)\n", info->base, get_error(info->base)));
389         return -EIO; 
390     }
391     write_data(info->base, buf, len);
392         
393     return ENOERR;
394 }
395
396 static Cyg_ErrNo
397 cf_disk_get_config(disk_channel *chan, 
398                    cyg_uint32    key,
399                    const void   *xbuf, 
400                    cyg_uint32   *len)
401 {
402     return -EINVAL;
403 }
404
405 static Cyg_ErrNo
406 cf_disk_set_config(disk_channel *chan, 
407                    cyg_uint32    key,
408                    const void   *xbuf, 
409                    cyg_uint32   *len)
410 {
411     return -EINVAL;
412 }
413
414 // ----------------------------------------------------------------------------
415 // EOF v85x_edb_v850_disk.c