diff options
author | Dave Airlie <airlied@redhat.com> | 2014-04-03 18:03:21 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2014-04-03 18:03:21 -0400 |
commit | 2614dc66837c2a6fd0e14e3f8e72343782c8b784 (patch) | |
tree | add8d8f2394ab8bc696ca787bf2c14ef45a88297 | |
parent | d9961b22716ddf59ca307fe862f93ff0ea919952 (diff) | |
parent | 06fb220b2d1a80be5621fa06ef276a3890e6be78 (diff) |
Merge branch 'msm-next' of git://people.freedesktop.org/~robclark/linux into drm-next
* 'msm-next' of git://people.freedesktop.org/~robclark/linux:
drm/omap: Don't dereference list head when the connectors list is empty
drm/msm/mdp: add timeout for irq wait
drm/msm: validate flags, etc
drm/msm: use componentised device support
drm/msm: add chip-id param
drm/msm: crank down gpu when inactive
drm/msm: spin helper
drm/msm: add hang_debug module param
drm/msm: hdmi audio support
-rw-r--r-- | drivers/gpu/drm/msm/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/adreno/a3xx_gpu.c | 105 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/adreno/adreno_gpu.c | 65 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/adreno/adreno_gpu.h | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/hdmi/hdmi.c | 50 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/hdmi/hdmi.h | 25 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/hdmi/hdmi_audio.c | 273 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 26 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp_kms.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/msm_drv.c | 139 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/msm_drv.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/msm_gem_submit.c | 15 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/msm_gpu.c | 85 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/msm_gpu.h | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/omap_fb.c | 3 | ||||
-rw-r--r-- | include/uapi/drm/msm_drm.h | 12 |
16 files changed, 742 insertions, 96 deletions
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 4f977a593bea..5e1e6b0cd8ac 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile | |||
@@ -7,6 +7,7 @@ msm-y := \ | |||
7 | adreno/adreno_gpu.o \ | 7 | adreno/adreno_gpu.o \ |
8 | adreno/a3xx_gpu.o \ | 8 | adreno/a3xx_gpu.o \ |
9 | hdmi/hdmi.o \ | 9 | hdmi/hdmi.o \ |
10 | hdmi/hdmi_audio.o \ | ||
10 | hdmi/hdmi_bridge.o \ | 11 | hdmi/hdmi_bridge.o \ |
11 | hdmi/hdmi_connector.o \ | 12 | hdmi/hdmi_connector.o \ |
12 | hdmi/hdmi_i2c.o \ | 13 | hdmi/hdmi_i2c.o \ |
diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index 461df93e825e..f20fbde5dc49 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c | |||
@@ -35,7 +35,11 @@ | |||
35 | A3XX_INT0_CP_AHB_ERROR_HALT | \ | 35 | A3XX_INT0_CP_AHB_ERROR_HALT | \ |
36 | A3XX_INT0_UCHE_OOB_ACCESS) | 36 | A3XX_INT0_UCHE_OOB_ACCESS) |
37 | 37 | ||
38 | static struct platform_device *a3xx_pdev; | 38 | |
39 | static bool hang_debug = false; | ||
40 | MODULE_PARM_DESC(hang_debug, "Dump registers when hang is detected (can be slow!)"); | ||
41 | module_param_named(hang_debug, hang_debug, bool, 0600); | ||
42 | static void a3xx_dump(struct msm_gpu *gpu); | ||
39 | 43 | ||
40 | static void a3xx_me_init(struct msm_gpu *gpu) | 44 | static void a3xx_me_init(struct msm_gpu *gpu) |
41 | { | 45 | { |
@@ -291,6 +295,9 @@ static int a3xx_hw_init(struct msm_gpu *gpu) | |||
291 | 295 | ||
292 | static void a3xx_recover(struct msm_gpu *gpu) | 296 | static void a3xx_recover(struct msm_gpu *gpu) |
293 | { | 297 | { |
298 | /* dump registers before resetting gpu, if enabled: */ | ||
299 | if (hang_debug) | ||
300 | a3xx_dump(gpu); | ||
294 | gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 1); | 301 | gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 1); |
295 | gpu_read(gpu, REG_A3XX_RBBM_SW_RESET_CMD); | 302 | gpu_read(gpu, REG_A3XX_RBBM_SW_RESET_CMD); |
296 | gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 0); | 303 | gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 0); |
@@ -311,27 +318,18 @@ static void a3xx_destroy(struct msm_gpu *gpu) | |||
311 | ocmem_free(OCMEM_GRAPHICS, a3xx_gpu->ocmem_hdl); | 318 | ocmem_free(OCMEM_GRAPHICS, a3xx_gpu->ocmem_hdl); |
312 | #endif | 319 | #endif |
313 | 320 | ||
314 | put_device(&a3xx_gpu->pdev->dev); | ||
315 | kfree(a3xx_gpu); | 321 | kfree(a3xx_gpu); |
316 | } | 322 | } |
317 | 323 | ||
318 | static void a3xx_idle(struct msm_gpu *gpu) | 324 | static void a3xx_idle(struct msm_gpu *gpu) |
319 | { | 325 | { |
320 | unsigned long t; | ||
321 | |||
322 | /* wait for ringbuffer to drain: */ | 326 | /* wait for ringbuffer to drain: */ |
323 | adreno_idle(gpu); | 327 | adreno_idle(gpu); |
324 | 328 | ||
325 | t = jiffies + ADRENO_IDLE_TIMEOUT; | ||
326 | |||
327 | /* then wait for GPU to finish: */ | 329 | /* then wait for GPU to finish: */ |
328 | do { | 330 | if (spin_until(!(gpu_read(gpu, REG_A3XX_RBBM_STATUS) & |
329 | uint32_t rbbm_status = gpu_read(gpu, REG_A3XX_RBBM_STATUS); | 331 | A3XX_RBBM_STATUS_GPU_BUSY))) |
330 | if (!(rbbm_status & A3XX_RBBM_STATUS_GPU_BUSY)) | 332 | DRM_ERROR("%s: timeout waiting for GPU to idle!\n", gpu->name); |
331 | return; | ||
332 | } while(time_before(jiffies, t)); | ||
333 | |||
334 | DRM_ERROR("timeout waiting for %s to idle!\n", gpu->name); | ||
335 | 333 | ||
336 | /* TODO maybe we need to reset GPU here to recover from hang? */ | 334 | /* TODO maybe we need to reset GPU here to recover from hang? */ |
337 | } | 335 | } |
@@ -352,7 +350,6 @@ static irqreturn_t a3xx_irq(struct msm_gpu *gpu) | |||
352 | return IRQ_HANDLED; | 350 | return IRQ_HANDLED; |
353 | } | 351 | } |
354 | 352 | ||
355 | #ifdef CONFIG_DEBUG_FS | ||
356 | static const unsigned int a3xx_registers[] = { | 353 | static const unsigned int a3xx_registers[] = { |
357 | 0x0000, 0x0002, 0x0010, 0x0012, 0x0018, 0x0018, 0x0020, 0x0027, | 354 | 0x0000, 0x0002, 0x0010, 0x0012, 0x0018, 0x0018, 0x0020, 0x0027, |
358 | 0x0029, 0x002b, 0x002e, 0x0033, 0x0040, 0x0042, 0x0050, 0x005c, | 355 | 0x0029, 0x002b, 0x002e, 0x0033, 0x0040, 0x0042, 0x0050, 0x005c, |
@@ -392,11 +389,18 @@ static const unsigned int a3xx_registers[] = { | |||
392 | 0x303c, 0x303c, 0x305e, 0x305f, | 389 | 0x303c, 0x303c, 0x305e, 0x305f, |
393 | }; | 390 | }; |
394 | 391 | ||
392 | #ifdef CONFIG_DEBUG_FS | ||
395 | static void a3xx_show(struct msm_gpu *gpu, struct seq_file *m) | 393 | static void a3xx_show(struct msm_gpu *gpu, struct seq_file *m) |
396 | { | 394 | { |
395 | struct drm_device *dev = gpu->dev; | ||
397 | int i; | 396 | int i; |
398 | 397 | ||
399 | adreno_show(gpu, m); | 398 | adreno_show(gpu, m); |
399 | |||
400 | mutex_lock(&dev->struct_mutex); | ||
401 | |||
402 | gpu->funcs->pm_resume(gpu); | ||
403 | |||
400 | seq_printf(m, "status: %08x\n", | 404 | seq_printf(m, "status: %08x\n", |
401 | gpu_read(gpu, REG_A3XX_RBBM_STATUS)); | 405 | gpu_read(gpu, REG_A3XX_RBBM_STATUS)); |
402 | 406 | ||
@@ -412,9 +416,36 @@ static void a3xx_show(struct msm_gpu *gpu, struct seq_file *m) | |||
412 | seq_printf(m, "IO:R %08x %08x\n", addr<<2, val); | 416 | seq_printf(m, "IO:R %08x %08x\n", addr<<2, val); |
413 | } | 417 | } |
414 | } | 418 | } |
419 | |||
420 | gpu->funcs->pm_suspend(gpu); | ||
421 | |||
422 | mutex_unlock(&dev->struct_mutex); | ||
415 | } | 423 | } |
416 | #endif | 424 | #endif |
417 | 425 | ||
426 | /* would be nice to not have to duplicate the _show() stuff with printk(): */ | ||
427 | static void a3xx_dump(struct msm_gpu *gpu) | ||
428 | { | ||
429 | int i; | ||
430 | |||
431 | adreno_dump(gpu); | ||
432 | printk("status: %08x\n", | ||
433 | gpu_read(gpu, REG_A3XX_RBBM_STATUS)); | ||
434 | |||
435 | /* dump these out in a form that can be parsed by demsm: */ | ||
436 | printk("IO:region %s 00000000 00020000\n", gpu->name); | ||
437 | for (i = 0; i < ARRAY_SIZE(a3xx_registers); i += 2) { | ||
438 | uint32_t start = a3xx_registers[i]; | ||
439 | uint32_t end = a3xx_registers[i+1]; | ||
440 | uint32_t addr; | ||
441 | |||
442 | for (addr = start; addr <= end; addr++) { | ||
443 | uint32_t val = gpu_read(gpu, addr); | ||
444 | printk("IO:R %08x %08x\n", addr<<2, val); | ||
445 | } | ||
446 | } | ||
447 | } | ||
448 | |||
418 | static const struct adreno_gpu_funcs funcs = { | 449 | static const struct adreno_gpu_funcs funcs = { |
419 | .base = { | 450 | .base = { |
420 | .get_param = adreno_get_param, | 451 | .get_param = adreno_get_param, |
@@ -439,7 +470,8 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev) | |||
439 | struct a3xx_gpu *a3xx_gpu = NULL; | 470 | struct a3xx_gpu *a3xx_gpu = NULL; |
440 | struct adreno_gpu *adreno_gpu; | 471 | struct adreno_gpu *adreno_gpu; |
441 | struct msm_gpu *gpu; | 472 | struct msm_gpu *gpu; |
442 | struct platform_device *pdev = a3xx_pdev; | 473 | struct msm_drm_private *priv = dev->dev_private; |
474 | struct platform_device *pdev = priv->gpu_pdev; | ||
443 | struct adreno_platform_config *config; | 475 | struct adreno_platform_config *config; |
444 | int ret; | 476 | int ret; |
445 | 477 | ||
@@ -460,7 +492,6 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev) | |||
460 | adreno_gpu = &a3xx_gpu->base; | 492 | adreno_gpu = &a3xx_gpu->base; |
461 | gpu = &adreno_gpu->base; | 493 | gpu = &adreno_gpu->base; |
462 | 494 | ||
463 | get_device(&pdev->dev); | ||
464 | a3xx_gpu->pdev = pdev; | 495 | a3xx_gpu->pdev = pdev; |
465 | 496 | ||
466 | gpu->fast_rate = config->fast_rate; | 497 | gpu->fast_rate = config->fast_rate; |
@@ -522,17 +553,24 @@ fail: | |||
522 | # include <mach/kgsl.h> | 553 | # include <mach/kgsl.h> |
523 | #endif | 554 | #endif |
524 | 555 | ||
525 | static int a3xx_probe(struct platform_device *pdev) | 556 | static void set_gpu_pdev(struct drm_device *dev, |
557 | struct platform_device *pdev) | ||
558 | { | ||
559 | struct msm_drm_private *priv = dev->dev_private; | ||
560 | priv->gpu_pdev = pdev; | ||
561 | } | ||
562 | |||
563 | static int a3xx_bind(struct device *dev, struct device *master, void *data) | ||
526 | { | 564 | { |
527 | static struct adreno_platform_config config = {}; | 565 | static struct adreno_platform_config config = {}; |
528 | #ifdef CONFIG_OF | 566 | #ifdef CONFIG_OF |
529 | struct device_node *child, *node = pdev->dev.of_node; | 567 | struct device_node *child, *node = dev->of_node; |
530 | u32 val; | 568 | u32 val; |
531 | int ret; | 569 | int ret; |
532 | 570 | ||
533 | ret = of_property_read_u32(node, "qcom,chipid", &val); | 571 | ret = of_property_read_u32(node, "qcom,chipid", &val); |
534 | if (ret) { | 572 | if (ret) { |
535 | dev_err(&pdev->dev, "could not find chipid: %d\n", ret); | 573 | dev_err(dev, "could not find chipid: %d\n", ret); |
536 | return ret; | 574 | return ret; |
537 | } | 575 | } |
538 | 576 | ||
@@ -548,7 +586,7 @@ static int a3xx_probe(struct platform_device *pdev) | |||
548 | for_each_child_of_node(child, pwrlvl) { | 586 | for_each_child_of_node(child, pwrlvl) { |
549 | ret = of_property_read_u32(pwrlvl, "qcom,gpu-freq", &val); | 587 | ret = of_property_read_u32(pwrlvl, "qcom,gpu-freq", &val); |
550 | if (ret) { | 588 | if (ret) { |
551 | dev_err(&pdev->dev, "could not find gpu-freq: %d\n", ret); | 589 | dev_err(dev, "could not find gpu-freq: %d\n", ret); |
552 | return ret; | 590 | return ret; |
553 | } | 591 | } |
554 | config.fast_rate = max(config.fast_rate, val); | 592 | config.fast_rate = max(config.fast_rate, val); |
@@ -558,12 +596,12 @@ static int a3xx_probe(struct platform_device *pdev) | |||
558 | } | 596 | } |
559 | 597 | ||
560 | if (!config.fast_rate) { | 598 | if (!config.fast_rate) { |
561 | dev_err(&pdev->dev, "could not find clk rates\n"); | 599 | dev_err(dev, "could not find clk rates\n"); |
562 | return -ENXIO; | 600 | return -ENXIO; |
563 | } | 601 | } |
564 | 602 | ||
565 | #else | 603 | #else |
566 | struct kgsl_device_platform_data *pdata = pdev->dev.platform_data; | 604 | struct kgsl_device_platform_data *pdata = dev->platform_data; |
567 | uint32_t version = socinfo_get_version(); | 605 | uint32_t version = socinfo_get_version(); |
568 | if (cpu_is_apq8064ab()) { | 606 | if (cpu_is_apq8064ab()) { |
569 | config.fast_rate = 450000000; | 607 | config.fast_rate = 450000000; |
@@ -609,14 +647,30 @@ static int a3xx_probe(struct platform_device *pdev) | |||
609 | config.bus_scale_table = pdata->bus_scale_table; | 647 | config.bus_scale_table = pdata->bus_scale_table; |
610 | # endif | 648 | # endif |
611 | #endif | 649 | #endif |
612 | pdev->dev.platform_data = &config; | 650 | dev->platform_data = &config; |
613 | a3xx_pdev = pdev; | 651 | set_gpu_pdev(dev_get_drvdata(master), to_platform_device(dev)); |
614 | return 0; | 652 | return 0; |
615 | } | 653 | } |
616 | 654 | ||
655 | static void a3xx_unbind(struct device *dev, struct device *master, | ||
656 | void *data) | ||
657 | { | ||
658 | set_gpu_pdev(dev_get_drvdata(master), NULL); | ||
659 | } | ||
660 | |||
661 | static const struct component_ops a3xx_ops = { | ||
662 | .bind = a3xx_bind, | ||
663 | .unbind = a3xx_unbind, | ||
664 | }; | ||
665 | |||
666 | static int a3xx_probe(struct platform_device *pdev) | ||
667 | { | ||
668 | return component_add(&pdev->dev, &a3xx_ops); | ||
669 | } | ||
670 | |||
617 | static int a3xx_remove(struct platform_device *pdev) | 671 | static int a3xx_remove(struct platform_device *pdev) |
618 | { | 672 | { |
619 | a3xx_pdev = NULL; | 673 | component_del(&pdev->dev, &a3xx_ops); |
620 | return 0; | 674 | return 0; |
621 | } | 675 | } |
622 | 676 | ||
@@ -624,7 +678,6 @@ static const struct of_device_id dt_match[] = { | |||
624 | { .compatible = "qcom,kgsl-3d0" }, | 678 | { .compatible = "qcom,kgsl-3d0" }, |
625 | {} | 679 | {} |
626 | }; | 680 | }; |
627 | MODULE_DEVICE_TABLE(of, dt_match); | ||
628 | 681 | ||
629 | static struct platform_driver a3xx_driver = { | 682 | static struct platform_driver a3xx_driver = { |
630 | .probe = a3xx_probe, | 683 | .probe = a3xx_probe, |
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index d321099abdd4..28ca8cd8b09e 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c | |||
@@ -73,6 +73,12 @@ int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value) | |||
73 | case MSM_PARAM_GMEM_SIZE: | 73 | case MSM_PARAM_GMEM_SIZE: |
74 | *value = adreno_gpu->gmem; | 74 | *value = adreno_gpu->gmem; |
75 | return 0; | 75 | return 0; |
76 | case MSM_PARAM_CHIP_ID: | ||
77 | *value = adreno_gpu->rev.patchid | | ||
78 | (adreno_gpu->rev.minor << 8) | | ||
79 | (adreno_gpu->rev.major << 16) | | ||
80 | (adreno_gpu->rev.core << 24); | ||
81 | return 0; | ||
76 | default: | 82 | default: |
77 | DBG("%s: invalid param: %u", gpu->name, param); | 83 | DBG("%s: invalid param: %u", gpu->name, param); |
78 | return -EINVAL; | 84 | return -EINVAL; |
@@ -225,19 +231,11 @@ void adreno_flush(struct msm_gpu *gpu) | |||
225 | void adreno_idle(struct msm_gpu *gpu) | 231 | void adreno_idle(struct msm_gpu *gpu) |
226 | { | 232 | { |
227 | struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); | 233 | struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); |
228 | uint32_t rptr, wptr = get_wptr(gpu->rb); | 234 | uint32_t wptr = get_wptr(gpu->rb); |
229 | unsigned long t; | ||
230 | |||
231 | t = jiffies + ADRENO_IDLE_TIMEOUT; | ||
232 | |||
233 | /* then wait for CP to drain ringbuffer: */ | ||
234 | do { | ||
235 | rptr = adreno_gpu->memptrs->rptr; | ||
236 | if (rptr == wptr) | ||
237 | return; | ||
238 | } while(time_before(jiffies, t)); | ||
239 | 235 | ||
240 | DRM_ERROR("%s: timeout waiting to drain ringbuffer!\n", gpu->name); | 236 | /* wait for CP to drain ringbuffer: */ |
237 | if (spin_until(adreno_gpu->memptrs->rptr == wptr)) | ||
238 | DRM_ERROR("%s: timeout waiting to drain ringbuffer!\n", gpu->name); | ||
241 | 239 | ||
242 | /* TODO maybe we need to reset GPU here to recover from hang? */ | 240 | /* TODO maybe we need to reset GPU here to recover from hang? */ |
243 | } | 241 | } |
@@ -260,22 +258,37 @@ void adreno_show(struct msm_gpu *gpu, struct seq_file *m) | |||
260 | } | 258 | } |
261 | #endif | 259 | #endif |
262 | 260 | ||
263 | void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords) | 261 | /* would be nice to not have to duplicate the _show() stuff with printk(): */ |
262 | void adreno_dump(struct msm_gpu *gpu) | ||
264 | { | 263 | { |
265 | struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); | 264 | struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); |
266 | uint32_t freedwords; | 265 | |
267 | unsigned long t = jiffies + ADRENO_IDLE_TIMEOUT; | 266 | printk("revision: %d (%d.%d.%d.%d)\n", |
268 | do { | 267 | adreno_gpu->info->revn, adreno_gpu->rev.core, |
269 | uint32_t size = gpu->rb->size / 4; | 268 | adreno_gpu->rev.major, adreno_gpu->rev.minor, |
270 | uint32_t wptr = get_wptr(gpu->rb); | 269 | adreno_gpu->rev.patchid); |
271 | uint32_t rptr = adreno_gpu->memptrs->rptr; | 270 | |
272 | freedwords = (rptr + (size - 1) - wptr) % size; | 271 | printk("fence: %d/%d\n", adreno_gpu->memptrs->fence, |
273 | 272 | gpu->submitted_fence); | |
274 | if (time_after(jiffies, t)) { | 273 | printk("rptr: %d\n", adreno_gpu->memptrs->rptr); |
275 | DRM_ERROR("%s: timeout waiting for ringbuffer space\n", gpu->name); | 274 | printk("wptr: %d\n", adreno_gpu->memptrs->wptr); |
276 | break; | 275 | printk("rb wptr: %d\n", get_wptr(gpu->rb)); |
277 | } | 276 | |
278 | } while(freedwords < ndwords); | 277 | } |
278 | |||
279 | static uint32_t ring_freewords(struct msm_gpu *gpu) | ||
280 | { | ||
281 | struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); | ||
282 | uint32_t size = gpu->rb->size / 4; | ||
283 | uint32_t wptr = get_wptr(gpu->rb); | ||
284 | uint32_t rptr = adreno_gpu->memptrs->rptr; | ||
285 | return (rptr + (size - 1) - wptr) % size; | ||
286 | } | ||
287 | |||
288 | void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords) | ||
289 | { | ||
290 | if (spin_until(ring_freewords(gpu) >= ndwords)) | ||
291 | DRM_ERROR("%s: timeout waiting for ringbuffer space\n", gpu->name); | ||
279 | } | 292 | } |
280 | 293 | ||
281 | static const char *iommu_ports[] = { | 294 | static const char *iommu_ports[] = { |
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index ca11ea4da165..63c36ce33020 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h | |||
@@ -76,7 +76,20 @@ struct adreno_platform_config { | |||
76 | #endif | 76 | #endif |
77 | }; | 77 | }; |
78 | 78 | ||
79 | #define ADRENO_IDLE_TIMEOUT (20 * 1000) | 79 | #define ADRENO_IDLE_TIMEOUT msecs_to_jiffies(1000) |
80 | |||
81 | #define spin_until(X) ({ \ | ||
82 | int __ret = -ETIMEDOUT; \ | ||
83 | unsigned long __t = jiffies + ADRENO_IDLE_TIMEOUT; \ | ||
84 | do { \ | ||
85 | if (X) { \ | ||
86 | __ret = 0; \ | ||
87 | break; \ | ||
88 | } \ | ||
89 | } while (time_before(jiffies, __t)); \ | ||
90 | __ret; \ | ||
91 | }) | ||
92 | |||
80 | 93 | ||
81 | static inline bool adreno_is_a3xx(struct adreno_gpu *gpu) | 94 | static inline bool adreno_is_a3xx(struct adreno_gpu *gpu) |
82 | { | 95 | { |
@@ -114,6 +127,7 @@ void adreno_idle(struct msm_gpu *gpu); | |||
114 | #ifdef CONFIG_DEBUG_FS | 127 | #ifdef CONFIG_DEBUG_FS |
115 | void adreno_show(struct msm_gpu *gpu, struct seq_file *m); | 128 | void adreno_show(struct msm_gpu *gpu, struct seq_file *m); |
116 | #endif | 129 | #endif |
130 | void adreno_dump(struct msm_gpu *gpu); | ||
117 | void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords); | 131 | void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords); |
118 | 132 | ||
119 | int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, | 133 | int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, |
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 6f1588aa9071..ae750f6928c1 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c | |||
@@ -17,8 +17,6 @@ | |||
17 | 17 | ||
18 | #include "hdmi.h" | 18 | #include "hdmi.h" |
19 | 19 | ||
20 | static struct platform_device *hdmi_pdev; | ||
21 | |||
22 | void hdmi_set_mode(struct hdmi *hdmi, bool power_on) | 20 | void hdmi_set_mode(struct hdmi *hdmi, bool power_on) |
23 | { | 21 | { |
24 | uint32_t ctrl = 0; | 22 | uint32_t ctrl = 0; |
@@ -67,7 +65,7 @@ void hdmi_destroy(struct kref *kref) | |||
67 | if (hdmi->i2c) | 65 | if (hdmi->i2c) |
68 | hdmi_i2c_destroy(hdmi->i2c); | 66 | hdmi_i2c_destroy(hdmi->i2c); |
69 | 67 | ||
70 | put_device(&hdmi->pdev->dev); | 68 | platform_set_drvdata(hdmi->pdev, NULL); |
71 | } | 69 | } |
72 | 70 | ||
73 | /* initialize connector */ | 71 | /* initialize connector */ |
@@ -75,7 +73,7 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder) | |||
75 | { | 73 | { |
76 | struct hdmi *hdmi = NULL; | 74 | struct hdmi *hdmi = NULL; |
77 | struct msm_drm_private *priv = dev->dev_private; | 75 | struct msm_drm_private *priv = dev->dev_private; |
78 | struct platform_device *pdev = hdmi_pdev; | 76 | struct platform_device *pdev = priv->hdmi_pdev; |
79 | struct hdmi_platform_config *config; | 77 | struct hdmi_platform_config *config; |
80 | int i, ret; | 78 | int i, ret; |
81 | 79 | ||
@@ -95,13 +93,13 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder) | |||
95 | 93 | ||
96 | kref_init(&hdmi->refcount); | 94 | kref_init(&hdmi->refcount); |
97 | 95 | ||
98 | get_device(&pdev->dev); | ||
99 | |||
100 | hdmi->dev = dev; | 96 | hdmi->dev = dev; |
101 | hdmi->pdev = pdev; | 97 | hdmi->pdev = pdev; |
102 | hdmi->config = config; | 98 | hdmi->config = config; |
103 | hdmi->encoder = encoder; | 99 | hdmi->encoder = encoder; |
104 | 100 | ||
101 | hdmi_audio_infoframe_init(&hdmi->audio.infoframe); | ||
102 | |||
105 | /* not sure about which phy maps to which msm.. probably I miss some */ | 103 | /* not sure about which phy maps to which msm.. probably I miss some */ |
106 | if (config->phy_init) | 104 | if (config->phy_init) |
107 | hdmi->phy = config->phy_init(hdmi); | 105 | hdmi->phy = config->phy_init(hdmi); |
@@ -228,6 +226,8 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder) | |||
228 | priv->bridges[priv->num_bridges++] = hdmi->bridge; | 226 | priv->bridges[priv->num_bridges++] = hdmi->bridge; |
229 | priv->connectors[priv->num_connectors++] = hdmi->connector; | 227 | priv->connectors[priv->num_connectors++] = hdmi->connector; |
230 | 228 | ||
229 | platform_set_drvdata(pdev, hdmi); | ||
230 | |||
231 | return hdmi; | 231 | return hdmi; |
232 | 232 | ||
233 | fail: | 233 | fail: |
@@ -249,17 +249,24 @@ fail: | |||
249 | 249 | ||
250 | #include <linux/of_gpio.h> | 250 | #include <linux/of_gpio.h> |
251 | 251 | ||
252 | static int hdmi_dev_probe(struct platform_device *pdev) | 252 | static void set_hdmi_pdev(struct drm_device *dev, |
253 | struct platform_device *pdev) | ||
254 | { | ||
255 | struct msm_drm_private *priv = dev->dev_private; | ||
256 | priv->hdmi_pdev = pdev; | ||
257 | } | ||
258 | |||
259 | static int hdmi_bind(struct device *dev, struct device *master, void *data) | ||
253 | { | 260 | { |
254 | static struct hdmi_platform_config config = {}; | 261 | static struct hdmi_platform_config config = {}; |
255 | #ifdef CONFIG_OF | 262 | #ifdef CONFIG_OF |
256 | struct device_node *of_node = pdev->dev.of_node; | 263 | struct device_node *of_node = dev->of_node; |
257 | 264 | ||
258 | int get_gpio(const char *name) | 265 | int get_gpio(const char *name) |
259 | { | 266 | { |
260 | int gpio = of_get_named_gpio(of_node, name, 0); | 267 | int gpio = of_get_named_gpio(of_node, name, 0); |
261 | if (gpio < 0) { | 268 | if (gpio < 0) { |
262 | dev_err(&pdev->dev, "failed to get gpio: %s (%d)\n", | 269 | dev_err(dev, "failed to get gpio: %s (%d)\n", |
263 | name, gpio); | 270 | name, gpio); |
264 | gpio = -1; | 271 | gpio = -1; |
265 | } | 272 | } |
@@ -305,7 +312,7 @@ static int hdmi_dev_probe(struct platform_device *pdev) | |||
305 | config.ddc_data_gpio = 71; | 312 | config.ddc_data_gpio = 71; |
306 | config.hpd_gpio = 72; | 313 | config.hpd_gpio = 72; |
307 | config.mux_en_gpio = -1; | 314 | config.mux_en_gpio = -1; |
308 | config.mux_sel_gpio = 13 + NR_GPIO_IRQS; | 315 | config.mux_sel_gpio = -1; |
309 | } else if (cpu_is_msm8960() || cpu_is_msm8960ab()) { | 316 | } else if (cpu_is_msm8960() || cpu_is_msm8960ab()) { |
310 | static const char *hpd_reg_names[] = {"8921_hdmi_mvs"}; | 317 | static const char *hpd_reg_names[] = {"8921_hdmi_mvs"}; |
311 | config.phy_init = hdmi_phy_8960_init; | 318 | config.phy_init = hdmi_phy_8960_init; |
@@ -336,14 +343,30 @@ static int hdmi_dev_probe(struct platform_device *pdev) | |||
336 | config.mux_sel_gpio = -1; | 343 | config.mux_sel_gpio = -1; |
337 | } | 344 | } |
338 | #endif | 345 | #endif |
339 | pdev->dev.platform_data = &config; | 346 | dev->platform_data = &config; |
340 | hdmi_pdev = pdev; | 347 | set_hdmi_pdev(dev_get_drvdata(master), to_platform_device(dev)); |
341 | return 0; | 348 | return 0; |
342 | } | 349 | } |
343 | 350 | ||
351 | static void hdmi_unbind(struct device *dev, struct device *master, | ||
352 | void *data) | ||
353 | { | ||
354 | set_hdmi_pdev(dev_get_drvdata(master), NULL); | ||
355 | } | ||
356 | |||
357 | static const struct component_ops hdmi_ops = { | ||
358 | .bind = hdmi_bind, | ||
359 | .unbind = hdmi_unbind, | ||
360 | }; | ||
361 | |||
362 | static int hdmi_dev_probe(struct platform_device *pdev) | ||
363 | { | ||
364 | return component_add(&pdev->dev, &hdmi_ops); | ||
365 | } | ||
366 | |||
344 | static int hdmi_dev_remove(struct platform_device *pdev) | 367 | static int hdmi_dev_remove(struct platform_device *pdev) |
345 | { | 368 | { |
346 | hdmi_pdev = NULL; | 369 | component_del(&pdev->dev, &hdmi_ops); |
347 | return 0; | 370 | return 0; |
348 | } | 371 | } |
349 | 372 | ||
@@ -351,7 +374,6 @@ static const struct of_device_id dt_match[] = { | |||
351 | { .compatible = "qcom,hdmi-tx" }, | 374 | { .compatible = "qcom,hdmi-tx" }, |
352 | {} | 375 | {} |
353 | }; | 376 | }; |
354 | MODULE_DEVICE_TABLE(of, dt_match); | ||
355 | 377 | ||
356 | static struct platform_driver hdmi_driver = { | 378 | static struct platform_driver hdmi_driver = { |
357 | .probe = hdmi_dev_probe, | 379 | .probe = hdmi_dev_probe, |
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h index 41b29add70b1..9fafee6a3e43 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.h +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/clk.h> | 22 | #include <linux/clk.h> |
23 | #include <linux/platform_device.h> | 23 | #include <linux/platform_device.h> |
24 | #include <linux/regulator/consumer.h> | 24 | #include <linux/regulator/consumer.h> |
25 | #include <linux/hdmi.h> | ||
25 | 26 | ||
26 | #include "msm_drv.h" | 27 | #include "msm_drv.h" |
27 | #include "hdmi.xml.h" | 28 | #include "hdmi.xml.h" |
@@ -30,6 +31,12 @@ | |||
30 | struct hdmi_phy; | 31 | struct hdmi_phy; |
31 | struct hdmi_platform_config; | 32 | struct hdmi_platform_config; |
32 | 33 | ||
34 | struct hdmi_audio { | ||
35 | bool enabled; | ||
36 | struct hdmi_audio_infoframe infoframe; | ||
37 | int rate; | ||
38 | }; | ||
39 | |||
33 | struct hdmi { | 40 | struct hdmi { |
34 | struct kref refcount; | 41 | struct kref refcount; |
35 | 42 | ||
@@ -38,6 +45,13 @@ struct hdmi { | |||
38 | 45 | ||
39 | const struct hdmi_platform_config *config; | 46 | const struct hdmi_platform_config *config; |
40 | 47 | ||
48 | /* audio state: */ | ||
49 | struct hdmi_audio audio; | ||
50 | |||
51 | /* video state: */ | ||
52 | bool power_on; | ||
53 | unsigned long int pixclock; | ||
54 | |||
41 | void __iomem *mmio; | 55 | void __iomem *mmio; |
42 | 56 | ||
43 | struct regulator *hpd_regs[2]; | 57 | struct regulator *hpd_regs[2]; |
@@ -132,6 +146,17 @@ struct hdmi_phy *hdmi_phy_8x60_init(struct hdmi *hdmi); | |||
132 | struct hdmi_phy *hdmi_phy_8x74_init(struct hdmi *hdmi); | 146 | struct hdmi_phy *hdmi_phy_8x74_init(struct hdmi *hdmi); |
133 | 147 | ||
134 | /* | 148 | /* |
149 | * audio: | ||
150 | */ | ||
151 | |||
152 | int hdmi_audio_update(struct hdmi *hdmi); | ||
153 | int hdmi_audio_info_setup(struct hdmi *hdmi, bool enabled, | ||
154 | uint32_t num_of_channels, uint32_t channel_allocation, | ||
155 | uint32_t level_shift, bool down_mix); | ||
156 | void hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate); | ||
157 | |||
158 | |||
159 | /* | ||
135 | * hdmi bridge: | 160 | * hdmi bridge: |
136 | */ | 161 | */ |
137 | 162 | ||
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c new file mode 100644 index 000000000000..872485f60134 --- /dev/null +++ b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c | |||
@@ -0,0 +1,273 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2013 Red Hat | ||
3 | * Author: Rob Clark <robdclark@gmail.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published by | ||
7 | * the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #include <linux/hdmi.h> | ||
19 | #include "hdmi.h" | ||
20 | |||
21 | |||
22 | /* Supported HDMI Audio channels */ | ||
23 | #define MSM_HDMI_AUDIO_CHANNEL_2 0 | ||
24 | #define MSM_HDMI_AUDIO_CHANNEL_4 1 | ||
25 | #define MSM_HDMI_AUDIO_CHANNEL_6 2 | ||
26 | #define MSM_HDMI_AUDIO_CHANNEL_8 3 | ||
27 | |||
28 | /* maps MSM_HDMI_AUDIO_CHANNEL_n consts used by audio driver to # of channels: */ | ||
29 | static int nchannels[] = { 2, 4, 6, 8 }; | ||
30 | |||
31 | /* Supported HDMI Audio sample rates */ | ||
32 | #define MSM_HDMI_SAMPLE_RATE_32KHZ 0 | ||
33 | #define MSM_HDMI_SAMPLE_RATE_44_1KHZ 1 | ||
34 | #define MSM_HDMI_SAMPLE_RATE_48KHZ 2 | ||
35 | #define MSM_HDMI_SAMPLE_RATE_88_2KHZ 3 | ||
36 | #define MSM_HDMI_SAMPLE_RATE_96KHZ 4 | ||
37 | #define MSM_HDMI_SAMPLE_RATE_176_4KHZ 5 | ||
38 | #define MSM_HDMI_SAMPLE_RATE_192KHZ 6 | ||
39 | #define MSM_HDMI_SAMPLE_RATE_MAX 7 | ||
40 | |||
41 | |||
42 | struct hdmi_msm_audio_acr { | ||
43 | uint32_t n; /* N parameter for clock regeneration */ | ||
44 | uint32_t cts; /* CTS parameter for clock regeneration */ | ||
45 | }; | ||
46 | |||
47 | struct hdmi_msm_audio_arcs { | ||
48 | unsigned long int pixclock; | ||
49 | struct hdmi_msm_audio_acr lut[MSM_HDMI_SAMPLE_RATE_MAX]; | ||
50 | }; | ||
51 | |||
52 | #define HDMI_MSM_AUDIO_ARCS(pclk, ...) { (1000 * (pclk)), __VA_ARGS__ } | ||
53 | |||
54 | /* Audio constants lookup table for hdmi_msm_audio_acr_setup */ | ||
55 | /* Valid Pixel-Clock rates: 25.2MHz, 27MHz, 27.03MHz, 74.25MHz, 148.5MHz */ | ||
56 | static const struct hdmi_msm_audio_arcs acr_lut[] = { | ||
57 | /* 25.200MHz */ | ||
58 | HDMI_MSM_AUDIO_ARCS(25200, { | ||
59 | {4096, 25200}, {6272, 28000}, {6144, 25200}, {12544, 28000}, | ||
60 | {12288, 25200}, {25088, 28000}, {24576, 25200} }), | ||
61 | /* 27.000MHz */ | ||
62 | HDMI_MSM_AUDIO_ARCS(27000, { | ||
63 | {4096, 27000}, {6272, 30000}, {6144, 27000}, {12544, 30000}, | ||
64 | {12288, 27000}, {25088, 30000}, {24576, 27000} }), | ||
65 | /* 27.027MHz */ | ||
66 | HDMI_MSM_AUDIO_ARCS(27030, { | ||
67 | {4096, 27027}, {6272, 30030}, {6144, 27027}, {12544, 30030}, | ||
68 | {12288, 27027}, {25088, 30030}, {24576, 27027} }), | ||
69 | /* 74.250MHz */ | ||
70 | HDMI_MSM_AUDIO_ARCS(74250, { | ||
71 | {4096, 74250}, {6272, 82500}, {6144, 74250}, {12544, 82500}, | ||
72 | {12288, 74250}, {25088, 82500}, {24576, 74250} }), | ||
73 | /* 148.500MHz */ | ||
74 | HDMI_MSM_AUDIO_ARCS(148500, { | ||
75 | {4096, 148500}, {6272, 165000}, {6144, 148500}, {12544, 165000}, | ||
76 | {12288, 148500}, {25088, 165000}, {24576, 148500} }), | ||
77 | }; | ||
78 | |||
79 | static const struct hdmi_msm_audio_arcs *get_arcs(unsigned long int pixclock) | ||
80 | { | ||
81 | int i; | ||
82 | |||
83 | for (i = 0; i < ARRAY_SIZE(acr_lut); i++) { | ||
84 | const struct hdmi_msm_audio_arcs *arcs = &acr_lut[i]; | ||
85 | if (arcs->pixclock == pixclock) | ||
86 | return arcs; | ||
87 | } | ||
88 | |||
89 | return NULL; | ||
90 | } | ||
91 | |||
92 | int hdmi_audio_update(struct hdmi *hdmi) | ||
93 | { | ||
94 | struct hdmi_audio *audio = &hdmi->audio; | ||
95 | struct hdmi_audio_infoframe *info = &audio->infoframe; | ||
96 | const struct hdmi_msm_audio_arcs *arcs = NULL; | ||
97 | bool enabled = audio->enabled; | ||
98 | uint32_t acr_pkt_ctrl, vbi_pkt_ctrl, aud_pkt_ctrl; | ||
99 | uint32_t infofrm_ctrl, audio_config; | ||
100 | |||
101 | DBG("audio: enabled=%d, channels=%d, channel_allocation=0x%x, " | ||
102 | "level_shift_value=%d, downmix_inhibit=%d, rate=%d", | ||
103 | audio->enabled, info->channels, info->channel_allocation, | ||
104 | info->level_shift_value, info->downmix_inhibit, audio->rate); | ||
105 | DBG("video: power_on=%d, pixclock=%lu", hdmi->power_on, hdmi->pixclock); | ||
106 | |||
107 | if (enabled && !(hdmi->power_on && hdmi->pixclock)) { | ||
108 | DBG("disabling audio: no video"); | ||
109 | enabled = false; | ||
110 | } | ||
111 | |||
112 | if (enabled) { | ||
113 | arcs = get_arcs(hdmi->pixclock); | ||
114 | if (!arcs) { | ||
115 | DBG("disabling audio: unsupported pixclock: %lu", | ||
116 | hdmi->pixclock); | ||
117 | enabled = false; | ||
118 | } | ||
119 | } | ||
120 | |||
121 | /* Read first before writing */ | ||
122 | acr_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_ACR_PKT_CTRL); | ||
123 | vbi_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_VBI_PKT_CTRL); | ||
124 | aud_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_AUDIO_PKT_CTRL1); | ||
125 | infofrm_ctrl = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0); | ||
126 | audio_config = hdmi_read(hdmi, REG_HDMI_AUDIO_CFG); | ||
127 | |||
128 | /* Clear N/CTS selection bits */ | ||
129 | acr_pkt_ctrl &= ~HDMI_ACR_PKT_CTRL_SELECT__MASK; | ||
130 | |||
131 | if (enabled) { | ||
132 | uint32_t n, cts, multiplier; | ||
133 | enum hdmi_acr_cts select; | ||
134 | uint8_t buf[14]; | ||
135 | |||
136 | n = arcs->lut[audio->rate].n; | ||
137 | cts = arcs->lut[audio->rate].cts; | ||
138 | |||
139 | if ((MSM_HDMI_SAMPLE_RATE_192KHZ == audio->rate) || | ||
140 | (MSM_HDMI_SAMPLE_RATE_176_4KHZ == audio->rate)) { | ||
141 | multiplier = 4; | ||
142 | n >>= 2; /* divide N by 4 and use multiplier */ | ||
143 | } else if ((MSM_HDMI_SAMPLE_RATE_96KHZ == audio->rate) || | ||
144 | (MSM_HDMI_SAMPLE_RATE_88_2KHZ == audio->rate)) { | ||
145 | multiplier = 2; | ||
146 | n >>= 1; /* divide N by 2 and use multiplier */ | ||
147 | } else { | ||
148 | multiplier = 1; | ||
149 | } | ||
150 | |||
151 | DBG("n=%u, cts=%u, multiplier=%u", n, cts, multiplier); | ||
152 | |||
153 | acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_SOURCE; | ||
154 | acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_AUDIO_PRIORITY; | ||
155 | acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_N_MULTIPLIER(multiplier); | ||
156 | |||
157 | if ((MSM_HDMI_SAMPLE_RATE_48KHZ == audio->rate) || | ||
158 | (MSM_HDMI_SAMPLE_RATE_96KHZ == audio->rate) || | ||
159 | (MSM_HDMI_SAMPLE_RATE_192KHZ == audio->rate)) | ||
160 | select = ACR_48; | ||
161 | else if ((MSM_HDMI_SAMPLE_RATE_44_1KHZ == audio->rate) || | ||
162 | (MSM_HDMI_SAMPLE_RATE_88_2KHZ == audio->rate) || | ||
163 | (MSM_HDMI_SAMPLE_RATE_176_4KHZ == audio->rate)) | ||
164 | select = ACR_44; | ||
165 | else /* default to 32k */ | ||
166 | select = ACR_32; | ||
167 | |||
168 | acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_SELECT(select); | ||
169 | |||
170 | hdmi_write(hdmi, REG_HDMI_ACR_0(select - 1), | ||
171 | HDMI_ACR_0_CTS(cts)); | ||
172 | hdmi_write(hdmi, REG_HDMI_ACR_1(select - 1), | ||
173 | HDMI_ACR_1_N(n)); | ||
174 | |||
175 | hdmi_write(hdmi, REG_HDMI_AUDIO_PKT_CTRL2, | ||
176 | COND(info->channels != 2, HDMI_AUDIO_PKT_CTRL2_LAYOUT) | | ||
177 | HDMI_AUDIO_PKT_CTRL2_OVERRIDE); | ||
178 | |||
179 | acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_CONT; | ||
180 | acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_SEND; | ||
181 | |||
182 | /* configure infoframe: */ | ||
183 | hdmi_audio_infoframe_pack(info, buf, sizeof(buf)); | ||
184 | hdmi_write(hdmi, REG_HDMI_AUDIO_INFO0, | ||
185 | (buf[3] << 0) || (buf[4] << 8) || | ||
186 | (buf[5] << 16) || (buf[6] << 24)); | ||
187 | hdmi_write(hdmi, REG_HDMI_AUDIO_INFO1, | ||
188 | (buf[7] << 0) || (buf[8] << 8)); | ||
189 | |||
190 | hdmi_write(hdmi, REG_HDMI_GC, 0); | ||
191 | |||
192 | vbi_pkt_ctrl |= HDMI_VBI_PKT_CTRL_GC_ENABLE; | ||
193 | vbi_pkt_ctrl |= HDMI_VBI_PKT_CTRL_GC_EVERY_FRAME; | ||
194 | |||
195 | aud_pkt_ctrl |= HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND; | ||
196 | |||
197 | infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND; | ||
198 | infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT; | ||
199 | infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE; | ||
200 | infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE; | ||
201 | |||
202 | audio_config &= ~HDMI_AUDIO_CFG_FIFO_WATERMARK__MASK; | ||
203 | audio_config |= HDMI_AUDIO_CFG_FIFO_WATERMARK(4); | ||
204 | audio_config |= HDMI_AUDIO_CFG_ENGINE_ENABLE; | ||
205 | } else { | ||
206 | hdmi_write(hdmi, REG_HDMI_GC, HDMI_GC_MUTE); | ||
207 | acr_pkt_ctrl &= ~HDMI_ACR_PKT_CTRL_CONT; | ||
208 | acr_pkt_ctrl &= ~HDMI_ACR_PKT_CTRL_SEND; | ||
209 | vbi_pkt_ctrl &= ~HDMI_VBI_PKT_CTRL_GC_ENABLE; | ||
210 | vbi_pkt_ctrl &= ~HDMI_VBI_PKT_CTRL_GC_EVERY_FRAME; | ||
211 | aud_pkt_ctrl &= ~HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND; | ||
212 | infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND; | ||
213 | infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT; | ||
214 | infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE; | ||
215 | infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE; | ||
216 | audio_config &= ~HDMI_AUDIO_CFG_ENGINE_ENABLE; | ||
217 | } | ||
218 | |||
219 | hdmi_write(hdmi, REG_HDMI_ACR_PKT_CTRL, acr_pkt_ctrl); | ||
220 | hdmi_write(hdmi, REG_HDMI_VBI_PKT_CTRL, vbi_pkt_ctrl); | ||
221 | hdmi_write(hdmi, REG_HDMI_AUDIO_PKT_CTRL1, aud_pkt_ctrl); | ||
222 | hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, infofrm_ctrl); | ||
223 | |||
224 | hdmi_write(hdmi, REG_HDMI_AUD_INT, | ||
225 | COND(enabled, HDMI_AUD_INT_AUD_FIFO_URUN_INT) | | ||
226 | COND(enabled, HDMI_AUD_INT_AUD_SAM_DROP_INT)); | ||
227 | |||
228 | hdmi_write(hdmi, REG_HDMI_AUDIO_CFG, audio_config); | ||
229 | |||
230 | |||
231 | DBG("audio %sabled", enabled ? "en" : "dis"); | ||
232 | |||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | int hdmi_audio_info_setup(struct hdmi *hdmi, bool enabled, | ||
237 | uint32_t num_of_channels, uint32_t channel_allocation, | ||
238 | uint32_t level_shift, bool down_mix) | ||
239 | { | ||
240 | struct hdmi_audio *audio; | ||
241 | |||
242 | if (!hdmi) | ||
243 | return -ENXIO; | ||
244 | |||
245 | audio = &hdmi->audio; | ||
246 | |||
247 | if (num_of_channels >= ARRAY_SIZE(nchannels)) | ||
248 | return -EINVAL; | ||
249 | |||
250 | audio->enabled = enabled; | ||
251 | audio->infoframe.channels = nchannels[num_of_channels]; | ||
252 | audio->infoframe.channel_allocation = channel_allocation; | ||
253 | audio->infoframe.level_shift_value = level_shift; | ||
254 | audio->infoframe.downmix_inhibit = down_mix; | ||
255 | |||
256 | return hdmi_audio_update(hdmi); | ||
257 | } | ||
258 | |||
259 | void hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate) | ||
260 | { | ||
261 | struct hdmi_audio *audio; | ||
262 | |||
263 | if (!hdmi) | ||
264 | return; | ||
265 | |||
266 | audio = &hdmi->audio; | ||
267 | |||
268 | if ((rate < 0) || (rate >= MSM_HDMI_SAMPLE_RATE_MAX)) | ||
269 | return; | ||
270 | |||
271 | audio->rate = rate; | ||
272 | hdmi_audio_update(hdmi); | ||
273 | } | ||
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c index 7d10e55403c6..f6cf745c249e 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | |||
@@ -19,11 +19,7 @@ | |||
19 | 19 | ||
20 | struct hdmi_bridge { | 20 | struct hdmi_bridge { |
21 | struct drm_bridge base; | 21 | struct drm_bridge base; |
22 | |||
23 | struct hdmi *hdmi; | 22 | struct hdmi *hdmi; |
24 | bool power_on; | ||
25 | |||
26 | unsigned long int pixclock; | ||
27 | }; | 23 | }; |
28 | #define to_hdmi_bridge(x) container_of(x, struct hdmi_bridge, base) | 24 | #define to_hdmi_bridge(x) container_of(x, struct hdmi_bridge, base) |
29 | 25 | ||
@@ -52,8 +48,8 @@ static void power_on(struct drm_bridge *bridge) | |||
52 | } | 48 | } |
53 | 49 | ||
54 | if (config->pwr_clk_cnt > 0) { | 50 | if (config->pwr_clk_cnt > 0) { |
55 | DBG("pixclock: %lu", hdmi_bridge->pixclock); | 51 | DBG("pixclock: %lu", hdmi->pixclock); |
56 | ret = clk_set_rate(hdmi->pwr_clks[0], hdmi_bridge->pixclock); | 52 | ret = clk_set_rate(hdmi->pwr_clks[0], hdmi->pixclock); |
57 | if (ret) { | 53 | if (ret) { |
58 | dev_err(dev->dev, "failed to set pixel clk: %s (%d)\n", | 54 | dev_err(dev->dev, "failed to set pixel clk: %s (%d)\n", |
59 | config->pwr_clk_names[0], ret); | 55 | config->pwr_clk_names[0], ret); |
@@ -102,12 +98,13 @@ static void hdmi_bridge_pre_enable(struct drm_bridge *bridge) | |||
102 | 98 | ||
103 | DBG("power up"); | 99 | DBG("power up"); |
104 | 100 | ||
105 | if (!hdmi_bridge->power_on) { | 101 | if (!hdmi->power_on) { |
106 | power_on(bridge); | 102 | power_on(bridge); |
107 | hdmi_bridge->power_on = true; | 103 | hdmi->power_on = true; |
104 | hdmi_audio_update(hdmi); | ||
108 | } | 105 | } |
109 | 106 | ||
110 | phy->funcs->powerup(phy, hdmi_bridge->pixclock); | 107 | phy->funcs->powerup(phy, hdmi->pixclock); |
111 | hdmi_set_mode(hdmi, true); | 108 | hdmi_set_mode(hdmi, true); |
112 | } | 109 | } |
113 | 110 | ||
@@ -129,9 +126,10 @@ static void hdmi_bridge_post_disable(struct drm_bridge *bridge) | |||
129 | hdmi_set_mode(hdmi, false); | 126 | hdmi_set_mode(hdmi, false); |
130 | phy->funcs->powerdown(phy); | 127 | phy->funcs->powerdown(phy); |
131 | 128 | ||
132 | if (hdmi_bridge->power_on) { | 129 | if (hdmi->power_on) { |
133 | power_off(bridge); | 130 | power_off(bridge); |
134 | hdmi_bridge->power_on = false; | 131 | hdmi->power_on = false; |
132 | hdmi_audio_update(hdmi); | ||
135 | } | 133 | } |
136 | } | 134 | } |
137 | 135 | ||
@@ -146,7 +144,7 @@ static void hdmi_bridge_mode_set(struct drm_bridge *bridge, | |||
146 | 144 | ||
147 | mode = adjusted_mode; | 145 | mode = adjusted_mode; |
148 | 146 | ||
149 | hdmi_bridge->pixclock = mode->clock * 1000; | 147 | hdmi->pixclock = mode->clock * 1000; |
150 | 148 | ||
151 | hdmi->hdmi_mode = drm_match_cea_mode(mode) > 1; | 149 | hdmi->hdmi_mode = drm_match_cea_mode(mode) > 1; |
152 | 150 | ||
@@ -194,9 +192,7 @@ static void hdmi_bridge_mode_set(struct drm_bridge *bridge, | |||
194 | DBG("frame_ctrl=%08x", frame_ctrl); | 192 | DBG("frame_ctrl=%08x", frame_ctrl); |
195 | hdmi_write(hdmi, REG_HDMI_FRAME_CTRL, frame_ctrl); | 193 | hdmi_write(hdmi, REG_HDMI_FRAME_CTRL, frame_ctrl); |
196 | 194 | ||
197 | // TODO until we have audio, this might be safest: | 195 | hdmi_audio_update(hdmi); |
198 | if (hdmi->hdmi_mode) | ||
199 | hdmi_write(hdmi, REG_HDMI_GC, HDMI_GC_MUTE); | ||
200 | } | 196 | } |
201 | 197 | ||
202 | static const struct drm_bridge_funcs hdmi_bridge_funcs = { | 198 | static const struct drm_bridge_funcs hdmi_bridge_funcs = { |
diff --git a/drivers/gpu/drm/msm/mdp/mdp_kms.c b/drivers/gpu/drm/msm/mdp/mdp_kms.c index 3be48f7c36be..03455b64a245 100644 --- a/drivers/gpu/drm/msm/mdp/mdp_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp_kms.c | |||
@@ -101,7 +101,8 @@ void mdp_irq_wait(struct mdp_kms *mdp_kms, uint32_t irqmask) | |||
101 | .count = 1, | 101 | .count = 1, |
102 | }; | 102 | }; |
103 | mdp_irq_register(mdp_kms, &wait.irq); | 103 | mdp_irq_register(mdp_kms, &wait.irq); |
104 | wait_event(wait_event, (wait.count <= 0)); | 104 | wait_event_timeout(wait_event, (wait.count <= 0), |
105 | msecs_to_jiffies(100)); | ||
105 | mdp_irq_unregister(mdp_kms, &wait.irq); | 106 | mdp_irq_unregister(mdp_kms, &wait.irq); |
106 | } | 107 | } |
107 | 108 | ||
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index e6adafc7eff3..f9de156b9e65 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c | |||
@@ -56,6 +56,10 @@ static char *vram; | |||
56 | MODULE_PARM_DESC(vram, "Configure VRAM size (for devices without IOMMU/GPUMMU"); | 56 | MODULE_PARM_DESC(vram, "Configure VRAM size (for devices without IOMMU/GPUMMU"); |
57 | module_param(vram, charp, 0); | 57 | module_param(vram, charp, 0); |
58 | 58 | ||
59 | /* | ||
60 | * Util/helpers: | ||
61 | */ | ||
62 | |||
59 | void __iomem *msm_ioremap(struct platform_device *pdev, const char *name, | 63 | void __iomem *msm_ioremap(struct platform_device *pdev, const char *name, |
60 | const char *dbgname) | 64 | const char *dbgname) |
61 | { | 65 | { |
@@ -143,6 +147,8 @@ static int msm_unload(struct drm_device *dev) | |||
143 | priv->vram.paddr, &attrs); | 147 | priv->vram.paddr, &attrs); |
144 | } | 148 | } |
145 | 149 | ||
150 | component_unbind_all(dev->dev, dev); | ||
151 | |||
146 | dev->dev_private = NULL; | 152 | dev->dev_private = NULL; |
147 | 153 | ||
148 | kfree(priv); | 154 | kfree(priv); |
@@ -175,6 +181,7 @@ static int msm_load(struct drm_device *dev, unsigned long flags) | |||
175 | struct msm_kms *kms; | 181 | struct msm_kms *kms; |
176 | int ret; | 182 | int ret; |
177 | 183 | ||
184 | |||
178 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | 185 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); |
179 | if (!priv) { | 186 | if (!priv) { |
180 | dev_err(dev->dev, "failed to allocate private data\n"); | 187 | dev_err(dev->dev, "failed to allocate private data\n"); |
@@ -226,6 +233,13 @@ static int msm_load(struct drm_device *dev, unsigned long flags) | |||
226 | (uint32_t)(priv->vram.paddr + size)); | 233 | (uint32_t)(priv->vram.paddr + size)); |
227 | } | 234 | } |
228 | 235 | ||
236 | platform_set_drvdata(pdev, dev); | ||
237 | |||
238 | /* Bind all our sub-components: */ | ||
239 | ret = component_bind_all(dev->dev, dev); | ||
240 | if (ret) | ||
241 | return ret; | ||
242 | |||
229 | switch (get_mdp_ver(pdev)) { | 243 | switch (get_mdp_ver(pdev)) { |
230 | case 4: | 244 | case 4: |
231 | kms = mdp4_kms_init(dev); | 245 | kms = mdp4_kms_init(dev); |
@@ -281,8 +295,6 @@ static int msm_load(struct drm_device *dev, unsigned long flags) | |||
281 | goto fail; | 295 | goto fail; |
282 | } | 296 | } |
283 | 297 | ||
284 | platform_set_drvdata(pdev, dev); | ||
285 | |||
286 | #ifdef CONFIG_DRM_MSM_FBDEV | 298 | #ifdef CONFIG_DRM_MSM_FBDEV |
287 | priv->fbdev = msm_fbdev_init(dev); | 299 | priv->fbdev = msm_fbdev_init(dev); |
288 | #endif | 300 | #endif |
@@ -311,7 +323,6 @@ static void load_gpu(struct drm_device *dev) | |||
311 | gpu = NULL; | 323 | gpu = NULL; |
312 | /* not fatal */ | 324 | /* not fatal */ |
313 | } | 325 | } |
314 | mutex_unlock(&dev->struct_mutex); | ||
315 | 326 | ||
316 | if (gpu) { | 327 | if (gpu) { |
317 | int ret; | 328 | int ret; |
@@ -321,10 +332,16 @@ static void load_gpu(struct drm_device *dev) | |||
321 | dev_err(dev->dev, "gpu hw init failed: %d\n", ret); | 332 | dev_err(dev->dev, "gpu hw init failed: %d\n", ret); |
322 | gpu->funcs->destroy(gpu); | 333 | gpu->funcs->destroy(gpu); |
323 | gpu = NULL; | 334 | gpu = NULL; |
335 | } else { | ||
336 | /* give inactive pm a chance to kick in: */ | ||
337 | msm_gpu_retire(gpu); | ||
324 | } | 338 | } |
339 | |||
325 | } | 340 | } |
326 | 341 | ||
327 | priv->gpu = gpu; | 342 | priv->gpu = gpu; |
343 | |||
344 | mutex_unlock(&dev->struct_mutex); | ||
328 | } | 345 | } |
329 | 346 | ||
330 | static int msm_open(struct drm_device *dev, struct drm_file *file) | 347 | static int msm_open(struct drm_device *dev, struct drm_file *file) |
@@ -647,6 +664,12 @@ static int msm_ioctl_gem_new(struct drm_device *dev, void *data, | |||
647 | struct drm_file *file) | 664 | struct drm_file *file) |
648 | { | 665 | { |
649 | struct drm_msm_gem_new *args = data; | 666 | struct drm_msm_gem_new *args = data; |
667 | |||
668 | if (args->flags & ~MSM_BO_FLAGS) { | ||
669 | DRM_ERROR("invalid flags: %08x\n", args->flags); | ||
670 | return -EINVAL; | ||
671 | } | ||
672 | |||
650 | return msm_gem_new_handle(dev, file, args->size, | 673 | return msm_gem_new_handle(dev, file, args->size, |
651 | args->flags, &args->handle); | 674 | args->flags, &args->handle); |
652 | } | 675 | } |
@@ -660,6 +683,11 @@ static int msm_ioctl_gem_cpu_prep(struct drm_device *dev, void *data, | |||
660 | struct drm_gem_object *obj; | 683 | struct drm_gem_object *obj; |
661 | int ret; | 684 | int ret; |
662 | 685 | ||
686 | if (args->op & ~MSM_PREP_FLAGS) { | ||
687 | DRM_ERROR("invalid op: %08x\n", args->op); | ||
688 | return -EINVAL; | ||
689 | } | ||
690 | |||
663 | obj = drm_gem_object_lookup(dev, file, args->handle); | 691 | obj = drm_gem_object_lookup(dev, file, args->handle); |
664 | if (!obj) | 692 | if (!obj) |
665 | return -ENOENT; | 693 | return -ENOENT; |
@@ -714,7 +742,14 @@ static int msm_ioctl_wait_fence(struct drm_device *dev, void *data, | |||
714 | struct drm_file *file) | 742 | struct drm_file *file) |
715 | { | 743 | { |
716 | struct drm_msm_wait_fence *args = data; | 744 | struct drm_msm_wait_fence *args = data; |
717 | return msm_wait_fence_interruptable(dev, args->fence, &TS(args->timeout)); | 745 | |
746 | if (args->pad) { | ||
747 | DRM_ERROR("invalid pad: %08x\n", args->pad); | ||
748 | return -EINVAL; | ||
749 | } | ||
750 | |||
751 | return msm_wait_fence_interruptable(dev, args->fence, | ||
752 | &TS(args->timeout)); | ||
718 | } | 753 | } |
719 | 754 | ||
720 | static const struct drm_ioctl_desc msm_ioctls[] = { | 755 | static const struct drm_ioctl_desc msm_ioctls[] = { |
@@ -819,18 +854,110 @@ static const struct dev_pm_ops msm_pm_ops = { | |||
819 | }; | 854 | }; |
820 | 855 | ||
821 | /* | 856 | /* |
857 | * Componentized driver support: | ||
858 | */ | ||
859 | |||
860 | #ifdef CONFIG_OF | ||
861 | /* NOTE: the CONFIG_OF case duplicates the same code as exynos or imx | ||
862 | * (or probably any other).. so probably some room for some helpers | ||
863 | */ | ||
864 | static int compare_of(struct device *dev, void *data) | ||
865 | { | ||
866 | return dev->of_node == data; | ||
867 | } | ||
868 | |||
869 | static int msm_drm_add_components(struct device *master, struct master *m) | ||
870 | { | ||
871 | struct device_node *np = master->of_node; | ||
872 | unsigned i; | ||
873 | int ret; | ||
874 | |||
875 | for (i = 0; ; i++) { | ||
876 | struct device_node *node; | ||
877 | |||
878 | node = of_parse_phandle(np, "connectors", i); | ||
879 | if (!node) | ||
880 | break; | ||
881 | |||
882 | ret = component_master_add_child(m, compare_of, node); | ||
883 | of_node_put(node); | ||
884 | |||
885 | if (ret) | ||
886 | return ret; | ||
887 | } | ||
888 | return 0; | ||
889 | } | ||
890 | #else | ||
891 | static int compare_dev(struct device *dev, void *data) | ||
892 | { | ||
893 | return dev == data; | ||
894 | } | ||
895 | |||
896 | static int msm_drm_add_components(struct device *master, struct master *m) | ||
897 | { | ||
898 | /* For non-DT case, it kinda sucks. We don't actually have a way | ||
899 | * to know whether or not we are waiting for certain devices (or if | ||
900 | * they are simply not present). But for non-DT we only need to | ||
901 | * care about apq8064/apq8060/etc (all mdp4/a3xx): | ||
902 | */ | ||
903 | static const char *devnames[] = { | ||
904 | "hdmi_msm.0", "kgsl-3d0.0", | ||
905 | }; | ||
906 | int i; | ||
907 | |||
908 | DBG("Adding components.."); | ||
909 | |||
910 | for (i = 0; i < ARRAY_SIZE(devnames); i++) { | ||
911 | struct device *dev; | ||
912 | int ret; | ||
913 | |||
914 | dev = bus_find_device_by_name(&platform_bus_type, | ||
915 | NULL, devnames[i]); | ||
916 | if (!dev) { | ||
917 | dev_info(master, "still waiting for %s\n", devnames[i]); | ||
918 | return -EPROBE_DEFER; | ||
919 | } | ||
920 | |||
921 | ret = component_master_add_child(m, compare_dev, dev); | ||
922 | if (ret) { | ||
923 | DBG("could not add child: %d", ret); | ||
924 | return ret; | ||
925 | } | ||
926 | } | ||
927 | |||
928 | return 0; | ||
929 | } | ||
930 | #endif | ||
931 | |||
932 | static int msm_drm_bind(struct device *dev) | ||
933 | { | ||
934 | return drm_platform_init(&msm_driver, to_platform_device(dev)); | ||
935 | } | ||
936 | |||
937 | static void msm_drm_unbind(struct device *dev) | ||
938 | { | ||
939 | drm_put_dev(platform_get_drvdata(to_platform_device(dev))); | ||
940 | } | ||
941 | |||
942 | static const struct component_master_ops msm_drm_ops = { | ||
943 | .add_components = msm_drm_add_components, | ||
944 | .bind = msm_drm_bind, | ||
945 | .unbind = msm_drm_unbind, | ||
946 | }; | ||
947 | |||
948 | /* | ||
822 | * Platform driver: | 949 | * Platform driver: |
823 | */ | 950 | */ |
824 | 951 | ||
825 | static int msm_pdev_probe(struct platform_device *pdev) | 952 | static int msm_pdev_probe(struct platform_device *pdev) |
826 | { | 953 | { |
827 | pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); | 954 | pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); |
828 | return drm_platform_init(&msm_driver, pdev); | 955 | return component_master_add(&pdev->dev, &msm_drm_ops); |
829 | } | 956 | } |
830 | 957 | ||
831 | static int msm_pdev_remove(struct platform_device *pdev) | 958 | static int msm_pdev_remove(struct platform_device *pdev) |
832 | { | 959 | { |
833 | drm_put_dev(platform_get_drvdata(pdev)); | 960 | component_master_del(&pdev->dev, &msm_drm_ops); |
834 | 961 | ||
835 | return 0; | 962 | return 0; |
836 | } | 963 | } |
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 3d63269c5b29..9d10ee0b5aac 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/clk.h> | 22 | #include <linux/clk.h> |
23 | #include <linux/cpufreq.h> | 23 | #include <linux/cpufreq.h> |
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/component.h> | ||
25 | #include <linux/platform_device.h> | 26 | #include <linux/platform_device.h> |
26 | #include <linux/pm.h> | 27 | #include <linux/pm.h> |
27 | #include <linux/pm_runtime.h> | 28 | #include <linux/pm_runtime.h> |
@@ -69,6 +70,9 @@ struct msm_drm_private { | |||
69 | 70 | ||
70 | struct msm_kms *kms; | 71 | struct msm_kms *kms; |
71 | 72 | ||
73 | /* subordinate devices, if present: */ | ||
74 | struct platform_device *hdmi_pdev, *gpu_pdev; | ||
75 | |||
72 | /* when we have more than one 'msm_gpu' these need to be an array: */ | 76 | /* when we have more than one 'msm_gpu' these need to be an array: */ |
73 | struct msm_gpu *gpu; | 77 | struct msm_gpu *gpu; |
74 | struct msm_file_private *lastctx; | 78 | struct msm_file_private *lastctx; |
diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 5423e914e491..1f1f4cffdaed 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c | |||
@@ -23,7 +23,6 @@ | |||
23 | * Cmdstream submission: | 23 | * Cmdstream submission: |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #define BO_INVALID_FLAGS ~(MSM_SUBMIT_BO_READ | MSM_SUBMIT_BO_WRITE) | ||
27 | /* make sure these don't conflict w/ MSM_SUBMIT_BO_x */ | 26 | /* make sure these don't conflict w/ MSM_SUBMIT_BO_x */ |
28 | #define BO_VALID 0x8000 | 27 | #define BO_VALID 0x8000 |
29 | #define BO_LOCKED 0x4000 | 28 | #define BO_LOCKED 0x4000 |
@@ -77,7 +76,7 @@ static int submit_lookup_objects(struct msm_gem_submit *submit, | |||
77 | goto out_unlock; | 76 | goto out_unlock; |
78 | } | 77 | } |
79 | 78 | ||
80 | if (submit_bo.flags & BO_INVALID_FLAGS) { | 79 | if (submit_bo.flags & ~MSM_SUBMIT_BO_FLAGS) { |
81 | DRM_ERROR("invalid flags: %x\n", submit_bo.flags); | 80 | DRM_ERROR("invalid flags: %x\n", submit_bo.flags); |
82 | ret = -EINVAL; | 81 | ret = -EINVAL; |
83 | goto out_unlock; | 82 | goto out_unlock; |
@@ -369,6 +368,18 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, | |||
369 | goto out; | 368 | goto out; |
370 | } | 369 | } |
371 | 370 | ||
371 | /* validate input from userspace: */ | ||
372 | switch (submit_cmd.type) { | ||
373 | case MSM_SUBMIT_CMD_BUF: | ||
374 | case MSM_SUBMIT_CMD_IB_TARGET_BUF: | ||
375 | case MSM_SUBMIT_CMD_CTX_RESTORE_BUF: | ||
376 | break; | ||
377 | default: | ||
378 | DRM_ERROR("invalid type: %08x\n", submit_cmd.type); | ||
379 | ret = -EINVAL; | ||
380 | goto out; | ||
381 | } | ||
382 | |||
372 | ret = submit_bo(submit, submit_cmd.submit_idx, | 383 | ret = submit_bo(submit, submit_cmd.submit_idx, |
373 | &msm_obj, &iova, NULL); | 384 | &msm_obj, &iova, NULL); |
374 | if (ret) | 385 | if (ret) |
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 0cfe3f426ee4..3e667ca1f2b9 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c | |||
@@ -154,9 +154,18 @@ static int disable_axi(struct msm_gpu *gpu) | |||
154 | 154 | ||
155 | int msm_gpu_pm_resume(struct msm_gpu *gpu) | 155 | int msm_gpu_pm_resume(struct msm_gpu *gpu) |
156 | { | 156 | { |
157 | struct drm_device *dev = gpu->dev; | ||
157 | int ret; | 158 | int ret; |
158 | 159 | ||
159 | DBG("%s", gpu->name); | 160 | DBG("%s: active_cnt=%d", gpu->name, gpu->active_cnt); |
161 | |||
162 | WARN_ON(!mutex_is_locked(&dev->struct_mutex)); | ||
163 | |||
164 | if (gpu->active_cnt++ > 0) | ||
165 | return 0; | ||
166 | |||
167 | if (WARN_ON(gpu->active_cnt <= 0)) | ||
168 | return -EINVAL; | ||
160 | 169 | ||
161 | ret = enable_pwrrail(gpu); | 170 | ret = enable_pwrrail(gpu); |
162 | if (ret) | 171 | if (ret) |
@@ -175,9 +184,18 @@ int msm_gpu_pm_resume(struct msm_gpu *gpu) | |||
175 | 184 | ||
176 | int msm_gpu_pm_suspend(struct msm_gpu *gpu) | 185 | int msm_gpu_pm_suspend(struct msm_gpu *gpu) |
177 | { | 186 | { |
187 | struct drm_device *dev = gpu->dev; | ||
178 | int ret; | 188 | int ret; |
179 | 189 | ||
180 | DBG("%s", gpu->name); | 190 | DBG("%s: active_cnt=%d", gpu->name, gpu->active_cnt); |
191 | |||
192 | WARN_ON(!mutex_is_locked(&dev->struct_mutex)); | ||
193 | |||
194 | if (--gpu->active_cnt > 0) | ||
195 | return 0; | ||
196 | |||
197 | if (WARN_ON(gpu->active_cnt < 0)) | ||
198 | return -EINVAL; | ||
181 | 199 | ||
182 | ret = disable_axi(gpu); | 200 | ret = disable_axi(gpu); |
183 | if (ret) | 201 | if (ret) |
@@ -195,6 +213,55 @@ int msm_gpu_pm_suspend(struct msm_gpu *gpu) | |||
195 | } | 213 | } |
196 | 214 | ||
197 | /* | 215 | /* |
216 | * Inactivity detection (for suspend): | ||
217 | */ | ||
218 | |||
219 | static void inactive_worker(struct work_struct *work) | ||
220 | { | ||
221 | struct msm_gpu *gpu = container_of(work, struct msm_gpu, inactive_work); | ||
222 | struct drm_device *dev = gpu->dev; | ||
223 | |||
224 | if (gpu->inactive) | ||
225 | return; | ||
226 | |||
227 | DBG("%s: inactive!\n", gpu->name); | ||
228 | mutex_lock(&dev->struct_mutex); | ||
229 | if (!(msm_gpu_active(gpu) || gpu->inactive)) { | ||
230 | disable_axi(gpu); | ||
231 | disable_clk(gpu); | ||
232 | gpu->inactive = true; | ||
233 | } | ||
234 | mutex_unlock(&dev->struct_mutex); | ||
235 | } | ||
236 | |||
237 | static void inactive_handler(unsigned long data) | ||
238 | { | ||
239 | struct msm_gpu *gpu = (struct msm_gpu *)data; | ||
240 | struct msm_drm_private *priv = gpu->dev->dev_private; | ||
241 | |||
242 | queue_work(priv->wq, &gpu->inactive_work); | ||
243 | } | ||
244 | |||
245 | /* cancel inactive timer and make sure we are awake: */ | ||
246 | static void inactive_cancel(struct msm_gpu *gpu) | ||
247 | { | ||
248 | DBG("%s", gpu->name); | ||
249 | del_timer(&gpu->inactive_timer); | ||
250 | if (gpu->inactive) { | ||
251 | enable_clk(gpu); | ||
252 | enable_axi(gpu); | ||
253 | gpu->inactive = false; | ||
254 | } | ||
255 | } | ||
256 | |||
257 | static void inactive_start(struct msm_gpu *gpu) | ||
258 | { | ||
259 | DBG("%s", gpu->name); | ||
260 | mod_timer(&gpu->inactive_timer, | ||
261 | round_jiffies_up(jiffies + DRM_MSM_INACTIVE_JIFFIES)); | ||
262 | } | ||
263 | |||
264 | /* | ||
198 | * Hangcheck detection for locked gpu: | 265 | * Hangcheck detection for locked gpu: |
199 | */ | 266 | */ |
200 | 267 | ||
@@ -206,7 +273,10 @@ static void recover_worker(struct work_struct *work) | |||
206 | dev_err(dev->dev, "%s: hangcheck recover!\n", gpu->name); | 273 | dev_err(dev->dev, "%s: hangcheck recover!\n", gpu->name); |
207 | 274 | ||
208 | mutex_lock(&dev->struct_mutex); | 275 | mutex_lock(&dev->struct_mutex); |
209 | gpu->funcs->recover(gpu); | 276 | if (msm_gpu_active(gpu)) { |
277 | inactive_cancel(gpu); | ||
278 | gpu->funcs->recover(gpu); | ||
279 | } | ||
210 | mutex_unlock(&dev->struct_mutex); | 280 | mutex_unlock(&dev->struct_mutex); |
211 | 281 | ||
212 | msm_gpu_retire(gpu); | 282 | msm_gpu_retire(gpu); |
@@ -281,6 +351,9 @@ static void retire_worker(struct work_struct *work) | |||
281 | } | 351 | } |
282 | 352 | ||
283 | mutex_unlock(&dev->struct_mutex); | 353 | mutex_unlock(&dev->struct_mutex); |
354 | |||
355 | if (!msm_gpu_active(gpu)) | ||
356 | inactive_start(gpu); | ||
284 | } | 357 | } |
285 | 358 | ||
286 | /* call from irq handler to schedule work to retire bo's */ | 359 | /* call from irq handler to schedule work to retire bo's */ |
@@ -302,6 +375,8 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, | |||
302 | 375 | ||
303 | gpu->submitted_fence = submit->fence; | 376 | gpu->submitted_fence = submit->fence; |
304 | 377 | ||
378 | inactive_cancel(gpu); | ||
379 | |||
305 | ret = gpu->funcs->submit(gpu, submit, ctx); | 380 | ret = gpu->funcs->submit(gpu, submit, ctx); |
306 | priv->lastctx = ctx; | 381 | priv->lastctx = ctx; |
307 | 382 | ||
@@ -357,11 +432,15 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, | |||
357 | gpu->dev = drm; | 432 | gpu->dev = drm; |
358 | gpu->funcs = funcs; | 433 | gpu->funcs = funcs; |
359 | gpu->name = name; | 434 | gpu->name = name; |
435 | gpu->inactive = true; | ||
360 | 436 | ||
361 | INIT_LIST_HEAD(&gpu->active_list); | 437 | INIT_LIST_HEAD(&gpu->active_list); |
362 | INIT_WORK(&gpu->retire_work, retire_worker); | 438 | INIT_WORK(&gpu->retire_work, retire_worker); |
439 | INIT_WORK(&gpu->inactive_work, inactive_worker); | ||
363 | INIT_WORK(&gpu->recover_work, recover_worker); | 440 | INIT_WORK(&gpu->recover_work, recover_worker); |
364 | 441 | ||
442 | setup_timer(&gpu->inactive_timer, inactive_handler, | ||
443 | (unsigned long)gpu); | ||
365 | setup_timer(&gpu->hangcheck_timer, hangcheck_handler, | 444 | setup_timer(&gpu->hangcheck_timer, hangcheck_handler, |
366 | (unsigned long)gpu); | 445 | (unsigned long)gpu); |
367 | 446 | ||
diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index 458db8c64c28..fad27008922f 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h | |||
@@ -72,6 +72,10 @@ struct msm_gpu { | |||
72 | 72 | ||
73 | uint32_t submitted_fence; | 73 | uint32_t submitted_fence; |
74 | 74 | ||
75 | /* is gpu powered/active? */ | ||
76 | int active_cnt; | ||
77 | bool inactive; | ||
78 | |||
75 | /* worker for handling active-list retiring: */ | 79 | /* worker for handling active-list retiring: */ |
76 | struct work_struct retire_work; | 80 | struct work_struct retire_work; |
77 | 81 | ||
@@ -91,7 +95,12 @@ struct msm_gpu { | |||
91 | uint32_t bsc; | 95 | uint32_t bsc; |
92 | #endif | 96 | #endif |
93 | 97 | ||
94 | /* Hang Detction: */ | 98 | /* Hang and Inactivity Detection: |
99 | */ | ||
100 | #define DRM_MSM_INACTIVE_PERIOD 66 /* in ms (roughly four frames) */ | ||
101 | #define DRM_MSM_INACTIVE_JIFFIES msecs_to_jiffies(DRM_MSM_INACTIVE_PERIOD) | ||
102 | struct timer_list inactive_timer; | ||
103 | struct work_struct inactive_work; | ||
95 | #define DRM_MSM_HANGCHECK_PERIOD 500 /* in ms */ | 104 | #define DRM_MSM_HANGCHECK_PERIOD 500 /* in ms */ |
96 | #define DRM_MSM_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_MSM_HANGCHECK_PERIOD) | 105 | #define DRM_MSM_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_MSM_HANGCHECK_PERIOD) |
97 | struct timer_list hangcheck_timer; | 106 | struct timer_list hangcheck_timer; |
@@ -99,6 +108,11 @@ struct msm_gpu { | |||
99 | struct work_struct recover_work; | 108 | struct work_struct recover_work; |
100 | }; | 109 | }; |
101 | 110 | ||
111 | static inline bool msm_gpu_active(struct msm_gpu *gpu) | ||
112 | { | ||
113 | return gpu->submitted_fence > gpu->funcs->last_fence(gpu); | ||
114 | } | ||
115 | |||
102 | static inline void gpu_write(struct msm_gpu *gpu, u32 reg, u32 data) | 116 | static inline void gpu_write(struct msm_gpu *gpu, u32 reg, u32 data) |
103 | { | 117 | { |
104 | msm_writel(data, gpu->mmio + (reg << 2)); | 118 | msm_writel(data, gpu->mmio + (reg << 2)); |
diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c index 0d5e9b7e8bbf..d2b8c49bfb4a 100644 --- a/drivers/gpu/drm/omapdrm/omap_fb.c +++ b/drivers/gpu/drm/omapdrm/omap_fb.c | |||
@@ -306,7 +306,8 @@ struct drm_connector *omap_framebuffer_get_next_connector( | |||
306 | struct drm_connector *connector = from; | 306 | struct drm_connector *connector = from; |
307 | 307 | ||
308 | if (!from) | 308 | if (!from) |
309 | return list_first_entry(connector_list, typeof(*from), head); | 309 | return list_first_entry_or_null(connector_list, typeof(*from), |
310 | head); | ||
310 | 311 | ||
311 | list_for_each_entry_from(connector, connector_list, head) { | 312 | list_for_each_entry_from(connector, connector_list, head) { |
312 | if (connector != from) { | 313 | if (connector != from) { |
diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h index d3c62074016d..0664c31f010c 100644 --- a/include/uapi/drm/msm_drm.h +++ b/include/uapi/drm/msm_drm.h | |||
@@ -50,6 +50,7 @@ struct drm_msm_timespec { | |||
50 | 50 | ||
51 | #define MSM_PARAM_GPU_ID 0x01 | 51 | #define MSM_PARAM_GPU_ID 0x01 |
52 | #define MSM_PARAM_GMEM_SIZE 0x02 | 52 | #define MSM_PARAM_GMEM_SIZE 0x02 |
53 | #define MSM_PARAM_CHIP_ID 0x03 | ||
53 | 54 | ||
54 | struct drm_msm_param { | 55 | struct drm_msm_param { |
55 | uint32_t pipe; /* in, MSM_PIPE_x */ | 56 | uint32_t pipe; /* in, MSM_PIPE_x */ |
@@ -69,6 +70,12 @@ struct drm_msm_param { | |||
69 | #define MSM_BO_WC 0x00020000 | 70 | #define MSM_BO_WC 0x00020000 |
70 | #define MSM_BO_UNCACHED 0x00040000 | 71 | #define MSM_BO_UNCACHED 0x00040000 |
71 | 72 | ||
73 | #define MSM_BO_FLAGS (MSM_BO_SCANOUT | \ | ||
74 | MSM_BO_GPU_READONLY | \ | ||
75 | MSM_BO_CACHED | \ | ||
76 | MSM_BO_WC | \ | ||
77 | MSM_BO_UNCACHED) | ||
78 | |||
72 | struct drm_msm_gem_new { | 79 | struct drm_msm_gem_new { |
73 | uint64_t size; /* in */ | 80 | uint64_t size; /* in */ |
74 | uint32_t flags; /* in, mask of MSM_BO_x */ | 81 | uint32_t flags; /* in, mask of MSM_BO_x */ |
@@ -85,6 +92,8 @@ struct drm_msm_gem_info { | |||
85 | #define MSM_PREP_WRITE 0x02 | 92 | #define MSM_PREP_WRITE 0x02 |
86 | #define MSM_PREP_NOSYNC 0x04 | 93 | #define MSM_PREP_NOSYNC 0x04 |
87 | 94 | ||
95 | #define MSM_PREP_FLAGS (MSM_PREP_READ | MSM_PREP_WRITE | MSM_PREP_NOSYNC) | ||
96 | |||
88 | struct drm_msm_gem_cpu_prep { | 97 | struct drm_msm_gem_cpu_prep { |
89 | uint32_t handle; /* in */ | 98 | uint32_t handle; /* in */ |
90 | uint32_t op; /* in, mask of MSM_PREP_x */ | 99 | uint32_t op; /* in, mask of MSM_PREP_x */ |
@@ -152,6 +161,9 @@ struct drm_msm_gem_submit_cmd { | |||
152 | */ | 161 | */ |
153 | #define MSM_SUBMIT_BO_READ 0x0001 | 162 | #define MSM_SUBMIT_BO_READ 0x0001 |
154 | #define MSM_SUBMIT_BO_WRITE 0x0002 | 163 | #define MSM_SUBMIT_BO_WRITE 0x0002 |
164 | |||
165 | #define MSM_SUBMIT_BO_FLAGS (MSM_SUBMIT_BO_READ | MSM_SUBMIT_BO_WRITE) | ||
166 | |||
155 | struct drm_msm_gem_submit_bo { | 167 | struct drm_msm_gem_submit_bo { |
156 | uint32_t flags; /* in, mask of MSM_SUBMIT_BO_x */ | 168 | uint32_t flags; /* in, mask of MSM_SUBMIT_BO_x */ |
157 | uint32_t handle; /* in, GEM handle */ | 169 | uint32_t handle; /* in, GEM handle */ |