summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--cli.c3
-rw-r--r--dma/nwl.c178
-rw-r--r--dma/nwl.h30
-rw-r--r--ipecamera/image.c2
-rw-r--r--ipecamera/model.h1
-rw-r--r--pci.c44
-rw-r--r--pci.h7
-rw-r--r--pcilib.h13
9 files changed, 255 insertions, 25 deletions
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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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 <stdio.h>
+#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 <time.h>
#include <stdint.h>
@@ -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);