summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/platform/vsp1/vsp1_dl.c72
-rw-r--r--drivers/media/platform/vsp1/vsp1_dl.h1
-rw-r--r--drivers/media/platform/vsp1/vsp1_wpf.c2
3 files changed, 70 insertions, 5 deletions
diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c
index e0f4816925d5..81ea1b2ce00d 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -28,9 +28,23 @@
* - DL swap
*/
+#define VSP1_DL_HEADER_SIZE 76
#define VSP1_DL_BODY_SIZE (2 * 4 * 256)
#define VSP1_DL_NUM_LISTS 3
+#define VSP1_DLH_INT_ENABLE (1 << 1)
+#define VSP1_DLH_AUTO_START (1 << 0)
+
+struct vsp1_dl_header {
+ u32 num_lists;
+ struct {
+ u32 num_bytes;
+ u32 addr;
+ } lists[8];
+ u32 next_header;
+ u32 flags;
+} __attribute__((__packed__));
+
struct vsp1_dl_entry {
u32 addr;
u32 data;
@@ -41,6 +55,7 @@ struct vsp1_dl_list {
struct vsp1_dl_manager *dlm;
+ struct vsp1_dl_header *header;
struct vsp1_dl_entry *body;
dma_addr_t dma;
size_t size;
@@ -48,8 +63,15 @@ struct vsp1_dl_list {
int reg_count;
};
+enum vsp1_dl_mode {
+ VSP1_DL_MODE_HEADER,
+ VSP1_DL_MODE_HEADERLESS,
+};
+
/**
* struct vsp1_dl_manager - Display List manager
+ * @index: index of the related WPF
+ * @mode: display list operation mode (header or headerless)
* @vsp1: the VSP1 device
* @lock: protects the active, queued and pending lists
* @free: array of all free display lists
@@ -58,6 +80,8 @@ struct vsp1_dl_list {
* @pending: list waiting to be queued to the hardware
*/
struct vsp1_dl_manager {
+ unsigned int index;
+ enum vsp1_dl_mode mode;
struct vsp1_device *vsp1;
spinlock_t lock;
@@ -74,26 +98,43 @@ struct vsp1_dl_manager {
static struct vsp1_dl_list *vsp1_dl_list_alloc(struct vsp1_dl_manager *dlm)
{
struct vsp1_dl_list *dl;
+ size_t header_size;
+
+ /* The body needs to be aligned on a 8 bytes boundary, pad the header
+ * size to allow allocating both in a single operation.
+ */
+ header_size = dlm->mode == VSP1_DL_MODE_HEADER
+ ? ALIGN(sizeof(struct vsp1_dl_header), 8)
+ : 0;
dl = kzalloc(sizeof(*dl), GFP_KERNEL);
if (!dl)
return NULL;
dl->dlm = dlm;
- dl->size = VSP1_DL_BODY_SIZE;
+ dl->size = header_size + VSP1_DL_BODY_SIZE;
- dl->body = dma_alloc_wc(dlm->vsp1->dev, dl->size, &dl->dma, GFP_KERNEL);
- if (!dl->body) {
+ dl->header = dma_alloc_wc(dlm->vsp1->dev, dl->size, &dl->dma,
+ GFP_KERNEL);
+ if (!dl->header) {
kfree(dl);
return NULL;
}
+ if (dlm->mode == VSP1_DL_MODE_HEADER) {
+ memset(dl->header, 0, sizeof(*dl->header));
+ dl->header->lists[0].addr = dl->dma + header_size;
+ dl->header->flags = VSP1_DLH_INT_ENABLE;
+ }
+
+ dl->body = ((void *)dl->header) + header_size;
+
return dl;
}
static void vsp1_dl_list_free(struct vsp1_dl_list *dl)
{
- dma_free_wc(dl->dlm->vsp1->dev, dl->size, dl->body, dl->dma);
+ dma_free_wc(dl->dlm->vsp1->dev, dl->size, dl->header, dl->dma);
kfree(dl);
}
@@ -159,6 +200,18 @@ void vsp1_dl_list_commit(struct vsp1_dl_list *dl)
spin_lock_irqsave(&dlm->lock, flags);
+ if (dl->dlm->mode == VSP1_DL_MODE_HEADER) {
+ /* Program the hardware with the display list body address and
+ * size. In header mode the caller guarantees that the hardware
+ * is idle at this point.
+ */
+ dl->header->lists[0].num_bytes = dl->reg_count * 8;
+ vsp1_write(vsp1, VI6_DL_HDR_ADDR(dlm->index), dl->dma);
+
+ dlm->active = dl;
+ goto done;
+ }
+
/* Once the UPD bit has been set the hardware can start processing the
* display list at any time and we can't touch the address and size
* registers. In that case mark the update as pending, it will be
@@ -214,6 +267,13 @@ void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm)
vsp1_dl_list_put(dlm->active);
dlm->active = NULL;
+ /* Header mode is used for mem-to-mem pipelines only. We don't need to
+ * perform any operation as there can't be any new display list queued
+ * in that case.
+ */
+ if (dlm->mode == VSP1_DL_MODE_HEADER)
+ goto done;
+
/* The UPD bit set indicates that the commit operation raced with the
* interrupt and occurred after the frame end event and UPD clear but
* before interrupt processing. The hardware hasn't taken the update
@@ -276,6 +336,7 @@ void vsp1_dlm_reset(struct vsp1_dl_manager *dlm)
}
struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1,
+ unsigned int index,
unsigned int prealloc)
{
struct vsp1_dl_manager *dlm;
@@ -285,6 +346,9 @@ struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1,
if (!dlm)
return NULL;
+ dlm->index = index;
+ dlm->mode = index == 0 && !vsp1->info->uapi
+ ? VSP1_DL_MODE_HEADERLESS : VSP1_DL_MODE_HEADER;
dlm->vsp1 = vsp1;
spin_lock_init(&dlm->lock);
diff --git a/drivers/media/platform/vsp1/vsp1_dl.h b/drivers/media/platform/vsp1/vsp1_dl.h
index 46f7ae337374..571ed6d8e7c2 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.h
+++ b/drivers/media/platform/vsp1/vsp1_dl.h
@@ -22,6 +22,7 @@ struct vsp1_dl_manager;
void vsp1_dlm_setup(struct vsp1_device *vsp1);
struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1,
+ unsigned int index,
unsigned int prealloc);
void vsp1_dlm_destroy(struct vsp1_dl_manager *dlm);
void vsp1_dlm_reset(struct vsp1_dl_manager *dlm);
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index 1013190e440b..d1fad9effb9b 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -202,7 +202,7 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
/* Initialize the display list manager if the WPF is used for display */
if ((vsp1->info->features & VSP1_HAS_LIF) && index == 0) {
- wpf->dlm = vsp1_dlm_create(vsp1, 4);
+ wpf->dlm = vsp1_dlm_create(vsp1, index, 4);
if (!wpf->dlm) {
ret = -ENOMEM;
goto error;