1 | /* flash.c |
---|
2 | * |
---|
3 | * Milkymist flash driver for RTEMS |
---|
4 | * |
---|
5 | * The license and distribution terms for this file may be |
---|
6 | * found in the file LICENSE in this distribution or at |
---|
7 | * http://www.rtems.org/license/LICENSE. |
---|
8 | * |
---|
9 | * COPYRIGHT (c) 2010, 2011 Sebastien Bourdeauducq |
---|
10 | */ |
---|
11 | |
---|
12 | #define RTEMS_STATUS_CHECKS_USE_PRINTK |
---|
13 | |
---|
14 | #include <rtems.h> |
---|
15 | #include <stdio.h> |
---|
16 | #include <bsp.h> |
---|
17 | #include <string.h> |
---|
18 | #include <rtems/libio.h> |
---|
19 | #include <rtems/status-checks.h> |
---|
20 | #include "../include/system_conf.h" |
---|
21 | #include <bsp/milkymist_flash.h> |
---|
22 | |
---|
23 | static struct flash_partition partitions[FLASH_PARTITION_COUNT] |
---|
24 | = FLASH_PARTITIONS; |
---|
25 | |
---|
26 | static rtems_id flash_lock; |
---|
27 | |
---|
28 | rtems_device_driver flash_initialize( |
---|
29 | rtems_device_major_number major, |
---|
30 | rtems_device_minor_number minor, |
---|
31 | void *arg |
---|
32 | ) |
---|
33 | { |
---|
34 | rtems_status_code sc; |
---|
35 | int i; |
---|
36 | char devname[16]; |
---|
37 | |
---|
38 | for (i=0;i<FLASH_PARTITION_COUNT;i++) { |
---|
39 | sprintf(devname, "/dev/flash%d", i+1); |
---|
40 | sc = rtems_io_register_name(devname, major, i); |
---|
41 | RTEMS_CHECK_SC(sc, "Create flash device"); |
---|
42 | } |
---|
43 | |
---|
44 | sc = rtems_semaphore_create( |
---|
45 | rtems_build_name('F', 'L', 'S', 'H'), |
---|
46 | 1, |
---|
47 | RTEMS_SIMPLE_BINARY_SEMAPHORE, |
---|
48 | 0, |
---|
49 | &flash_lock |
---|
50 | ); |
---|
51 | RTEMS_CHECK_SC(sc, "create semaphore"); |
---|
52 | |
---|
53 | return RTEMS_SUCCESSFUL; |
---|
54 | } |
---|
55 | |
---|
56 | rtems_device_driver flash_read( |
---|
57 | rtems_device_major_number major, |
---|
58 | rtems_device_minor_number minor, |
---|
59 | void *arg |
---|
60 | ) |
---|
61 | { |
---|
62 | rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg; |
---|
63 | void *startaddr; |
---|
64 | int len; |
---|
65 | |
---|
66 | if (minor >= FLASH_PARTITION_COUNT) |
---|
67 | return RTEMS_UNSATISFIED; |
---|
68 | |
---|
69 | startaddr = (void *)(partitions[minor].start_address |
---|
70 | + (unsigned int)rw_args->offset); |
---|
71 | len = partitions[minor].length - rw_args->offset; |
---|
72 | if (len > rw_args->count) |
---|
73 | len = rw_args->count; |
---|
74 | if (len <= 0) { |
---|
75 | rw_args->bytes_moved = 0; |
---|
76 | return RTEMS_SUCCESSFUL; |
---|
77 | } |
---|
78 | |
---|
79 | rtems_semaphore_obtain(flash_lock, RTEMS_WAIT, RTEMS_NO_TIMEOUT); |
---|
80 | memcpy(rw_args->buffer, startaddr, len); |
---|
81 | rtems_semaphore_release(flash_lock); |
---|
82 | |
---|
83 | rw_args->bytes_moved = len; |
---|
84 | return RTEMS_SUCCESSFUL; |
---|
85 | } |
---|
86 | |
---|
87 | rtems_device_driver flash_write( |
---|
88 | rtems_device_major_number major, |
---|
89 | rtems_device_minor_number minor, |
---|
90 | void *arg |
---|
91 | ) |
---|
92 | { |
---|
93 | rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg; |
---|
94 | volatile unsigned short *startaddr; |
---|
95 | unsigned short *srcdata; |
---|
96 | int len; |
---|
97 | int this_time; |
---|
98 | int remaining; |
---|
99 | int i; |
---|
100 | |
---|
101 | if (minor >= FLASH_PARTITION_COUNT) |
---|
102 | return RTEMS_UNSATISFIED; |
---|
103 | |
---|
104 | startaddr = (unsigned short *)(partitions[minor].start_address |
---|
105 | + (unsigned int)rw_args->offset); |
---|
106 | len = partitions[minor].length - rw_args->offset; |
---|
107 | if (len > rw_args->count) |
---|
108 | len = rw_args->count; |
---|
109 | if (len <= 2) { |
---|
110 | rw_args->bytes_moved = 0; |
---|
111 | return RTEMS_SUCCESSFUL; |
---|
112 | } |
---|
113 | len /= 2; |
---|
114 | srcdata = (unsigned short *)rw_args->buffer; |
---|
115 | remaining = len; |
---|
116 | |
---|
117 | rtems_semaphore_obtain(flash_lock, RTEMS_WAIT, RTEMS_NO_TIMEOUT); |
---|
118 | while (remaining > 0) { |
---|
119 | this_time = remaining; |
---|
120 | if (this_time > 256) |
---|
121 | this_time = 256; |
---|
122 | /* Issue "Buffered Programming Setup" command |
---|
123 | * and wait for buffer available. |
---|
124 | */ |
---|
125 | do { |
---|
126 | *startaddr = 0x00e8; |
---|
127 | } while (!(*startaddr & 0x0080)); |
---|
128 | /* Load word count */ |
---|
129 | *startaddr = this_time-1; |
---|
130 | /* Fill buffer */ |
---|
131 | for(i=0;i<this_time;i++) |
---|
132 | startaddr[i] = srcdata[i]; |
---|
133 | /* Issue "Buffer Programming Confirm" command */ |
---|
134 | *startaddr = 0x00d0; |
---|
135 | while (!(*startaddr & 0x0080)); /* read status register, wait for ready */ |
---|
136 | *startaddr = 0x0050; /* clear status register */ |
---|
137 | /* update state */ |
---|
138 | startaddr += this_time; |
---|
139 | srcdata += this_time; |
---|
140 | remaining -= this_time; |
---|
141 | } |
---|
142 | *startaddr = 0x00ff; /* back to read array mode */ |
---|
143 | rtems_semaphore_release(flash_lock); |
---|
144 | |
---|
145 | rw_args->bytes_moved = 2*len; |
---|
146 | return RTEMS_SUCCESSFUL; |
---|
147 | } |
---|
148 | |
---|
149 | rtems_device_driver flash_control( |
---|
150 | rtems_device_major_number major, |
---|
151 | rtems_device_minor_number minor, |
---|
152 | void *arg |
---|
153 | ) |
---|
154 | { |
---|
155 | rtems_libio_ioctl_args_t *args = arg; |
---|
156 | unsigned int eraseaddr_i; |
---|
157 | volatile unsigned short *eraseaddr; |
---|
158 | |
---|
159 | if (minor >= FLASH_PARTITION_COUNT) { |
---|
160 | args->ioctl_return = -1; |
---|
161 | return RTEMS_UNSATISFIED; |
---|
162 | } |
---|
163 | |
---|
164 | switch (args->command) { |
---|
165 | case FLASH_GET_SIZE: |
---|
166 | *((unsigned int *)args->buffer) = partitions[minor].length; |
---|
167 | break; |
---|
168 | case FLASH_GET_BLOCKSIZE: |
---|
169 | *((unsigned int *)args->buffer) = 128*1024; |
---|
170 | break; |
---|
171 | case FLASH_ERASE_BLOCK: |
---|
172 | eraseaddr_i = (unsigned int)args->buffer; |
---|
173 | if (eraseaddr_i >= partitions[minor].length) { |
---|
174 | args->ioctl_return = -1; |
---|
175 | return RTEMS_UNSATISFIED; |
---|
176 | } |
---|
177 | eraseaddr_i = eraseaddr_i + partitions[minor].start_address; |
---|
178 | eraseaddr = (unsigned short *)eraseaddr_i; |
---|
179 | rtems_semaphore_obtain(flash_lock, RTEMS_WAIT, RTEMS_NO_TIMEOUT); |
---|
180 | *eraseaddr = 0x0020; /* erase */ |
---|
181 | *eraseaddr = 0x00d0; |
---|
182 | while(!(*eraseaddr & 0x0080)); /* read status register, wait for ready */ |
---|
183 | *eraseaddr = 0x0050; /* clear status register */ |
---|
184 | *eraseaddr = 0x00ff; /* back to read array mode */ |
---|
185 | rtems_semaphore_release(flash_lock); |
---|
186 | break; |
---|
187 | default: |
---|
188 | args->ioctl_return = -1; |
---|
189 | return RTEMS_UNSATISFIED; |
---|
190 | } |
---|
191 | args->ioctl_return = 0; |
---|
192 | return RTEMS_SUCCESSFUL; |
---|
193 | } |
---|