[rtems commit] bsp/gen5200: New ATA driver

Sebastian Huber sebh at rtems.org
Wed Feb 20 08:21:08 UTC 2013


Module:    rtems
Branch:    master
Commit:    57bcb88ef5348a18ae22bd45ac42b0a2646a3264
Changeset: http://git.rtems.org/rtems/commit/?id=57bcb88ef5348a18ae22bd45ac42b0a2646a3264

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Mon Feb 18 17:00:28 2013 +0100

bsp/gen5200: New ATA driver

This is a replacement for the ATA task.  The performance is much better.

---

 c/src/lib/libbsp/powerpc/gen5200/Makefile.am       |   74 +++--
 .../powerpc/gen5200/ide/ata-dma-pio-single.c       |  188 ++++++++++
 .../lib/libbsp/powerpc/gen5200/ide/ata-instance.c  |   40 +++
 c/src/lib/libbsp/powerpc/gen5200/ide/ata.c         |  231 ++++++++++++
 c/src/lib/libbsp/powerpc/gen5200/include/ata.h     |  338 ++++++++++++++++++
 .../lib/libbsp/powerpc/gen5200/include/bestcomm.h  |  370 ++++++++++++++++++++
 .../libbsp/powerpc/gen5200/include/bestcomm_ops.h  |  224 ++++++++++++
 c/src/lib/libbsp/powerpc/gen5200/include/bsp.h     |    5 +-
 c/src/lib/libbsp/powerpc/gen5200/preinstall.am     |   34 ++-
 .../lib/libbsp/powerpc/gen5200/startup/bestcomm.c  |  107 ++++++
 10 files changed, 1566 insertions(+), 45 deletions(-)

diff --git a/c/src/lib/libbsp/powerpc/gen5200/Makefile.am b/c/src/lib/libbsp/powerpc/gen5200/Makefile.am
index a1cf57d..68bddd7 100644
--- a/c/src/lib/libbsp/powerpc/gen5200/Makefile.am
+++ b/c/src/lib/libbsp/powerpc/gen5200/Makefile.am
@@ -83,20 +83,27 @@ libbsp_a_SOURCES += console/console.c
 libbsp_a_SOURCES += i2c/i2c.c i2c/i2cdrv.c i2c/mpc5200mbus.c i2c/mpc5200mbus.h
 # ide
 libbsp_a_SOURCES += ide/idecfg.c ide/pcmcia_ide.c ide/pcmcia_ide.h
-
-include_bsp_HEADERS = ../../shared/include/irq-generic.h \
-	../../shared/include/irq-info.h \
-	../../shared/include/utility.h \
-	../../shared/include/bootcard.h \
-	../../shared/include/u-boot.h \
-	../shared/include/u-boot-board-info.h \
-	include/irq.h \
-	include/i2cdrv.h \
-	include/i2c.h \
-	include/mpc5200.h \
-	include/mscan-base.h \
-	include/u-boot-config.h \
-	mscan/mscan.h
+libbsp_a_SOURCES += ide/ata.c
+libbsp_a_SOURCES += ide/ata-instance.c
+libbsp_a_SOURCES += ide/ata-dma-pio-single.c
+
+include_bsp_HEADERS =
+include_bsp_HEADERS += ../../shared/include/bootcard.h
+include_bsp_HEADERS += ../../shared/include/irq-generic.h
+include_bsp_HEADERS += ../../shared/include/irq-info.h
+include_bsp_HEADERS += ../../shared/include/u-boot.h
+include_bsp_HEADERS += ../../shared/include/utility.h
+include_bsp_HEADERS += ../shared/include/u-boot-board-info.h
+include_bsp_HEADERS += include/ata.h
+include_bsp_HEADERS += include/bestcomm.h
+include_bsp_HEADERS += include/bestcomm_ops.h
+include_bsp_HEADERS += include/i2cdrv.h
+include_bsp_HEADERS += include/i2c.h
+include_bsp_HEADERS += include/irq.h
+include_bsp_HEADERS += include/mpc5200.h
+include_bsp_HEADERS += include/mscan-base.h
+include_bsp_HEADERS += include/u-boot-config.h
+include_bsp_HEADERS += mscan/mscan.h
 
 # irq
 libbsp_a_SOURCES += include/irq.h \
@@ -123,25 +130,26 @@ libbsp_a_SOURCES += tod/todcfg.c tod/pcf8563.c tod/pcf8563.h \
     ../../shared/tod.c
 
 # startup
-libbsp_a_SOURCES += ../../shared/bootcard.c \
-	../../shared/bsplibc.c \
-	../../shared/bsppost.c \
-	../../shared/bsppretaskinghook.c \
-	../../shared/bsppredriverhook.c \
-	../../shared/gnatinstallhandler.c \
-	../../shared/sbrk.c \
-	../../shared/src/bsp-uboot-board-info.c \
-	../shared/showbats.c \
-	../shared/uboot_dump_bdinfo.c \
-	../shared/uboot_getenv.c \
-	../../shared/bspclean.c \
-	startup/bspreset.c \
-	../../shared/bspgetworkarea.c \
-	../shared/startup/bspidle.c \
-	../shared/src/memcpy.c \
-	startup/bspstart.c \
-	startup/cpuinit.c  \
-	startup/uboot_support.c
+libbsp_a_SOURCES += ../../shared/bootcard.c
+libbsp_a_SOURCES += ../../shared/bspclean.c
+libbsp_a_SOURCES += ../../shared/bspgetworkarea.c
+libbsp_a_SOURCES += ../../shared/bsplibc.c
+libbsp_a_SOURCES += ../../shared/bsppost.c
+libbsp_a_SOURCES += ../../shared/bsppredriverhook.c
+libbsp_a_SOURCES += ../../shared/bsppretaskinghook.c
+libbsp_a_SOURCES += ../../shared/gnatinstallhandler.c
+libbsp_a_SOURCES += ../../shared/sbrk.c
+libbsp_a_SOURCES += ../../shared/src/bsp-uboot-board-info.c
+libbsp_a_SOURCES += ../shared/showbats.c
+libbsp_a_SOURCES += ../shared/src/memcpy.c
+libbsp_a_SOURCES += ../shared/startup/bspidle.c
+libbsp_a_SOURCES += ../shared/uboot_dump_bdinfo.c
+libbsp_a_SOURCES += ../shared/uboot_getenv.c
+libbsp_a_SOURCES += startup/bspreset.c
+libbsp_a_SOURCES += startup/bspstart.c
+libbsp_a_SOURCES += startup/cpuinit.c 
+libbsp_a_SOURCES += startup/uboot_support.c
+libbsp_a_SOURCES += startup/bestcomm.c
 
 if HAS_NETWORKING
 libbsp_a_SOURCES += network_5200/network.c
diff --git a/c/src/lib/libbsp/powerpc/gen5200/ide/ata-dma-pio-single.c b/c/src/lib/libbsp/powerpc/gen5200/ide/ata-dma-pio-single.c
new file mode 100644
index 0000000..dee1ca1
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/gen5200/ide/ata-dma-pio-single.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2011-2013 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems at embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#define NDEBUG
+
+#include <bsp/ata.h>
+
+#include <libcpu/powerpc-utility.h>
+
+#include <bsp.h>
+#include <bsp/irq.h>
+
+typedef enum {
+  DATA_CURRENT = 0,
+  DATA_END,
+  DATA_REG
+} variables;
+
+typedef enum {
+  INC_0_NE = 0,
+  INC_2_NE
+} increments;
+
+/*
+ * for
+ *   idx0 = DATA_CURRENT, idx1 = DATA_REG
+ *   idx0 != DATA_END
+ *   idx0 += 2, idx1 += 0
+ * do
+ *   *idx0 = *idx1 [INT, 16 bit] OR *idx1 = *idx0 [INT, 16 bit]
+ */
+static const uint32_t ops[] = {
+  LCD(0, VAR(DATA_CURRENT), 0, VAR(DATA_REG), TERM_FIRST, VAR(DATA_END), INC_2_NE, INC_0_NE),
+    0, /* Transfer opcode, see transfer() */
+};
+
+static bool is_last_transfer(const ata_driver_dma_pio_single *self)
+{
+  return self->transfer_current + 1 == self->transfer_end;
+}
+
+static void start_sector_transfer(ata_driver_dma_pio_single *self)
+{
+  uint16_t *current = ata_sg_get_sector_data_begin(&self->sg_context, self->transfer_current);
+  bestcomm_task_set_variable(&self->task, DATA_CURRENT, (uint32_t) current);
+  bestcomm_task_set_variable(&self->task, DATA_END, (uint32_t) ata_sg_get_sector_data_end(&self->sg_context, current));
+  bestcomm_task_start(&self->task);
+
+  bool last = is_last_transfer(self);
+  ++self->transfer_current;
+
+  if (!last) {
+    ata_flush_sector(ata_sg_get_sector_data_begin(&self->sg_context, self->transfer_current));
+  }
+}
+
+static void dma_pio_single_interrupt_handler(void *arg)
+{
+  ata_driver_dma_pio_single *self = arg;
+  bool ok = ata_check_status();
+  bool send_event = false;
+  if (ok && self->transfer_current != self->transfer_end) {
+    bool enable_dma_interrupt = self->read && is_last_transfer(self);
+    if (enable_dma_interrupt) {
+      bestcomm_task_irq_clear(&self->task);
+      bestcomm_task_irq_enable(&self->task);
+    }
+
+    start_sector_transfer(self);
+  } else {
+    send_event = true;
+  }
+
+  if (send_event) {
+    bestcomm_task_wakeup_event_task(&self->task);
+  }
+}
+
+static bool transfer_dma_pio_single(ata_driver *super, bool read, rtems_blkdev_sg_buffer *sg, size_t sg_count)
+{
+  bool ok = true;
+  ata_driver_dma_pio_single *self = (ata_driver_dma_pio_single *) super;
+
+  self->read = read;
+  ata_sg_reset(&self->sg_context, sg, sg_count);
+  rtems_blkdev_bnum start_sector = ata_sg_get_start_sector(&self->sg_context);
+  rtems_blkdev_bnum sector_count = ata_sg_get_sector_count(&self->sg_context);
+  rtems_blkdev_bnum relative_sector = 0;
+
+  ata_flush_sector(ata_sg_get_sector_data_begin(&self->sg_context, relative_sector));
+
+  uint8_t command = ata_read_or_write_sectors_command(read);
+
+  uint32_t opcode;
+  if (read) {
+    opcode = DRD1A(INT, INIT_ALWAYS, DEST_DEREF_IDX(0), SZ_16, SRC_DEREF_IDX(1), SZ_16);
+  } else {
+    opcode = DRD1A(INT, INIT_ALWAYS, DEST_DEREF_IDX(1), SZ_16, SRC_DEREF_IDX(0), SZ_16);
+  }
+
+  bestcomm_task_irq_disable(&self->task);
+  bestcomm_task_associate_with_current_task(&self->task);
+
+  size_t transfer_opcode_index = 1; /* See ops */
+  bestcomm_task_set_opcode(&self->task, transfer_opcode_index, opcode);
+
+  while (ok && relative_sector < sector_count) {
+    rtems_blkdev_bnum remaining_sectors = sector_count - relative_sector;
+    rtems_blkdev_bnum transfer_count = ata_max_transfer_count(remaining_sectors);
+
+    self->transfer_current = relative_sector;
+    self->transfer_end = relative_sector + transfer_count;
+
+    ok = ata_execute_io_command(command, start_sector + relative_sector, transfer_count);
+    if (ok) {
+      if (!read) {
+        ok = ata_wait_for_data_request();
+        assert(ok);
+
+        rtems_interrupt_level level;
+        rtems_interrupt_disable(level);
+        start_sector_transfer(self);
+        rtems_interrupt_enable(level);
+      }
+
+      bestcomm_task_wait(&self->task);
+
+      ok = ata_check_status();
+
+      relative_sector += ATA_PER_TRANSFER_SECTOR_COUNT_MAX;
+    }
+  }
+
+  return ok;
+}
+
+static int io_control_dma_pio_single(
+  rtems_disk_device *dd,
+  uint32_t cmd,
+  void *arg
+)
+{
+  return ata_driver_io_control(dd, cmd, arg, transfer_dma_pio_single);
+}
+
+void ata_driver_dma_pio_single_create(ata_driver_dma_pio_single *self, const char *device_file_path, TaskId task_index)
+{
+  ata_driver_create(&self->super, device_file_path, io_control_dma_pio_single);
+
+  self->read = false;
+
+  if (ata_driver_is_card_present(&self->super)) {
+    bestcomm_task_create_and_load(&self->task, task_index, ops, sizeof(ops));
+
+    bestcomm_task_set_variable(&self->task, DATA_REG, (uint32_t) &ATA->write.data);
+
+    bestcomm_task_set_increment_and_condition(&self->task, INC_0_NE, 0, COND_NE);
+    bestcomm_task_set_increment_and_condition(&self->task, INC_2_NE, 2, COND_NE);
+
+    bestcomm_task_enable_combined_write(&self->task, true);
+    bestcomm_task_enable_read_buffer(&self->task, true);
+    bestcomm_task_enable_speculative_read(&self->task, true);
+
+    ata_clear_interrupts();
+
+    rtems_status_code sc = rtems_interrupt_handler_install(
+      BSP_SIU_IRQ_ATA,
+      "ATA",
+      RTEMS_INTERRUPT_UNIQUE,
+      dma_pio_single_interrupt_handler,
+      self
+    );
+    if (sc != RTEMS_SUCCESSFUL) {
+      mpc5200_fatal(MPC5200_FATAL_ATA_DMA_SINGLE_IRQ_INSTALL);
+    }
+  }
+}
diff --git a/c/src/lib/libbsp/powerpc/gen5200/ide/ata-instance.c b/c/src/lib/libbsp/powerpc/gen5200/ide/ata-instance.c
new file mode 100644
index 0000000..60380a8
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/gen5200/ide/ata-instance.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2011-2013 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems at embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <bsp/ata.h>
+
+#include <libchip/ata.h>
+
+#include <bsp.h>
+
+static ata_driver_dma_pio_single ata_driver_instance;
+
+rtems_status_code rtems_ata_initialize(
+  rtems_device_major_number major,
+  rtems_device_minor_number minor_arg,
+  void *arg
+)
+{
+  rtems_status_code sc = rtems_disk_io_initialize();
+
+  if (sc == RTEMS_SUCCESSFUL) {
+    bestcomm_glue_init();
+
+    ata_driver_dma_pio_single_create(&ata_driver_instance, "/dev/hda", TASK_PCI_TX);
+  } else {
+    mpc5200_fatal(MPC5200_FATAL_ATA_DISK_IO_INIT);
+  }
+
+  return sc;
+}
diff --git a/c/src/lib/libbsp/powerpc/gen5200/ide/ata.c b/c/src/lib/libbsp/powerpc/gen5200/ide/ata.c
new file mode 100644
index 0000000..2fce1e1
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/gen5200/ide/ata.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2010-2013 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems at embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#define NDEBUG
+
+#include <bsp/ata.h>
+
+#include <bsp.h>
+#include <bsp/mpc5200.h>
+
+bool ata_execute_io_command(uint8_t command, uint32_t lba, uint32_t sector_count_32)
+{
+  assert(sector_count_32 >= 1);
+  assert(sector_count_32 <= 256);
+
+  assert(ata_is_drive_ready_for_selection());
+
+  ATA->write.head = (uint8_t) (0xe0 | ((lba >> 24) & 0x0f));
+
+  ata_wait_400_nano_seconds();
+  ata_wait_for_drive_ready();
+
+  /*
+   * It seems that the write to the ATA device registers is sometimes not
+   * successful.  The write is retried until the read back values are all right
+   * or a timeout is reached.
+   */
+  bool ok = false;
+  uint8_t sector = (uint8_t) lba;
+  uint8_t cylinder_low = (uint8_t) (lba >> 8);
+  uint8_t cylinder_high = (uint8_t) (lba >> 16);
+  uint8_t sector_count = (uint8_t) sector_count_32;
+  int i;
+  for (i = 0; !ok && i < 100; ++i) {
+    ATA->write.sector = sector;
+    ATA->write.cylinder_low = cylinder_low;
+    ATA->write.cylinder_high = cylinder_high;
+    ATA->write.sector_count = sector_count;
+
+    uint8_t actual_sector = ATA->read.sector;
+    uint8_t actual_cylinder_low = ATA->read.cylinder_low;
+    uint8_t actual_cylinder_high = ATA->read.cylinder_high;
+    uint8_t actual_sector_count = ATA->read.sector_count;
+
+    ok = actual_cylinder_high == cylinder_high
+      && actual_cylinder_low == cylinder_low
+      && actual_sector == sector
+      && actual_sector_count == sector_count;
+  }
+
+  if (ok) {
+    ATA->write.command = command;
+  }
+
+  return ok;
+}
+
+void ata_reset_device(void)
+{
+  ATA->write.control = DCTRL_SRST;
+  rtems_task_wake_after(1);
+  ATA->write.control = 0;
+  rtems_task_wake_after(RTEMS_MILLISECONDS_TO_TICKS(2));
+  ata_wait_for_not_busy();
+}
+
+bool ata_set_transfer_mode(uint8_t mode)
+{
+  assert(ata_is_drive_ready_for_selection());
+
+  ATA->write.head = 0xe0;
+
+  ata_wait_400_nano_seconds();
+  ata_wait_for_drive_ready();
+
+  ATA->write.feature = 0x3;
+  ATA->write.sector_count = mode;
+  ATA->write.command = 0xef;
+
+  ata_wait_for_not_busy();
+
+  return ata_check_status();
+}
+
+static bool probe()
+{
+  bool card_present = true;
+
+#ifdef BRS5L
+  volatile struct mpc5200_::mpc5200_gpt *gpt = &mpc5200.gpt[GPT2];
+
+  /* Enable card detection on GPT2 */
+  gpt->emsel = (GPT_EMSEL_GPIO_IN | GPT_EMSEL_TIMER_MS_GPIO);
+
+  /* Check for card detection (-CD0) */
+  if ((gpt->status & GPT_STATUS_PIN) != 0) {
+    card_present = false;
+  }
+#endif
+
+  return card_present;
+}
+
+static void create_lock(ata_driver *self)
+{
+  rtems_status_code sc = rtems_semaphore_create(
+    rtems_build_name('A', 'T', 'A', ' '),
+    1,
+    RTEMS_LOCAL | RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY,
+    0,
+    &self->lock
+  );
+  assert(sc == RTEMS_SUCCESSFUL);
+}
+
+static void destroy_lock(const ata_driver *self)
+{
+  rtems_status_code sc = rtems_semaphore_delete(self->lock);
+  assert(sc == RTEMS_SUCCESSFUL);
+}
+
+void ata_driver_create(ata_driver *self, const char *device_file_path, rtems_block_device_ioctl io_control)
+{
+  self->card_present = probe();
+
+  if (ata_driver_is_card_present(self)) {
+    create_lock(self);
+    ata_reset_device();
+
+    uint16_t sector_buffer[256];
+    ata_dev_t ata_device;
+    rtems_status_code sc = ata_identify_device(0, 0, sector_buffer, &ata_device);
+
+    if (sc == RTEMS_SUCCESSFUL && ata_device.lba_avaible) {
+      sc = ide_controller_config_io_speed(0, ata_device.modes_available);
+
+      if (sc == RTEMS_SUCCESSFUL) {
+        sc = rtems_blkdev_create(
+          device_file_path,
+          ATA_SECTOR_SIZE,
+          ata_device.lba_sectors,
+          io_control,
+          self
+        );
+
+        if (sc != RTEMS_SUCCESSFUL) {
+          mpc5200_fatal(MPC5200_FATAL_ATA_DISK_CREATE);
+        }
+      }
+    }
+  }
+}
+
+void ata_driver_destroy(ata_driver *self)
+{
+  destroy_lock(self);
+  /* TODO */
+  assert(0);
+}
+
+static bool transfer_pio_polled(ata_driver *self, bool read, rtems_blkdev_sg_buffer *sg, size_t sg_count)
+{
+  bool ok = true;
+
+  ata_sg_context sg_context;
+  ata_sg_create(&sg_context, sg, sg_count);
+  rtems_blkdev_bnum start_sector = ata_sg_get_start_sector(&sg_context);
+  rtems_blkdev_bnum sector_count = ata_sg_get_sector_count(&sg_context);
+  rtems_blkdev_bnum relative_sector = 0;
+
+  uint8_t command = ata_read_or_write_sectors_command(read);
+
+  while (ok && relative_sector < sector_count) {
+    rtems_blkdev_bnum remaining_sectors = sector_count - relative_sector;
+    rtems_blkdev_bnum transfer_count = ata_max_transfer_count(remaining_sectors);
+    rtems_blkdev_bnum transfer_end = relative_sector + transfer_count;
+
+    ok = ata_execute_io_command(command, start_sector + relative_sector, transfer_count);
+
+    rtems_blkdev_bnum transfer;
+    for (transfer = relative_sector; ok && transfer < transfer_end; ++transfer) {
+      uint16_t *current = ata_sg_get_sector_data_begin(&sg_context, transfer);
+      uint16_t *end = ata_sg_get_sector_data_end(&sg_context, current);
+
+      ok = ata_wait_for_data_request();
+
+      if (ok) {
+        if (read) {
+          while (current != end) {
+            *current = ATA->read.data;
+            ++current;
+          }
+        } else {
+          while (current != end) {
+            ATA->write.data = *current;
+            ++current;
+          }
+        }
+      }
+    }
+
+    if (ok) {
+      ata_wait_for_not_busy();
+      ok = ata_check_status();
+    }
+
+    relative_sector += ATA_PER_TRANSFER_SECTOR_COUNT_MAX;
+  }
+
+  return ok;
+}
+
+int ata_driver_io_control_pio_polled(
+  rtems_disk_device *dd,
+  uint32_t cmd,
+  void *arg
+)
+{
+  return ata_driver_io_control(dd, cmd, arg, transfer_pio_polled);
+}
diff --git a/c/src/lib/libbsp/powerpc/gen5200/include/ata.h b/c/src/lib/libbsp/powerpc/gen5200/include/ata.h
new file mode 100644
index 0000000..38cd536
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/gen5200/include/ata.h
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2010-2013 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems at embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef GEN5200_ATA_H
+#define GEN5200_ATA_H
+
+#include "bestcomm.h"
+
+#include <assert.h>
+
+#include <rtems.h>
+#include <rtems/diskdevs.h>
+#include <rtems/bdbuf.h>
+
+#include <libchip/ata_internal.h>
+#include <libchip/ide_ctrl_io.h>
+#include <libchip/ide_ctrl_cfg.h>
+
+#include <libcpu/powerpc-utility.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define DCTRL_SRST BSP_BBIT8(5)
+#define DCTRL_NIEN BSP_BBIT8(6)
+
+#define DAST_BSY BSP_BBIT8(0)
+#define DAST_DRDY BSP_BBIT8(1)
+#define DAST_DRQ BSP_BBIT8(4)
+#define DAST_ERR BSP_BBIT8(7)
+
+#define DST_BSY BSP_BBIT16(0)
+#define DST_DRDY BSP_BBIT16(1)
+#define DST_DRQ BSP_BBIT16(4)
+#define DST_ERR BSP_BBIT16(7)
+
+#define DDMA_HUT BSP_BBIT8(1)
+#define DDMA_FR BSP_BBIT8(2)
+#define DDMA_FE BSP_BBIT8(3)
+#define DDMA_IE BSP_BBIT8(4)
+#define DDMA_UDMA BSP_BBIT8(5)
+#define DDMA_READ BSP_BBIT8(6)
+#define DDMA_WRITE BSP_BBIT8(7)
+
+#define ATA_SECTOR_SHIFT 9
+
+#define ATA_PER_TRANSFER_SECTOR_COUNT_MAX 256
+
+typedef union {
+  struct {
+    uint8_t alternate_status;
+    uint8_t reserved_0[3];
+    uint16_t data;
+    uint8_t reserved_1[2];
+    uint8_t error;
+    uint8_t reserved_2[3];
+    uint8_t sector_count;
+    uint8_t reserved_3[3];
+    uint8_t sector;
+    uint8_t reserved_4[3];
+    uint8_t cylinder_low;
+    uint8_t reserved_5[3];
+    uint8_t cylinder_high;
+    uint8_t reserved_6[3];
+    uint8_t head;
+    uint8_t reserved_7[3];
+    uint16_t status;
+    uint8_t reserved_8[2];
+  } read;
+
+  struct {
+    uint8_t control;
+    uint8_t reserved_0[3];
+    uint16_t data;
+    uint8_t reserved_1[2];
+    uint8_t feature;
+    uint8_t reserved_2[3];
+    uint8_t sector_count;
+    uint8_t reserved_3[3];
+    uint8_t sector;
+    uint8_t reserved_4[3];
+    uint8_t cylinder_low;
+    uint8_t reserved_5[3];
+    uint8_t cylinder_high;
+    uint8_t reserved_6[3];
+    uint8_t head;
+    uint8_t reserved_7[3];
+    uint8_t command;
+    uint8_t dma_control;
+    uint8_t reserved_8[2];
+  } write;
+} ata_drive_registers;
+
+#define ATA ((volatile ata_drive_registers *) 0xf0003a5c)
+
+static inline bool ata_is_data_request(void)
+{
+  return (ATA->read.alternate_status & DAST_DRQ) != 0;
+}
+
+static inline bool ata_is_drive_ready_for_selection(void)
+{
+  return (ATA->read.alternate_status & (DAST_BSY | DAST_DRQ)) == 0;
+}
+
+static inline void ata_wait_400_nano_seconds(void)
+{
+  ATA->read.alternate_status;
+}
+
+static inline void ata_wait_for_drive_ready(void)
+{
+  while ((ATA->read.alternate_status & (DAST_BSY | DAST_DRQ | DAST_DRDY)) != DAST_DRDY) {
+    /* Wait */
+  }
+}
+
+static inline void ata_wait_for_not_busy(void)
+{
+  ata_wait_400_nano_seconds();
+
+  while ((ATA->read.alternate_status & DAST_BSY) != 0) {
+    /* Wait */
+  }
+}
+
+static inline bool ata_wait_for_data_request(void)
+{
+  ata_wait_400_nano_seconds();
+
+  uint8_t alternate_status;
+  do {
+    alternate_status = ATA->read.alternate_status;
+  } while ((alternate_status & DAST_BSY) == DAST_BSY);
+
+  return (alternate_status & (DAST_ERR | DAST_DRQ)) == DAST_DRQ;
+}
+
+static inline bool ata_check_status(void)
+{
+  return (ATA->read.status & (DST_BSY | DST_ERR)) == 0;
+}
+
+static inline void ata_clear_interrupts(void)
+{
+  ATA->read.status;
+}
+
+static inline uint8_t ata_read_or_write_sectors_command(bool read)
+{
+  return read ? 0x20 : 0x30;
+}
+
+static inline rtems_blkdev_bnum ata_max_transfer_count(rtems_blkdev_bnum sector_count)
+{
+  return sector_count > ATA_PER_TRANSFER_SECTOR_COUNT_MAX ?
+    ATA_PER_TRANSFER_SECTOR_COUNT_MAX
+      : sector_count;
+}
+
+static inline void ata_flush_sector(uint16_t *begin)
+{
+  /* XXX: The dcbi operation does not work properly */
+  rtems_cache_flush_multiple_data_lines(begin, ATA_SECTOR_SIZE);
+}
+
+void ata_reset_device();
+
+bool ata_set_transfer_mode(uint8_t mode);
+
+bool ata_execute_io_command(uint8_t command, uint32_t lba, uint32_t sector_count);
+
+static inline bool ata_execute_io_command_with_sg(uint8_t command, const rtems_blkdev_sg_buffer *sg)
+{
+  uint32_t lba = sg->block;
+  uint32_t sector_count = sg->length / ATA_SECTOR_SIZE;
+  return ata_execute_io_command(command, lba, sector_count);
+}
+
+typedef struct {
+  const rtems_blkdev_sg_buffer *sg;
+
+  size_t sg_count;
+
+  rtems_blkdev_bnum sg_buffer_offset_mask;
+
+  int sg_index_shift;
+} ata_sg_context;
+
+static inline void ata_sg_reset(ata_sg_context *self, const rtems_blkdev_sg_buffer *sg, size_t sg_count)
+{
+  self->sg = sg;
+  self->sg_count = sg_count;
+  uint32_t sectors_per_buffer = self->sg[0].length >> ATA_SECTOR_SHIFT;
+  self->sg_buffer_offset_mask = sectors_per_buffer - 1;
+  self->sg_index_shift = __builtin_ffs((int) sectors_per_buffer) - 1;
+}
+
+static inline void ata_sg_create_default(ata_sg_context *self)
+{
+  ata_sg_reset(self, NULL, 0);
+}
+
+static inline void ata_sg_create(ata_sg_context *self, const rtems_blkdev_sg_buffer *sg, size_t sg_count)
+{
+  ata_sg_reset(self, sg, sg_count);
+}
+
+static inline rtems_blkdev_bnum ata_sg_get_start_sector(const ata_sg_context *self)
+{
+  return self->sg[0].block;
+}
+
+static inline rtems_blkdev_bnum ata_sg_get_sector_count(const ata_sg_context *self)
+{
+  return (self->sg_buffer_offset_mask + 1) * self->sg_count;
+}
+
+static inline uint16_t *ata_sg_get_sector_data_begin(const ata_sg_context *self, rtems_blkdev_bnum relative_sector)
+{
+  uint16_t *begin = (uint16_t *)(self->sg[relative_sector >> self->sg_index_shift].buffer);
+
+  return begin + ((relative_sector & self->sg_buffer_offset_mask) << (ATA_SECTOR_SHIFT - 1));
+}
+
+static inline uint16_t *ata_sg_get_sector_data_end(const ata_sg_context *self, uint16_t *begin)
+{
+  return begin + ATA_SECTOR_SIZE / 2;
+}
+
+typedef struct {
+  rtems_id lock;
+
+  bool card_present;
+} ata_driver;
+
+void ata_driver_create(ata_driver *self, const char *device_file_path, rtems_block_device_ioctl io_control);
+
+void ata_driver_destroy(ata_driver *self);
+
+static inline void ata_driver_lock(const ata_driver *self)
+{
+  rtems_status_code sc = rtems_semaphore_obtain(self->lock, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+  assert(sc == RTEMS_SUCCESSFUL);
+}
+
+static inline void ata_driver_unlock(const ata_driver *self)
+{
+  rtems_status_code sc = rtems_semaphore_release(self->lock);
+  assert(sc == RTEMS_SUCCESSFUL);
+}
+
+static inline bool ata_driver_is_card_present(const ata_driver *self)
+{
+  return self->card_present;
+}
+
+static inline void ata_driver_io_request(
+  ata_driver *self,
+  rtems_blkdev_request *request,
+  bool (*transfer)(ata_driver *, bool, rtems_blkdev_sg_buffer *, size_t)
+)
+{
+  assert(request->req == RTEMS_BLKDEV_REQ_READ || request->req == RTEMS_BLKDEV_REQ_WRITE);
+  bool read = request->req != RTEMS_BLKDEV_REQ_WRITE;
+  rtems_blkdev_sg_buffer *sg = &request->bufs[0];
+  uint32_t sg_count = request->bufnum;
+  ata_driver_lock(self);
+  bool ok = (*transfer)(self, read, sg, sg_count);
+  ata_driver_unlock(self);
+  rtems_status_code sc = ok ? RTEMS_SUCCESSFUL : RTEMS_IO_ERROR;
+  rtems_blkdev_request_done(request, sc);
+}
+
+static inline int ata_driver_io_control(
+  rtems_disk_device *dd,
+  uint32_t cmd,
+  void *arg,
+  bool (*transfer)(ata_driver *, bool, rtems_blkdev_sg_buffer *, size_t)
+)
+{
+  ata_driver *self = (ata_driver *) rtems_disk_get_driver_data(dd);
+
+  switch (cmd) {
+    case RTEMS_BLKIO_REQUEST:
+      ata_driver_io_request(self, (rtems_blkdev_request *) arg, transfer);
+      return 0;
+    case RTEMS_BLKIO_CAPABILITIES:
+      *(uint32_t *) arg = RTEMS_BLKDEV_CAP_MULTISECTOR_CONT;
+      return 0;
+    default:
+      return rtems_blkdev_ioctl(dd, cmd, arg);
+  }
+}
+
+int ata_driver_io_control_pio_polled(
+  rtems_disk_device *dd,
+  uint32_t cmd,
+  void *arg
+);
+
+typedef struct {
+  ata_driver super;
+
+  bestcomm_task task;
+
+  bool read;
+
+  ata_sg_context sg_context;
+
+  rtems_blkdev_bnum transfer_current;
+
+  rtems_blkdev_bnum transfer_end;
+} ata_driver_dma_pio_single;
+
+void ata_driver_dma_pio_single_create(
+  ata_driver_dma_pio_single *self,
+  const char *device_file_path,
+  TaskId task_index
+);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* GEN5200_ATA_H */
diff --git a/c/src/lib/libbsp/powerpc/gen5200/include/bestcomm.h b/c/src/lib/libbsp/powerpc/gen5200/include/bestcomm.h
new file mode 100644
index 0000000..7a127b6
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/gen5200/include/bestcomm.h
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 2010-2013 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems at embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef GEN5200_BESTCOMM_H
+#define GEN5200_BESTCOMM_H
+
+#include "bestcomm_ops.h"
+
+#include <assert.h>
+
+#include <rtems.h>
+
+#include <bsp/mpc5200.h>
+#include <bsp/bestcomm/bestcomm_api.h>
+#include <bsp/bestcomm/bestcomm_glue.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @defgroup BestComm BestComm Support
+ *
+ * @ingroup BestCommm
+ *
+ * @brief BestComm support.
+ *
+ * @{
+ */
+
+typedef struct {
+  uint32_t *tdt_begin;
+  uint32_t *tdt_last;
+  volatile uint32_t (*var_table)[32];
+  uint32_t fdt_and_pragmas;
+  uint32_t reserved_0;
+  uint32_t reserved_1;
+  uint32_t *context_begin;
+  uint32_t reserved_2;
+} bestcomm_task_entry;
+
+#define BESTCOMM_TASK_ENTRY_TABLE ((volatile bestcomm_task_entry *) 0xf0008000)
+
+#define BESTCOMM_IRQ_EVENT RTEMS_EVENT_13
+
+typedef struct {
+  int task_index;
+  rtems_id event_task_id;
+} bestcomm_irq;
+
+void bestcomm_irq_create(bestcomm_irq *self, int task_index);
+
+void bestcomm_irq_destroy(const bestcomm_irq *self);
+
+static inline void bestcomm_irq_enable(const bestcomm_irq *self)
+{
+  bestcomm_glue_irq_enable(self->task_index);
+}
+
+static inline void bestcomm_irq_disable(const bestcomm_irq *self)
+{
+  bestcomm_glue_irq_disable(self->task_index);
+}
+
+static inline void bestcomm_irq_clear(const bestcomm_irq *self)
+{
+  SDMA_CLEAR_IEVENT(&mpc5200.sdma.IntPend, self->task_index);
+}
+
+static inline int bestcomm_irq_get_task_index(const bestcomm_irq *self)
+{
+  return self->task_index;
+}
+
+static inline rtems_id bestcomm_irq_get_event_task_id(const bestcomm_irq *self)
+{
+  return self->event_task_id;
+}
+
+static inline void bestcomm_irq_set_event_task_id(bestcomm_irq *self, rtems_id id)
+{
+  self->event_task_id = id;
+}
+
+static inline void bestcomm_irq_wakeup_event_task(const bestcomm_irq *self)
+{
+  rtems_status_code sc = rtems_event_send(self->event_task_id, BESTCOMM_IRQ_EVENT);
+  assert(sc == RTEMS_SUCCESSFUL);
+}
+
+static inline void bestcomm_irq_wait(const bestcomm_irq *self)
+{
+  rtems_event_set events;
+  rtems_status_code sc = rtems_event_receive(
+    BESTCOMM_IRQ_EVENT,
+    RTEMS_EVENT_ALL | RTEMS_WAIT,
+    RTEMS_NO_TIMEOUT,
+    &events
+  );
+  assert(sc == RTEMS_SUCCESSFUL);
+  assert(events == BESTCOMM_IRQ_EVENT);
+}
+
+static inline bool bestcomm_irq_peek(const bestcomm_irq *self)
+{
+  rtems_event_set events;
+  rtems_status_code sc = rtems_event_receive(0, 0, 0, &events);
+  assert(sc == RTEMS_SUCCESSFUL);
+
+  return (events & BESTCOMM_IRQ_EVENT) != 0;
+}
+
+typedef struct {
+  volatile uint16_t *task_control_register;
+
+  volatile uint32_t (*variable_table)[32];
+
+  TaskId task_index;
+
+  bestcomm_irq irq;
+
+  uint32_t *tdt_begin;
+
+  size_t tdt_opcode_count;
+} bestcomm_task;
+
+void bestcomm_task_create(bestcomm_task *self, TaskId task_index);
+
+void bestcomm_task_create_and_load(
+  bestcomm_task *self,
+  TaskId task_index,
+  const uint32_t *tdt_source_begin,
+  size_t tdt_size
+);
+
+void bestcomm_task_destroy(bestcomm_task *self);
+
+void bestcomm_task_load(bestcomm_task *self, const uint32_t *tdt_source_begin, size_t tdt_size);
+
+static inline void bestcomm_task_set_priority(bestcomm_task *self, int priority)
+{
+  /* Allow higher priority initiator to block current initiator */
+  mpc5200.sdma.ipr[self->task_index] = SDMA_IPR_PRIOR(priority);
+}
+
+static inline void bestcomm_task_irq_enable(const bestcomm_task *self)
+{
+  bestcomm_irq_enable(&self->irq);
+}
+
+static inline void bestcomm_task_irq_disable(const bestcomm_task *self)
+{
+  bestcomm_irq_disable(&self->irq);
+}
+
+static inline void bestcomm_task_irq_clear(const bestcomm_task *self)
+{
+  bestcomm_irq_clear(&self->irq);
+}
+
+static inline rtems_id bestcomm_task_get_event_task_id(const bestcomm_task *self)
+{
+  return bestcomm_irq_get_event_task_id(&self->irq);
+}
+
+static inline void bestcomm_task_set_event_task_id(bestcomm_task *self, rtems_id id)
+{
+  bestcomm_irq_set_event_task_id(&self->irq, id);
+}
+
+static inline void bestcomm_task_associate_with_current_task(bestcomm_task *self)
+{
+  bestcomm_task_set_event_task_id(self, rtems_task_self());
+}
+
+static inline void bestcomm_task_start(const bestcomm_task *self)
+{
+  *self->task_control_register = SDMA_TCR_EN | SDMA_TCR_HIGH_EN;
+}
+
+static inline void bestcomm_task_start_with_autostart(const bestcomm_task *self)
+{
+  *self->task_control_register = (uint16_t)
+    (SDMA_TCR_EN | SDMA_TCR_HIGH_EN | SDMA_TCR_AUTO_START | SDMA_TCR_AS(self->task_index));
+}
+
+static inline void bestcomm_task_stop(const bestcomm_task *self)
+{
+  *self->task_control_register = 0;
+}
+
+static inline void bestcomm_task_wakeup_event_task(const bestcomm_task *self)
+{
+  bestcomm_irq_wakeup_event_task(&self->irq);
+}
+
+static inline void bestcomm_task_wait(const bestcomm_task *self)
+{
+  bestcomm_irq_wait(&self->irq);
+}
+
+static inline bool bestcomm_task_peek(const bestcomm_task *self)
+{
+  return bestcomm_irq_peek(&self->irq);
+}
+
+static inline bool bestcomm_task_is_running(const bestcomm_task *self)
+{
+  return (*self->task_control_register & SDMA_TCR_EN) != 0;
+}
+
+static inline uint32_t bestcomm_get_task_variable(const bestcomm_task *self, size_t index)
+{
+  assert(index < VAR_COUNT);
+  return (*self->variable_table)[index];
+}
+
+static inline volatile uint32_t *bestcomm_task_get_address_of_variable(const bestcomm_task *self, size_t index)
+{
+  assert(index < VAR_COUNT);
+  return &(*self->variable_table)[index];
+}
+
+static inline void bestcomm_task_set_variable(const bestcomm_task *self, size_t index, uint32_t value)
+{
+  assert(index < VAR_COUNT);
+  (*self->variable_table)[index] = value;
+}
+
+static inline uint32_t bestcomm_task_get_increment_and_condition(const bestcomm_task *self, size_t index)
+{
+  assert(index < INC_COUNT);
+  return (*self->variable_table)[INC(index)];
+}
+
+static inline void bestcomm_task_set_increment_and_condition_32(
+  const bestcomm_task *self,
+  size_t index,
+  uint32_t inc_and_cond
+)
+{
+  assert(index < INC_COUNT);
+  (*self->variable_table)[INC(index)] = inc_and_cond;
+}
+
+static inline void bestcomm_task_set_increment_and_condition(
+  const bestcomm_task *self,
+  size_t index,
+  int16_t inc,
+  int cond
+)
+{
+  bestcomm_task_set_increment_and_condition_32(self, index, INC_INIT(cond, inc));
+}
+
+static inline void bestcomm_task_set_increment(const bestcomm_task *self, size_t index, int16_t inc)
+{
+  bestcomm_task_set_increment_and_condition_32(self, index, INC_INIT(0, inc));
+}
+
+void bestcomm_task_clear_variables(const bestcomm_task *self);
+
+static inline uint32_t bestcomm_task_get_opcode(const bestcomm_task *self, size_t index)
+{
+  assert(index < self->tdt_opcode_count);
+  return self->tdt_begin[index];
+}
+
+static inline void bestcomm_task_set_opcode(bestcomm_task *self, size_t index, uint32_t opcode)
+{
+  assert(index < self->tdt_opcode_count);
+  self->tdt_begin[index] = opcode;
+}
+
+static inline void bestcomm_task_set_initiator(const bestcomm_task *self, int initiator)
+{
+  rtems_interrupt_level level;
+  rtems_interrupt_disable(level);
+  *self->task_control_register = BSP_BFLD16SET(*self->task_control_register, initiator, 3, 7);
+  rtems_interrupt_enable(level);
+}
+
+static inline volatile bestcomm_task_entry *bestcomm_task_get_task_entry(const bestcomm_task *self)
+{
+  return &BESTCOMM_TASK_ENTRY_TABLE[self->task_index];
+}
+
+static inline void bestcomm_task_set_pragma(const bestcomm_task *self, int bit_pos, bool enable)
+{
+  volatile bestcomm_task_entry *entry = bestcomm_task_get_task_entry(self);
+  uint32_t mask = BSP_BIT32(bit_pos);
+  uint32_t bit = enable ? mask : 0;
+  entry->fdt_and_pragmas = (entry->fdt_and_pragmas & ~mask) | bit;
+}
+
+static inline void bestcomm_task_enable_precise_increment(const bestcomm_task *self, bool enable)
+{
+  bestcomm_task_set_pragma(self, SDMA_PRAGMA_BIT_PRECISE_INC, enable);
+}
+
+static inline void bestcomm_task_enable_error_reset(const bestcomm_task *self, bool enable)
+{
+  bestcomm_task_set_pragma(self, SDMA_PRAGMA_BIT_RST_ERROR_NO, !enable);
+}
+
+static inline void bestcomm_task_enable_pack_data(const bestcomm_task *self, bool enable)
+{
+  bestcomm_task_set_pragma(self, SDMA_PRAGMA_BIT_PACK, enable);
+}
+
+static inline void bestcomm_task_enable_integer_mode(const bestcomm_task *self, bool enable)
+{
+  bestcomm_task_set_pragma(self, SDMA_PRAGMA_BIT_INTEGER, enable);
+}
+
+static inline void bestcomm_task_enable_speculative_read(const bestcomm_task *self, bool enable)
+{
+  bestcomm_task_set_pragma(self, SDMA_PRAGMA_BIT_SPECREAD, enable);
+}
+
+static inline void bestcomm_task_enable_combined_write(const bestcomm_task *self, bool enable)
+{
+  bestcomm_task_set_pragma(self, SDMA_PRAGMA_BIT_CW, enable);
+}
+
+static inline void bestcomm_task_enable_read_buffer(const bestcomm_task *self, bool enable)
+{
+  bestcomm_task_set_pragma(self, SDMA_PRAGMA_BIT_RL, enable);
+}
+
+static inline volatile uint16_t *bestcomm_task_get_task_control_register(const bestcomm_task *self)
+{
+  return self->task_control_register;
+}
+
+static inline int bestcomm_task_get_task_index(const bestcomm_task *self)
+{
+  return self->task_index;
+}
+
+static inline void bestcomm_task_free_tdt(bestcomm_task *self)
+{
+  bestcomm_free(self->tdt_begin);
+  self->tdt_begin = NULL;
+}
+
+static inline void bestcomm_task_clear_pragmas(const bestcomm_task *self)
+{
+  volatile bestcomm_task_entry *entry = bestcomm_task_get_task_entry(self);
+  entry->fdt_and_pragmas &= ~0xffU;
+}
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* GEN5200_BESTCOMM_H */
diff --git a/c/src/lib/libbsp/powerpc/gen5200/include/bestcomm_ops.h b/c/src/lib/libbsp/powerpc/gen5200/include/bestcomm_ops.h
new file mode 100644
index 0000000..d9fc8f0
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/gen5200/include/bestcomm_ops.h
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2010-2013 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems at embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef BESTCOMM_OPS_H
+#define BESTCOMM_OPS_H
+
+#include <bsp/utility.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @defgroup BestCommOps BestComm Ops
+ *
+ * @ingroup BestComm
+ *
+ * @brief BestComm ops.
+ *
+ * @{
+ */
+
+#define VAR(i) (i)
+#define VAR_COUNT 24
+#define INC(i) (24 + (i))
+#define INC_COUNT 8
+#define IDX(i) (48 + (i))
+#define IDX_COUNT 8
+
+#define COND_ONCE 0
+#define COND_LT 1
+#define COND_GT 2
+#define COND_NE 3
+#define COND_EQ 4
+#define COND_LE 5
+#define COND_GE 6
+#define COND_FOREVER 7
+
+#define INC_INIT(cond, val) \
+  (BSP_FLD32(cond, 29, 31) \
+    | BSP_FLD32((int16_t) (val), 0, 15))
+
+#define TERM_FIRST 0
+#define TERM_SECOND 1
+#define TERM_INIT 2
+#define TERM_UNUSED 3
+
+#define DEREF 1
+
+#define LCD_TERM(val) BSP_FLD32(val, 13, 14)
+
+#define LCD(deref0, iniidx0, deref1, iniidx1, term, termop, inc0, inc1) \
+  (BSP_BIT32(31) \
+    | BSP_FLD32(deref0, 29, 29) \
+    | BSP_FLD32(iniidx0, 23, 28) \
+    | BSP_FLD32(deref1, 21, 21) \
+    | BSP_FLD32(iniidx1, 15, 20) \
+    | LCD_TERM(term) \
+    | BSP_FLD32(termop, 6, 11) \
+    | BSP_FLD32(inc0, 3, 5) \
+    | BSP_FLD32(inc1, 0, 2))
+
+#define LCDEXT(deref0, iniidx0, deref1, iniidx1, term, termop, inc0, inc1) \
+  (BSP_BIT32(30) \
+    | LCD(deref0, iniidx0, deref1, iniidx1, term, termop, inc0, inc1))
+
+#define LCDPLUS(deref0, iniidx0, deref1, iniidx1, term, termop, inc0, inc1) \
+  (BSP_BIT32(22) \
+    | LCD(deref0, iniidx0, deref1, iniidx1, term, termop, inc0, inc1))
+
+#define LCDINIT(val) \
+  (BSP_BIT32(31) \
+    | BSP_FLD32((val) >> 13, 15, 29) \
+    | LCD_TERM(TERM_INIT) \
+    | BSP_FLD32(val, 0, 12))
+
+#define MORE 0x4
+
+#define TFD 0x2
+
+#define INT 0x1
+
+#define DRD_FLAGS(val) BSP_FLD32(val, 26, 28)
+
+#define INIT_ALWAYS 0
+#define INIT_SCTMR_0 1
+#define INIT_SCTMR_1 2
+#define INIT_FEC_RX 3
+#define INIT_FEC_TX 4
+#define INIT_ATA_RX 5
+#define INIT_ATA_TX 6
+#define INIT_SCPCI_RX 7
+#define INIT_SCPCI_TX 8
+#define INIT_PSC3_RX 9
+#define INIT_PSC3_TX 10
+#define INIT_PSC2_RX 11
+#define INIT_PSC2_TX 12
+#define INIT_PSC1_RX 13
+#define INIT_PSC1_TX 14
+#define INIT_SCTMR_2 15
+#define INIT_SCLPC 16
+#define INIT_PSC5_RX 17
+#define INIT_PSC5_TX 18
+#define INIT_PSC4_RX 19
+#define INIT_PSC4_TX 20
+#define INIT_I2C2_RX 21
+#define INIT_I2C2_TX 22
+#define INIT_I2C1_RX 23
+#define INIT_I2C1_TX 24
+#define INIT_PSC6_RX 25
+#define INIT_PSC6_TX 26
+#define INIT_IRDA_RX 25
+#define INIT_IRDA_TX 26
+#define INIT_SCTMR_3 27
+#define INIT_SCTMR_4 28
+#define INIT_SCTMR_5 29
+#define INIT_SCTMR_6 30
+#define INIT_SCTMR_7 31
+
+#define DRD_INIT(val) BSP_FLD32(val, 21, 25)
+
+#define SZ_8 1
+#define SZ_16 2
+#define SZ_32 0
+#define SZ_DYN 3
+
+#define DRD_RS(val) BSP_FLD32(val, 19, 20)
+
+#define DRD_WS(val) BSP_FLD32(val, 17, 18)
+
+#define DEST_VAR(val) (val)
+#define DEST_IDX(val) (BSP_BIT32(5) | (val))
+#define DEST_DEREF_IDX(val) (BSP_BIT32(5) | BSP_BIT32(4) | (val))
+
+#define SRC_VAR(val) (val)
+#define SRC_INC(val) (BSP_BIT32(5) | (val))
+#define SRC_EU_RESULT (BSP_BIT32(5) | BSP_BIT32(4) | BSP_BIT32(1) | BSP_BIT32(0))
+#define SRC_DEREF_EU_RESULT (BSP_BIT32(6) | BSP_BIT32(4) | BSP_BIT32(1) | BSP_BIT32(0))
+#define SRC_IDX(val) (BSP_BIT32(6) | BSP_BIT32(5) | (val))
+#define SRC_DEREF_IDX(val) (BSP_BIT32(6) | BSP_BIT32(5) | BSP_BIT32(4) | (val))
+#define SRC_NONE (BSP_BIT32(5) | BSP_BIT32(4) | BSP_BIT32(3) | BSP_BIT32(2) | BSP_BIT32(1) | BSP_BIT32(0))
+
+#define DRD1A(flags, init, dest, ws, src, rs) \
+  (DRD_FLAGS(flags) \
+    | DRD_INIT(init) \
+    | DRD_RS(rs) \
+    | DRD_WS(ws) \
+    | BSP_FLD32(dest, 10, 15) \
+    | BSP_FLD32(src, 3, 9))
+
+#define DRD1AEURESULT(flags, init, dest, ws, rs) \
+  (DRD1A(flags, init, rs, ws, dest, SRC_EU_RESULT) \
+    | BSP_FLD32(1, 0, 3))
+
+#define FUNC_LOAD_ACC 0
+#define FUNC_UNLOAD_ACC 1
+#define FUNC_AND 2
+#define FUNC_OR 3
+#define FUNC_XOR 4
+#define FUNC_ANDN 5
+#define FUNC_NOT 6
+#define FUNC_ADD 7
+#define FUNC_SUB 8
+#define FUNC_LSH 9
+#define FUNC_RSH 10
+#define FUNC_CRC8 11
+#define FUNC_CRC16 12
+#define FUNC_CRC32 13
+#define FUNC_ENDIAN32 14
+#define FUNC_ENDIAN16 15
+
+#define DRD2A(flags, func) \
+  (BSP_BIT32(30) | BSP_BIT32(29) \
+    | DRD_FLAGS(flags) \
+    | BSP_FLD32(func, 0, 3))
+
+#define DRD2A5(flags, init, func, ws, rs) \
+  (DRD2A(flags, func) \
+    | DRD_RS(rs) \
+    | DRD_WS(ws) \
+    | DRD_INIT(init))
+
+#define OP_VAR(val) (val)
+#define OP_EU_RESULT (BSP_BIT32(4) | BSP_BIT32(3) | BSP_BIT32(1) | BSP_BIT32(0))
+#define OP_NONE (BSP_BIT32(4) | BSP_BIT32(3) | BSP_BIT32(2) | BSP_BIT32(1) | BSP_BIT32(0))
+#define OP_IDX(val) (BSP_BIT32(5) | (val))
+#define OP_DEREF_IDX(val) (BSP_BIT32(5) | BSP_BIT32(4) | (val))
+
+#define DRD2B1(dest, op0, op1) \
+  (BSP_FLD32(dest, 22, 27) \
+    | BSP_FLD32(SRC_EU_RESULT, 14, 20) \
+    | BSP_FLD32(3, 12, 13) \
+    | BSP_FLD32(op0, 6, 11) \
+    | BSP_FLD32(op1, 0, 5))
+
+#define DRD2B2(op0, op1) \
+  (BSP_BIT32(29) \
+    | BSP_FLD32(3, 26, 27) \
+    | BSP_FLD32(op0, 20, 25) \
+    | BSP_FLD32(op1, 14, 19) \
+    | BSP_FLD32(0, 12, 13) \
+    | BSP_FLD32(OP_NONE, 6, 11) \
+    | BSP_FLD32(OP_NONE, 0, 5))
+
+#define NOP 0x1f8
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* BESTCOMM_OPS_H */
diff --git a/c/src/lib/libbsp/powerpc/gen5200/include/bsp.h b/c/src/lib/libbsp/powerpc/gen5200/include/bsp.h
index 8564936..9f30e66 100644
--- a/c/src/lib/libbsp/powerpc/gen5200/include/bsp.h
+++ b/c/src/lib/libbsp/powerpc/gen5200/include/bsp.h
@@ -230,7 +230,10 @@ typedef enum {
   MPC5200_FATAL_MSCAN_A_INIT,
   MPC5200_FATAL_MSCAN_B_INIT,
   MPC5200_FATAL_MSCAN_A_SET_MODE,
-  MPC5200_FATAL_MSCAN_B_SET_MODE
+  MPC5200_FATAL_MSCAN_B_SET_MODE,
+  MPC5200_FATAL_ATA_DISK_IO_INIT,
+  MPC5200_FATAL_ATA_DISK_CREATE,
+  MPC5200_FATAL_ATA_DMA_SINGLE_IRQ_INSTALL
 } mpc5200_fatal_code;
 
 void mpc5200_fatal(mpc5200_fatal_code code) RTEMS_COMPILER_NO_RETURN_ATTRIBUTE;
diff --git a/c/src/lib/libbsp/powerpc/gen5200/preinstall.am b/c/src/lib/libbsp/powerpc/gen5200/preinstall.am
index ec764f2..6720cd2 100644
--- a/c/src/lib/libbsp/powerpc/gen5200/preinstall.am
+++ b/c/src/lib/libbsp/powerpc/gen5200/preinstall.am
@@ -157,6 +157,10 @@ $(PROJECT_INCLUDE)/bsp/bestcomm/task_api/bestcomm_api_mem.h: bestcomm/task_api/b
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/bestcomm/task_api/bestcomm_api_mem.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/bestcomm/task_api/bestcomm_api_mem.h
 
+$(PROJECT_INCLUDE)/bsp/bootcard.h: ../../shared/include/bootcard.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/bootcard.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/bootcard.h
+
 $(PROJECT_INCLUDE)/bsp/irq-generic.h: ../../shared/include/irq-generic.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq-generic.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq-generic.h
@@ -165,25 +169,29 @@ $(PROJECT_INCLUDE)/bsp/irq-info.h: ../../shared/include/irq-info.h $(PROJECT_INC
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq-info.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq-info.h
 
-$(PROJECT_INCLUDE)/bsp/utility.h: ../../shared/include/utility.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
-	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/utility.h
-PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/utility.h
-
-$(PROJECT_INCLUDE)/bsp/bootcard.h: ../../shared/include/bootcard.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
-	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/bootcard.h
-PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/bootcard.h
-
 $(PROJECT_INCLUDE)/bsp/u-boot.h: ../../shared/include/u-boot.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/u-boot.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/u-boot.h
 
+$(PROJECT_INCLUDE)/bsp/utility.h: ../../shared/include/utility.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/utility.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/utility.h
+
 $(PROJECT_INCLUDE)/bsp/u-boot-board-info.h: ../shared/include/u-boot-board-info.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/u-boot-board-info.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/u-boot-board-info.h
 
-$(PROJECT_INCLUDE)/bsp/irq.h: include/irq.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
-	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq.h
-PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq.h
+$(PROJECT_INCLUDE)/bsp/ata.h: include/ata.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/ata.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/ata.h
+
+$(PROJECT_INCLUDE)/bsp/bestcomm.h: include/bestcomm.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/bestcomm.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/bestcomm.h
+
+$(PROJECT_INCLUDE)/bsp/bestcomm_ops.h: include/bestcomm_ops.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/bestcomm_ops.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/bestcomm_ops.h
 
 $(PROJECT_INCLUDE)/bsp/i2cdrv.h: include/i2cdrv.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/i2cdrv.h
@@ -193,6 +201,10 @@ $(PROJECT_INCLUDE)/bsp/i2c.h: include/i2c.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/i2c.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/i2c.h
 
+$(PROJECT_INCLUDE)/bsp/irq.h: include/irq.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq.h
+
 $(PROJECT_INCLUDE)/bsp/mpc5200.h: include/mpc5200.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/mpc5200.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/mpc5200.h
diff --git a/c/src/lib/libbsp/powerpc/gen5200/startup/bestcomm.c b/c/src/lib/libbsp/powerpc/gen5200/startup/bestcomm.c
new file mode 100644
index 0000000..cbb1c0e
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/gen5200/startup/bestcomm.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2010-2013 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems at embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#define NDEBUG
+
+#include <bsp/bestcomm.h>
+
+#include <string.h>
+
+#include <bsp/mpc5200.h>
+
+static void bestcomm_irq_handler(void *arg)
+{
+  bestcomm_irq *self = arg;
+
+  bestcomm_irq_clear(self);
+  bestcomm_irq_wakeup_event_task(self);
+}
+
+void bestcomm_irq_create(bestcomm_irq *self, int task_index)
+{
+  assert(task_index >= 0 && task_index <= 15);
+
+  self->task_index = task_index;
+  self->event_task_id = rtems_task_self();
+  bestcomm_glue_irq_install(task_index, bestcomm_irq_handler, self);
+}
+
+void bestcomm_irq_destroy(const bestcomm_irq *self)
+{
+  bestcomm_glue_irq_install(self->task_index, NULL, NULL);
+}
+
+void bestcomm_task_create(bestcomm_task *self, TaskId task_index)
+{
+  self->task_control_register = &mpc5200.sdma.tcr[task_index];
+  self->variable_table = BESTCOMM_TASK_ENTRY_TABLE[task_index].var_table;
+  self->task_index = task_index;
+  self->tdt_begin = NULL;
+  self->tdt_opcode_count = 0;
+  bestcomm_task_stop(self);
+  bestcomm_irq_create(&self->irq, task_index);
+}
+
+void bestcomm_task_create_and_load(
+  bestcomm_task *self,
+  TaskId task_index,
+  const uint32_t *tdt_source_begin,
+  size_t tdt_size
+)
+{
+  bestcomm_task_create(self, task_index);
+  bestcomm_task_load(self, tdt_source_begin, tdt_size);
+}
+
+void bestcomm_task_destroy(bestcomm_task *self)
+{
+  bestcomm_task_stop(self);
+  bestcomm_task_free_tdt(self);
+}
+
+void bestcomm_task_load(bestcomm_task *self, const uint32_t *tdt_source_begin, size_t tdt_size)
+{
+  assert(tdt_size % 4 == 0);
+
+  bestcomm_task_irq_disable(self);
+  bestcomm_task_stop(self);
+  bestcomm_task_irq_clear(self);
+  bestcomm_task_irq_enable(self);
+  bestcomm_task_free_tdt(self);
+  bestcomm_task_clear_variables(self);
+
+  self->tdt_opcode_count = tdt_size / 4;
+
+  self->tdt_begin = bestcomm_malloc(tdt_size);
+  assert(self->tdt_begin != NULL);
+  uint32_t *tdt_last = self->tdt_begin + self->tdt_opcode_count - 1;
+
+  memcpy(self->tdt_begin, tdt_source_begin, tdt_size);
+
+  volatile bestcomm_task_entry *entry = bestcomm_task_get_task_entry(self);
+  entry->tdt_begin = self->tdt_begin;
+  entry->tdt_last = tdt_last;
+
+  bestcomm_task_clear_pragmas(self);
+  bestcomm_task_set_priority(self, 0);
+}
+
+void bestcomm_task_clear_variables(const bestcomm_task *self)
+{
+  int i;
+
+  for (i = 0; i < 32; ++i) {
+    (*self->variable_table)[i] = 0;
+  }
+}




More information about the vc mailing list