blob: e238d9b9376b83039f045878b1d8c2f20757581d [file] [log] [blame]
Takashi Saito1517b032015-09-07 01:40:25 -03001/*
2 * vsp1_dl.h -- R-Car VSP1 Display List
3 *
4 * Copyright (C) 2015 Renesas Corporation
5 *
6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 */
13
14#include <linux/device.h>
15#include <linux/dma-mapping.h>
16#include <linux/gfp.h>
17#include <linux/slab.h>
18
19#include "vsp1.h"
20#include "vsp1_dl.h"
Takashi Saito1517b032015-09-07 01:40:25 -030021
Laurent Pinchartf81e83c2016-03-03 13:36:34 -030022#define VSP1_DL_NUM_ENTRIES 256
Takashi Saito1517b032015-09-07 01:40:25 -030023#define VSP1_DL_NUM_LISTS 3
24
Laurent Pinchart12161982015-11-14 22:48:27 -020025#define VSP1_DLH_INT_ENABLE (1 << 1)
26#define VSP1_DLH_AUTO_START (1 << 0)
27
Laurent Pinchartf81e83c2016-03-03 13:36:34 -030028struct vsp1_dl_header_list {
29 u32 num_bytes;
30 u32 addr;
31} __attribute__((__packed__));
32
Laurent Pinchart12161982015-11-14 22:48:27 -020033struct vsp1_dl_header {
34 u32 num_lists;
Laurent Pinchartf81e83c2016-03-03 13:36:34 -030035 struct vsp1_dl_header_list lists[8];
Laurent Pinchart12161982015-11-14 22:48:27 -020036 u32 next_header;
37 u32 flags;
38} __attribute__((__packed__));
39
Takashi Saito1517b032015-09-07 01:40:25 -030040struct vsp1_dl_entry {
41 u32 addr;
42 u32 data;
43} __attribute__((__packed__));
44
Laurent Pinchartf81e83c2016-03-03 13:36:34 -030045/**
46 * struct vsp1_dl_body - Display list body
47 * @list: entry in the display list list of bodies
48 * @vsp1: the VSP1 device
49 * @entries: array of entries
50 * @dma: DMA address of the entries
51 * @size: size of the DMA memory in bytes
52 * @num_entries: number of stored entries
53 */
54struct vsp1_dl_body {
Laurent Pinchartc2dd25132015-11-08 20:06:57 -020055 struct list_head list;
Laurent Pinchartf81e83c2016-03-03 13:36:34 -030056 struct vsp1_device *vsp1;
Takashi Saito1517b032015-09-07 01:40:25 -030057
Laurent Pinchartf81e83c2016-03-03 13:36:34 -030058 struct vsp1_dl_entry *entries;
Takashi Saito1517b032015-09-07 01:40:25 -030059 dma_addr_t dma;
Takashi Saito1517b032015-09-07 01:40:25 -030060 size_t size;
Takashi Saito1517b032015-09-07 01:40:25 -030061
Laurent Pinchartf81e83c2016-03-03 13:36:34 -030062 unsigned int num_entries;
63};
64
65/**
66 * struct vsp1_dl_list - Display list
67 * @list: entry in the display list manager lists
68 * @dlm: the display list manager
69 * @header: display list header, NULL for headerless lists
70 * @dma: DMA address for the header
71 * @body0: first display list body
72 * @fragments: list of extra display list bodies
73 */
74struct vsp1_dl_list {
75 struct list_head list;
76 struct vsp1_dl_manager *dlm;
77
78 struct vsp1_dl_header *header;
79 dma_addr_t dma;
80
81 struct vsp1_dl_body body0;
82 struct list_head fragments;
Takashi Saito1517b032015-09-07 01:40:25 -030083};
84
Laurent Pinchart12161982015-11-14 22:48:27 -020085enum vsp1_dl_mode {
86 VSP1_DL_MODE_HEADER,
87 VSP1_DL_MODE_HEADERLESS,
88};
89
Laurent Pinchartef9621b2015-11-14 22:27:52 -020090/**
91 * struct vsp1_dl_manager - Display List manager
Laurent Pinchart12161982015-11-14 22:48:27 -020092 * @index: index of the related WPF
93 * @mode: display list operation mode (header or headerless)
Laurent Pinchartef9621b2015-11-14 22:27:52 -020094 * @vsp1: the VSP1 device
95 * @lock: protects the active, queued and pending lists
96 * @free: array of all free display lists
97 * @active: list currently being processed (loaded) by hardware
98 * @queued: list queued to the hardware (written to the DL registers)
99 * @pending: list waiting to be queued to the hardware
100 */
101struct vsp1_dl_manager {
Laurent Pinchart12161982015-11-14 22:48:27 -0200102 unsigned int index;
103 enum vsp1_dl_mode mode;
Laurent Pinchartef9621b2015-11-14 22:27:52 -0200104 struct vsp1_device *vsp1;
105
106 spinlock_t lock;
107 struct list_head free;
108 struct vsp1_dl_list *active;
109 struct vsp1_dl_list *queued;
110 struct vsp1_dl_list *pending;
111};
112
Takashi Saito1517b032015-09-07 01:40:25 -0300113/* -----------------------------------------------------------------------------
Laurent Pinchartf81e83c2016-03-03 13:36:34 -0300114 * Display List Body Management
115 */
116
117/*
118 * Initialize a display list body object and allocate DMA memory for the body
119 * data. The display list body object is expected to have been initialized to
120 * 0 when allocated.
121 */
122static int vsp1_dl_body_init(struct vsp1_device *vsp1,
123 struct vsp1_dl_body *dlb, unsigned int num_entries,
124 size_t extra_size)
125{
126 size_t size = num_entries * sizeof(*dlb->entries) + extra_size;
127
128 dlb->vsp1 = vsp1;
129 dlb->size = size;
130
131 dlb->entries = dma_alloc_wc(vsp1->dev, dlb->size, &dlb->dma,
132 GFP_KERNEL);
133 if (!dlb->entries)
134 return -ENOMEM;
135
136 return 0;
137}
138
139/*
140 * Cleanup a display list body and free allocated DMA memory allocated.
141 */
142static void vsp1_dl_body_cleanup(struct vsp1_dl_body *dlb)
143{
144 dma_free_wc(dlb->vsp1->dev, dlb->size, dlb->entries, dlb->dma);
145}
146
147/**
148 * vsp1_dl_fragment_alloc - Allocate a display list fragment
149 * @vsp1: The VSP1 device
150 * @num_entries: The maximum number of entries that the fragment can contain
151 *
152 * Allocate a display list fragment with enough memory to contain the requested
153 * number of entries.
154 *
155 * Return a pointer to a fragment on success or NULL if memory can't be
156 * allocated.
157 */
158struct vsp1_dl_body *vsp1_dl_fragment_alloc(struct vsp1_device *vsp1,
159 unsigned int num_entries)
160{
161 struct vsp1_dl_body *dlb;
162 int ret;
163
164 dlb = kzalloc(sizeof(*dlb), GFP_KERNEL);
165 if (!dlb)
166 return NULL;
167
168 ret = vsp1_dl_body_init(vsp1, dlb, num_entries, 0);
169 if (ret < 0) {
170 kfree(dlb);
171 return NULL;
172 }
173
174 return dlb;
175}
176
177/**
178 * vsp1_dl_fragment_free - Free a display list fragment
179 * @dlb: The fragment
180 *
181 * Free the given display list fragment and the associated DMA memory.
182 *
183 * Fragments must only be freed explicitly if they are not added to a display
184 * list, as the display list will take ownership of them and free them
185 * otherwise. Manual free typically happens at cleanup time for fragments that
186 * have been allocated but not used.
187 *
188 * Passing a NULL pointer to this function is safe, in that case no operation
189 * will be performed.
190 */
191void vsp1_dl_fragment_free(struct vsp1_dl_body *dlb)
192{
193 if (!dlb)
194 return;
195
196 vsp1_dl_body_cleanup(dlb);
197 kfree(dlb);
198}
199
200/**
201 * vsp1_dl_fragment_write - Write a register to a display list fragment
202 * @dlb: The fragment
203 * @reg: The register address
204 * @data: The register value
205 *
206 * Write the given register and value to the display list fragment. The maximum
207 * number of entries that can be written in a fragment is specified when the
208 * fragment is allocated by vsp1_dl_fragment_alloc().
209 */
210void vsp1_dl_fragment_write(struct vsp1_dl_body *dlb, u32 reg, u32 data)
211{
212 dlb->entries[dlb->num_entries].addr = reg;
213 dlb->entries[dlb->num_entries].data = data;
214 dlb->num_entries++;
215}
216
217/* -----------------------------------------------------------------------------
Takashi Saito1517b032015-09-07 01:40:25 -0300218 * Display List Transaction Management
219 */
220
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200221static struct vsp1_dl_list *vsp1_dl_list_alloc(struct vsp1_dl_manager *dlm)
Takashi Saito1517b032015-09-07 01:40:25 -0300222{
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200223 struct vsp1_dl_list *dl;
Laurent Pinchart12161982015-11-14 22:48:27 -0200224 size_t header_size;
Laurent Pinchartf81e83c2016-03-03 13:36:34 -0300225 int ret;
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200226
227 dl = kzalloc(sizeof(*dl), GFP_KERNEL);
228 if (!dl)
229 return NULL;
230
Laurent Pinchartf81e83c2016-03-03 13:36:34 -0300231 INIT_LIST_HEAD(&dl->fragments);
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200232 dl->dlm = dlm;
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200233
Laurent Pinchartf81e83c2016-03-03 13:36:34 -0300234 /* Initialize the display list body and allocate DMA memory for the body
235 * and the optional header. Both are allocated together to avoid memory
236 * fragmentation, with the header located right after the body in
237 * memory.
238 */
239 header_size = dlm->mode == VSP1_DL_MODE_HEADER
240 ? ALIGN(sizeof(struct vsp1_dl_header), 8)
241 : 0;
242
243 ret = vsp1_dl_body_init(dlm->vsp1, &dl->body0, VSP1_DL_NUM_ENTRIES,
244 header_size);
245 if (ret < 0) {
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200246 kfree(dl);
247 return NULL;
248 }
249
Laurent Pinchart12161982015-11-14 22:48:27 -0200250 if (dlm->mode == VSP1_DL_MODE_HEADER) {
Laurent Pinchartf81e83c2016-03-03 13:36:34 -0300251 size_t header_offset = VSP1_DL_NUM_ENTRIES
252 * sizeof(*dl->body0.entries);
253
254 dl->header = ((void *)dl->body0.entries) + header_offset;
255 dl->dma = dl->body0.dma + header_offset;
256
Laurent Pinchart12161982015-11-14 22:48:27 -0200257 memset(dl->header, 0, sizeof(*dl->header));
Laurent Pinchartf81e83c2016-03-03 13:36:34 -0300258 dl->header->lists[0].addr = dl->body0.dma;
Laurent Pinchart12161982015-11-14 22:48:27 -0200259 dl->header->flags = VSP1_DLH_INT_ENABLE;
260 }
261
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200262 return dl;
263}
264
Laurent Pinchartf81e83c2016-03-03 13:36:34 -0300265static void vsp1_dl_list_free_fragments(struct vsp1_dl_list *dl)
266{
267 struct vsp1_dl_body *dlb, *next;
268
269 list_for_each_entry_safe(dlb, next, &dl->fragments, list) {
270 list_del(&dlb->list);
271 vsp1_dl_body_cleanup(dlb);
272 kfree(dlb);
273 }
274}
275
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200276static void vsp1_dl_list_free(struct vsp1_dl_list *dl)
277{
Laurent Pinchartf81e83c2016-03-03 13:36:34 -0300278 vsp1_dl_body_cleanup(&dl->body0);
279 vsp1_dl_list_free_fragments(dl);
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200280 kfree(dl);
281}
282
283/**
284 * vsp1_dl_list_get - Get a free display list
285 * @dlm: The display list manager
286 *
287 * Get a display list from the pool of free lists and return it.
288 *
289 * This function must be called without the display list manager lock held.
290 */
291struct vsp1_dl_list *vsp1_dl_list_get(struct vsp1_dl_manager *dlm)
292{
293 struct vsp1_dl_list *dl = NULL;
294 unsigned long flags;
295
296 spin_lock_irqsave(&dlm->lock, flags);
297
298 if (!list_empty(&dlm->free)) {
299 dl = list_first_entry(&dlm->free, struct vsp1_dl_list, list);
300 list_del(&dl->list);
301 }
302
303 spin_unlock_irqrestore(&dlm->lock, flags);
304
305 return dl;
306}
307
Laurent Pinchartd2c1b022016-03-03 09:26:47 -0300308/* This function must be called with the display list manager lock held.*/
309static void __vsp1_dl_list_put(struct vsp1_dl_list *dl)
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200310{
311 if (!dl)
Takashi Saito1517b032015-09-07 01:40:25 -0300312 return;
313
Laurent Pinchartf81e83c2016-03-03 13:36:34 -0300314 vsp1_dl_list_free_fragments(dl);
315 dl->body0.num_entries = 0;
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200316
317 list_add_tail(&dl->list, &dl->dlm->free);
Takashi Saito1517b032015-09-07 01:40:25 -0300318}
319
Laurent Pinchartd2c1b022016-03-03 09:26:47 -0300320/**
321 * vsp1_dl_list_put - Release a display list
322 * @dl: The display list
323 *
324 * Release the display list and return it to the pool of free lists.
325 *
326 * Passing a NULL pointer to this function is safe, in that case no operation
327 * will be performed.
328 */
329void vsp1_dl_list_put(struct vsp1_dl_list *dl)
330{
331 unsigned long flags;
332
333 if (!dl)
334 return;
335
336 spin_lock_irqsave(&dl->dlm->lock, flags);
337 __vsp1_dl_list_put(dl);
338 spin_unlock_irqrestore(&dl->dlm->lock, flags);
339}
340
Laurent Pinchartf81e83c2016-03-03 13:36:34 -0300341/**
342 * vsp1_dl_list_write - Write a register to the display list
343 * @dl: The display list
344 * @reg: The register address
345 * @data: The register value
346 *
347 * Write the given register and value to the display list. Up to 256 registers
348 * can be written per display list.
349 */
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200350void vsp1_dl_list_write(struct vsp1_dl_list *dl, u32 reg, u32 data)
Takashi Saito1517b032015-09-07 01:40:25 -0300351{
Laurent Pinchartf81e83c2016-03-03 13:36:34 -0300352 vsp1_dl_fragment_write(&dl->body0, reg, data);
353}
354
355/**
356 * vsp1_dl_list_add_fragment - Add a fragment to the display list
357 * @dl: The display list
358 * @dlb: The fragment
359 *
360 * Add a display list body as a fragment to a display list. Registers contained
361 * in fragments are processed after registers contained in the main display
362 * list, in the order in which fragments are added.
363 *
364 * Adding a fragment to a display list passes ownership of the fragment to the
365 * list. The caller must not touch the fragment after this call, and must not
366 * free it explicitly with vsp1_dl_fragment_free().
367 *
368 * Fragments are only usable for display lists in header mode. Attempt to
369 * add a fragment to a header-less display list will return an error.
370 */
371int vsp1_dl_list_add_fragment(struct vsp1_dl_list *dl,
372 struct vsp1_dl_body *dlb)
373{
374 /* Multi-body lists are only available in header mode. */
375 if (dl->dlm->mode != VSP1_DL_MODE_HEADER)
376 return -EINVAL;
377
378 list_add_tail(&dlb->list, &dl->fragments);
379 return 0;
Takashi Saito1517b032015-09-07 01:40:25 -0300380}
381
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200382void vsp1_dl_list_commit(struct vsp1_dl_list *dl)
Takashi Saito1517b032015-09-07 01:40:25 -0300383{
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200384 struct vsp1_dl_manager *dlm = dl->dlm;
385 struct vsp1_device *vsp1 = dlm->vsp1;
Takashi Saito1517b032015-09-07 01:40:25 -0300386 unsigned long flags;
387 bool update;
388
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200389 spin_lock_irqsave(&dlm->lock, flags);
Takashi Saito1517b032015-09-07 01:40:25 -0300390
Laurent Pinchart12161982015-11-14 22:48:27 -0200391 if (dl->dlm->mode == VSP1_DL_MODE_HEADER) {
Laurent Pinchartf81e83c2016-03-03 13:36:34 -0300392 struct vsp1_dl_header_list *hdr = dl->header->lists;
393 struct vsp1_dl_body *dlb;
394 unsigned int num_lists = 0;
395
396 /* Fill the header with the display list bodies addresses and
397 * sizes. The address of the first body has already been filled
398 * when the display list was allocated.
399 *
400 * In header mode the caller guarantees that the hardware is
401 * idle at this point.
Laurent Pinchart12161982015-11-14 22:48:27 -0200402 */
Laurent Pinchartf81e83c2016-03-03 13:36:34 -0300403 hdr->num_bytes = dl->body0.num_entries
404 * sizeof(*dl->header->lists);
405
406 list_for_each_entry(dlb, &dl->fragments, list) {
407 num_lists++;
408 hdr++;
409
410 hdr->addr = dlb->dma;
411 hdr->num_bytes = dlb->num_entries
412 * sizeof(*dl->header->lists);
413 }
414
415 dl->header->num_lists = num_lists;
Laurent Pinchart12161982015-11-14 22:48:27 -0200416 vsp1_write(vsp1, VI6_DL_HDR_ADDR(dlm->index), dl->dma);
417
418 dlm->active = dl;
419 goto done;
420 }
421
Takashi Saito1517b032015-09-07 01:40:25 -0300422 /* Once the UPD bit has been set the hardware can start processing the
423 * display list at any time and we can't touch the address and size
424 * registers. In that case mark the update as pending, it will be
425 * queued up to the hardware by the frame end interrupt handler.
426 */
427 update = !!(vsp1_read(vsp1, VI6_DL_BODY_SIZE) & VI6_DL_BODY_SIZE_UPD);
428 if (update) {
Laurent Pinchartd2c1b022016-03-03 09:26:47 -0300429 __vsp1_dl_list_put(dlm->pending);
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200430 dlm->pending = dl;
Takashi Saito1517b032015-09-07 01:40:25 -0300431 goto done;
432 }
433
434 /* Program the hardware with the display list body address and size.
435 * The UPD bit will be cleared by the device when the display list is
436 * processed.
437 */
Laurent Pinchartf81e83c2016-03-03 13:36:34 -0300438 vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), dl->body0.dma);
Takashi Saito1517b032015-09-07 01:40:25 -0300439 vsp1_write(vsp1, VI6_DL_BODY_SIZE, VI6_DL_BODY_SIZE_UPD |
Laurent Pinchartf81e83c2016-03-03 13:36:34 -0300440 (dl->body0.num_entries * sizeof(*dl->header->lists)));
Takashi Saito1517b032015-09-07 01:40:25 -0300441
Laurent Pinchartd2c1b022016-03-03 09:26:47 -0300442 __vsp1_dl_list_put(dlm->queued);
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200443 dlm->queued = dl;
Takashi Saito1517b032015-09-07 01:40:25 -0300444
445done:
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200446 spin_unlock_irqrestore(&dlm->lock, flags);
Takashi Saito1517b032015-09-07 01:40:25 -0300447}
448
449/* -----------------------------------------------------------------------------
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200450 * Display List Manager
Takashi Saito1517b032015-09-07 01:40:25 -0300451 */
452
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200453/* Interrupt Handling */
454void vsp1_dlm_irq_display_start(struct vsp1_dl_manager *dlm)
Takashi Saito1517b032015-09-07 01:40:25 -0300455{
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200456 spin_lock(&dlm->lock);
Takashi Saito1517b032015-09-07 01:40:25 -0300457
458 /* The display start interrupt signals the end of the display list
459 * processing by the device. The active display list, if any, won't be
460 * accessed anymore and can be reused.
461 */
Laurent Pinchartd2c1b022016-03-03 09:26:47 -0300462 __vsp1_dl_list_put(dlm->active);
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200463 dlm->active = NULL;
Takashi Saito1517b032015-09-07 01:40:25 -0300464
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200465 spin_unlock(&dlm->lock);
Takashi Saito1517b032015-09-07 01:40:25 -0300466}
467
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200468void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm)
Takashi Saito1517b032015-09-07 01:40:25 -0300469{
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200470 struct vsp1_device *vsp1 = dlm->vsp1;
Takashi Saito1517b032015-09-07 01:40:25 -0300471
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200472 spin_lock(&dlm->lock);
473
Laurent Pinchartd2c1b022016-03-03 09:26:47 -0300474 __vsp1_dl_list_put(dlm->active);
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200475 dlm->active = NULL;
Takashi Saito1517b032015-09-07 01:40:25 -0300476
Laurent Pinchart12161982015-11-14 22:48:27 -0200477 /* Header mode is used for mem-to-mem pipelines only. We don't need to
478 * perform any operation as there can't be any new display list queued
479 * in that case.
480 */
481 if (dlm->mode == VSP1_DL_MODE_HEADER)
482 goto done;
483
Takashi Saito1517b032015-09-07 01:40:25 -0300484 /* The UPD bit set indicates that the commit operation raced with the
485 * interrupt and occurred after the frame end event and UPD clear but
486 * before interrupt processing. The hardware hasn't taken the update
487 * into account yet, we'll thus skip one frame and retry.
488 */
489 if (vsp1_read(vsp1, VI6_DL_BODY_SIZE) & VI6_DL_BODY_SIZE_UPD)
490 goto done;
491
492 /* The device starts processing the queued display list right after the
493 * frame end interrupt. The display list thus becomes active.
494 */
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200495 if (dlm->queued) {
496 dlm->active = dlm->queued;
497 dlm->queued = NULL;
Takashi Saito1517b032015-09-07 01:40:25 -0300498 }
499
500 /* Now that the UPD bit has been cleared we can queue the next display
501 * list to the hardware if one has been prepared.
502 */
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200503 if (dlm->pending) {
504 struct vsp1_dl_list *dl = dlm->pending;
Takashi Saito1517b032015-09-07 01:40:25 -0300505
Laurent Pinchartf81e83c2016-03-03 13:36:34 -0300506 vsp1_write(vsp1, VI6_DL_HDR_ADDR(0), dl->body0.dma);
Takashi Saito1517b032015-09-07 01:40:25 -0300507 vsp1_write(vsp1, VI6_DL_BODY_SIZE, VI6_DL_BODY_SIZE_UPD |
Laurent Pinchartf81e83c2016-03-03 13:36:34 -0300508 (dl->body0.num_entries *
509 sizeof(*dl->header->lists)));
Takashi Saito1517b032015-09-07 01:40:25 -0300510
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200511 dlm->queued = dl;
512 dlm->pending = NULL;
Takashi Saito1517b032015-09-07 01:40:25 -0300513 }
514
515done:
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200516 spin_unlock(&dlm->lock);
Takashi Saito1517b032015-09-07 01:40:25 -0300517}
518
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200519/* Hardware Setup */
520void vsp1_dlm_setup(struct vsp1_device *vsp1)
Takashi Saito1517b032015-09-07 01:40:25 -0300521{
Laurent Pinchart351bbf92015-11-01 15:18:56 -0200522 u32 ctrl = (256 << VI6_DL_CTRL_AR_WAIT_SHIFT)
523 | VI6_DL_CTRL_DC2 | VI6_DL_CTRL_DC1 | VI6_DL_CTRL_DC0
524 | VI6_DL_CTRL_DLE;
Takashi Saito1517b032015-09-07 01:40:25 -0300525
Laurent Pinchart351bbf92015-11-01 15:18:56 -0200526 /* The DRM pipeline operates with display lists in Continuous Frame
527 * Mode, all other pipelines use manual start.
Takashi Saito1517b032015-09-07 01:40:25 -0300528 */
529 if (vsp1->drm)
Laurent Pinchart351bbf92015-11-01 15:18:56 -0200530 ctrl |= VI6_DL_CTRL_CFM0 | VI6_DL_CTRL_NH0;
Takashi Saito1517b032015-09-07 01:40:25 -0300531
532 vsp1_write(vsp1, VI6_DL_CTRL, ctrl);
533 vsp1_write(vsp1, VI6_DL_SWAP, VI6_DL_SWAP_LWS);
534}
535
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200536void vsp1_dlm_reset(struct vsp1_dl_manager *dlm)
Takashi Saito1517b032015-09-07 01:40:25 -0300537{
Laurent Pinchartd2c1b022016-03-03 09:26:47 -0300538 unsigned long flags;
539
540 spin_lock_irqsave(&dlm->lock, flags);
541
542 __vsp1_dl_list_put(dlm->active);
543 __vsp1_dl_list_put(dlm->queued);
544 __vsp1_dl_list_put(dlm->pending);
545
546 spin_unlock_irqrestore(&dlm->lock, flags);
Takashi Saito1517b032015-09-07 01:40:25 -0300547
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200548 dlm->active = NULL;
549 dlm->queued = NULL;
550 dlm->pending = NULL;
Takashi Saito1517b032015-09-07 01:40:25 -0300551}
552
Laurent Pinchartef9621b2015-11-14 22:27:52 -0200553struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1,
Laurent Pinchart12161982015-11-14 22:48:27 -0200554 unsigned int index,
Laurent Pinchartef9621b2015-11-14 22:27:52 -0200555 unsigned int prealloc)
Takashi Saito1517b032015-09-07 01:40:25 -0300556{
Laurent Pinchartef9621b2015-11-14 22:27:52 -0200557 struct vsp1_dl_manager *dlm;
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200558 unsigned int i;
559
Laurent Pinchartef9621b2015-11-14 22:27:52 -0200560 dlm = devm_kzalloc(vsp1->dev, sizeof(*dlm), GFP_KERNEL);
561 if (!dlm)
562 return NULL;
563
Laurent Pinchart12161982015-11-14 22:48:27 -0200564 dlm->index = index;
565 dlm->mode = index == 0 && !vsp1->info->uapi
566 ? VSP1_DL_MODE_HEADERLESS : VSP1_DL_MODE_HEADER;
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200567 dlm->vsp1 = vsp1;
568
569 spin_lock_init(&dlm->lock);
570 INIT_LIST_HEAD(&dlm->free);
571
572 for (i = 0; i < prealloc; ++i) {
573 struct vsp1_dl_list *dl;
574
575 dl = vsp1_dl_list_alloc(dlm);
576 if (!dl)
Laurent Pinchartef9621b2015-11-14 22:27:52 -0200577 return NULL;
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200578
579 list_add_tail(&dl->list, &dlm->free);
580 }
581
Laurent Pinchartef9621b2015-11-14 22:27:52 -0200582 return dlm;
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200583}
584
Laurent Pinchartef9621b2015-11-14 22:27:52 -0200585void vsp1_dlm_destroy(struct vsp1_dl_manager *dlm)
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200586{
587 struct vsp1_dl_list *dl, *next;
588
Laurent Pinchartef9621b2015-11-14 22:27:52 -0200589 if (!dlm)
590 return;
591
Laurent Pinchartc2dd25132015-11-08 20:06:57 -0200592 list_for_each_entry_safe(dl, next, &dlm->free, list) {
593 list_del(&dl->list);
594 vsp1_dl_list_free(dl);
595 }
Takashi Saito1517b032015-09-07 01:40:25 -0300596}