@@ -141,6 +141,30 @@ struct vsp1_dl_body_pool {
141
141
struct vsp1_device * vsp1 ;
142
142
};
143
143
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
+
144
168
/**
145
169
* struct vsp1_dl_list - Display list
146
170
* @list: entry in the display list manager lists
@@ -187,6 +211,7 @@ struct vsp1_dl_list {
187
211
* @queued: list queued to the hardware (written to the DL registers)
188
212
* @pending: list waiting to be queued to the hardware
189
213
* @pool: body pool for the display list bodies
214
+ * @autofld_cmds: command pool to support auto-fld interlaced mode
190
215
*/
191
216
struct vsp1_dl_manager {
192
217
unsigned int index ;
@@ -200,6 +225,7 @@ struct vsp1_dl_manager {
200
225
struct vsp1_dl_list * pending ;
201
226
202
227
struct vsp1_dl_body_pool * pool ;
228
+ struct vsp1_dl_cmd_pool * cmdpool ;
203
229
};
204
230
205
231
/* -----------------------------------------------------------------------------
@@ -363,6 +389,157 @@ void vsp1_dl_body_write(struct vsp1_dl_body *dlb, u32 reg, u32 data)
363
389
}
364
390
365
391
/* -----------------------------------------------------------------------------
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
+ /* ----------------------------------------------------------------------------
366
543
* Display List Transaction Management
367
544
*/
368
545
@@ -464,6 +641,12 @@ static void __vsp1_dl_list_put(struct vsp1_dl_list *dl)
464
641
465
642
vsp1_dl_list_bodies_put (dl );
466
643
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
+
467
650
/*
468
651
* body0 is reused as as an optimisation as presently every display list
469
652
* 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,
915
1098
list_add_tail (& dl -> list , & dlm -> free );
916
1099
}
917
1100
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
+
918
1110
return dlm ;
919
1111
}
920
1112
@@ -931,4 +1123,5 @@ void vsp1_dlm_destroy(struct vsp1_dl_manager *dlm)
931
1123
}
932
1124
933
1125
vsp1_dl_body_pool_destroy (dlm -> pool );
1126
+ vsp1_dl_ext_cmd_pool_destroy (dlm -> cmdpool );
934
1127
}
0 commit comments