Skip to content

Commit 211afd5

Browse files
committed
Merge tag 'drm-vc4-next-2016-03-14' of github.com:anholt/linux into drm-next
This pull request covers what's left for 4.6. Notably, it includes a significant 3D performance improvement and a fix to HDMI hotplug detection for the Pi2/3. * tag 'drm-vc4-next-2016-03-14' of github.com:anholt/linux: drm/vc4: Recognize a more specific compatible string for V3D. dt-bindings: Add binding docs for V3D. drm/vc4: Return -EFAULT on copy_from_user() failure drm/vc4: Respect GPIO_ACTIVE_LOW on HDMI HPD if set in the devicetree. drm/vc4: Let gpiolib know that we're OK with sleeping for HPD. drm/vc4: improve throughput by pipelining binning and rendering jobs
2 parents f2c4882 + 90d7116 commit 211afd5

File tree

7 files changed

+193
-57
lines changed

7 files changed

+193
-57
lines changed

Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ Optional properties for HDMI:
3535
as an interrupt/status bit in the HDMI controller
3636
itself). See bindings/pinctrl/brcm,bcm2835-gpio.txt
3737

38+
Required properties for V3D:
39+
- compatible: Should be "brcm,bcm2835-v3d"
40+
- reg: Physical base address and length of the V3D's registers
41+
- interrupts: The interrupt number
42+
See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt
43+
3844
Example:
3945
pixelvalve@7e807000 {
4046
compatible = "brcm,bcm2835-pixelvalve2";
@@ -60,6 +66,12 @@ hdmi: hdmi@7e902000 {
6066
clock-names = "pixel", "hdmi";
6167
};
6268

69+
v3d: v3d@7ec00000 {
70+
compatible = "brcm,bcm2835-v3d";
71+
reg = <0x7ec00000 0x1000>;
72+
interrupts = <1 10>;
73+
};
74+
6375
vc4: gpu {
6476
compatible = "brcm,bcm2835-vc4";
6577
};

drivers/gpu/drm/vc4/vc4_bo.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -499,11 +499,12 @@ vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data,
499499
if (IS_ERR(bo))
500500
return PTR_ERR(bo);
501501

502-
ret = copy_from_user(bo->base.vaddr,
502+
if (copy_from_user(bo->base.vaddr,
503503
(void __user *)(uintptr_t)args->data,
504-
args->size);
505-
if (ret != 0)
504+
args->size)) {
505+
ret = -EFAULT;
506506
goto fail;
507+
}
507508
/* Clear the rest of the memory from allocating from the BO
508509
* cache.
509510
*/

drivers/gpu/drm/vc4/vc4_drv.h

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ struct vc4_dev {
5252
/* Protects bo_cache and the BO stats. */
5353
struct mutex bo_lock;
5454

55-
/* Sequence number for the last job queued in job_list.
55+
/* Sequence number for the last job queued in bin_job_list.
5656
* Starts at 0 (no jobs emitted).
5757
*/
5858
uint64_t emit_seqno;
@@ -62,11 +62,19 @@ struct vc4_dev {
6262
*/
6363
uint64_t finished_seqno;
6464

65-
/* List of all struct vc4_exec_info for jobs to be executed.
66-
* The first job in the list is the one currently programmed
67-
* into ct0ca/ct1ca for execution.
65+
/* List of all struct vc4_exec_info for jobs to be executed in
66+
* the binner. The first job in the list is the one currently
67+
* programmed into ct0ca for execution.
6868
*/
69-
struct list_head job_list;
69+
struct list_head bin_job_list;
70+
71+
/* List of all struct vc4_exec_info for jobs that have
72+
* completed binning and are ready for rendering. The first
73+
* job in the list is the one currently programmed into ct1ca
74+
* for execution.
75+
*/
76+
struct list_head render_job_list;
77+
7078
/* List of the finished vc4_exec_infos waiting to be freed by
7179
* job_done_work.
7280
*/
@@ -296,11 +304,20 @@ struct vc4_exec_info {
296304
};
297305

298306
static inline struct vc4_exec_info *
299-
vc4_first_job(struct vc4_dev *vc4)
307+
vc4_first_bin_job(struct vc4_dev *vc4)
308+
{
309+
if (list_empty(&vc4->bin_job_list))
310+
return NULL;
311+
return list_first_entry(&vc4->bin_job_list, struct vc4_exec_info, head);
312+
}
313+
314+
static inline struct vc4_exec_info *
315+
vc4_first_render_job(struct vc4_dev *vc4)
300316
{
301-
if (list_empty(&vc4->job_list))
317+
if (list_empty(&vc4->render_job_list))
302318
return NULL;
303-
return list_first_entry(&vc4->job_list, struct vc4_exec_info, head);
319+
return list_first_entry(&vc4->render_job_list,
320+
struct vc4_exec_info, head);
304321
}
305322

306323
/**
@@ -414,7 +431,9 @@ int vc4_wait_seqno_ioctl(struct drm_device *dev, void *data,
414431
struct drm_file *file_priv);
415432
int vc4_wait_bo_ioctl(struct drm_device *dev, void *data,
416433
struct drm_file *file_priv);
417-
void vc4_submit_next_job(struct drm_device *dev);
434+
void vc4_submit_next_bin_job(struct drm_device *dev);
435+
void vc4_submit_next_render_job(struct drm_device *dev);
436+
void vc4_move_job_to_render(struct drm_device *dev, struct vc4_exec_info *exec);
418437
int vc4_wait_for_seqno(struct drm_device *dev, uint64_t seqno,
419438
uint64_t timeout_ns, bool interruptible);
420439
void vc4_job_handle_completed(struct vc4_dev *vc4);

drivers/gpu/drm/vc4/vc4_gem.c

Lines changed: 89 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,10 @@ vc4_save_hang_state(struct drm_device *dev)
141141
struct vc4_dev *vc4 = to_vc4_dev(dev);
142142
struct drm_vc4_get_hang_state *state;
143143
struct vc4_hang_state *kernel_state;
144-
struct vc4_exec_info *exec;
144+
struct vc4_exec_info *exec[2];
145145
struct vc4_bo *bo;
146146
unsigned long irqflags;
147-
unsigned int i, unref_list_count;
147+
unsigned int i, j, unref_list_count, prev_idx;
148148

149149
kernel_state = kcalloc(1, sizeof(*kernel_state), GFP_KERNEL);
150150
if (!kernel_state)
@@ -153,37 +153,55 @@ vc4_save_hang_state(struct drm_device *dev)
153153
state = &kernel_state->user_state;
154154

155155
spin_lock_irqsave(&vc4->job_lock, irqflags);
156-
exec = vc4_first_job(vc4);
157-
if (!exec) {
156+
exec[0] = vc4_first_bin_job(vc4);
157+
exec[1] = vc4_first_render_job(vc4);
158+
if (!exec[0] && !exec[1]) {
158159
spin_unlock_irqrestore(&vc4->job_lock, irqflags);
159160
return;
160161
}
161162

162-
unref_list_count = 0;
163-
list_for_each_entry(bo, &exec->unref_list, unref_head)
164-
unref_list_count++;
163+
/* Get the bos from both binner and renderer into hang state. */
164+
state->bo_count = 0;
165+
for (i = 0; i < 2; i++) {
166+
if (!exec[i])
167+
continue;
168+
169+
unref_list_count = 0;
170+
list_for_each_entry(bo, &exec[i]->unref_list, unref_head)
171+
unref_list_count++;
172+
state->bo_count += exec[i]->bo_count + unref_list_count;
173+
}
174+
175+
kernel_state->bo = kcalloc(state->bo_count,
176+
sizeof(*kernel_state->bo), GFP_ATOMIC);
165177

166-
state->bo_count = exec->bo_count + unref_list_count;
167-
kernel_state->bo = kcalloc(state->bo_count, sizeof(*kernel_state->bo),
168-
GFP_ATOMIC);
169178
if (!kernel_state->bo) {
170179
spin_unlock_irqrestore(&vc4->job_lock, irqflags);
171180
return;
172181
}
173182

174-
for (i = 0; i < exec->bo_count; i++) {
175-
drm_gem_object_reference(&exec->bo[i]->base);
176-
kernel_state->bo[i] = &exec->bo[i]->base;
177-
}
183+
prev_idx = 0;
184+
for (i = 0; i < 2; i++) {
185+
if (!exec[i])
186+
continue;
178187

179-
list_for_each_entry(bo, &exec->unref_list, unref_head) {
180-
drm_gem_object_reference(&bo->base.base);
181-
kernel_state->bo[i] = &bo->base.base;
182-
i++;
188+
for (j = 0; j < exec[i]->bo_count; j++) {
189+
drm_gem_object_reference(&exec[i]->bo[j]->base);
190+
kernel_state->bo[j + prev_idx] = &exec[i]->bo[j]->base;
191+
}
192+
193+
list_for_each_entry(bo, &exec[i]->unref_list, unref_head) {
194+
drm_gem_object_reference(&bo->base.base);
195+
kernel_state->bo[j + prev_idx] = &bo->base.base;
196+
j++;
197+
}
198+
prev_idx = j + 1;
183199
}
184200

185-
state->start_bin = exec->ct0ca;
186-
state->start_render = exec->ct1ca;
201+
if (exec[0])
202+
state->start_bin = exec[0]->ct0ca;
203+
if (exec[1])
204+
state->start_render = exec[1]->ct1ca;
187205

188206
spin_unlock_irqrestore(&vc4->job_lock, irqflags);
189207

@@ -267,13 +285,15 @@ vc4_hangcheck_elapsed(unsigned long data)
267285
struct vc4_dev *vc4 = to_vc4_dev(dev);
268286
uint32_t ct0ca, ct1ca;
269287
unsigned long irqflags;
270-
struct vc4_exec_info *exec;
288+
struct vc4_exec_info *bin_exec, *render_exec;
271289

272290
spin_lock_irqsave(&vc4->job_lock, irqflags);
273-
exec = vc4_first_job(vc4);
291+
292+
bin_exec = vc4_first_bin_job(vc4);
293+
render_exec = vc4_first_render_job(vc4);
274294

275295
/* If idle, we can stop watching for hangs. */
276-
if (!exec) {
296+
if (!bin_exec && !render_exec) {
277297
spin_unlock_irqrestore(&vc4->job_lock, irqflags);
278298
return;
279299
}
@@ -284,9 +304,12 @@ vc4_hangcheck_elapsed(unsigned long data)
284304
/* If we've made any progress in execution, rearm the timer
285305
* and wait.
286306
*/
287-
if (ct0ca != exec->last_ct0ca || ct1ca != exec->last_ct1ca) {
288-
exec->last_ct0ca = ct0ca;
289-
exec->last_ct1ca = ct1ca;
307+
if ((bin_exec && ct0ca != bin_exec->last_ct0ca) ||
308+
(render_exec && ct1ca != render_exec->last_ct1ca)) {
309+
if (bin_exec)
310+
bin_exec->last_ct0ca = ct0ca;
311+
if (render_exec)
312+
render_exec->last_ct1ca = ct1ca;
290313
spin_unlock_irqrestore(&vc4->job_lock, irqflags);
291314
vc4_queue_hangcheck(dev);
292315
return;
@@ -386,11 +409,13 @@ vc4_flush_caches(struct drm_device *dev)
386409
* The job_lock should be held during this.
387410
*/
388411
void
389-
vc4_submit_next_job(struct drm_device *dev)
412+
vc4_submit_next_bin_job(struct drm_device *dev)
390413
{
391414
struct vc4_dev *vc4 = to_vc4_dev(dev);
392-
struct vc4_exec_info *exec = vc4_first_job(vc4);
415+
struct vc4_exec_info *exec;
393416

417+
again:
418+
exec = vc4_first_bin_job(vc4);
394419
if (!exec)
395420
return;
396421

@@ -400,11 +425,40 @@ vc4_submit_next_job(struct drm_device *dev)
400425
V3D_WRITE(V3D_BPOA, 0);
401426
V3D_WRITE(V3D_BPOS, 0);
402427

403-
if (exec->ct0ca != exec->ct0ea)
428+
/* Either put the job in the binner if it uses the binner, or
429+
* immediately move it to the to-be-rendered queue.
430+
*/
431+
if (exec->ct0ca != exec->ct0ea) {
404432
submit_cl(dev, 0, exec->ct0ca, exec->ct0ea);
433+
} else {
434+
vc4_move_job_to_render(dev, exec);
435+
goto again;
436+
}
437+
}
438+
439+
void
440+
vc4_submit_next_render_job(struct drm_device *dev)
441+
{
442+
struct vc4_dev *vc4 = to_vc4_dev(dev);
443+
struct vc4_exec_info *exec = vc4_first_render_job(vc4);
444+
445+
if (!exec)
446+
return;
447+
405448
submit_cl(dev, 1, exec->ct1ca, exec->ct1ea);
406449
}
407450

451+
void
452+
vc4_move_job_to_render(struct drm_device *dev, struct vc4_exec_info *exec)
453+
{
454+
struct vc4_dev *vc4 = to_vc4_dev(dev);
455+
bool was_empty = list_empty(&vc4->render_job_list);
456+
457+
list_move_tail(&exec->head, &vc4->render_job_list);
458+
if (was_empty)
459+
vc4_submit_next_render_job(dev);
460+
}
461+
408462
static void
409463
vc4_update_bo_seqnos(struct vc4_exec_info *exec, uint64_t seqno)
410464
{
@@ -443,14 +497,14 @@ vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec)
443497
exec->seqno = seqno;
444498
vc4_update_bo_seqnos(exec, seqno);
445499

446-
list_add_tail(&exec->head, &vc4->job_list);
500+
list_add_tail(&exec->head, &vc4->bin_job_list);
447501

448502
/* If no job was executing, kick ours off. Otherwise, it'll
449-
* get started when the previous job's frame done interrupt
503+
* get started when the previous job's flush done interrupt
450504
* occurs.
451505
*/
452-
if (vc4_first_job(vc4) == exec) {
453-
vc4_submit_next_job(dev);
506+
if (vc4_first_bin_job(vc4) == exec) {
507+
vc4_submit_next_bin_job(dev);
454508
vc4_queue_hangcheck(dev);
455509
}
456510

@@ -859,7 +913,8 @@ vc4_gem_init(struct drm_device *dev)
859913
{
860914
struct vc4_dev *vc4 = to_vc4_dev(dev);
861915

862-
INIT_LIST_HEAD(&vc4->job_list);
916+
INIT_LIST_HEAD(&vc4->bin_job_list);
917+
INIT_LIST_HEAD(&vc4->render_job_list);
863918
INIT_LIST_HEAD(&vc4->job_done_list);
864919
INIT_LIST_HEAD(&vc4->seqno_cb_list);
865920
spin_lock_init(&vc4->job_lock);

drivers/gpu/drm/vc4/vc4_hdmi.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ struct vc4_hdmi {
4747
void __iomem *hdmicore_regs;
4848
void __iomem *hd_regs;
4949
int hpd_gpio;
50+
bool hpd_active_low;
5051

5152
struct clk *pixel_clock;
5253
struct clk *hsm_clock;
@@ -166,7 +167,8 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
166167
struct vc4_dev *vc4 = to_vc4_dev(dev);
167168

168169
if (vc4->hdmi->hpd_gpio) {
169-
if (gpio_get_value(vc4->hdmi->hpd_gpio))
170+
if (gpio_get_value_cansleep(vc4->hdmi->hpd_gpio) ^
171+
vc4->hdmi->hpd_active_low)
170172
return connector_status_connected;
171173
else
172174
return connector_status_disconnected;
@@ -517,11 +519,17 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
517519
* we'll use the HDMI core's register.
518520
*/
519521
if (of_find_property(dev->of_node, "hpd-gpios", &value)) {
520-
hdmi->hpd_gpio = of_get_named_gpio(dev->of_node, "hpd-gpios", 0);
522+
enum of_gpio_flags hpd_gpio_flags;
523+
524+
hdmi->hpd_gpio = of_get_named_gpio_flags(dev->of_node,
525+
"hpd-gpios", 0,
526+
&hpd_gpio_flags);
521527
if (hdmi->hpd_gpio < 0) {
522528
ret = hdmi->hpd_gpio;
523529
goto err_unprepare_hsm;
524530
}
531+
532+
hdmi->hpd_active_low = hpd_gpio_flags & OF_GPIO_ACTIVE_LOW;
525533
}
526534

527535
vc4->hdmi = hdmi;

0 commit comments

Comments
 (0)