RTEMS  5.1
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
ata.h
1 /*
2  * Copyright (c) 2010-2013 embedded brains GmbH. All rights reserved.
3  *
4  * embedded brains GmbH
5  * Dornierstr. 4
6  * 82178 Puchheim
7  * Germany
8  * <rtems@embedded-brains.de>
9  *
10  * The license and distribution terms for this file may be
11  * found in the file LICENSE in this distribution or at
12  * http://www.rtems.org/license/LICENSE.
13  */
14 
15 #ifndef GEN5200_ATA_H
16 #define GEN5200_ATA_H
17 
18 #include "bestcomm.h"
19 
20 #include <assert.h>
21 
22 #include <rtems.h>
23 #include <rtems/diskdevs.h>
24 #include <rtems/bdbuf.h>
25 
26 #include <libchip/ata_internal.h>
27 #include <libchip/ide_ctrl_io.h>
28 #include <libchip/ide_ctrl_cfg.h>
29 
30 #include <libcpu/powerpc-utility.h>
31 
32 #ifdef __cplusplus
33 extern "C" {
34 #endif /* __cplusplus */
35 
36 #define DCTRL_SRST BSP_BBIT8(5)
37 #define DCTRL_NIEN BSP_BBIT8(6)
38 
39 #define DAST_BSY BSP_BBIT8(0)
40 #define DAST_DRDY BSP_BBIT8(1)
41 #define DAST_DRQ BSP_BBIT8(4)
42 #define DAST_ERR BSP_BBIT8(7)
43 
44 #define DST_BSY BSP_BBIT16(0)
45 #define DST_DRDY BSP_BBIT16(1)
46 #define DST_DRQ BSP_BBIT16(4)
47 #define DST_ERR BSP_BBIT16(7)
48 
49 #define DDMA_HUT BSP_BBIT8(1)
50 #define DDMA_FR BSP_BBIT8(2)
51 #define DDMA_FE BSP_BBIT8(3)
52 #define DDMA_IE BSP_BBIT8(4)
53 #define DDMA_UDMA BSP_BBIT8(5)
54 #define DDMA_READ BSP_BBIT8(6)
55 #define DDMA_WRITE BSP_BBIT8(7)
56 
57 #define ATA_SECTOR_SHIFT 9
58 
59 #define ATA_PER_TRANSFER_SECTOR_COUNT_MAX 256
60 
61 typedef union {
62  struct {
63  uint8_t alternate_status;
64  uint8_t reserved_0[3];
65  uint16_t data;
66  uint8_t reserved_1[2];
67  uint8_t error;
68  uint8_t reserved_2[3];
69  uint8_t sector_count;
70  uint8_t reserved_3[3];
71  uint8_t sector;
72  uint8_t reserved_4[3];
73  uint8_t cylinder_low;
74  uint8_t reserved_5[3];
75  uint8_t cylinder_high;
76  uint8_t reserved_6[3];
77  uint8_t head;
78  uint8_t reserved_7[3];
79  uint16_t status;
80  uint8_t reserved_8[2];
81  } read;
82 
83  struct {
84  uint8_t control;
85  uint8_t reserved_0[3];
86  uint16_t data;
87  uint8_t reserved_1[2];
88  uint8_t feature;
89  uint8_t reserved_2[3];
90  uint8_t sector_count;
91  uint8_t reserved_3[3];
92  uint8_t sector;
93  uint8_t reserved_4[3];
94  uint8_t cylinder_low;
95  uint8_t reserved_5[3];
96  uint8_t cylinder_high;
97  uint8_t reserved_6[3];
98  uint8_t head;
99  uint8_t reserved_7[3];
100  uint8_t command;
101  uint8_t dma_control;
102  uint8_t reserved_8[2];
103  } write;
105 
106 #define ATA ((volatile ata_drive_registers *) 0xf0003a5c)
107 
108 static inline bool ata_is_data_request(void)
109 {
110  return (ATA->read.alternate_status & DAST_DRQ) != 0;
111 }
112 
113 static inline bool ata_is_drive_ready_for_selection(void)
114 {
115  return (ATA->read.alternate_status & (DAST_BSY | DAST_DRQ)) == 0;
116 }
117 
118 static inline void ata_wait_400_nano_seconds(void)
119 {
120  ATA->read.alternate_status;
121 }
122 
123 static inline void ata_wait_for_drive_ready(void)
124 {
125  while ((ATA->read.alternate_status & (DAST_BSY | DAST_DRQ | DAST_DRDY)) != DAST_DRDY) {
126  /* Wait */
127  }
128 }
129 
130 static inline void ata_wait_for_not_busy(void)
131 {
132  ata_wait_400_nano_seconds();
133 
134  while ((ATA->read.alternate_status & DAST_BSY) != 0) {
135  /* Wait */
136  }
137 }
138 
139 static inline bool ata_wait_for_data_request(void)
140 {
141  ata_wait_400_nano_seconds();
142 
143  uint8_t alternate_status;
144  do {
145  alternate_status = ATA->read.alternate_status;
146  } while ((alternate_status & DAST_BSY) == DAST_BSY);
147 
148  return (alternate_status & (DAST_ERR | DAST_DRQ)) == DAST_DRQ;
149 }
150 
151 static inline bool ata_check_status(void)
152 {
153  return (ATA->read.status & (DST_BSY | DST_ERR)) == 0;
154 }
155 
156 static inline void ata_clear_interrupts(void)
157 {
158  ATA->read.status;
159 }
160 
161 static inline uint8_t ata_read_or_write_sectors_command(bool read)
162 {
163  return read ? 0x20 : 0x30;
164 }
165 
166 static inline rtems_blkdev_bnum ata_max_transfer_count(rtems_blkdev_bnum sector_count)
167 {
168  return sector_count > ATA_PER_TRANSFER_SECTOR_COUNT_MAX ?
169  ATA_PER_TRANSFER_SECTOR_COUNT_MAX
170  : sector_count;
171 }
172 
173 static inline void ata_flush_sector(uint16_t *begin)
174 {
175  /* XXX: The dcbi operation does not work properly */
176  rtems_cache_flush_multiple_data_lines(begin, ATA_SECTOR_SIZE);
177 }
178 
179 void ata_reset_device(void);
180 
181 bool ata_set_transfer_mode(uint8_t mode);
182 
183 bool ata_execute_io_command(uint8_t command, uint32_t lba, uint32_t sector_count);
184 
185 static inline bool ata_execute_io_command_with_sg(uint8_t command, const rtems_blkdev_sg_buffer *sg)
186 {
187  uint32_t lba = sg->block;
188  uint32_t sector_count = sg->length / ATA_SECTOR_SIZE;
189  return ata_execute_io_command(command, lba, sector_count);
190 }
191 
192 typedef struct {
193  const rtems_blkdev_sg_buffer *sg;
194 
195  size_t sg_count;
196 
197  rtems_blkdev_bnum sg_buffer_offset_mask;
198 
199  int sg_index_shift;
201 
202 static inline void ata_sg_reset(ata_sg_context *self, const rtems_blkdev_sg_buffer *sg, size_t sg_count)
203 {
204  self->sg = sg;
205  self->sg_count = sg_count;
206  uint32_t sectors_per_buffer = self->sg[0].length >> ATA_SECTOR_SHIFT;
207  self->sg_buffer_offset_mask = sectors_per_buffer - 1;
208  self->sg_index_shift = __builtin_ffs((int) sectors_per_buffer) - 1;
209 }
210 
211 static inline void ata_sg_create_default(ata_sg_context *self)
212 {
213  ata_sg_reset(self, NULL, 0);
214 }
215 
216 static inline void ata_sg_create(ata_sg_context *self, const rtems_blkdev_sg_buffer *sg, size_t sg_count)
217 {
218  ata_sg_reset(self, sg, sg_count);
219 }
220 
221 static inline rtems_blkdev_bnum ata_sg_get_start_sector(const ata_sg_context *self)
222 {
223  return self->sg[0].block;
224 }
225 
226 static inline rtems_blkdev_bnum ata_sg_get_sector_count(const ata_sg_context *self)
227 {
228  return (self->sg_buffer_offset_mask + 1) * self->sg_count;
229 }
230 
231 static inline uint16_t *ata_sg_get_sector_data_begin(const ata_sg_context *self, rtems_blkdev_bnum relative_sector)
232 {
233  uint16_t *begin = (uint16_t *)(self->sg[relative_sector >> self->sg_index_shift].buffer);
234 
235  return begin + ((relative_sector & self->sg_buffer_offset_mask) << (ATA_SECTOR_SHIFT - 1));
236 }
237 
238 static inline uint16_t *ata_sg_get_sector_data_end(const ata_sg_context *self, uint16_t *begin)
239 {
240  return begin + ATA_SECTOR_SIZE / 2;
241 }
242 
243 typedef struct {
244  rtems_id lock;
245 
246  bool card_present;
247 } ata_driver;
248 
249 void ata_driver_create(ata_driver *self, const char *device_file_path, rtems_block_device_ioctl io_control);
250 
251 void ata_driver_destroy(ata_driver *self);
252 
253 static inline void ata_driver_lock(const ata_driver *self)
254 {
256  assert(sc == RTEMS_SUCCESSFUL);
257  (void) sc;
258 }
259 
260 static inline void ata_driver_unlock(const ata_driver *self)
261 {
263  assert(sc == RTEMS_SUCCESSFUL);
264  (void) sc;
265 }
266 
267 static inline bool ata_driver_is_card_present(const ata_driver *self)
268 {
269  return self->card_present;
270 }
271 
272 static inline void ata_driver_io_request(
273  ata_driver *self,
274  rtems_blkdev_request *request,
275  bool (*transfer)(ata_driver *, bool, rtems_blkdev_sg_buffer *, size_t)
276 )
277 {
278  assert(request->req == RTEMS_BLKDEV_REQ_READ || request->req == RTEMS_BLKDEV_REQ_WRITE);
279  bool read = request->req != RTEMS_BLKDEV_REQ_WRITE;
280  rtems_blkdev_sg_buffer *sg = &request->bufs[0];
281  uint32_t sg_count = request->bufnum;
282  ata_driver_lock(self);
283  bool ok = (*transfer)(self, read, sg, sg_count);
284  ata_driver_unlock(self);
286  rtems_blkdev_request_done(request, sc);
287 }
288 
289 static inline int ata_driver_io_control(
290  rtems_disk_device *dd,
291  uint32_t cmd,
292  void *arg,
293  bool (*transfer)(ata_driver *, bool, rtems_blkdev_sg_buffer *, size_t)
294 )
295 {
296  ata_driver *self = (ata_driver *) rtems_disk_get_driver_data(dd);
297 
298  switch (cmd) {
299  case RTEMS_BLKIO_REQUEST:
300  ata_driver_io_request(self, (rtems_blkdev_request *) arg, transfer);
301  return 0;
302  case RTEMS_BLKIO_CAPABILITIES:
303  *(uint32_t *) arg = RTEMS_BLKDEV_CAP_MULTISECTOR_CONT;
304  return 0;
305  default:
306  return rtems_blkdev_ioctl(dd, cmd, arg);
307  }
308 }
309 
310 int ata_driver_io_control_pio_polled(
311  rtems_disk_device *dd,
312  uint32_t cmd,
313  void *arg
314 );
315 
316 typedef struct {
317  ata_driver super;
318 
319  bestcomm_task task;
320 
321  bool read;
322 
323  ata_sg_context sg_context;
324 
325  rtems_blkdev_bnum transfer_current;
326 
327  rtems_blkdev_bnum transfer_end;
329 
330 void ata_driver_dma_pio_single_create(
332  const char *device_file_path,
333  TaskId task_index
334 );
335 
336 #ifdef __cplusplus
337 }
338 #endif /* __cplusplus */
339 
340 #endif /* GEN5200_ATA_H */
Definition: status.h:47
ssize_t read(int fd, void *buffer, size_t count)
Definition: read.c:27
uint32_t rtems_blkdev_bnum
Block device block index type.
Definition: diskdevs.h:45
int(* rtems_block_device_ioctl)(rtems_disk_device *dd, uint32_t req, void *argp)
Block device IO control handler type.
Definition: diskdevs.h:50
Definition: ata.h:243
ssize_t write(int fd, const void *buffer, size_t count)
Definition: write.c:30
uint32_t bufnum
Definition: blkdev.h:126
void rtems_cache_flush_multiple_data_lines(const void *d_addr, size_t n_bytes)
Flushes multiple data cache lines.
Definition: cacheimpl.h:109
Description of a disk device (logical and physical disks).
Definition: diskdevs.h:157
Information for the Assert Handler.
General purpose assembler macros, linker command file support and some inline functions for direct re...
The block device transfer request is used to read or write a number of blocks from or to the device.
Definition: blkdev.h:102
rtems_status_code
Classic API Status.
Definition: status.h:43
rtems_status_code rtems_semaphore_release(rtems_id id)
RTEMS Semaphore Release.
Definition: semrelease.c:28
Definition: ata.h:316
Definition: ata.h:61
rtems_status_code rtems_semaphore_obtain(rtems_id id, rtems_option option_set, rtems_interval timeout)
RTEMS Obtain Semaphore.
Definition: semobtain.c:51
Block Device Disk Management API.
Definition: ata.h:192
Definition: blkdev.h:50
Block device scatter or gather buffer structure.
Definition: blkdev.h:68
#define RTEMS_WAIT
Definition: options.h:53
Definition: bestcomm.h:127
Definition: intercom.c:74
rtems_blkdev_bnum block
Definition: blkdev.h:72
#define RTEMS_BLKDEV_CAP_MULTISECTOR_CONT
Only consecutive multi-sector buffer requests are supported.
Definition: blkdev.h:264
Definition: blkdev.h:51
uint32_t length
Definition: blkdev.h:77
int rtems_blkdev_ioctl(rtems_disk_device *dd, uint32_t req, void *argp)
Common IO control primitive.
Definition: blkdev-ioctl.c:24
#define RTEMS_NO_TIMEOUT
Constant for indefinite wait.
Definition: rtems.h:174
Objects_Id rtems_id
Used to manage and manipulate RTEMS object identifiers.
Definition: types.h:83
rtems_blkdev_request_op req
Definition: blkdev.h:106
rtems_blkdev_sg_buffer bufs[RTEMS_ZERO_LENGTH_ARRAY]
Definition: blkdev.h:145
Definition: status.h:168
Block Device Buffer Management.
#define NULL
Requests a GPIO pin group configuration.
Definition: bestcomm_api.h:77