From 57bcb88ef5348a18ae22bd45ac42b0a2646a3264 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 18 Feb 2013 17:00:28 +0100 Subject: 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(-) create mode 100644 c/src/lib/libbsp/powerpc/gen5200/ide/ata-dma-pio-single.c create mode 100644 c/src/lib/libbsp/powerpc/gen5200/ide/ata-instance.c create mode 100644 c/src/lib/libbsp/powerpc/gen5200/ide/ata.c create mode 100644 c/src/lib/libbsp/powerpc/gen5200/include/ata.h create mode 100644 c/src/lib/libbsp/powerpc/gen5200/include/bestcomm.h create mode 100644 c/src/lib/libbsp/powerpc/gen5200/include/bestcomm_ops.h create mode 100644 c/src/lib/libbsp/powerpc/gen5200/startup/bestcomm.c diff --git a/c/src/lib/libbsp/powerpc/gen5200/Makefile.am b/c/src/lib/libbsp/powerpc/gen5200/Makefile.am index a1cf57df4a..68bddd74a1 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 0000000000..dee1ca10be --- /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 + * + * + * 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 + +#include + +#include +#include + +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 0000000000..60380a8008 --- /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 + * + * + * 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 + +#include + +#include + +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 0000000000..2fce1e1219 --- /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 + * + * + * 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 + +#include +#include + +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 0000000000..38cd536af0 --- /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 + * + * + * 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 + +#include +#include +#include + +#include +#include +#include + +#include + +#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 0000000000..7a127b6442 --- /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 + * + * + * 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 + +#include + +#include +#include +#include + +#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 0000000000..d9fc8f0f46 --- /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 + * + * + * 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 + +#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 8564936786..9f30e66488 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 ec764f2310..6720cd2db2 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 0000000000..cbb1c0e91d --- /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 + * + * + * 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 + +#include + +#include + +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; + } +} -- cgit v1.2.3