source: rtems/bsps/powerpc/gen5200/ata/ata-dma-pio-single.c @ fc79b26

Last change on this file since fc79b26 was fc79b26, checked in by Sebastian Huber <sebastian.huber@…>, on Apr 23, 2018 at 10:53:28 AM

bsps: Move ATA drivers to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

  • Property mode set to 100644
File size: 5.3 KB
Line 
1/*
2 * Copyright (c) 2011-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#define NDEBUG
16
17#include <bsp/ata.h>
18
19#include <libcpu/powerpc-utility.h>
20
21#include <bsp.h>
22#include <bsp/fatal.h>
23#include <bsp/irq.h>
24
25typedef enum {
26  DATA_CURRENT = 0,
27  DATA_END,
28  DATA_REG
29} variables;
30
31typedef enum {
32  INC_0_NE = 0,
33  INC_2_NE
34} increments;
35
36/*
37 * for
38 *   idx0 = DATA_CURRENT, idx1 = DATA_REG
39 *   idx0 != DATA_END
40 *   idx0 += 2, idx1 += 0
41 * do
42 *   *idx0 = *idx1 [INT, 16 bit] OR *idx1 = *idx0 [INT, 16 bit]
43 */
44static const uint32_t ops[] = {
45  LCD(0, VAR(DATA_CURRENT), 0, VAR(DATA_REG), TERM_FIRST, VAR(DATA_END), INC_2_NE, INC_0_NE),
46    0, /* Transfer opcode, see transfer() */
47};
48
49static bool is_last_transfer(const ata_driver_dma_pio_single *self)
50{
51  return self->transfer_current + 1 == self->transfer_end;
52}
53
54static void start_sector_transfer(ata_driver_dma_pio_single *self)
55{
56  uint16_t *current = ata_sg_get_sector_data_begin(&self->sg_context, self->transfer_current);
57  bestcomm_task_set_variable(&self->task, DATA_CURRENT, (uint32_t) current);
58  bestcomm_task_set_variable(&self->task, DATA_END, (uint32_t) ata_sg_get_sector_data_end(&self->sg_context, current));
59  bestcomm_task_start(&self->task);
60
61  bool last = is_last_transfer(self);
62  ++self->transfer_current;
63
64  if (!last) {
65    ata_flush_sector(ata_sg_get_sector_data_begin(&self->sg_context, self->transfer_current));
66  }
67}
68
69static void dma_pio_single_interrupt_handler(void *arg)
70{
71  ata_driver_dma_pio_single *self = arg;
72  bool ok = ata_check_status();
73  bool send_event = false;
74  if (ok && self->transfer_current != self->transfer_end) {
75    bool enable_dma_interrupt = self->read && is_last_transfer(self);
76    if (enable_dma_interrupt) {
77      bestcomm_task_irq_clear(&self->task);
78      bestcomm_task_irq_enable(&self->task);
79    }
80
81    start_sector_transfer(self);
82  } else {
83    send_event = true;
84  }
85
86  if (send_event) {
87    bestcomm_task_wakeup_event_task(&self->task);
88  }
89}
90
91static bool transfer_dma_pio_single(ata_driver *super, bool read, rtems_blkdev_sg_buffer *sg, size_t sg_count)
92{
93  bool ok = true;
94  ata_driver_dma_pio_single *self = (ata_driver_dma_pio_single *) super;
95
96  self->read = read;
97  ata_sg_reset(&self->sg_context, sg, sg_count);
98  rtems_blkdev_bnum start_sector = ata_sg_get_start_sector(&self->sg_context);
99  rtems_blkdev_bnum sector_count = ata_sg_get_sector_count(&self->sg_context);
100  rtems_blkdev_bnum relative_sector = 0;
101
102  ata_flush_sector(ata_sg_get_sector_data_begin(&self->sg_context, relative_sector));
103
104  uint8_t command = ata_read_or_write_sectors_command(read);
105
106  uint32_t opcode;
107  if (read) {
108    opcode = DRD1A(INT, INIT_ALWAYS, DEST_DEREF_IDX(0), SZ_16, SRC_DEREF_IDX(1), SZ_16);
109  } else {
110    opcode = DRD1A(INT, INIT_ALWAYS, DEST_DEREF_IDX(1), SZ_16, SRC_DEREF_IDX(0), SZ_16);
111  }
112
113  bestcomm_task_irq_disable(&self->task);
114  bestcomm_task_associate_with_current_task(&self->task);
115
116  size_t transfer_opcode_index = 1; /* See ops */
117  bestcomm_task_set_opcode(&self->task, transfer_opcode_index, opcode);
118
119  while (ok && relative_sector < sector_count) {
120    rtems_blkdev_bnum remaining_sectors = sector_count - relative_sector;
121    rtems_blkdev_bnum transfer_count = ata_max_transfer_count(remaining_sectors);
122
123    self->transfer_current = relative_sector;
124    self->transfer_end = relative_sector + transfer_count;
125
126    ok = ata_execute_io_command(command, start_sector + relative_sector, transfer_count);
127    if (ok) {
128      if (!read) {
129        ok = ata_wait_for_data_request();
130        assert(ok);
131
132        rtems_interrupt_level level;
133        rtems_interrupt_disable(level);
134        start_sector_transfer(self);
135        rtems_interrupt_enable(level);
136      }
137
138      bestcomm_task_wait(&self->task);
139
140      ok = ata_check_status();
141
142      relative_sector += ATA_PER_TRANSFER_SECTOR_COUNT_MAX;
143    }
144  }
145
146  return ok;
147}
148
149static int io_control_dma_pio_single(
150  rtems_disk_device *dd,
151  uint32_t cmd,
152  void *arg
153)
154{
155  return ata_driver_io_control(dd, cmd, arg, transfer_dma_pio_single);
156}
157
158void ata_driver_dma_pio_single_create(ata_driver_dma_pio_single *self, const char *device_file_path, TaskId task_index)
159{
160  ata_driver_create(&self->super, device_file_path, io_control_dma_pio_single);
161
162  self->read = false;
163
164  if (ata_driver_is_card_present(&self->super)) {
165    bestcomm_task_create_and_load(&self->task, task_index, ops, sizeof(ops));
166
167    bestcomm_task_set_variable(&self->task, DATA_REG, (uint32_t) &ATA->write.data);
168
169    bestcomm_task_set_increment_and_condition(&self->task, INC_0_NE, 0, COND_NE);
170    bestcomm_task_set_increment_and_condition(&self->task, INC_2_NE, 2, COND_NE);
171
172    bestcomm_task_enable_combined_write(&self->task, true);
173    bestcomm_task_enable_read_buffer(&self->task, true);
174    bestcomm_task_enable_speculative_read(&self->task, true);
175
176    ata_clear_interrupts();
177
178    rtems_status_code sc = rtems_interrupt_handler_install(
179      BSP_SIU_IRQ_ATA,
180      "ATA",
181      RTEMS_INTERRUPT_UNIQUE,
182      dma_pio_single_interrupt_handler,
183      self
184    );
185    if (sc != RTEMS_SUCCESSFUL) {
186      bsp_fatal(MPC5200_FATAL_ATA_DMA_SINGLE_IRQ_INSTALL);
187    }
188  }
189}
Note: See TracBrowser for help on using the repository browser.