source: rtems/bsps/powerpc/gen5200/include/bsp/ata.h

Last change on this file was bcef89f2, checked in by Sebastian Huber <sebastian.huber@…>, on 05/19/23 at 06:18:25

Update company name

The embedded brains GmbH & Co. KG is the legal successor of embedded
brains GmbH.

  • Property mode set to 100644
File size: 9.1 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/*
4 * Copyright (C) 2010, 2013 embedded brains GmbH & Co. KG
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#ifndef GEN5200_ATA_H
29#define GEN5200_ATA_H
30
31#include "bestcomm.h"
32
33#include <assert.h>
34
35#include <rtems.h>
36#include <rtems/diskdevs.h>
37#include <rtems/bdbuf.h>
38
39#include <libchip/ata_internal.h>
40#include <libchip/ide_ctrl_io.h>
41#include <libchip/ide_ctrl_cfg.h>
42
43#include <libcpu/powerpc-utility.h>
44
45#ifdef __cplusplus
46extern "C" {
47#endif /* __cplusplus */
48
49#define DCTRL_SRST BSP_BBIT8(5)
50#define DCTRL_NIEN BSP_BBIT8(6)
51
52#define DAST_BSY BSP_BBIT8(0)
53#define DAST_DRDY BSP_BBIT8(1)
54#define DAST_DRQ BSP_BBIT8(4)
55#define DAST_ERR BSP_BBIT8(7)
56
57#define DST_BSY BSP_BBIT16(0)
58#define DST_DRDY BSP_BBIT16(1)
59#define DST_DRQ BSP_BBIT16(4)
60#define DST_ERR BSP_BBIT16(7)
61
62#define DDMA_HUT BSP_BBIT8(1)
63#define DDMA_FR BSP_BBIT8(2)
64#define DDMA_FE BSP_BBIT8(3)
65#define DDMA_IE BSP_BBIT8(4)
66#define DDMA_UDMA BSP_BBIT8(5)
67#define DDMA_READ BSP_BBIT8(6)
68#define DDMA_WRITE BSP_BBIT8(7)
69
70#define ATA_SECTOR_SHIFT 9
71
72#define ATA_PER_TRANSFER_SECTOR_COUNT_MAX 256
73
74typedef union {
75  struct {
76    uint8_t alternate_status;
77    uint8_t reserved_0[3];
78    uint16_t data;
79    uint8_t reserved_1[2];
80    uint8_t error;
81    uint8_t reserved_2[3];
82    uint8_t sector_count;
83    uint8_t reserved_3[3];
84    uint8_t sector;
85    uint8_t reserved_4[3];
86    uint8_t cylinder_low;
87    uint8_t reserved_5[3];
88    uint8_t cylinder_high;
89    uint8_t reserved_6[3];
90    uint8_t head;
91    uint8_t reserved_7[3];
92    uint16_t status;
93    uint8_t reserved_8[2];
94  } read;
95
96  struct {
97    uint8_t control;
98    uint8_t reserved_0[3];
99    uint16_t data;
100    uint8_t reserved_1[2];
101    uint8_t feature;
102    uint8_t reserved_2[3];
103    uint8_t sector_count;
104    uint8_t reserved_3[3];
105    uint8_t sector;
106    uint8_t reserved_4[3];
107    uint8_t cylinder_low;
108    uint8_t reserved_5[3];
109    uint8_t cylinder_high;
110    uint8_t reserved_6[3];
111    uint8_t head;
112    uint8_t reserved_7[3];
113    uint8_t command;
114    uint8_t dma_control;
115    uint8_t reserved_8[2];
116  } write;
117} ata_drive_registers;
118
119#define ATA ((volatile ata_drive_registers *) 0xf0003a5c)
120
121static inline bool ata_is_data_request(void)
122{
123  return (ATA->read.alternate_status & DAST_DRQ) != 0;
124}
125
126static inline bool ata_is_drive_ready_for_selection(void)
127{
128  return (ATA->read.alternate_status & (DAST_BSY | DAST_DRQ)) == 0;
129}
130
131static inline void ata_wait_400_nano_seconds(void)
132{
133  ATA->read.alternate_status;
134}
135
136static inline void ata_wait_for_drive_ready(void)
137{
138  while ((ATA->read.alternate_status & (DAST_BSY | DAST_DRQ | DAST_DRDY)) != DAST_DRDY) {
139    /* Wait */
140  }
141}
142
143static inline void ata_wait_for_not_busy(void)
144{
145  ata_wait_400_nano_seconds();
146
147  while ((ATA->read.alternate_status & DAST_BSY) != 0) {
148    /* Wait */
149  }
150}
151
152static inline bool ata_wait_for_data_request(void)
153{
154  ata_wait_400_nano_seconds();
155
156  uint8_t alternate_status;
157  do {
158    alternate_status = ATA->read.alternate_status;
159  } while ((alternate_status & DAST_BSY) == DAST_BSY);
160
161  return (alternate_status & (DAST_ERR | DAST_DRQ)) == DAST_DRQ;
162}
163
164static inline bool ata_check_status(void)
165{
166  return (ATA->read.status & (DST_BSY | DST_ERR)) == 0;
167}
168
169static inline void ata_clear_interrupts(void)
170{
171  ATA->read.status;
172}
173
174static inline uint8_t ata_read_or_write_sectors_command(bool read)
175{
176  return read ? 0x20 : 0x30;
177}
178
179static inline rtems_blkdev_bnum ata_max_transfer_count(rtems_blkdev_bnum sector_count)
180{
181  return sector_count > ATA_PER_TRANSFER_SECTOR_COUNT_MAX ?
182    ATA_PER_TRANSFER_SECTOR_COUNT_MAX
183      : sector_count;
184}
185
186static inline void ata_flush_sector(uint16_t *begin)
187{
188  /* XXX: The dcbi operation does not work properly */
189  rtems_cache_flush_multiple_data_lines(begin, ATA_SECTOR_SIZE);
190}
191
192void ata_reset_device(void);
193
194bool ata_set_transfer_mode(uint8_t mode);
195
196bool ata_execute_io_command(uint8_t command, uint32_t lba, uint32_t sector_count);
197
198static inline bool ata_execute_io_command_with_sg(uint8_t command, const rtems_blkdev_sg_buffer *sg)
199{
200  uint32_t lba = sg->block;
201  uint32_t sector_count = sg->length / ATA_SECTOR_SIZE;
202  return ata_execute_io_command(command, lba, sector_count);
203}
204
205typedef struct {
206  const rtems_blkdev_sg_buffer *sg;
207
208  size_t sg_count;
209
210  rtems_blkdev_bnum sg_buffer_offset_mask;
211
212  int sg_index_shift;
213} ata_sg_context;
214
215static inline void ata_sg_reset(ata_sg_context *self, const rtems_blkdev_sg_buffer *sg, size_t sg_count)
216{
217  self->sg = sg;
218  self->sg_count = sg_count;
219  uint32_t sectors_per_buffer = self->sg[0].length >> ATA_SECTOR_SHIFT;
220  self->sg_buffer_offset_mask = sectors_per_buffer - 1;
221  self->sg_index_shift = __builtin_ffs((int) sectors_per_buffer) - 1;
222}
223
224static inline void ata_sg_create_default(ata_sg_context *self)
225{
226  ata_sg_reset(self, NULL, 0);
227}
228
229static inline void ata_sg_create(ata_sg_context *self, const rtems_blkdev_sg_buffer *sg, size_t sg_count)
230{
231  ata_sg_reset(self, sg, sg_count);
232}
233
234static inline rtems_blkdev_bnum ata_sg_get_start_sector(const ata_sg_context *self)
235{
236  return self->sg[0].block;
237}
238
239static inline rtems_blkdev_bnum ata_sg_get_sector_count(const ata_sg_context *self)
240{
241  return (self->sg_buffer_offset_mask + 1) * self->sg_count;
242}
243
244static inline uint16_t *ata_sg_get_sector_data_begin(const ata_sg_context *self, rtems_blkdev_bnum relative_sector)
245{
246  uint16_t *begin = (uint16_t *)(self->sg[relative_sector >> self->sg_index_shift].buffer);
247
248  return begin + ((relative_sector & self->sg_buffer_offset_mask) << (ATA_SECTOR_SHIFT - 1));
249}
250
251static inline uint16_t *ata_sg_get_sector_data_end(const ata_sg_context *self, uint16_t *begin)
252{
253  return begin + ATA_SECTOR_SIZE / 2;
254}
255
256typedef struct {
257  rtems_id lock;
258
259  bool card_present;
260} ata_driver;
261
262void ata_driver_create(ata_driver *self, const char *device_file_path, rtems_block_device_ioctl io_control);
263
264void ata_driver_destroy(ata_driver *self);
265
266static inline void ata_driver_lock(const ata_driver *self)
267{
268  rtems_status_code sc = rtems_semaphore_obtain(self->lock, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
269  assert(sc == RTEMS_SUCCESSFUL);
270  (void) sc;
271}
272
273static inline void ata_driver_unlock(const ata_driver *self)
274{
275  rtems_status_code sc = rtems_semaphore_release(self->lock);
276  assert(sc == RTEMS_SUCCESSFUL);
277  (void) sc;
278}
279
280static inline bool ata_driver_is_card_present(const ata_driver *self)
281{
282  return self->card_present;
283}
284
285static inline void ata_driver_io_request(
286  ata_driver *self,
287  rtems_blkdev_request *request,
288  bool (*transfer)(ata_driver *, bool, rtems_blkdev_sg_buffer *, size_t)
289)
290{
291  assert(request->req == RTEMS_BLKDEV_REQ_READ || request->req == RTEMS_BLKDEV_REQ_WRITE);
292  bool read = request->req != RTEMS_BLKDEV_REQ_WRITE;
293  rtems_blkdev_sg_buffer *sg = &request->bufs[0];
294  uint32_t sg_count = request->bufnum;
295  ata_driver_lock(self);
296  bool ok = (*transfer)(self, read, sg, sg_count);
297  ata_driver_unlock(self);
298  rtems_status_code sc = ok ? RTEMS_SUCCESSFUL : RTEMS_IO_ERROR;
299  rtems_blkdev_request_done(request, sc);
300}
301
302static inline int ata_driver_io_control(
303  rtems_disk_device *dd,
304  uint32_t cmd,
305  void *arg,
306  bool (*transfer)(ata_driver *, bool, rtems_blkdev_sg_buffer *, size_t)
307)
308{
309  ata_driver *self = (ata_driver *) rtems_disk_get_driver_data(dd);
310
311  switch (cmd) {
312    case RTEMS_BLKIO_REQUEST:
313      ata_driver_io_request(self, (rtems_blkdev_request *) arg, transfer);
314      return 0;
315    case RTEMS_BLKIO_CAPABILITIES:
316      *(uint32_t *) arg = RTEMS_BLKDEV_CAP_MULTISECTOR_CONT;
317      return 0;
318    default:
319      return rtems_blkdev_ioctl(dd, cmd, arg);
320  }
321}
322
323int ata_driver_io_control_pio_polled(
324  rtems_disk_device *dd,
325  uint32_t cmd,
326  void *arg
327);
328
329typedef struct {
330  ata_driver super;
331
332  bestcomm_task task;
333
334  bool read;
335
336  ata_sg_context sg_context;
337
338  rtems_blkdev_bnum transfer_current;
339
340  rtems_blkdev_bnum transfer_end;
341} ata_driver_dma_pio_single;
342
343void ata_driver_dma_pio_single_create(
344  ata_driver_dma_pio_single *self,
345  const char *device_file_path,
346  TaskId task_index
347);
348
349#ifdef __cplusplus
350}
351#endif /* __cplusplus */
352
353#endif /* GEN5200_ATA_H */
Note: See TracBrowser for help on using the repository browser.