This adds support for the OMAP4460 SDMA engine found on the Pandaboard.
The driver currently only supports memory-to-memory transfer. Those can
be requested through the Flounder interface described in if/omap_sdma.if.
failure CONFLICT "Cache already contains an item with the requested key",
};
+// errors generated by OMAP SDMA driver
+errors omap_sdma OMAP_SDMA_ERR_ {
+ failure NO_AVAIL_CHANNEL "All channels are currently allocated",
+ failure TRANSACTION "Memory Transaction error occured",
+ failure SUPERVISOR "Supvervisor transaction error occured",
+ failure MISALIGNED_ADDRESS "Transfer addresses were misaligned",
+ failure HARDWARE_LIMIT_SIZE "Transfer size values too large for hardware",
+ failure HARDWARE_LIMIT_ADDR "Transfer address modifier values too large for hardware",
+ failure OUT_OF_BOUNDS "Transfer access outside frame cap boundaries",
+ failure CAP_LOOKUP "Failure during frame capability lookup",
+};
+
// common/generic errors
errors common ERR_ {
failure NOTIMP "Not implemented",
armv7/sbin/memtest \
armv7/sbin/kaluga \
armv7/sbin/fish \
+ armv7/sbin/sdma \
armv7/sbin/usb_manager \
armv7/sbin/usb_keyboard \
"skb",
"skb_map",
"octopus",
+ "omap_sdma",
"spawn",
"terminal",
"terminal_config",
"mem",
"xmplthc",
"octopus",
+ "omap_sdma",
"ata_rw28" ],
arch <- allArchitectures
]
--- /dev/null
+/*
+ * Copyright (c) 2014, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr 6, CH-8092 Zurich.
+ */
+
+interface omap_sdma "Interface for the OMAP44xx SDMA driver" {
+
+ alias uint24 uint32;
+
+ typedef enum {
+ DATA_TYPE_8BIT,
+ DATA_TYPE_16BIT,
+ DATA_TYPE_32BIT
+ } data_type;
+
+ /**
+ * The count_2d struct is used to specify the size of the transferred
+ * frame. It is represented as a two-dimensional grid consisting of pixels.
+ * The x_count and y_count are specified as an amount of pixels.
+ *
+ * +---> x The represented grid cannot exceed the boundaries of
+ * | frame capability found in the addr_2d struct.
+ * v
+ *
+ * y
+ */
+
+ typedef struct {
+ data_type pixel_size;
+
+ uint32 y_count;
+ uint32 x_count;
+ } count_2d;
+
+ /**
+ * The addr_2d struct can be used for flexible addressing. The x_start and
+ * y_start values define the start offset on each axis. The values of
+ * {x,y}_modify are used to calculate the address of consecutive accesses.
+ *
+ * For normal sequential access, set {x,y}_start to 0 and {x,y}_modify to 1.
+ *
+ * All values have the unit of one pixel, its size is defined in the
+ * count_2d struct. The following pseudo code gives a formal definition
+ * how these values are used:
+ *
+ * pixel_t *addr; // 8, 16 or 32 bit integer pointer
+ *
+ * addr += x_start + (y_count * y_start);
+ * for (y = 1; y <= y_count; y++) {
+ * for (x = 1; x <= x_count; x++) {
+ *
+ * access( *addr );
+ *
+ * if (x < x_count) {
+ * // within the frame
+ * addr += x_modify;
+ * } else {
+ * // at the end of a frame
+ * addr += y_modify;
+ * }
+ * }
+ * }
+ */
+
+ typedef struct {
+ cap cap;
+
+ uint32 x_start;
+ uint32 y_start;
+
+ int32 x_modify;
+ int32 y_modify;
+ } addr_2d;
+
+ /**
+ * Copies the whole content of the source frame into the destination frame.
+ */
+ rpc mem_copy(in cap dst, in cap src, out errval err);
+
+ /**
+ * Fills the whole destination frame with the specified color value.
+ */
+ rpc mem_fill(in cap dst, in uint8 color, out errval err);
+
+ /**
+ * Copies the amount of data specified by count_2d from the source frame
+ * to the destination frame. For both, source and destination, flexible
+ * address generation can be used for stride access, see above.
+ *
+ * If the 'transparent' boolean is set, the color value will be used for
+ * transparent copy mode: Source data values matching the color value will
+ * not be written to the destination. For a pixel size of 32 bits, only the
+ * lower 24 bits of the color value are used for comparison.
+ * The color value is ignored if the boolean is set to false.
+ */
+ rpc mem_copy_2d(in addr_2d dst, in addr_2d src, in count_2d count,
+ in bool transparent, in uint24 color, out errval err);
+
+ /**
+ * Fills the destination frame with the specified color value, using
+ * the flexible, two-dimensional addressing mode described above.
+ * As the color value is 24 bits wide, the upper 8 bits are set to zero
+ * when using a pixel size of 32 bits.
+ */
+ rpc mem_fill_2d(in addr_2d dst, in uint24 color,
+ in count_2d count, out errval err);
+
+};
--- /dev/null
+--------------------------------------------------------------------------
+-- Copyright (c) 2007-2014, ETH Zurich.
+-- All rights reserved.
+--
+-- This file is distributed under the terms in the attached LICENSE file.
+-- If you do not find this file, copies can be found by writing to:
+-- ETH Zurich D-INFK, CAB F.78, Universitaetstr 6, CH-8092 Zurich.
+--
+-- Hakefile for omap44xx sdma driver
+--
+--------------------------------------------------------------------------
+
+[
+ build application { target = "sdma",
+ cFiles = (find withSuffices [".c"]),
+ mackerelDevices = [ "omap/omap44xx_sdma" ],
+
+ flounderDefs = [ "omap_sdma" ],
+ flounderBindings = [ "omap_sdma" ],
+ flounderTHCStubs = [ "omap_sdma" ],
+
+ addLibraries = ["driverkit", "thc"],
+ architectures = ["armv7", "armv7-m"]
+ }
+]
--- /dev/null
+/*
+ * Copyright (c) 2014, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr 6, CH-8092 Zurich.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <barrelfish/barrelfish.h>
+#include <barrelfish/waitset.h>
+#include <barrelfish/inthandler.h>
+#include <driverkit/driverkit.h>
+
+#include <thc/thc.h>
+
+#include <arch/arm/omap44xx/device_registers.h>
+
+#include "sdma.h"
+#include "omap_sdma.h"
+
+// Channel State. Filled by the interrupt callback, read by the request task.
+static struct {
+ awe_t *request;
+ errval_t err;
+} channel_state[OMAP44XX_SDMA_NUM_CHANNEL];
+
+/**
+ * \brief Interrupt callback which will be called when a channel interrupt
+ * occurs.
+ *
+ * \param channel Channel which triggered the interrupt
+ * \param err State of the channel, SYS_ERR_OK if transfer completed
+ */
+static void sdma_irq_handler(omap_sdma_channel_t channel, errval_t err)
+{
+ channel_state[channel].err = err;
+ THCSchedule(channel_state[channel].request);
+}
+
+/**
+ * \brief Execute a transfer on the SDMA engine. Blocks until the transfer is
+ * completed or an error occurred.
+ *
+ * \param conf Pointer to valid & initialized channel configuration
+ */
+static errval_t run_omap_sdma_transfer(struct omap_sdma_channel_conf *conf)
+{
+ errval_t err;
+ omap_sdma_channel_t channel;
+
+ err = omap_sdma_allocate_channel(&channel);
+ if (err_is_fail(err)) return err;
+
+ // configure and enable allocated channel
+ omap_sdma_set_channel_conf(channel, conf);
+ omap_sdma_enable_channel(channel, true);
+
+ // this task will be rescheduled by the IRQ handler
+ THCSuspend(&channel_state[channel].request);
+
+ // read status flag set by IRQ handler
+ err = channel_state[channel].err;
+
+ omap_sdma_free_channel(channel);
+
+ return err;
+}
+
+/**
+ * \brief Converts the pixel size of the Flounder interface description to the
+ * element size needed for the hardware.
+ *
+ */
+static omap44xx_sdma_data_type_t extract_data_type(omap_sdma_data_type_t pixel_size)
+{
+ omap44xx_sdma_data_type_t data_type;
+
+ switch(pixel_size) {
+ case omap_sdma_DATA_TYPE_8BIT:
+ data_type = omap44xx_sdma_DATA_TYPE_8BIT;
+ break;
+ case omap_sdma_DATA_TYPE_16BIT:
+ data_type = omap44xx_sdma_DATA_TYPE_16BIT;
+ break;
+ case omap_sdma_DATA_TYPE_32BIT:
+ default:
+ data_type = omap44xx_sdma_DATA_TYPE_32BIT;
+ break;
+ }
+
+ return data_type;
+}
+
+/**
+ * \brief Initializes a configuration struct for the given parameters. It is
+ * the callers responsibility ensure that the start address and count values
+ * are valid.
+ */
+static void init_channel_conf(struct omap_sdma_channel_conf *conf,
+ lpaddr_t dst_start, lpaddr_t src_start,
+ int32_t dst_x_modify, int32_t dst_y_modify,
+ int32_t src_x_modify, int32_t src_y_modify,
+ omap_sdma_count_2d_t count,
+ omap44xx_sdma_color_mode_t color_mode, uint32_t color)
+{
+ assert(conf);
+
+ omap44xx_sdma_data_type_t data_type = extract_data_type(count.pixel_size);
+
+ // OMAP4460 TRM: SDMA 16.4.5
+ int32_t es = 1 << (data_type);
+ int32_t src_element_index = (src_x_modify - 1) * es + 1;
+ int32_t src_frame_index = (src_y_modify - 1) * es + 1;
+
+ int32_t dst_element_index = (dst_x_modify - 1) * es + 1;
+ int32_t dst_frame_index = (dst_y_modify - 1) * es + 1;
+
+ *conf = (struct omap_sdma_channel_conf) {
+ // low priority for software-synchronized transfers
+ .read_priority = omap44xx_sdma_PORT_PRIORITY_LOW,
+ .write_priority = omap44xx_sdma_PORT_PRIORITY_LOW,
+
+ // normal copy/transparent copy/constant fill
+ .color_mode = color_mode,
+ .color = color,
+
+ // wait for last write to complete
+ .write_mode = omap44xx_sdma_WRITE_MODE_LAST_NON_POSTED,
+
+ // channel linking is not used
+ .enable_link = false,
+ .next_channel = 0,
+
+ // always use double indexing mode, packed & burst transfer
+ .src_conf = {
+ .start_address = src_start,
+ .addr_mode = omap44xx_sdma_ADDR_MODE_DOUBLE_IDX,
+ .element_index = src_element_index,
+ .frame_index = src_frame_index,
+ .packed_transfer = omap44xx_sdma_SRC_PACKED_ENABLE,
+ .burst_mode = omap44xx_sdma_BURST_EN_64BYTE,
+ },
+
+ .dst_conf = {
+ .start_address = dst_start,
+ .addr_mode = omap44xx_sdma_ADDR_MODE_DOUBLE_IDX,
+ .element_index = dst_element_index,
+ .frame_index = dst_frame_index,
+ .packed_transfer = omap44xx_sdma_DST_PACKED_ENABLE,
+ .burst_mode = omap44xx_sdma_BURST_EN_64BYTE,
+ },
+
+ // conversion of omap_count_2d
+ .transfer_size = {
+ .element_number = count.x_count,
+ .frame_number = count.y_count,
+ .data_type = data_type,
+ },
+ };
+}
+
+/**
+ * \brief Splits the physical frame size into two factors, as the SDMA engine
+ * needs the memory region to be specified in EN * FN.
+ *
+ * \param bits Size of the frame as a power of two.
+ * \param retcount Pointer to count struct which will be filled with frame size
+ */
+static void init_count_1d(uint8_t bits, omap_sdma_count_2d_t *retcount)
+{
+ assert(retcount);
+
+ // split frame size: 2^b = 2^(b/2) * 2^(b - b/2)
+ uint8_t x_bits = MIN(bits, OMAP44XX_SDMA_MAX_EN_BITS);
+ uint8_t y_bits = bits - x_bits;
+
+ // fill count struct
+ retcount->pixel_size = omap_sdma_DATA_TYPE_8BIT;
+ retcount->x_count = 1 << x_bits;
+ retcount->y_count = 1 << y_bits;
+}
+
+/**
+ * \brief Performs a 32bit integer multiplication and checks for overflow.
+ */
+inline static bool i32_mull_overflow(int32_t y, int32_t x, int32_t* prod) {
+ int64_t i64prod=(int64_t)x*y;
+ if (i64prod > INT32_MAX || i64prod < INT32_MIN) return true;
+ *prod = i64prod & 0xffffffff;
+ return false;
+}
+
+/**
+ * \brief Calculates the start address for a given frame capability in a
+ * two-dimensional transfer.
+ *
+ * \param cap frame capability in which the transfer should happen
+ * \param addr addr_2d struct containing start offset and modifiers
+ * \param count count_2d struct specifing size of the transfer
+ * \param retaddr filled with the physical start address of the transfer
+ *
+ * This function also does some sanity checks, to ensure that the hardware will
+ * not access any values outside the frame boundaries.
+ */
+static errval_t frame_address_2d(struct capref cap, omap_sdma_addr_2d_t *addr,
+ omap_sdma_count_2d_t *count, lpaddr_t *retaddr)
+{
+ assert(addr);
+ assert(count);
+ assert(retaddr);
+
+ errval_t err;
+ struct frame_identity id;
+
+ err = invoke_frame_identify(cap, &id);
+ if (err_is_fail(err)) return err_push(err, OMAP_SDMA_ERR_CAP_LOOKUP);
+
+ lpaddr_t frame_start = id.base;
+ int32_t frame_size = (1 << id.bits);
+
+ // image size cannot exceed hardware limits
+ if (count->x_count > OMAP44XX_SDMA_MAX_EN ||
+ count->y_count > OMAP44XX_SDMA_MAX_FN
+ ) {
+ return OMAP_SDMA_ERR_HARDWARE_LIMIT_SIZE;
+ }
+
+ // pixel size in bytes
+ int32_t pixel_size = 1 << extract_data_type(count->pixel_size);
+ // image size in pixels
+ int32_t x_cnt = count->x_count;
+ int32_t y_cnt = count->y_count;
+
+ // {x,y} modifiers and their accumulated value
+ // (all value in bytes, not pixels!)
+ int32_t x_mod, y_mod,
+ x_mod_sum, y_mod_sum;
+
+ // x_mod = addr->x_modify * pixel_size
+ // y_mod = addr->y_modify * pixel_size
+ // x_mod_sum = (x_cnt-1) * x_mod;
+ // y_mod_sum = (y_cnt-1) * y_mod;
+
+ // check for integer overflow
+ if (
+ (addr->x_modify > INT16_MAX || addr->x_modify < INT16_MIN) ||
+ i32_mull_overflow(addr->x_modify, pixel_size, &x_mod) ||
+ i32_mull_overflow(addr->y_modify, pixel_size, &y_mod) ||
+ i32_mull_overflow(x_cnt-1, x_mod, &x_mod_sum) ||
+ i32_mull_overflow(y_cnt-1, y_mod, &y_mod_sum)
+ ) {
+ return OMAP_SDMA_ERR_HARDWARE_LIMIT_ADDR;
+ }
+
+ // first access performed by the device (start offset)
+ int32_t first_access = (addr->y_start * y_cnt + addr->x_start) * pixel_size;
+ // last access performed by the device
+ int32_t last_access = first_access + (y_cnt * x_mod_sum) + y_mod_sum;
+
+ int32_t lowest_access, highest_access;
+
+ if (x_mod >= 0 && y_mod >= 0) {
+ // monotonic access
+ // first access is smallest, last access is largest
+ lowest_access = first_access;
+ highest_access = last_access;
+ } else if (x_mod < 0 && y_mod < 0) {
+ // monotonic access
+ // last access is smallest, first access is largest
+ lowest_access = last_access;
+ highest_access = first_access;
+ } else {
+ // non-monotonic access
+ if (x_mod > 0) {
+ // x_mod > 0, y_mod < 0
+ if (x_mod_sum + y_mod < 0) {
+ lowest_access = last_access - x_mod_sum;
+ highest_access = first_access + x_mod_sum;
+ } else {
+ lowest_access = first_access;
+ highest_access = last_access;
+ }
+ } else {
+ // x_mod < 0, y_mod > 0
+ if (x_mod_sum + y_mod > 0) {
+ lowest_access = first_access + x_mod_sum;
+ highest_access = last_access - x_mod_sum;
+ } else {
+ lowest_access = last_access;
+ highest_access = first_access;
+ }
+ }
+ }
+
+ // all accesses have to be within frame boundaries
+ if (lowest_access < 0 || highest_access >= frame_size) {
+ return OMAP_SDMA_ERR_OUT_OF_BOUNDS;
+ }
+
+ *retaddr = frame_start + first_access;
+
+ return SYS_ERR_OK;
+}
+
+/**
+ * \brief Stub to perform simple frame-to-frame memory copy
+ * \see Flounder definition in if/omap_sdma.if
+ */
+errval_t mem_copy(struct capref dst_cap, struct capref src_cap)
+{
+ errval_t err;
+ omap_sdma_count_2d_t count;
+ struct frame_identity src_id, dst_id;
+
+ // get frame sizes
+ err = invoke_frame_identify(src_cap, &src_id);
+ if (err_is_fail(err)) return err_push(err, OMAP_SDMA_ERR_CAP_LOOKUP);
+
+ err = invoke_frame_identify(dst_cap, &dst_id);
+ if (err_is_fail(err)) return err_push(err, OMAP_SDMA_ERR_CAP_LOOKUP);
+
+ // infer element/frame number for smaller frame
+ init_count_1d(MIN(dst_id.bits, dst_id.bits), &count);
+
+ // configure and initiate transfer
+ struct omap_sdma_channel_conf conf;
+ init_channel_conf(&conf, dst_id.base, src_id.base, 1, 1, 1, 1, count,
+ omap44xx_sdma_DISABLE_COLOR_MODE, 0);
+ err = run_omap_sdma_transfer(&conf);
+
+ return err;
+}
+
+/**
+ * \brief Stub to fill a memory frame with a constant value
+ * \see Flounder definition in if/omap_sdma.if
+ */
+errval_t mem_fill(struct capref dst_cap, uint8_t color)
+{
+ errval_t err;
+ omap_sdma_count_2d_t count;
+ struct frame_identity dst_id;
+
+ // get frame size and infer element/frame number
+ err = invoke_frame_identify(dst_cap, &dst_id);
+ if (err_is_fail(err)) return err_push(err, OMAP_SDMA_ERR_CAP_LOOKUP);
+ init_count_1d(dst_id.bits, &count);
+
+ // configure and initiate transfer
+ struct omap_sdma_channel_conf conf;
+ init_channel_conf(&conf, dst_id.base, 0, 1, 1, 1, 1, count,
+ omap44xx_sdma_CONSTANT_FILL, color);
+ err = run_omap_sdma_transfer(&conf);
+
+ return err;
+}
+
+/**
+ * \brief Stub to perform a two-dimensional memory copy
+ * \see Flounder definition in if/omap_sdma.if
+ */
+errval_t mem_copy_2d(omap_sdma_addr_2d_t dst, omap_sdma_addr_2d_t src,
+ omap_sdma_count_2d_t count, bool transparent, uint32_t color)
+{
+ errval_t err;
+ lpaddr_t src_start, dst_start;
+
+ // check boundaries and calculate start address for source/dest frames
+ err = frame_address_2d(dst.cap, &dst, &count, &dst_start);
+ if (err_is_fail(err)) return err;
+
+ err = frame_address_2d(src.cap, &src, &count, &src_start);
+ if (err_is_fail(err)) return err;
+
+ // use transparent copy mode if requested
+ omap44xx_sdma_color_mode_t color_mode = (transparent) ?
+ omap44xx_sdma_TRANSPARENT_COPY :
+ omap44xx_sdma_DISABLE_COLOR_MODE;
+
+ struct omap_sdma_channel_conf conf;
+ init_channel_conf(&conf, dst_start, src_start,
+ dst.x_modify, dst.y_modify,
+ src.x_modify, src.y_modify,
+ count, color_mode, color);
+
+ err = run_omap_sdma_transfer(&conf);
+ return err;
+}
+
+/**
+ * \brief Stub to fill parts of a frame using two-dimensional indeces
+ * \see Flounder definition in if/omap_sdma.if
+ */
+errval_t mem_fill_2d(omap_sdma_addr_2d_t dst, omap_sdma_count_2d_t count, uint32_t color)
+{
+ errval_t err;
+ lpaddr_t dst_start;
+
+ err = frame_address_2d(dst.cap, &dst, &count, &dst_start);
+ if (err_is_fail(err)) return err;
+
+ struct omap_sdma_channel_conf conf;
+ init_channel_conf(&conf, dst_start, 0,
+ dst.x_modify, dst.y_modify, 0, 0,
+ count, omap44xx_sdma_CONSTANT_FILL, color);
+
+ err = run_omap_sdma_transfer(&conf);
+ return err;
+}
+
+int main(int argc, char **argv)
+{
+ errval_t err;
+ lvaddr_t dev_base;
+
+ err = map_device_register(OMAP44XX_SDMA, 0x1000, &dev_base);
+ if (err_is_fail(err)) {
+ USER_PANIC_ERR(err, "unable to map SDMA registers");
+ }
+
+ omap_sdma_init((mackerel_addr_t)dev_base, sdma_irq_handler);
+ start_service();
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr 6, CH-8092 Zurich.
+ */
+
+#include <barrelfish/barrelfish.h>
+
+#ifdef OMAP_SDMA_KERNELBENCH
+ #include <arch/armv7/gic.h>
+ #include <arm_hal.h>
+ #include <exceptions.h>
+ #include <kernel.h>
+#else
+ #include <barrelfish/waitset.h>
+ #include <barrelfish/inthandler.h>
+ #include <driverkit/driverkit.h>
+#endif
+
+#include <string.h>
+
+#include "omap_sdma.h"
+#include <omap44xx_map.h>
+
+static omap44xx_sdma_t devsdma;
+static bool allocated_channel[OMAP44XX_SDMA_NUM_CHANNEL];
+
+static omap_sdma_irq_handler_t irq_callback;
+
+static inline errval_t omap_sdma_read_csr(omap44xx_sdma_dma4_csr_t csr)
+{
+ if (omap44xx_sdma_dma4_csr_misaligned_adrs_err_extract(csr)) {
+ return OMAP_SDMA_ERR_MISALIGNED_ADDRESS;
+ } else if (omap44xx_sdma_dma4_csr_supervisor_err_extract(csr)) {
+ return OMAP_SDMA_ERR_SUPERVISOR;
+ } else if (omap44xx_sdma_dma4_csr_trans_err_extract(csr)) {
+ return OMAP_SDMA_ERR_TRANSACTION;
+ }
+
+ return SYS_ERR_OK;
+}
+
+static void omap_sdma_irq_handler(void *arg)
+{
+ uint32_t irqstatus = omap44xx_sdma_dma4_irqstatus_line_rd(&devsdma, OMAP44XX_SDMA_IRQ_LINE);
+
+ for (omap_sdma_channel_t channel=0; channel<OMAP44XX_SDMA_NUM_CHANNEL; channel++) {
+ bool active = (irqstatus >> channel) & 0x1;
+ if(!active) continue;
+
+ SDMA_PRINT("interrupt on channel %u\n", channel);
+
+ // read out status flags
+ omap44xx_sdma_dma4_csr_t csr = omap44xx_sdma_dma4_csr_rd(&devsdma, channel);
+
+ // check for errors
+ errval_t err = omap_sdma_read_csr(csr);
+
+ if (err_is_ok(err)) {
+ // no error found, check for "End of Block" event
+ if(omap44xx_sdma_dma4_csr_block_extract(csr)) {
+ irq_callback(channel, err);
+ }
+ } else {
+ // OMAP4460 Multimedia Device Silicon Errata, Revision A:
+ // 1.7 sDMA Channel Is Not Disabled After A Transaction Error
+ if (err_no(err) == OMAP_SDMA_ERR_TRANSACTION) {
+ // Workaround: disable channel by software
+ omap44xx_sdma_dma4_ccr_enable_wrf(&devsdma, channel, 0);
+ }
+
+ irq_callback(channel, err);
+ }
+
+ // clear all read status flags
+ omap44xx_sdma_dma4_csr_wr(&devsdma, channel, csr);
+ }
+
+ SDMA_PRINT("interrupt finished\n");
+
+ // clear all set status bits
+ omap44xx_sdma_dma4_irqstatus_line_wr(&devsdma, OMAP44XX_SDMA_IRQ_LINE, irqstatus);
+}
+
+
+#ifdef OMAP_SDMA_KERNELBENCH
+// This interrupt handler is for use in the SDMA kernel benchmark only!
+// It depends on GCC's code generation to create the prologue and epilogue
+// for it to be a valid interrupt handler.
+//
+// Vanilla Barrelfish is not designed handle interrupts in the kernel.
+__attribute__((interrupt("IRQ")))
+static void omap_sdma_kernel_irq_handler(void)
+{
+ int irq = gic_get_active_irq();
+ if(irq == OMAP44XX_SDMA_IRQ) {
+ omap_sdma_irq_handler(NULL);
+ }
+ gic_ack_irq(irq);
+}
+#endif
+
+static void omap_sdma_irq_config(omap_sdma_channel_t channel)
+{
+ omap44xx_sdma_dma4_cicr_t dma4_cicr = omap44xx_sdma_dma4_cicr_rd(&devsdma, channel);
+
+ dma4_cicr = omap44xx_sdma_dma4_cicr_super_block_ie_insert(dma4_cicr, 0x0);
+ dma4_cicr = omap44xx_sdma_dma4_cicr_drain_ie_insert(dma4_cicr, 0x0);
+ dma4_cicr = omap44xx_sdma_dma4_cicr_misaligned_err_ie_insert(dma4_cicr, 0x1);
+ dma4_cicr = omap44xx_sdma_dma4_cicr_supervisor_err_ie_insert(dma4_cicr, 0x1);
+ dma4_cicr = omap44xx_sdma_dma4_cicr_trans_err_ie_insert(dma4_cicr, 0x1);
+ dma4_cicr = omap44xx_sdma_dma4_cicr_pkt_ie_insert(dma4_cicr, 0x0);
+ dma4_cicr = omap44xx_sdma_dma4_cicr_block_ie_insert(dma4_cicr, 0x1);
+ dma4_cicr = omap44xx_sdma_dma4_cicr_last_ie_insert(dma4_cicr, 0x0);
+ dma4_cicr = omap44xx_sdma_dma4_cicr_frame_ie_insert(dma4_cicr, 0x0);
+ dma4_cicr = omap44xx_sdma_dma4_cicr_half_ie_insert(dma4_cicr, 0x0);
+ dma4_cicr = omap44xx_sdma_dma4_cicr_drop_ie_insert(dma4_cicr, 0x0);
+
+ omap44xx_sdma_dma4_cicr_wr(&devsdma, channel, dma4_cicr);
+}
+
+/**
+ * \brief Initialzes a channel configuraton struct with its reset values.
+ */
+void omap_sdma_init_channel_conf(struct omap_sdma_channel_conf *conf) {
+ // this function initializes the config struct with default values
+
+ // TRM reset values
+ conf->read_priority = omap44xx_sdma_PORT_PRIORITY_LOW;
+ conf->write_priority = omap44xx_sdma_PORT_PRIORITY_LOW;
+
+ conf->color_mode = omap44xx_sdma_DISABLE_COLOR_MODE;
+ conf->color = 0x000000;
+
+ // no reset value here, use sane default
+ conf->write_mode = omap44xx_sdma_WRITE_MODE_LAST_NON_POSTED;
+
+ struct omap_sdma_transfer_size *transfer_size = &conf->transfer_size;
+ transfer_size->element_number = 0;
+ transfer_size->frame_number = 0;
+ transfer_size->data_type = omap44xx_sdma_DATA_TYPE_32BIT;
+
+ // default transfer config
+ struct omap_sdma_transfer_conf *src_conf = &conf->src_conf;
+ struct omap_sdma_transfer_conf *dst_conf = &conf->dst_conf;
+ src_conf->start_address = 0;
+ src_conf->addr_mode = omap44xx_sdma_ADDR_MODE_POST_INCR;
+ src_conf->element_index = 0;
+ src_conf->frame_index = 0;
+ src_conf->packed_transfer = omap44xx_sdma_SRC_PACKED_DISABLE;
+ src_conf->burst_mode = omap44xx_sdma_BURST_EN_SINGLE;
+
+ // use the same default values for the destination port
+ memcpy(dst_conf, src_conf, sizeof(struct omap_sdma_transfer_conf));
+
+ conf->enable_link = false;
+ conf->next_channel = 0;
+}
+
+static omap44xx_sdma_dma4_ccr_t omap_sdma_channel_conf_ccr(
+ omap44xx_sdma_dma4_ccr_t dma4_ccr,
+ struct omap_sdma_channel_conf *conf)
+{
+ dma4_ccr = omap44xx_sdma_dma4_ccr_src_amode_insert(dma4_ccr, conf->src_conf.addr_mode);
+ dma4_ccr = omap44xx_sdma_dma4_ccr_dst_amode_insert(dma4_ccr, conf->dst_conf.addr_mode);
+
+ assert(
+ (conf->read_priority == omap44xx_sdma_PORT_PRIORITY_LOW) ||
+ (conf->read_priority == omap44xx_sdma_PORT_PRIORITY_HIGH)
+ );
+ dma4_ccr = omap44xx_sdma_dma4_ccr_read_priority_insert(dma4_ccr, conf->read_priority);
+
+ assert(
+ (conf->write_priority == omap44xx_sdma_PORT_PRIORITY_LOW) ||
+ (conf->write_priority == omap44xx_sdma_PORT_PRIORITY_HIGH)
+ );
+ dma4_ccr = omap44xx_sdma_dma4_ccr_write_priority_insert(dma4_ccr, conf->write_priority);
+
+ omap44xx_sdma_transparent_copy_t
+ transparent_copy = (conf->color_mode == omap44xx_sdma_TRANSPARENT_COPY);
+ omap44xx_sdma_const_fill_t
+ const_fill = (conf->color_mode == omap44xx_sdma_CONSTANT_FILL);
+
+ dma4_ccr = omap44xx_sdma_dma4_ccr_transparent_copy_enable_insert(dma4_ccr, transparent_copy);
+ dma4_ccr = omap44xx_sdma_dma4_ccr_const_fill_enable_insert(dma4_ccr, const_fill);
+
+ return dma4_ccr;
+}
+
+
+static omap44xx_sdma_dma4_color_t omap_sdma_channel_conf_color(
+ omap44xx_sdma_dma4_color_t dma4_color,
+ struct omap_sdma_channel_conf *conf)
+{
+ // DMA4_COLORi can only be a 24 bit value
+ assert((conf->color & 0xFF000000) == 0);
+
+ return omap44xx_sdma_dma4_color_color_key_pattern_insert(dma4_color, conf->color);
+}
+
+static omap44xx_sdma_dma4_clnk_ctrl_t omap_sdma_channel_conf_clnk_ctrl(
+ omap44xx_sdma_dma4_clnk_ctrl_t dma4_clnk_ctrl,
+ struct omap_sdma_channel_conf *conf)
+{
+ // if we enable channel linking, the next channel has to be valid
+ assert(!conf->enable_link || conf->next_channel < OMAP44XX_SDMA_NUM_CHANNEL);
+
+ dma4_clnk_ctrl = omap44xx_sdma_dma4_clnk_ctrl_nextlch_id_insert(
+ dma4_clnk_ctrl, conf->next_channel);
+ dma4_clnk_ctrl = omap44xx_sdma_dma4_clnk_ctrl_enable_lnk_insert(
+ dma4_clnk_ctrl, conf->enable_link ? 1 : 0);
+
+ return dma4_clnk_ctrl;
+}
+
+static omap44xx_sdma_dma4_csdp_t omap_sdma_channel_conf_csdp(
+ omap44xx_sdma_dma4_csdp_t dma4_csdp,
+ struct omap_sdma_channel_conf *conf)
+{
+ assert(
+ (conf->write_mode == omap44xx_sdma_WRITE_MODE_NONE_POSTED) ||
+ (conf->write_mode == omap44xx_sdma_WRITE_MODE_ALL_POSTED) ||
+ (conf->write_mode == omap44xx_sdma_WRITE_MODE_LAST_NON_POSTED)
+ );
+
+ dma4_csdp = omap44xx_sdma_dma4_csdp_write_mode_insert(dma4_csdp, conf->write_mode);
+
+ // In memory to memory transfers, the endianness is always little endian
+ dma4_csdp = omap44xx_sdma_dma4_csdp_src_endian_insert(dma4_csdp, omap44xx_sdma_ENDIAN_LITTLE);
+ dma4_csdp = omap44xx_sdma_dma4_csdp_src_endian_lock_insert(dma4_csdp, omap44xx_sdma_ENDIAN_LOCK_ADAPT);
+
+ dma4_csdp = omap44xx_sdma_dma4_csdp_dst_endian_insert(dma4_csdp, omap44xx_sdma_ENDIAN_LITTLE);
+ dma4_csdp = omap44xx_sdma_dma4_csdp_dst_endian_lock_insert(dma4_csdp, omap44xx_sdma_ENDIAN_LOCK_ADAPT);
+
+ struct omap_sdma_transfer_conf *src_conf = &conf->src_conf;
+ dma4_csdp = omap44xx_sdma_dma4_csdp_src_burst_en_insert(dma4_csdp, src_conf->burst_mode);
+ dma4_csdp = omap44xx_sdma_dma4_csdp_src_packed_insert(dma4_csdp,
+ src_conf->packed_transfer
+ ? omap44xx_sdma_SRC_PACKED_ENABLE
+ : omap44xx_sdma_SRC_PACKED_DISABLE);
+
+ struct omap_sdma_transfer_conf *dst_conf = &conf->dst_conf;
+ dma4_csdp = omap44xx_sdma_dma4_csdp_dst_burst_en_insert(dma4_csdp, dst_conf->burst_mode);
+ dma4_csdp = omap44xx_sdma_dma4_csdp_dst_packed_insert(dma4_csdp,
+ dst_conf->packed_transfer
+ ? omap44xx_sdma_DST_PACKED_ENABLE
+ : omap44xx_sdma_DST_PACKED_DISABLE);
+
+ struct omap_sdma_transfer_size *transfer_size = &conf->transfer_size;
+
+ dma4_csdp = omap44xx_sdma_dma4_csdp_data_type_insert(dma4_csdp, transfer_size->data_type);
+
+ return dma4_csdp;
+}
+
+static void inline omap_sdma_channel_conf_assert_transfer_size(
+ struct omap_sdma_transfer_size *transfer_size)
+{
+ assert(
+ (transfer_size->data_type == omap44xx_sdma_DATA_TYPE_8BIT) ||
+ (transfer_size->data_type == omap44xx_sdma_DATA_TYPE_16BIT) ||
+ (transfer_size->data_type == omap44xx_sdma_DATA_TYPE_32BIT)
+ );
+
+ // element number is 24 bit
+ assert((transfer_size->element_number & 0xFF000000) == 0);
+}
+
+static void inline omap_sdma_channel_conf_assert_transfer_conf(
+ struct omap_sdma_transfer_conf *transfer_conf)
+{
+
+ // constant addressing mode is not allowed for memory to memory transfers
+ assert(
+ (transfer_conf->addr_mode == omap44xx_sdma_ADDR_MODE_POST_INCR) ||
+ (transfer_conf->addr_mode == omap44xx_sdma_ADDR_MODE_SINGLE_IDX) ||
+ (transfer_conf->addr_mode == omap44xx_sdma_ADDR_MODE_DOUBLE_IDX)
+ );
+
+ assert(
+ (transfer_conf->burst_mode == omap44xx_sdma_BURST_EN_SINGLE) ||
+ (transfer_conf->burst_mode == omap44xx_sdma_BURST_EN_16BYTE) ||
+ (transfer_conf->burst_mode == omap44xx_sdma_BURST_EN_32BYTE) ||
+ (transfer_conf->burst_mode == omap44xx_sdma_BURST_EN_64BYTE)
+ );
+
+ // if post-incrementing with burst transfers is used,
+ // data must be packed to DMA data-port width (TRM Section 16.4.7)
+ assert(
+ (transfer_conf->burst_mode == omap44xx_sdma_BURST_EN_SINGLE) ||
+ (transfer_conf->addr_mode != omap44xx_sdma_ADDR_MODE_POST_INCR) ||
+ (transfer_conf->packed_transfer == omap44xx_sdma_SRC_PACKED_ENABLE)
+ );
+}
+
+/**
+ * \brief Configure an allocated channel with the given struct.
+ *
+ * \param channel Channel to configure
+ * \param conf Complete channel configuration
+ *
+ * This function will write all values of the struct to the SDMA device
+ * registers. Some basic santiy checks (using assert statements) are performed,
+ * but is it the callers responsibility to ensure that the configuration is
+ * sane and valid.
+ */
+void omap_sdma_set_channel_conf(omap_sdma_channel_t channel,
+ struct omap_sdma_channel_conf *conf)
+{
+ // check transfer config and size parameters
+ assert(channel < OMAP44XX_SDMA_NUM_CHANNEL);
+
+ omap_sdma_channel_conf_assert_transfer_size(&conf->transfer_size);
+
+ omap_sdma_channel_conf_assert_transfer_conf(&conf->src_conf);
+ omap_sdma_channel_conf_assert_transfer_conf(&conf->dst_conf);
+
+
+ // Channel Control Register
+ omap44xx_sdma_dma4_ccr_t dma4_ccr;
+ dma4_ccr = omap44xx_sdma_dma4_ccr_rd(&devsdma, channel);
+ dma4_ccr = omap_sdma_channel_conf_ccr(dma4_ccr, conf);
+ omap44xx_sdma_dma4_ccr_wr(&devsdma, channel, dma4_ccr);
+
+ // Channel Color Register
+ omap44xx_sdma_dma4_color_t dma4_color;
+ dma4_color = omap44xx_sdma_dma4_color_rd(&devsdma, channel);
+ dma4_color = omap_sdma_channel_conf_color(channel, conf);
+ omap44xx_sdma_dma4_color_wr(&devsdma, channel, dma4_color);
+
+ // Channel Link Control Register
+ omap44xx_sdma_dma4_clnk_ctrl_t dma4_clnk_ctrl;
+ dma4_clnk_ctrl = omap44xx_sdma_dma4_clnk_ctrl_rd(&devsdma, channel);
+ dma4_clnk_ctrl = omap_sdma_channel_conf_clnk_ctrl(channel, conf);
+ omap44xx_sdma_dma4_clnk_ctrl_wr(&devsdma, channel, dma4_clnk_ctrl);
+
+ // Channel Source Destination Parameters
+ omap44xx_sdma_dma4_csdp_t dma4_csdp;
+ dma4_csdp = omap44xx_sdma_dma4_csdp_rd(&devsdma, channel);
+ dma4_csdp = omap_sdma_channel_conf_csdp(channel, conf);
+ omap44xx_sdma_dma4_csdp_wr(&devsdma, channel, dma4_csdp);
+
+ // Channel Element Number
+ omap44xx_sdma_dma4_cen_wr(&devsdma, channel, conf->transfer_size.element_number);
+
+ // Channel Frame Number
+ omap44xx_sdma_dma4_cfn_wr(&devsdma, channel, conf->transfer_size.frame_number);
+
+ // Channel Source Element Index
+ omap44xx_sdma_dma4_csei_wr(&devsdma, channel, conf->src_conf.element_index);
+ // Channel Source Frame Index
+ omap44xx_sdma_dma4_csfi_wr(&devsdma, channel, conf->src_conf.frame_index);
+ // Channel Destination Element Index
+ omap44xx_sdma_dma4_cdei_wr(&devsdma, channel, conf->dst_conf.element_index);
+ // Channel Destination Frame Index
+ omap44xx_sdma_dma4_cdfi_wr(&devsdma, channel, conf->dst_conf.frame_index);
+
+ // Channel Source Start Address
+ omap44xx_sdma_dma4_cssa_wr(&devsdma, channel, conf->src_conf.start_address);
+
+ // Channel Source Destination Address
+ omap44xx_sdma_dma4_cdsa_wr(&devsdma, channel, conf->dst_conf.start_address);
+}
+
+/**
+ * \brief Start a SDMA transfer on a pre-configured channel
+ *
+ * \param channel Pre-configured channel to enable
+ * \param interrupt Indicate an interrupt should be sent on completion or error
+ *
+ * It is the callers responsibility to ensure that the channel was configured
+ * properly before this function is called.
+ */
+void omap_sdma_enable_channel(omap_sdma_channel_t channel, bool interrupt)
+{
+ assert(channel < OMAP44XX_SDMA_NUM_CHANNEL);
+
+ // clear all channel status flags
+ omap44xx_sdma_dma4_csr_wr(&devsdma, channel, 0xFFFFFFFF);
+
+ uint32_t irqenable = omap44xx_sdma_dma4_irqenable_rd(&devsdma, OMAP44XX_SDMA_IRQ_LINE);
+ if (interrupt) {
+ // set channel
+ irqenable |= 1 << channel;
+ // reset irq status for this channel
+ omap44xx_sdma_dma4_irqstatus_line_wr(&devsdma, OMAP44XX_SDMA_IRQ_LINE, 1 << channel);
+ } else {
+ // clear channel
+ irqenable &= ~(1 << channel);
+ }
+ omap44xx_sdma_dma4_irqenable_wr(&devsdma, OMAP44XX_SDMA_IRQ_LINE, irqenable);
+
+ omap44xx_sdma_dma4_ccr_enable_wrf(&devsdma, channel, 1);
+}
+
+/**
+ * \brief Poll a enabled channel for completion of the transfer.
+ */
+errval_t omap_sdma_poll_channel(omap_sdma_channel_t channel)
+{
+ assert(channel < OMAP44XX_SDMA_NUM_CHANNEL);
+
+ // interrupts should be disabled in polling mode
+ assert((omap44xx_sdma_dma4_irqenable_rd(
+ &devsdma, OMAP44XX_SDMA_IRQ_LINE) & 1 << channel) == 0x0
+ );
+
+ for (;;) {
+ omap44xx_sdma_dma4_csr_t csr = omap44xx_sdma_dma4_csr_rd(&devsdma, channel);
+
+ errval_t err = omap_sdma_read_csr(csr);
+
+ if (err_is_fail(err)) return err;
+
+ if(omap44xx_sdma_dma4_csr_block_extract(csr)) {
+ return err;
+ }
+ }
+}
+
+/**
+ * \brief Allocate a SDMA channel. Will return an error if there are no channels
+ * available.
+ */
+errval_t omap_sdma_allocate_channel(omap_sdma_channel_t *channel)
+{
+ assert(channel != NULL);
+
+ for (omap_sdma_channel_t c = 0; c<OMAP44XX_SDMA_NUM_CHANNEL; c++) {
+ if (!allocated_channel[c]) {
+ allocated_channel[c] = true;
+ *channel = c;
+ return SYS_ERR_OK;
+ }
+ }
+ return OMAP_SDMA_ERR_NO_AVAIL_CHANNEL;
+}
+
+/**
+ * \brief Frees a previously allocated SDMA channel.
+ */
+void omap_sdma_free_channel(omap_sdma_channel_t channel)
+{
+ assert(allocated_channel[channel]);
+ allocated_channel[channel] = false;
+}
+
+/**
+ * \brief Initializes this Mackerel wrapper.
+ *
+ * \param dev_base Virtual address where the SDMA module is mapped to
+ * \param irq_cb Mandatory interrupt callback
+ *
+ * The caller has map the SDMA hardware registers before calling this function.
+ * The interrupt callback is executed for every time an SDMA channel triggered
+ * an interrupt. The source channel and the the reason of the interrupt are
+ * passed to the callback as an the argument.
+ */
+errval_t omap_sdma_init(mackerel_addr_t dev_base, omap_sdma_irq_handler_t irq_cb)
+{
+ // init global variables
+ STATIC_ASSERT_SIZEOF(bool, 1);
+ memset(allocated_channel, false, OMAP44XX_SDMA_NUM_CHANNEL);
+
+ omap44xx_sdma_initialize(&devsdma, dev_base);
+
+ // check if we can read the revision
+ assert(omap44xx_sdma_dma4_revision_rd(&devsdma) == 0x10900);
+
+ assert(irq_cb != NULL);
+ irq_callback = irq_cb;
+
+ errval_t err = SYS_ERR_OK;
+#ifdef OMAP_SDMA_KERNELBENCH
+ // in kernelspace, we hijack the normal interrupt handler by overwriting
+ // the global interrupt handler table entry.
+
+ // this is obvioulsy a hack (!) and ONLY for use in the sdma kernel
+ // benchmark which will not allow the kernel to continue after this
+ uintptr_t *irq_handler_entry = (uintptr_t*)
+ (ETABLE_ADDR + JUMP_TABLE_OFFSET + ARM_EVECTOR_IRQ);
+ *irq_handler_entry = (uintptr_t) omap_sdma_kernel_irq_handler;
+
+ // enable the SDMA interrupt in the global interrupt controller
+ gic_enable_interrupt(OMAP44XX_SDMA_IRQ, GIC_IRQ_CPU_TRG_ALL, 0,
+ GIC_IRQ_EDGE_TRIGGERED, GIC_IRQ_N_TO_N);
+#else
+ // in userspace, register normal interrupt handler
+ err = inthandler_setup_arm(omap_sdma_irq_handler, NULL, OMAP44XX_SDMA_IRQ);
+#endif
+
+ // set fifo depth to maximum burst size
+ omap44xx_sdma_dma4_gcr_max_channel_fifo_depth_wrf(&devsdma, 64);
+
+ // configure error and interrupt handling of the device
+ for(omap_sdma_channel_t channel = 0;
+ channel < OMAP44XX_SDMA_NUM_CHANNEL;
+ channel++)
+ {
+ omap_sdma_irq_config(channel);
+ }
+
+ return err;
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr 6, CH-8092 Zurich.
+ */
+
+#ifndef OMAP44XX_SDMA_H_
+#define OMAP44XX_SDMA_H_
+
+#include <stdbool.h>
+#include <dev/omap/omap44xx_sdma_dev.h>
+
+typedef uint8_t omap_sdma_channel_t;
+
+typedef void (*omap_sdma_irq_handler_t)(omap_sdma_channel_t, errval_t);
+
+typedef uint8_t omap44xx_sdma_color_mode_t;
+#define omap44xx_sdma_DISABLE_COLOR_MODE ((omap44xx_sdma_color_mode_t)0x0)
+#define omap44xx_sdma_TRANSPARENT_COPY ((omap44xx_sdma_color_mode_t)0x1)
+#define omap44xx_sdma_CONSTANT_FILL ((omap44xx_sdma_color_mode_t)0x2)
+
+#define OMAP44XX_SDMA_IRQ_LINE (0)
+#define OMAP44XX_SDMA_NUM_CHANNEL (32u)
+#define OMAP44XX_SDMA_IRQ (32 + 12 + OMAP44XX_SDMA_IRQ_LINE) // MA_IRQ_12
+
+#define OMAP44XX_SDMA_MAX_FN 0x0000FFFF
+#define OMAP44XX_SDMA_MAX_EN 0x00FFFFFF
+
+#define OMAP44XX_SDMA_MAX_FN_BITS 15
+#define OMAP44XX_SDMA_MAX_EN_BITS 23
+
+#ifdef SDMA_DEBUG
+#define SDMA_PRINT(...) do{ printf(__VA_ARGS__ ); } while( false )
+#else
+#define SDMA_PRINT(...) do{ } while ( false )
+#endif
+
+struct omap_sdma_transfer_conf {
+ lpaddr_t start_address;
+ omap44xx_sdma_addr_mode_t addr_mode;
+ int16_t element_index;
+ int32_t frame_index;
+ bool packed_transfer;
+ omap44xx_sdma_burst_en_t burst_mode;
+};
+
+struct omap_sdma_transfer_size {
+ uint32_t element_number;
+ uint16_t frame_number;
+ omap44xx_sdma_data_type_t data_type;
+};
+
+/// The values in this struct are directly written into the hardware registers.
+/// While there are some basic sanity checks, it is the users responsibility to
+/// ensure that writes to these physical addresses are allowed.
+///
+/// The naming follows more or less Chapter 16 of the OMAP4466 TRM (Rev. AA)
+
+struct omap_sdma_channel_conf {
+ omap44xx_sdma_port_priority_t read_priority;
+ omap44xx_sdma_port_priority_t write_priority;
+
+ omap44xx_sdma_color_mode_t color_mode;
+ uint32_t color;
+
+ omap44xx_sdma_write_mode_t write_mode;
+
+ struct omap_sdma_transfer_size transfer_size;
+ struct omap_sdma_transfer_conf src_conf;
+ struct omap_sdma_transfer_conf dst_conf;
+
+ bool enable_link;
+ omap_sdma_channel_t next_channel;
+};
+
+errval_t omap_sdma_init(mackerel_addr_t dev_base, omap_sdma_irq_handler_t);
+
+errval_t omap_sdma_allocate_channel(omap_sdma_channel_t *channel);
+void omap_sdma_free_channel(omap_sdma_channel_t channel);
+
+void omap_sdma_init_channel_conf(struct omap_sdma_channel_conf *conf);
+
+void omap_sdma_set_channel_conf(omap_sdma_channel_t channel,
+ struct omap_sdma_channel_conf *conf);
+
+void omap_sdma_enable_channel(omap_sdma_channel_t channel, bool interrupt);
+
+errval_t omap_sdma_poll_channel(omap_sdma_channel_t channel);
+
+#endif // OMAP44XX_SDMA_H_
--- /dev/null
+/*
+ * Copyright (c) 2014, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr 6, CH-8092 Zurich.
+ */
+
+#ifndef SDMA_H_
+#define SDMA_H_
+
+#include <if/omap_sdma_defs.h>
+
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+
+void start_service(void);
+
+errval_t mem_copy(struct capref dst_cap, struct capref src_cap);
+errval_t mem_fill(struct capref dst_cap, uint8_t color);
+
+errval_t mem_copy_2d(omap_sdma_addr_2d_t dst, omap_sdma_addr_2d_t src,
+ omap_sdma_count_2d_t count, bool transparent, uint32_t color);
+errval_t mem_fill_2d(omap_sdma_addr_2d_t dst, omap_sdma_count_2d_t count, uint32_t color);
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2014, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr 6, CH-8092 Zurich.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include <barrelfish/barrelfish.h>
+#include <barrelfish/nameservice_client.h>
+
+#include <if/omap_sdma_defs.h>
+#include <if/omap_sdma_thc.h>
+#include <thc/thc.h>
+
+#include "sdma.h"
+
+static void run_service(struct omap_sdma_thc_service_binding_t *sv)
+{
+ omap_sdma_service_msg_t msg;
+ bool loop = true;
+
+ // this is the bitmap of messages we are interested in receiving
+ struct omap_sdma_service_selector selector = {
+ .mem_copy = 1, .mem_copy_2d = 1,
+ .mem_fill = 1, .mem_fill_2d = 1,
+ };
+
+ while (loop) {
+ // receive any message
+ sv->recv_any(sv, &msg, selector);
+
+ errval_t reterr = SYS_ERR_OK;
+
+ // dispatch it
+ switch(msg.msg) {
+ case omap_sdma_mem_copy:
+ reterr = mem_copy(
+ msg.args.mem_copy.in.dst,
+ msg.args.mem_copy.in.src);
+ sv->send.mem_copy(sv, reterr);
+ break;
+ case omap_sdma_mem_fill:
+ reterr = mem_fill(
+ msg.args.mem_fill.in.dst,
+ msg.args.mem_fill.in.color);
+ sv->send.mem_fill(sv, reterr);
+ break;
+ case omap_sdma_mem_copy_2d:
+ reterr = mem_copy_2d(
+ msg.args.mem_copy_2d.in.dst,
+ msg.args.mem_copy_2d.in.src,
+ msg.args.mem_copy_2d.in.count,
+ msg.args.mem_copy_2d.in.transparent,
+ msg.args.mem_copy_2d.in.color);
+ sv->send.mem_copy_2d(sv, reterr);
+ break;
+ case omap_sdma_mem_fill_2d:
+ reterr = mem_fill_2d(
+ msg.args.mem_fill_2d.in.dst,
+ msg.args.mem_fill_2d.in.count,
+ msg.args.mem_fill_2d.in.color);
+ sv->send.mem_fill_2d(sv, reterr);
+ break;
+ default:
+ debug_printf("unexpected message: %d\n", msg.msg);
+ loop = false;
+ break;
+ }
+ }
+
+ free(sv);
+}
+
+void start_service(void)
+{
+ errval_t err;
+
+ struct omap_sdma_thc_export_info e_info;
+ struct omap_sdma_thc_service_binding_t *sv;
+ struct omap_sdma_binding *b;
+ iref_t iref;
+
+ err = omap_sdma_thc_export(&e_info, "sdma",
+ get_default_waitset(),
+ IDC_EXPORT_FLAGS_DEFAULT,
+ &iref);
+ if (err_is_fail(err)) {
+ USER_PANIC_ERR(err, "thc export failed");
+ }
+
+ DO_FINISH({
+ while(true) {
+ err = omap_sdma_thc_accept(&e_info, &b);
+ if (err_is_fail(err)) {
+ USER_PANIC_ERR(err, "thc accept failed");
+ }
+
+ sv = malloc(sizeof(struct omap_sdma_thc_service_binding_t));
+ assert(sv != NULL);
+
+ err = omap_sdma_thc_init_service(sv, b, b);
+ if (err_is_fail(err)) {
+ USER_PANIC_ERR(err, "thc init failed");
+ }
+
+ ASYNC({run_service(sv);});
+ }
+ });
+}