diff options
author | root <root@iss-tomyspiel-l> | 2011-06-18 06:37:00 +0200 |
---|---|---|
committer | root <root@iss-tomyspiel-l> | 2011-06-18 06:37:00 +0200 |
commit | 70937611e34577151a6607640050e8b164a54e70 (patch) | |
tree | 23cc1c9573dafd8584e0f0697f79fde3dad49258 | |
parent | 4b5a2c9625acd583573005ef66d17d919469009d (diff) | |
download | ipecamera-70937611e34577151a6607640050e8b164a54e70.tar.gz ipecamera-70937611e34577151a6607640050e8b164a54e70.tar.bz2 ipecamera-70937611e34577151a6607640050e8b164a54e70.tar.xz ipecamera-70937611e34577151a6607640050e8b164a54e70.zip |
DMA engine initialization and basic intrastructure for DMA read/write
-rw-r--r-- | cli.c | 72 | ||||
-rw-r--r-- | dma/nwl.c | 98 | ||||
-rw-r--r-- | dma/nwl.h | 5 | ||||
-rw-r--r-- | pci.c | 38 | ||||
-rw-r--r-- | pcilib.h | 3 |
5 files changed, 189 insertions, 27 deletions
@@ -55,6 +55,12 @@ typedef enum { } MODE; typedef enum { + ACCESS_BAR, + ACCESS_DMA, + ACCESS_FIFO +} ACCESS_MODE; + +typedef enum { OPT_DEVICE = 'd', OPT_MODEL = 'm', OPT_BAR = 'b', @@ -112,30 +118,30 @@ void Usage(int argc, char *argv[], const char *format, ...) { "Usage:\n" " %s <mode> [options] [hex data]\n" " Modes:\n" -" -i - Device Info\n" -" -l - List Data Banks & Registers\n" -" -p - Performance Evaluation\n" -" -r <addr|reg> - Read Data/Register\n" -" -w <addr|reg> - Write Data/Register\n" -" -g [event] - Grab Event\n" -" --reset - Reset board\n" -" --help - Help message\n" +" -i - Device Info\n" +" -l - List Data Banks & Registers\n" +" -p - Performance Evaluation\n" +" -r <addr|reg|dmaX> - Read Data/Register\n" +" -w <addr|reg|dmaX> - Write Data/Register\n" +" -g [event] - Grab Event\n" +" --reset - Reset board\n" +" --help - Help message\n" "\n" " Addressing:\n" -" -d <device> - FPGA device (/dev/fpga0)\n" -" -m <model> - Memory model (autodetected)\n" -" pci - Plain\n" -" ipecamera - IPE Camera\n" -" -b <bank> - Data/Register bank (autodetected)\n" +" -d <device> - FPGA device (/dev/fpga0)\n" +" -m <model> - Memory model (autodetected)\n" +" pci - Plain\n" +" ipecamera - IPE Camera\n" +" -b <bank> - Data/Register bank (autodetected)\n" "\n" " Options:\n" -" -s <size> - Number of words (default: 1)\n" -" -a <bitness> - Bits per word (default: 32)\n" -" -e <l|b> - Endianess Little/Big (default: host)\n" -" -o <file> - Output to file (default: stdout)\n" +" -s <size> - Number of words (default: 1)\n" +" -a <bitness> - Bits per word (default: 32)\n" +" -e <l|b> - Endianess Little/Big (default: host)\n" +" -o <file> - Output to file (default: stdout)\n" "\n" " Information:\n" -" -q - Quiete mode (suppress warnings)\n" +" -q - Quiete mode (suppress warnings)\n" "\n" " Data:\n" " Data can be specified as sequence of hexdecimal number or\n" @@ -398,7 +404,7 @@ int Benchmark(pcilib_t *handle, pcilib_bar_t bar) { #define pci2host16(endianess, value) endianess? -int ReadData(pcilib_t *handle, pcilib_bar_t bar, uintptr_t addr, size_t n, access_t access, int endianess) { +int ReadData(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_addr_t dma, pcilib_bar_t bar, uintptr_t addr, size_t n, access_t access, int endianess) { void *buf; int i, err; int size = n * abs(access); @@ -416,7 +422,15 @@ int ReadData(pcilib_t *handle, pcilib_bar_t bar, uintptr_t addr, size_t n, acces err = posix_memalign( (void**)&buf, 256, size ); if ((err)||(!buf)) Error("Allocation of %i bytes of memory have failed", size); - pcilib_read(handle, bar, addr, size, buf); + if (mode == ACCESS_DMA) { + pcilib_dma_t dmaid = pcilib_find_dma_by_addr(handle, PCILIB_DMA_FROM_DEVICE, dma); + if (dmaid == PCILIB_DMA_INVALID) Error("Invalid DMA engine (%lu) is specified", dma); + pcilib_read_dma(handle, dmaid, size, buf); + + addr = 0; + } else { + pcilib_read(handle, bar, addr, size, buf); + } if (endianess) pcilib_swap(buf, buf, abs(access), n); for (i = 0; i < n; i++) { @@ -443,6 +457,9 @@ int ReadData(pcilib_t *handle, pcilib_bar_t bar, uintptr_t addr, size_t n, acces free(buf); } + + + int ReadRegister(pcilib_t *handle, pcilib_model_t model, const char *bank, const char *reg) { int i; int err; @@ -548,7 +565,7 @@ int ReadRegisterRange(pcilib_t *handle, pcilib_model_t model, const char *bank, printf("\n\n"); } -int WriteData(pcilib_t *handle, pcilib_bar_t bar, uintptr_t addr, size_t n, access_t access, int endianess, char ** data) { +int WriteData(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_addr_t dma, pcilib_bar_t bar, uintptr_t addr, size_t n, access_t access, int endianess, char ** data) { void *buf, *check; int res, i, err; int size = n * abs(access); @@ -574,7 +591,7 @@ int WriteData(pcilib_t *handle, pcilib_bar_t bar, uintptr_t addr, size_t n, acce if (memcmp(buf, check, size)) { printf("Write failed: the data written and read differ, the foolowing is read back:\n"); if (endianess) pcilib_swap(check, check, abs(access), n); - ReadData(handle, bar, addr, n, access, endianess); + ReadData(handle, mode, dma, bar, addr, n, access, endianess); exit(-1); } @@ -687,6 +704,7 @@ int main(int argc, char **argv) { pcilib_model_t model = PCILIB_MODEL_DETECT; MODE mode = MODE_INVALID; + ACCESS_MODE amode = ACCESS_BAR; const char *fpga_device = DEFAULT_FPGA_DEVICE; pcilib_bar_t bar = PCILIB_BAR_DETECT; const char *addr = NULL; @@ -695,6 +713,7 @@ int main(int argc, char **argv) { char **data = NULL; const char *event = NULL; + pcilib_dma_addr_t dma; uintptr_t start = -1; size_t size = 1; access_t access = 4; @@ -848,7 +867,10 @@ int main(int argc, char **argv) { } if (addr) { - if ((isxnumber(addr))&&(sscanf(addr, "%lx", &start) == 1)) { + if (!strncmp(addr, "dma", 3)) { + dma = atoi(addr + 3); + amode = ACCESS_DMA; + } else if ((isxnumber(addr))&&(sscanf(addr, "%lx", &start) == 1)) { // check if the address in the register range pcilib_register_range_t *ranges = pcilib_model[model].ranges; @@ -896,7 +918,7 @@ int main(int argc, char **argv) { break; case MODE_READ: if (addr) { - ReadData(handle, bar, start, size, access, endianess); + ReadData(handle, amode, dma, bar, start, size, access, endianess); } else { Error("Address to read is not specified"); } @@ -906,7 +928,7 @@ int main(int argc, char **argv) { else ReadRegisterRange(handle, model, bank, start, size); break; case MODE_WRITE: - WriteData(handle, bar, start, size, access, endianess, data); + WriteData(handle, amode, dma, bar, start, size, access, endianess, data); break; case MODE_WRITE_REGISTER: if (reg) WriteRegister(handle, model, bank, reg, data); @@ -3,6 +3,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/time.h> #include "pci.h" #include "pcilib.h" @@ -63,10 +64,45 @@ #define DMA_ENG_NUMBER 0x0000FF00 /**< DMA engine number */ #define DMA_ENG_BD_MAX_BC 0x3F000000 /**< DMA engine max buffer size */ + /* Shift constants for selected masks */ #define DMA_ENG_NUMBER_SHIFT 8 #define DMA_ENG_BD_MAX_BC_SHIFT 24 +/** @name Bitmasks of REG_DMA_ENG_CTRL_STATUS register. + * @{ + */ +/* Interrupt activity and acknowledgement bits */ +#define DMA_ENG_INT_ENABLE 0x00000001 /**< Enable interrupts */ +#define DMA_ENG_INT_DISABLE 0x00000000 /**< Disable interrupts */ +#define DMA_ENG_INT_ACTIVE_MASK 0x00000002 /**< Interrupt active? */ +#define DMA_ENG_INT_ACK 0x00000002 /**< Interrupt ack */ +#define DMA_ENG_INT_BDCOMP 0x00000004 /**< Int - BD completion */ +#define DMA_ENG_INT_BDCOMP_ACK 0x00000004 /**< Acknowledge */ +#define DMA_ENG_INT_ALERR 0x00000008 /**< Int - BD align error */ +#define DMA_ENG_INT_ALERR_ACK 0x00000008 /**< Acknowledge */ +#define DMA_ENG_INT_FETERR 0x00000010 /**< Int - BD fetch error */ +#define DMA_ENG_INT_FETERR_ACK 0x00000010 /**< Acknowledge */ +#define DMA_ENG_INT_ABORTERR 0x00000020 /**< Int - DMA abort error */ +#define DMA_ENG_INT_ABORTERR_ACK 0x00000020 /**< Acknowledge */ +#define DMA_ENG_INT_CHAINEND 0x00000080 /**< Int - BD chain ended */ +#define DMA_ENG_INT_CHAINEND_ACK 0x00000080 /**< Acknowledge */ + +/* DMA engine control */ +#define DMA_ENG_ENABLE_MASK 0x00000100 /**< DMA enabled? */ +#define DMA_ENG_ENABLE 0x00000100 /**< Enable DMA */ +#define DMA_ENG_DISABLE 0x00000000 /**< Disable DMA */ +#define DMA_ENG_STATE_MASK 0x00000C00 /**< Current DMA state? */ +#define DMA_ENG_RUNNING 0x00000400 /**< DMA running */ +#define DMA_ENG_IDLE 0x00000000 /**< DMA idle */ +#define DMA_ENG_WAITING 0x00000800 /**< DMA waiting */ +#define DMA_ENG_STATE_WAITED 0x00001000 /**< DMA waited earlier */ +#define DMA_ENG_WAITED_ACK 0x00001000 /**< Acknowledge */ +#define DMA_ENG_USER_RESET 0x00004000 /**< Reset only user logic */ +#define DMA_ENG_RESET 0x00008000 /**< Reset DMA engine + user */ + +#define DMA_ENG_ALLINT_MASK 0x000000BE /**< To get only int events */ + #define DMA_ENGINE_PER_SIZE 0x100 /**< Separation between engine regs */ #define DMA_OFFSET 0 /**< Starting register offset */ /**< Size of DMA engine reg space */ @@ -96,6 +132,7 @@ struct nwl_dma_s { pcilib_register_bank_description_t *dma_bank; char *base_addr; + pcilib_dma_t n_engines; pcilib_nwl_engine_description_t engines[PCILIB_MAX_DMA_ENGINES + 1]; }; @@ -105,6 +142,8 @@ struct nwl_dma_s { static int nwl_read_engine_config(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *info, char *base) { uint32_t val; + info->base_addr = base; + nwl_read_register(val, ctx, base, REG_DMA_ENG_CAP); if ((val & DMA_ENG_PRESENT_MASK) == 0) return PCILIB_ERROR_NOTAVAILABLE; @@ -135,6 +174,54 @@ static int nwl_read_engine_config(nwl_dma_t *ctx, pcilib_nwl_engine_description_ return 0; } +static int nwl_stop_engine(nwl_dma_t *ctx, pcilib_dma_t dma) { + uint32_t val; + struct timeval start, cur; + + pcilib_nwl_engine_description_t *info = ctx->engines + dma; + char *base = ctx->engines[dma].base_addr; + + // Disable IRQ + nwl_read_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS); + val &= ~(DMA_ENG_INT_ENABLE); + nwl_write_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS); + + + // Reseting + val = DMA_ENG_DISABLE|DMA_ENG_USER_RESET; nwl_write_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS); + gettimeofday(&start, NULL); + do { + nwl_read_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS); + gettimeofday(&cur, NULL); + } while ((val & (DMA_ENG_STATE_MASK|DMA_ENG_USER_RESET))&&(((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)) < PCILIB_REGISTER_TIMEOUT)); + + if (val & DMA_ENG_RESET) { + pcilib_error("Timeout during reset of DMA engine %i", info->desc.addr); + return PCILIB_ERROR_TIMEOUT; + } + + + val = DMA_ENG_RESET; nwl_write_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS); + gettimeofday(&start, NULL); + do { + nwl_read_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS); + gettimeofday(&cur, NULL); + } while ((val & DMA_ENG_RESET)&&(((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)) < PCILIB_REGISTER_TIMEOUT)); + + if (val & DMA_ENG_RESET) { + pcilib_error("Timeout during reset of DMA engine %i", info->desc.addr); + return PCILIB_ERROR_TIMEOUT; + } + + // Acknowledge asserted engine interrupts + if (val & DMA_ENG_INT_ACTIVE_MASK) { + val |= DMA_ENG_ALLINT_MASK; + nwl_write_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS); + } + + return 0; +} + pcilib_dma_context_t *dma_nwl_init(pcilib_t *pcilib) { int i; int err; @@ -159,20 +246,31 @@ pcilib_dma_context_t *dma_nwl_init(pcilib_t *pcilib) { for (i = 0, n_engines = 0; i < 2 * PCILIB_MAX_DMA_ENGINES; i++) { char *addr = ctx->base_addr + DMA_OFFSET + i * DMA_ENGINE_PER_SIZE; err = nwl_read_engine_config(ctx, ctx->engines + n_engines, addr); + if (!err) err = nwl_stop_engine(ctx, n_engines); if (!err) { ctx->engines[n_engines].base_addr = addr; pcilib_set_dma_engine_description(pcilib, n_engines, (pcilib_dma_engine_description_t*)(ctx->engines + n_engines)); ++n_engines; } + } pcilib_set_dma_engine_description(pcilib, n_engines, NULL); + + ctx->n_engines = n_engines; } return (pcilib_dma_context_t*)ctx; } void dma_nwl_free(pcilib_dma_context_t *vctx) { + pcilib_dma_t i; nwl_dma_t *ctx = (nwl_dma_t*)vctx; if (ctx) { + for (i = 0; i < ctx->n_engines; i++) nwl_stop_engine(vctx, i); free(ctx); } } + +int dma_nwl_read(pcilib_dma_context_t *vctx, pcilib_dma_t dma, size_t size, void *buf) { + nwl_dma_t *ctx = (nwl_dma_t*)vctx; + printf("Reading dma: %i\n", dma); +} @@ -17,10 +17,13 @@ typedef struct { pcilib_dma_context_t *dma_nwl_init(pcilib_t *ctx); void dma_nwl_free(pcilib_dma_context_t *vctx); +int dma_nwl_read(pcilib_dma_context_t *ctx, pcilib_dma_t dma, size_t size, void *buf); + #ifdef _PCILIB_DMA_NWL_C pcilib_dma_api_description_t nwl_dma_api = { dma_nwl_init, - dma_nwl_free + dma_nwl_free, + dma_nwl_read }; #else extern pcilib_dma_api_description_t nwl_dma_api; @@ -270,6 +270,44 @@ int pcilib_write(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, v pcilib_unmap_bar(ctx, bar, data); } +pcilib_dma_t pcilib_find_dma_by_addr(pcilib_t *ctx, pcilib_dma_direction_t direction, pcilib_dma_addr_t dma) { + pcilib_dma_t i; + + const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx); + if (!info) { + pcilib_error("DMA Engine is not configured in the current model"); + return PCILIB_ERROR_NOTSUPPORTED; + } + + for (i = 0; info->engines[i]; i++) { + if ((info->engines[i]->addr == dma)&&((info->engines[i]->direction&direction)==direction)) break; + } + + if (info->engines[i]) return i; + return PCILIB_DMA_INVALID; +} + +int pcilib_read_dma(pcilib_t *ctx, pcilib_dma_t dma, size_t size, void *buf) { + const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx); + + if (!ctx->model_info->dma_api) { + pcilib_error("DMA Engine is not configured in the current model"); + return PCILIB_ERROR_NOTSUPPORTED; + } + + if (!ctx->model_info->dma_api->read) { + pcilib_error("The DMA read is not supported by configured DMA engine"); + return PCILIB_ERROR_NOTSUPPORTED; + } + + if (!info->engines[dma]) { + pcilib_error("The DMA engine (%i) is not supported by device", dma); + return PCILIB_ERROR_OUTOFRANGE; + } + + return ctx->model_info->dma_api->read(ctx->dma_ctx, dma, size, buf); +} + pcilib_register_bank_t pcilib_find_bank_by_addr(pcilib_t *ctx, pcilib_register_bank_addr_t bank) { pcilib_register_bank_t i; @@ -66,6 +66,7 @@ typedef enum { #define PCILIB_BAR_INVALID ((pcilib_bar_t)-1) #define PCILIB_BAR0 0 #define PCILIB_BAR1 1 +#define PCILIB_DMA_INVALID ((pcilib_dma_t)-1) #define PCILIB_REGISTER_INVALID ((pcilib_register_t)-1) #define PCILIB_ADDRESS_INVALID ((uintptr_t)-1) #define PCILIB_REGISTER_BANK_INVALID ((pcilib_register_bank_t)-1) @@ -163,7 +164,7 @@ typedef struct { pcilib_dma_context_t *(*init)(pcilib_t *ctx); void (*free)(pcilib_dma_context_t *ctx); -// int (*read)(pcilib_dma_context_t *ctx, pcilib_event_t event_mask, pcilib_callback_t callback, void *user); + int (*read)(pcilib_dma_context_t *ctx, pcilib_dma_t dma, size_t size, void *buf); // int (*write)(pcilib_dma_context_t *ctx); } pcilib_dma_api_description_t; |