@@ -141,6 +141,30 @@ struct vsp1_dl_body_pool {
141141 struct vsp1_device * vsp1 ;
142142};
143143
144+ /**
145+ * struct vsp1_cmd_pool - Display List commands pool
146+ * @dma: DMA address of the entries
147+ * @size: size of the full DMA memory pool in bytes
148+ * @mem: CPU memory pointer for the pool
149+ * @cmds: Array of command structures for the pool
150+ * @free: Free pool entries
151+ * @lock: Protects the free list
152+ * @vsp1: the VSP1 device
153+ */
154+ struct vsp1_dl_cmd_pool {
155+ /* DMA allocation */
156+ dma_addr_t dma ;
157+ size_t size ;
158+ void * mem ;
159+
160+ struct vsp1_dl_ext_cmd * cmds ;
161+ struct list_head free ;
162+
163+ spinlock_t lock ;
164+
165+ struct vsp1_device * vsp1 ;
166+ };
167+
144168/**
145169 * struct vsp1_dl_list - Display list
146170 * @list: entry in the display list manager lists
@@ -187,6 +211,7 @@ struct vsp1_dl_list {
187211 * @queued: list queued to the hardware (written to the DL registers)
188212 * @pending: list waiting to be queued to the hardware
189213 * @pool: body pool for the display list bodies
214+ * @autofld_cmds: command pool to support auto-fld interlaced mode
190215 */
191216struct vsp1_dl_manager {
192217 unsigned int index ;
@@ -200,6 +225,7 @@ struct vsp1_dl_manager {
200225 struct vsp1_dl_list * pending ;
201226
202227 struct vsp1_dl_body_pool * pool ;
228+ struct vsp1_dl_cmd_pool * cmdpool ;
203229};
204230
205231/* -----------------------------------------------------------------------------
@@ -363,6 +389,157 @@ void vsp1_dl_body_write(struct vsp1_dl_body *dlb, u32 reg, u32 data)
363389}
364390
365391/* -----------------------------------------------------------------------------
392+ * Display List Extended Command Management
393+ */
394+
395+ enum vsp1_extcmd_type {
396+ VSP1_EXTCMD_AUTODISP ,
397+ VSP1_EXTCMD_AUTOFLD ,
398+ };
399+
400+ struct vsp1_extended_command_info {
401+ u16 opcode ;
402+ size_t body_size ;
403+ };
404+
405+ static const struct vsp1_extended_command_info vsp1_extended_commands [] = {
406+ [VSP1_EXTCMD_AUTODISP ] = { 0x02 , 96 },
407+ [VSP1_EXTCMD_AUTOFLD ] = { 0x03 , 160 },
408+ };
409+
410+ /**
411+ * vsp1_dl_cmd_pool_create - Create a pool of commands from a single allocation
412+ * @vsp1: The VSP1 device
413+ * @type: The command pool type
414+ * @num_cmds: The number of commands to allocate
415+ *
416+ * Allocate a pool of commands each with enough memory to contain the private
417+ * data of each command. The allocation sizes are dependent upon the command
418+ * type.
419+ *
420+ * Return a pointer to the pool on success or NULL if memory can't be allocated.
421+ */
422+ static struct vsp1_dl_cmd_pool *
423+ vsp1_dl_cmd_pool_create (struct vsp1_device * vsp1 , enum vsp1_extcmd_type type ,
424+ unsigned int num_cmds )
425+ {
426+ struct vsp1_dl_cmd_pool * pool ;
427+ unsigned int i ;
428+ size_t cmd_size ;
429+
430+ pool = kzalloc (sizeof (* pool ), GFP_KERNEL );
431+ if (!pool )
432+ return NULL ;
433+
434+ spin_lock_init (& pool -> lock );
435+ INIT_LIST_HEAD (& pool -> free );
436+
437+ pool -> cmds = kcalloc (num_cmds , sizeof (* pool -> cmds ), GFP_KERNEL );
438+ if (!pool -> cmds ) {
439+ kfree (pool );
440+ return NULL ;
441+ }
442+
443+ cmd_size = sizeof (struct vsp1_pre_ext_dl_body ) +
444+ vsp1_extended_commands [type ].body_size ;
445+ cmd_size = ALIGN (cmd_size , 16 );
446+
447+ pool -> size = cmd_size * num_cmds ;
448+ pool -> mem = dma_alloc_wc (vsp1 -> bus_master , pool -> size , & pool -> dma ,
449+ GFP_KERNEL );
450+ if (!pool -> mem ) {
451+ kfree (pool -> cmds );
452+ kfree (pool );
453+ return NULL ;
454+ }
455+
456+ for (i = 0 ; i < num_cmds ; ++ i ) {
457+ struct vsp1_dl_ext_cmd * cmd = & pool -> cmds [i ];
458+ size_t cmd_offset = i * cmd_size ;
459+ /* data_offset must be 16 byte aligned for DMA. */
460+ size_t data_offset = sizeof (struct vsp1_pre_ext_dl_body ) +
461+ cmd_offset ;
462+
463+ cmd -> pool = pool ;
464+ cmd -> opcode = vsp1_extended_commands [type ].opcode ;
465+
466+ /*
467+ * TODO: Auto-disp can utilise more than one extended body
468+ * command per cmd.
469+ */
470+ cmd -> num_cmds = 1 ;
471+ cmd -> cmds = pool -> mem + cmd_offset ;
472+ cmd -> cmd_dma = pool -> dma + cmd_offset ;
473+
474+ cmd -> data = pool -> mem + data_offset ;
475+ cmd -> data_dma = pool -> dma + data_offset ;
476+
477+ list_add_tail (& cmd -> free , & pool -> free );
478+ }
479+
480+ return pool ;
481+ }
482+
483+ static
484+ struct vsp1_dl_ext_cmd * vsp1_dl_ext_cmd_get (struct vsp1_dl_cmd_pool * pool )
485+ {
486+ struct vsp1_dl_ext_cmd * cmd = NULL ;
487+ unsigned long flags ;
488+
489+ spin_lock_irqsave (& pool -> lock , flags );
490+
491+ if (!list_empty (& pool -> free )) {
492+ cmd = list_first_entry (& pool -> free , struct vsp1_dl_ext_cmd ,
493+ free );
494+ list_del (& cmd -> free );
495+ }
496+
497+ spin_unlock_irqrestore (& pool -> lock , flags );
498+
499+ return cmd ;
500+ }
501+
502+ static void vsp1_dl_ext_cmd_put (struct vsp1_dl_ext_cmd * cmd )
503+ {
504+ unsigned long flags ;
505+
506+ if (!cmd )
507+ return ;
508+
509+ /* Reset flags, these mark data usage. */
510+ cmd -> flags = 0 ;
511+
512+ spin_lock_irqsave (& cmd -> pool -> lock , flags );
513+ list_add_tail (& cmd -> free , & cmd -> pool -> free );
514+ spin_unlock_irqrestore (& cmd -> pool -> lock , flags );
515+ }
516+
517+ static void vsp1_dl_ext_cmd_pool_destroy (struct vsp1_dl_cmd_pool * pool )
518+ {
519+ if (!pool )
520+ return ;
521+
522+ if (pool -> mem )
523+ dma_free_wc (pool -> vsp1 -> bus_master , pool -> size , pool -> mem ,
524+ pool -> dma );
525+
526+ kfree (pool -> cmds );
527+ kfree (pool );
528+ }
529+
530+ struct vsp1_dl_ext_cmd * vsp1_dl_get_pre_cmd (struct vsp1_dl_list * dl )
531+ {
532+ struct vsp1_dl_manager * dlm = dl -> dlm ;
533+
534+ if (dl -> pre_cmd )
535+ return dl -> pre_cmd ;
536+
537+ dl -> pre_cmd = vsp1_dl_ext_cmd_get (dlm -> cmdpool );
538+
539+ return dl -> pre_cmd ;
540+ }
541+
542+ /* ----------------------------------------------------------------------------
366543 * Display List Transaction Management
367544 */
368545
@@ -464,6 +641,12 @@ static void __vsp1_dl_list_put(struct vsp1_dl_list *dl)
464641
465642 vsp1_dl_list_bodies_put (dl );
466643
644+ vsp1_dl_ext_cmd_put (dl -> pre_cmd );
645+ vsp1_dl_ext_cmd_put (dl -> post_cmd );
646+
647+ dl -> pre_cmd = NULL ;
648+ dl -> post_cmd = NULL ;
649+
467650 /*
468651 * body0 is reused as as an optimisation as presently every display list
469652 * has at least one body, thus we reinitialise the entries list.
@@ -915,6 +1098,15 @@ struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1,
9151098 list_add_tail (& dl -> list , & dlm -> free );
9161099 }
9171100
1101+ if (vsp1_feature (vsp1 , VSP1_HAS_EXT_DL )) {
1102+ dlm -> cmdpool = vsp1_dl_cmd_pool_create (vsp1 ,
1103+ VSP1_EXTCMD_AUTOFLD , prealloc );
1104+ if (!dlm -> cmdpool ) {
1105+ vsp1_dlm_destroy (dlm );
1106+ return NULL ;
1107+ }
1108+ }
1109+
9181110 return dlm ;
9191111}
9201112
@@ -931,4 +1123,5 @@ void vsp1_dlm_destroy(struct vsp1_dl_manager *dlm)
9311123 }
9321124
9331125 vsp1_dl_body_pool_destroy (dlm -> pool );
1126+ vsp1_dl_ext_cmd_pool_destroy (dlm -> cmdpool );
9341127}
0 commit comments