From 4b5a2c9625acd583573005ef66d17d919469009d Mon Sep 17 00:00:00 2001 From: root Date: Fri, 17 Jun 2011 23:40:33 +0200 Subject: Enumerate DMA engines --- Makefile | 2 +- cli.c | 3 +- dma/nwl.c | 178 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ dma/nwl.h | 30 +++++++++ ipecamera/image.c | 2 +- ipecamera/model.h | 1 + pci.c | 44 +++++++++----- pci.h | 7 +-- pcilib.h | 13 ++-- 9 files changed, 255 insertions(+), 25 deletions(-) create mode 100644 dma/nwl.c create mode 100644 dma/nwl.h diff --git a/Makefile b/Makefile index d8bf40b..c5efffa 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ include common.mk ############################################################### # Target definitions -OBJECTS = pci.o default.o tools.o ipecamera/model.o ipecamera/image.o +OBJECTS = pci.o default.o tools.o dma/nwl.o ipecamera/model.o ipecamera/image.o libpcilib.so: $(OBJECTS) echo -e "LD \t$@" diff --git a/cli.c b/cli.c index 4a5aafc..aac39f5 100644 --- a/cli.c +++ b/cli.c @@ -217,8 +217,9 @@ void List(pcilib_t *handle, pcilib_model_t model, const char *bank) { break; } - printf(", Size: %08lx", engine->max_bytes); + printf(", Address Width: %02lu bits\n", engine->addr_bits); } + printf("\n"); } if ((bank)&&(bank != (char*)-1)) banks = NULL; diff --git a/dma/nwl.c b/dma/nwl.c new file mode 100644 index 0000000..5a1a719 --- /dev/null +++ b/dma/nwl.c @@ -0,0 +1,178 @@ +#define _PCILIB_DMA_NWL_C + +#include +#include +#include + +#include "pci.h" +#include "pcilib.h" +#include "error.h" +#include "tools.h" +#include "nwl.h" + +/* Common DMA registers */ +#define REG_DMA_CTRL_STATUS 0x4000 /**< DMA Common Ctrl & Status */ + +/* These engine registers are applicable to both S2C and C2S channels. + * Register field mask and shift definitions are later in this file. + */ + +#define REG_DMA_ENG_CAP 0x00000000 /**< DMA Engine Capabilities */ +#define REG_DMA_ENG_CTRL_STATUS 0x00000004 /**< DMA Engine Control */ +#define REG_DMA_ENG_NEXT_BD 0x00000008 /**< HW Next desc pointer */ +#define REG_SW_NEXT_BD 0x0000000C /**< SW Next desc pointer */ +#define REG_DMA_ENG_LAST_BD 0x00000010 /**< HW Last completed pointer */ +#define REG_DMA_ENG_ACTIVE_TIME 0x00000014 /**< DMA Engine Active Time */ +#define REG_DMA_ENG_WAIT_TIME 0x00000018 /**< DMA Engine Wait Time */ +#define REG_DMA_ENG_COMP_BYTES 0x0000001C /**< DMA Engine Completed Bytes */ + +/* Register masks. The following constants define bit locations of various + * control bits in the registers. For further information on the meaning of + * the various bit masks, refer to the hardware spec. + * + * Masks have been written assuming HW bits 0-31 correspond to SW bits 0-31 + */ + +/** @name Bitmasks of REG_DMA_CTRL_STATUS register. + * @{ + */ +#define DMA_INT_ENABLE 0x00000001 /**< Enable global interrupts */ +#define DMA_INT_DISABLE 0x00000000 /**< Disable interrupts */ +#define DMA_INT_ACTIVE_MASK 0x00000002 /**< Interrupt active? */ +#define DMA_INT_PENDING_MASK 0x00000004 /**< Engine interrupt pending */ +#define DMA_INT_MSI_MODE 0x00000008 /**< MSI or Legacy mode? */ +#define DMA_USER_INT_ENABLE 0x00000010 /**< Enable user interrupts */ +#define DMA_USER_INT_ACTIVE_MASK 0x00000020 /**< Int - user interrupt */ +#define DMA_USER_INT_ACK 0x00000020 /**< Acknowledge */ +#define DMA_MPS_USED 0x00000700 /**< MPS Used */ +#define DMA_MRRS_USED 0x00007000 /**< MRRS Used */ +#define DMA_S2C_ENG_INT_VAL 0x00FF0000 /**< IRQ value of 1st 8 S2Cs */ +#define DMA_C2S_ENG_INT_VAL 0xFF000000 /**< IRQ value of 1st 8 C2Ss */ + +/** @name Bitmasks of REG_DMA_ENG_CAP register. + * @{ + */ +/* DMA engine characteristics */ +#define DMA_ENG_PRESENT_MASK 0x00000001 /**< DMA engine present? */ +#define DMA_ENG_DIRECTION_MASK 0x00000002 /**< DMA engine direction */ +#define DMA_ENG_C2S 0x00000002 /**< DMA engine - C2S */ +#define DMA_ENG_S2C 0x00000000 /**< DMA engine - S2C */ +#define DMA_ENG_TYPE_MASK 0x00000030 /**< DMA engine type */ +#define DMA_ENG_BLOCK 0x00000000 /**< DMA engine - Block type */ +#define DMA_ENG_PACKET 0x00000010 /**< DMA engine - Packet type */ +#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 + +#define DMA_ENGINE_PER_SIZE 0x100 /**< Separation between engine regs */ +#define DMA_OFFSET 0 /**< Starting register offset */ + /**< Size of DMA engine reg space */ +#define DMA_SIZE (MAX_DMA_ENGINES * DMA_ENGINE_PER_SIZE) + +/* +pcilib_register_bank_description_t ipecamera_register_banks[] = { + { PCILIB_REGISTER_DMABANK0, PCILIB_BAR0, 128, PCILIB_DEFAULT_PROTOCOL, DMA_NWL_OFFSET, DMA_NWL_OFFSET, PCILIB_LITTLE_ENDIAN, 32, PCILIB_LITTLE_ENDIAN, "%lx", "dma", "NorthWest Logick DMA Engine" }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL } +}; + +pcilib_register_description_t dma_nwl_registers[] = { + {0, 0, 32, 0, PCILIB_REGISTER_R , PCILIB_REGISTER_DMABANK, "dma_capabilities", ""}, + {1, 0, 32, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_DMABANK, "dma_control", ""}, +}; +*/ + +typedef struct { + pcilib_dma_engine_description_t desc; + char *base_addr; +} pcilib_nwl_engine_description_t; + + +struct nwl_dma_s { + pcilib_t *pcilib; + + pcilib_register_bank_description_t *dma_bank; + char *base_addr; + + pcilib_nwl_engine_description_t engines[PCILIB_MAX_DMA_ENGINES + 1]; +}; + +#define nwl_read_register(var, ctx, base, reg) pcilib_datacpy(&var, base + reg, 4, 1, ctx->dma_bank->raw_endianess) +#define nwl_write_register(var, ctx, base, reg) pcilib_datacpy(base + reg, &var, 4, 1, ctx->dma_bank->raw_endianess) + +static int nwl_read_engine_config(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *info, char *base) { + uint32_t val; + + nwl_read_register(val, ctx, base, REG_DMA_ENG_CAP); + + if ((val & DMA_ENG_PRESENT_MASK) == 0) return PCILIB_ERROR_NOTAVAILABLE; + + info->desc.addr = (val & DMA_ENG_NUMBER) >> DMA_ENG_NUMBER_SHIFT; + + switch (val & DMA_ENG_DIRECTION_MASK) { + case DMA_ENG_C2S: + info->desc.direction = PCILIB_DMA_FROM_DEVICE; + break; + default: + info->desc.direction = PCILIB_DMA_TO_DEVICE; + } + + switch (val & DMA_ENG_TYPE_MASK) { + case DMA_ENG_BLOCK: + info->desc.type = PCILIB_DMA_TYPE_BLOCK; + break; + case DMA_ENG_PACKET: + info->desc.type = PCILIB_DMA_TYPE_PACKET; + break; + default: + info->desc.type = PCILIB_DMA_TYPE_UNKNOWN; + } + + info->desc.addr_bits = (val & DMA_ENG_BD_MAX_BC) >> DMA_ENG_BD_MAX_BC_SHIFT; + + return 0; +} + +pcilib_dma_context_t *dma_nwl_init(pcilib_t *pcilib) { + int i; + int err; + pcilib_dma_t n_engines; + + pcilib_model_description_t *model_info = pcilib_get_model_description(pcilib); + + nwl_dma_t *ctx = malloc(sizeof(nwl_dma_t)); + if (ctx) { + memset(ctx, 0, sizeof(nwl_dma_t)); + ctx->pcilib = pcilib; + pcilib_register_bank_t dma_bank = pcilib_find_bank_by_addr(pcilib, PCILIB_REGISTER_BANK_DMA); + + if (dma_bank == PCILIB_REGISTER_BANK_INVALID) { + pcilib_error("DMA Register Bank could not be found"); + return NULL; + } + + ctx->dma_bank = model_info->banks + dma_bank; + ctx->base_addr = pcilib_resolve_register_address(pcilib, ctx->dma_bank->bar, ctx->dma_bank->read_addr); + + 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) { + 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); + } + return (pcilib_dma_context_t*)ctx; +} + +void dma_nwl_free(pcilib_dma_context_t *vctx) { + nwl_dma_t *ctx = (nwl_dma_t*)vctx; + if (ctx) { + free(ctx); + } +} diff --git a/dma/nwl.h b/dma/nwl.h new file mode 100644 index 0000000..63fccfb --- /dev/null +++ b/dma/nwl.h @@ -0,0 +1,30 @@ +#ifndef _PCILIB_DMA_NWL_H +#define _PCILIB_DMA_NWL_H + +#include +#include "pcilib.h" + +typedef struct nwl_dma_s nwl_dma_t; + +/* +typedef struct { + pcilib_dma_engine_info_t info; + // offset +} pcilib_dma_engine_info_t; +*/ + + +pcilib_dma_context_t *dma_nwl_init(pcilib_t *ctx); +void dma_nwl_free(pcilib_dma_context_t *vctx); + +#ifdef _PCILIB_DMA_NWL_C +pcilib_dma_api_description_t nwl_dma_api = { + dma_nwl_init, + dma_nwl_free +}; +#else +extern pcilib_dma_api_description_t nwl_dma_api; +#endif + + +#endif /* _PCILIB_DMA_NWL_H */ diff --git a/ipecamera/image.c b/ipecamera/image.c index 0dc51fc..d9a19cc 100644 --- a/ipecamera/image.c +++ b/ipecamera/image.c @@ -160,7 +160,7 @@ pcilib_context_t *ipecamera_init(pcilib_t *pcilib) { } } - return (void*)ctx; + return (pcilib_context_t*)ctx; } void ipecamera_free(pcilib_context_t *vctx) { diff --git a/ipecamera/model.h b/ipecamera/model.h index 9898084..0ee1be5 100644 --- a/ipecamera/model.h +++ b/ipecamera/model.h @@ -15,6 +15,7 @@ pcilib_register_bank_description_t ipecamera_register_banks[] = { { PCILIB_REGISTER_BANK0, PCILIB_BAR0, 128, IPECAMERA_REGISTER_PROTOCOL, IPECAMERA_REGISTER_READ, IPECAMERA_REGISTER_WRITE, PCILIB_LITTLE_ENDIAN, 8, PCILIB_LITTLE_ENDIAN, "%lu", "cmosis", "CMOSIS CMV2000 Registers" }, { PCILIB_REGISTER_BANK1, PCILIB_BAR0, 64, PCILIB_DEFAULT_PROTOCOL, IPECAMERA_REGISTER_SPACE, IPECAMERA_REGISTER_SPACE, PCILIB_LITTLE_ENDIAN, 32, PCILIB_LITTLE_ENDIAN, "0x%lx", "fpga", "IPECamera Registers" }, + { PCILIB_REGISTER_BANK_DMA, PCILIB_BAR0, 0x2000, PCILIB_DEFAULT_PROTOCOL, 0, 0, PCILIB_LITTLE_ENDIAN, 32, PCILIB_LITTLE_ENDIAN, "0x%lx", "dma", "DMA Registers"}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL } }; diff --git a/pci.c b/pci.c index f40b9ed..ec16476 100644 --- a/pci.c +++ b/pci.c @@ -47,9 +47,10 @@ struct pcilib_s { // size_t data_size; - pcilib_dma_context_t *dma_ctx; + pcilib_model_description_t *model_info; - pcilib_event_context_t *event_ctx; + pcilib_dma_context_t *dma_ctx; + pcilib_context_t *event_ctx; #ifdef PCILIB_FILE_IO int file_io_handle; @@ -93,6 +94,9 @@ pcilib_t *pcilib_open(const char *device, pcilib_model_t model) { ctx->model = model; if (!model) model = pcilib_get_model(ctx); + + ctx->model_info = pcilib_model + model; + api = pcilib_model[model].event_api; if ((api)&&(api->init)) ctx->event_ctx = api->init(ctx); } @@ -100,6 +104,10 @@ pcilib_t *pcilib_open(const char *device, pcilib_model_t model) { return ctx; } +pcilib_model_description_t *pcilib_get_model_description(pcilib_t *ctx) { + return ctx->model_info; +} + const pcilib_board_info_t *pcilib_get_board_info(pcilib_t *ctx) { int ret; @@ -116,18 +124,6 @@ const pcilib_board_info_t *pcilib_get_board_info(pcilib_t *ctx) { return &ctx->board_info; } -const pcilib_dma_info_t *pcilib_get_dma_info(pcilib_t *ctx) { - if (!ctx->dma_ctx) { - pcilib_model_t model = pcilib_get_model(ctx); - pcilib_dma_api_description_t *api = pcilib_model[model].dma_api; - if ((api)&&(api->init)) ctx->dma_ctx = api->init(ctx); - - if (!ctx->dma_ctx) return NULL; - } - - return &ctx->dma_info; -} - pcilib_context_t *pcilib_get_implementation_context(pcilib_t *ctx) { return ctx->event_ctx; } @@ -507,6 +503,26 @@ char *pcilib_resolve_register_address(pcilib_t *ctx, pcilib_bar_t bar, uintptr_ return NULL; } +const pcilib_dma_info_t *pcilib_get_dma_info(pcilib_t *ctx) { + if (!ctx->dma_ctx) { + pcilib_model_t model = pcilib_get_model(ctx); + pcilib_dma_api_description_t *api = pcilib_model[model].dma_api; + + if ((api)&&(api->init)) { + pcilib_map_register_space(ctx); + ctx->dma_ctx = api->init(ctx); + } + + if (!ctx->dma_ctx) return NULL; + } + + return &ctx->dma_info; +} + +int pcilib_set_dma_engine_description(pcilib_t *ctx, pcilib_dma_t engine, pcilib_dma_engine_description_t *desc) { + ctx->dma_info.engines[engine] = desc; +} + char *pcilib_resolve_data_space(pcilib_t *ctx, uintptr_t addr, size_t *size) { int err; diff --git a/pci.h b/pci.h index 0a7a55e..0785c5b 100644 --- a/pci.h +++ b/pci.h @@ -6,23 +6,22 @@ #include "driver/pciDriver.h" -typedef void pcilib_event_context_t; -typedef void pcilib_dma_context_t; - #include "pcilib.h" +int pcilib_set_dma_engine_description(pcilib_t *ctx, pcilib_dma_t engine, pcilib_dma_engine_description_t *desc); const pcilib_board_info_t *pcilib_get_board_info(pcilib_t *ctx); const pcilib_dma_info_t *pcilib_get_dma_info(pcilib_t *ctx); #ifdef _PCILIB_PCI_C # include "ipecamera/model.h" +# include "dma/nwl.h" # include "default.h" pcilib_model_description_t pcilib_model[3] = { { 4, PCILIB_HOST_ENDIAN, NULL, NULL, NULL, NULL, NULL }, { 4, PCILIB_HOST_ENDIAN, NULL, NULL, NULL, NULL, NULL }, - { 4, PCILIB_BIG_ENDIAN, ipecamera_registers, ipecamera_register_banks, ipecamera_register_ranges, ipecamera_events, NULL, &ipecamera_image_api } + { 4, PCILIB_LITTLE_ENDIAN, ipecamera_registers, ipecamera_register_banks, ipecamera_register_ranges, ipecamera_events, &nwl_dma_api, &ipecamera_image_api } }; pcilib_protocol_description_t pcilib_protocol[3] = { diff --git a/pcilib.h b/pcilib.h index 6d52714..f0e0746 100644 --- a/pcilib.h +++ b/pcilib.h @@ -2,6 +2,7 @@ #define _PCITOOL_PCILIB_H #define PCILIB_MAX_BANKS 6 +#define PCILIB_MAX_DMA_ENGINES 32 #include #include @@ -18,6 +19,7 @@ struct timespec { typedef struct pcilib_s pcilib_t; typedef void pcilib_context_t; +typedef void pcilib_dma_context_t; typedef uint8_t pcilib_bar_t; /**< Type holding the PCI Bar number */ typedef uint8_t pcilib_register_t; /**< Type holding the register ID within the Bank */ @@ -71,6 +73,7 @@ typedef enum { #define PCILIB_REGISTER_BANK1 1 #define PCILIB_REGISTER_BANK2 2 #define PCILIB_REGISTER_BANK3 3 +#define PCILIB_REGISTER_BANK_DMA 128 #define PCILIB_EVENT0 1 #define PCILIB_EVENT1 2 #define PCILIB_EVENT2 4 @@ -139,18 +142,19 @@ typedef enum { typedef enum { PCILIB_DMA_TYPE_BLOCK, - PCILIB_DMA_TYPE_PACKET + PCILIB_DMA_TYPE_PACKET, + PCILIB_DMA_TYPE_UNKNOWN } pcilib_dma_type_t; typedef struct { pcilib_dma_addr_t addr; pcilib_dma_type_t type; pcilib_dma_direction_t direction; - size_t max_bytes; + size_t addr_bits; } pcilib_dma_engine_description_t; typedef struct { - pcilib_dma_engine_description_t **engines; + pcilib_dma_engine_description_t *engines[PCILIB_MAX_DMA_ENGINES + 1]; } pcilib_dma_info_t; typedef int (*pcilib_callback_t)(pcilib_event_t event, pcilib_event_id_t event_id, void *user); @@ -198,6 +202,7 @@ extern pcilib_model_description_t pcilib_model[]; int pcilib_set_error_handler(void (*err)(const char *msg, ...), void (*warn)(const char *msg, ...)); pcilib_model_t pcilib_get_model(pcilib_t *ctx); +pcilib_model_description_t *pcilib_get_model_description(pcilib_t *ctx); pcilib_context_t *pcilib_get_implementation_context(pcilib_t *ctx); pcilib_t *pcilib_open(const char *device, pcilib_model_t model); @@ -205,7 +210,7 @@ void pcilib_close(pcilib_t *ctx); void *pcilib_map_bar(pcilib_t *ctx, pcilib_bar_t bar); void pcilib_unmap_bar(pcilib_t *ctx, pcilib_bar_t bar, void *data); -char *pcilib_resolve_register_address(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr); +char *pcilib_resolve_register_address(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr); // addr is offset if bar is specified char *pcilib_resolve_data_space(pcilib_t *ctx, uintptr_t addr, size_t *size); pcilib_register_bank_t pcilib_find_bank_by_addr(pcilib_t *ctx, pcilib_register_bank_addr_t bank); -- cgit v1.2.3