diff options
Diffstat (limited to 'drivers/gpu/drm')
179 files changed, 7490 insertions, 2858 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 22866d1c3d69..01657830b470 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -425,6 +425,8 @@ int amdgpu_fence_driver_start_ring(struct amdgpu_ring *ring, unsigned irq_type); int amdgpu_fence_emit(struct amdgpu_ring *ring, void *owner, struct amdgpu_fence **fence); +int amdgpu_fence_recreate(struct amdgpu_ring *ring, void *owner, + uint64_t seq, struct amdgpu_fence **fence); void amdgpu_fence_process(struct amdgpu_ring *ring); int amdgpu_fence_wait_next(struct amdgpu_ring *ring); int amdgpu_fence_wait_empty(struct amdgpu_ring *ring); @@ -435,9 +437,6 @@ int amdgpu_fence_wait(struct amdgpu_fence *fence, bool interruptible); int amdgpu_fence_wait_any(struct amdgpu_device *adev, struct amdgpu_fence **fences, bool intr); -long amdgpu_fence_wait_seq_timeout(struct amdgpu_device *adev, - u64 *target_seq, bool intr, - long timeout); struct amdgpu_fence *amdgpu_fence_ref(struct amdgpu_fence *fence); void amdgpu_fence_unref(struct amdgpu_fence **fence); @@ -1622,6 +1621,7 @@ struct amdgpu_vce { unsigned fb_version; atomic_t handles[AMDGPU_MAX_VCE_HANDLES]; struct drm_file *filp[AMDGPU_MAX_VCE_HANDLES]; + uint32_t img_size[AMDGPU_MAX_VCE_HANDLES]; struct delayed_work idle_work; const struct firmware *fw; /* VCE firmware */ struct amdgpu_ring ring[AMDGPU_MAX_VCE_RINGS]; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c index 36d34e0afbc3..f82a2dd83874 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c @@ -30,6 +30,7 @@ #include <drm/drmP.h> #include "amdgpu.h" +#include "amdgpu_trace.h" static int amdgpu_bo_list_create(struct amdgpu_fpriv *fpriv, struct amdgpu_bo_list **result, @@ -124,6 +125,8 @@ static int amdgpu_bo_list_set(struct amdgpu_device *adev, gws_obj = entry->robj; if (entry->prefered_domains == AMDGPU_GEM_DOMAIN_OA) oa_obj = entry->robj; + + trace_amdgpu_bo_list_set(list, entry->robj); } for (i = 0; i < list->num_entries; ++i) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index f09b2cba40ca..d63135bf29c0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -181,8 +181,6 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) } p->chunks[i].chunk_id = user_chunk.chunk_id; p->chunks[i].length_dw = user_chunk.length_dw; - if (p->chunks[i].chunk_id == AMDGPU_CHUNK_ID_IB) - p->num_ibs++; size = p->chunks[i].length_dw; cdata = (void __user *)(unsigned long)user_chunk.chunk_data; @@ -199,7 +197,12 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) goto out; } - if (p->chunks[i].chunk_id == AMDGPU_CHUNK_ID_FENCE) { + switch (p->chunks[i].chunk_id) { + case AMDGPU_CHUNK_ID_IB: + p->num_ibs++; + break; + + case AMDGPU_CHUNK_ID_FENCE: size = sizeof(struct drm_amdgpu_cs_chunk_fence); if (p->chunks[i].length_dw * sizeof(uint32_t) >= size) { uint32_t handle; @@ -221,6 +224,14 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) r = -EINVAL; goto out; } + break; + + case AMDGPU_CHUNK_ID_DEPENDENCIES: + break; + + default: + r = -EINVAL; + goto out; } } @@ -445,8 +456,9 @@ static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, bo for (i = 0; i < parser->nchunks; i++) drm_free_large(parser->chunks[i].kdata); kfree(parser->chunks); - for (i = 0; i < parser->num_ibs; i++) - amdgpu_ib_free(parser->adev, &parser->ibs[i]); + if (parser->ibs) + for (i = 0; i < parser->num_ibs; i++) + amdgpu_ib_free(parser->adev, &parser->ibs[i]); kfree(parser->ibs); if (parser->uf.bo) drm_gem_object_unreference_unlocked(&parser->uf.bo->gem_base); @@ -654,6 +666,55 @@ static int amdgpu_cs_ib_fill(struct amdgpu_device *adev, return 0; } +static int amdgpu_cs_dependencies(struct amdgpu_device *adev, + struct amdgpu_cs_parser *p) +{ + struct amdgpu_ib *ib; + int i, j, r; + + if (!p->num_ibs) + return 0; + + /* Add dependencies to first IB */ + ib = &p->ibs[0]; + for (i = 0; i < p->nchunks; ++i) { + struct drm_amdgpu_cs_chunk_dep *deps; + struct amdgpu_cs_chunk *chunk; + unsigned num_deps; + + chunk = &p->chunks[i]; + + if (chunk->chunk_id != AMDGPU_CHUNK_ID_DEPENDENCIES) + continue; + + deps = (struct drm_amdgpu_cs_chunk_dep *)chunk->kdata; + num_deps = chunk->length_dw * 4 / + sizeof(struct drm_amdgpu_cs_chunk_dep); + + for (j = 0; j < num_deps; ++j) { + struct amdgpu_fence *fence; + struct amdgpu_ring *ring; + + r = amdgpu_cs_get_ring(adev, deps[j].ip_type, + deps[j].ip_instance, + deps[j].ring, &ring); + if (r) + return r; + + r = amdgpu_fence_recreate(ring, p->filp, + deps[j].handle, + &fence); + if (r) + return r; + + amdgpu_sync_fence(&ib->sync, fence); + amdgpu_fence_unref(&fence); + } + } + + return 0; +} + int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { struct amdgpu_device *adev = dev->dev_private; @@ -688,11 +749,16 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) else DRM_ERROR("Failed to process the buffer list %d!\n", r); } - } else { + } + + if (!r) { reserved_buffers = true; r = amdgpu_cs_ib_fill(adev, &parser); } + if (!r) + r = amdgpu_cs_dependencies(adev, &parser); + if (r) { amdgpu_cs_parser_fini(&parser, r, reserved_buffers); up_read(&adev->exclusive_lock); @@ -730,9 +796,9 @@ int amdgpu_cs_wait_ioctl(struct drm_device *dev, void *data, { union drm_amdgpu_wait_cs *wait = data; struct amdgpu_device *adev = dev->dev_private; - uint64_t seq[AMDGPU_MAX_RINGS] = {0}; - struct amdgpu_ring *ring = NULL; unsigned long timeout = amdgpu_gem_timeout(wait->in.timeout); + struct amdgpu_fence *fence = NULL; + struct amdgpu_ring *ring = NULL; struct amdgpu_ctx *ctx; long r; @@ -745,9 +811,12 @@ int amdgpu_cs_wait_ioctl(struct drm_device *dev, void *data, if (r) return r; - seq[ring->idx] = wait->in.handle; + r = amdgpu_fence_recreate(ring, filp, wait->in.handle, &fence); + if (r) + return r; - r = amdgpu_fence_wait_seq_timeout(adev, seq, true, timeout); + r = fence_wait_timeout(&fence->base, true, timeout); + amdgpu_fence_unref(&fence); amdgpu_ctx_put(ctx); if (r < 0) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index fec487d1c870..ba46be361c9b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1191,7 +1191,9 @@ static int amdgpu_early_init(struct amdgpu_device *adev) return -EINVAL; } - + adev->ip_block_enabled = kcalloc(adev->num_ip_blocks, sizeof(bool), GFP_KERNEL); + if (adev->ip_block_enabled == NULL) + return -ENOMEM; if (adev->ip_blocks == NULL) { DRM_ERROR("No IP blocks found!\n"); @@ -1575,8 +1577,7 @@ void amdgpu_device_fini(struct amdgpu_device *adev) amdgpu_fence_driver_fini(adev); amdgpu_fbdev_fini(adev); r = amdgpu_fini(adev); - if (adev->ip_block_enabled) - kfree(adev->ip_block_enabled); + kfree(adev->ip_block_enabled); adev->ip_block_enabled = NULL; adev->accel_working = false; /* free i2c buses */ @@ -2000,4 +2001,10 @@ int amdgpu_debugfs_init(struct drm_minor *minor) void amdgpu_debugfs_cleanup(struct drm_minor *minor) { } +#else +static int amdgpu_debugfs_regs_init(struct amdgpu_device *adev) +{ + return 0; +} +static void amdgpu_debugfs_regs_cleanup(struct amdgpu_device *adev) { } #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c index 5c9918d01bf9..a7189a1fa6a1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c @@ -136,6 +136,38 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, void *owner, } /** + * amdgpu_fence_recreate - recreate a fence from an user fence + * + * @ring: ring the fence is associated with + * @owner: creator of the fence + * @seq: user fence sequence number + * @fence: resulting amdgpu fence object + * + * Recreates a fence command from the user fence sequence number (all asics). + * Returns 0 on success, -ENOMEM on failure. + */ +int amdgpu_fence_recreate(struct amdgpu_ring *ring, void *owner, + uint64_t seq, struct amdgpu_fence **fence) +{ + struct amdgpu_device *adev = ring->adev; + + if (seq > ring->fence_drv.sync_seq[ring->idx]) + return -EINVAL; + + *fence = kmalloc(sizeof(struct amdgpu_fence), GFP_KERNEL); + if ((*fence) == NULL) + return -ENOMEM; + + (*fence)->seq = seq; + (*fence)->ring = ring; + (*fence)->owner = owner; + fence_init(&(*fence)->base, &amdgpu_fence_ops, + &adev->fence_queue.lock, adev->fence_context + ring->idx, + (*fence)->seq); + return 0; +} + +/** * amdgpu_fence_check_signaled - callback from fence_queue * * this function is called with fence_queue lock held, which is also used @@ -517,12 +549,14 @@ static bool amdgpu_fence_any_seq_signaled(struct amdgpu_device *adev, u64 *seq) * the wait timeout, or an error for all other cases. * -EDEADLK is returned when a GPU lockup has been detected. */ -long amdgpu_fence_wait_seq_timeout(struct amdgpu_device *adev, u64 *target_seq, - bool intr, long timeout) +static long amdgpu_fence_wait_seq_timeout(struct amdgpu_device *adev, + u64 *target_seq, bool intr, + long timeout) { uint64_t last_seq[AMDGPU_MAX_RINGS]; bool signaled; - int i, r; + int i; + long r; if (timeout == 0) { return amdgpu_fence_any_seq_signaled(adev, target_seq); @@ -1023,7 +1057,7 @@ static int amdgpu_debugfs_fence_info(struct seq_file *m, void *data) amdgpu_fence_process(ring); - seq_printf(m, "--- ring %d ---\n", i); + seq_printf(m, "--- ring %d (%s) ---\n", i, ring->name); seq_printf(m, "Last signaled fence 0x%016llx\n", (unsigned long long)atomic64_read(&ring->fence_drv.last_seq)); seq_printf(m, "Last emitted 0x%016llx\n", @@ -1031,7 +1065,8 @@ static int amdgpu_debugfs_fence_info(struct seq_file *m, void *data) for (j = 0; j < AMDGPU_MAX_RINGS; ++j) { struct amdgpu_ring *other = adev->rings[j]; - if (i != j && other && other->fence_drv.initialized) + if (i != j && other && other->fence_drv.initialized && + ring->fence_drv.sync_seq[j]) seq_printf(m, "Last sync to ring %d 0x%016llx\n", j, ring->fence_drv.sync_seq[j]); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index 0ec222295fee..ae43b58c9733 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -352,7 +352,7 @@ unsigned long amdgpu_gem_timeout(uint64_t timeout_ns) if (((int64_t)timeout_ns) < 0) return MAX_SCHEDULE_TIMEOUT; - timeout = ktime_sub_ns(ktime_get(), timeout_ns); + timeout = ktime_sub(ns_to_ktime(timeout_ns), ktime_get()); if (ktime_to_ns(timeout) < 0) return 0; @@ -496,7 +496,7 @@ error_unreserve: error_free: drm_free_large(vm_bos); - if (r) + if (r && r != -ERESTARTSYS) DRM_ERROR("Couldn't update BO_VA (%d)\n", r); } @@ -525,8 +525,8 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, return -EINVAL; } - invalid_flags = ~(AMDGPU_VM_PAGE_READABLE | AMDGPU_VM_PAGE_WRITEABLE | - AMDGPU_VM_PAGE_EXECUTABLE); + invalid_flags = ~(AMDGPU_VM_DELAY_UPDATE | AMDGPU_VM_PAGE_READABLE | + AMDGPU_VM_PAGE_WRITEABLE | AMDGPU_VM_PAGE_EXECUTABLE); if ((args->flags & invalid_flags)) { dev_err(&dev->pdev->dev, "invalid flags 0x%08X vs 0x%08X\n", args->flags, invalid_flags); @@ -579,7 +579,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, break; } - if (!r) + if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE)) amdgpu_gem_va_update_vm(adev, bo_va); drm_gem_object_unreference_unlocked(gobj); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h index b56dd64bd4ea..961d7265c286 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h @@ -30,19 +30,21 @@ TRACE_EVENT(amdgpu_cs, TP_PROTO(struct amdgpu_cs_parser *p, int i), TP_ARGS(p, i), TP_STRUCT__entry( + __field(struct amdgpu_bo_list *, bo_list) __field(u32, ring) __field(u32, dw) __field(u32, fences) ), TP_fast_assign( + __entry->bo_list = p->bo_list; __entry->ring = p->ibs[i].ring->idx; __entry->dw = p->ibs[i].length_dw; __entry->fences = amdgpu_fence_count_emitted( p->ibs[i].ring); ), - TP_printk("ring=%u, dw=%u, fences=%u", - __entry->ring, __entry->dw, + TP_printk("bo_list=%p, ring=%u, dw=%u, fences=%u", + __entry->bo_list, __entry->ring, __entry->dw, __entry->fences) ); @@ -61,6 +63,54 @@ TRACE_EVENT(amdgpu_vm_grab_id, TP_printk("vmid=%u, ring=%u", __entry->vmid, __entry->ring) ); +TRACE_EVENT(amdgpu_vm_bo_map, + TP_PROTO(struct amdgpu_bo_va *bo_va, + struct amdgpu_bo_va_mapping *mapping), + TP_ARGS(bo_va, mapping), + TP_STRUCT__entry( + __field(struct amdgpu_bo *, bo) + __field(long, start) + __field(long, last) + __field(u64, offset) + __field(u32, flags) + ), + + TP_fast_assign( + __entry->bo = bo_va->bo; + __entry->start = mapping->it.start; + __entry->last = mapping->it.last; + __entry->offset = mapping->offset; + __entry->flags = mapping->flags; + ), + TP_printk("bo=%p, start=%lx, last=%lx, offset=%010llx, flags=%08x", + __entry->bo, __entry->start, __entry->last, + __entry->offset, __entry->flags) +); + +TRACE_EVENT(amdgpu_vm_bo_unmap, + TP_PROTO(struct amdgpu_bo_va *bo_va, + struct amdgpu_bo_va_mapping *mapping), + TP_ARGS(bo_va, mapping), + TP_STRUCT__entry( + __field(struct amdgpu_bo *, bo) + __field(long, start) + __field(long, last) + __field(u64, offset) + __field(u32, flags) + ), + + TP_fast_assign( + __entry->bo = bo_va->bo; + __entry->start = mapping->it.start; + __entry->last = mapping->it.last; + __entry->offset = mapping->offset; + __entry->flags = mapping->flags; + ), + TP_printk("bo=%p, start=%lx, last=%lx, offset=%010llx, flags=%08x", + __entry->bo, __entry->start, __entry->last, + __entry->offset, __entry->flags) +); + TRACE_EVENT(amdgpu_vm_bo_update, TP_PROTO(struct amdgpu_bo_va_mapping *mapping), TP_ARGS(mapping), @@ -121,6 +171,21 @@ TRACE_EVENT(amdgpu_vm_flush, __entry->pd_addr, __entry->ring, __entry->id) ); +TRACE_EVENT(amdgpu_bo_list_set, + TP_PROTO(struct amdgpu_bo_list *list, struct amdgpu_bo *bo), + TP_ARGS(list, bo), + TP_STRUCT__entry( + __field(struct amdgpu_bo_list *, list) + __field(struct amdgpu_bo *, bo) + ), + + TP_fast_assign( + __entry->list = list; + __entry->bo = bo; + ), + TP_printk("list=%p, bo=%p", __entry->list, __entry->bo) +); + DECLARE_EVENT_CLASS(amdgpu_fence_request, TP_PROTO(struct drm_device *dev, int ring, u32 seqno), diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index d3706a498293..dd3415d2e45d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -674,7 +674,7 @@ static int amdgpu_ttm_tt_populate(struct ttm_tt *ttm) return 0; if (gtt && gtt->userptr) { - ttm->sg = kcalloc(1, sizeof(struct sg_table), GFP_KERNEL); + ttm->sg = kzalloc(sizeof(struct sg_table), GFP_KERNEL); if (!ttm->sg) return -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index 1127a504f118..d3ca73090e39 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c @@ -464,28 +464,42 @@ int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, * @p: parser context * @lo: address of lower dword * @hi: address of higher dword + * @size: minimum size * * Patch relocation inside command stream with real buffer address */ -int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx, int lo, int hi) +static int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx, + int lo, int hi, unsigned size, uint32_t index) { struct amdgpu_bo_va_mapping *mapping; struct amdgpu_ib *ib = &p->ibs[ib_idx]; struct amdgpu_bo *bo; uint64_t addr; + if (index == 0xffffffff) + index = 0; + addr = ((uint64_t)amdgpu_get_ib_value(p, ib_idx, lo)) | ((uint64_t)amdgpu_get_ib_value(p, ib_idx, hi)) << 32; + addr += ((uint64_t)size) * ((uint64_t)index); mapping = amdgpu_cs_find_mapping(p, addr, &bo); if (mapping == NULL) { - DRM_ERROR("Can't find BO for addr 0x%010Lx %d %d\n", + DRM_ERROR("Can't find BO for addr 0x%010Lx %d %d %d %d\n", + addr, lo, hi, size, index); + return -EINVAL; + } + + if ((addr + (uint64_t)size) > + ((uint64_t)mapping->it.last + 1) * AMDGPU_GPU_PAGE_SIZE) { + DRM_ERROR("BO to small for addr 0x%010Lx %d %d\n", addr, lo, hi); return -EINVAL; } addr -= ((uint64_t)mapping->it.start) * AMDGPU_GPU_PAGE_SIZE; addr += amdgpu_bo_gpu_offset(bo); + addr -= ((uint64_t)size) * ((uint64_t)index); ib->ptr[lo] = addr & 0xFFFFFFFF; ib->ptr[hi] = addr >> 32; @@ -494,6 +508,48 @@ int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx, int lo, int } /** + * amdgpu_vce_validate_handle - validate stream handle + * + * @p: parser context + * @handle: handle to validate + * @allocated: allocated a new handle? + * + * Validates the handle and return the found session index or -EINVAL + * we we don't have another free session index. + */ +static int amdgpu_vce_validate_handle(struct amdgpu_cs_parser *p, + uint32_t handle, bool *allocated) +{ + unsigned i; + + *allocated = false; + + /* validate the handle */ + for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) { + if (atomic_read(&p->adev->vce.handles[i]) == handle) { + if (p->adev->vce.filp[i] != p->filp) { + DRM_ERROR("VCE handle collision detected!\n"); + return -EINVAL; + } + return i; + } + } + + /* handle not found try to alloc a new one */ + for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) { + if (!atomic_cmpxchg(&p->adev->vce.handles[i], 0, handle)) { + p->adev->vce.filp[i] = p->filp; + p->adev->vce.img_size[i] = 0; + *allocated = true; + return i; + } + } + + DRM_ERROR("No more free VCE handles!\n"); + return -EINVAL; +} + +/** * amdgpu_vce_cs_parse - parse and validate the command stream * * @p: parser context @@ -501,10 +557,15 @@ int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx, int lo, int */ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) { - uint32_t handle = 0; - bool destroy = false; - int i, r, idx = 0; struct amdgpu_ib *ib = &p->ibs[ib_idx]; + unsigned fb_idx = 0, bs_idx = 0; + int session_idx = -1; + bool destroyed = false; + bool created = false; + bool allocated = false; + uint32_t tmp, handle = 0; + uint32_t *size = &tmp; + int i, r = 0, idx = 0; amdgpu_vce_note_usage(p->adev); @@ -514,16 +575,44 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) if ((len < 8) || (len & 3)) { DRM_ERROR("invalid VCE command length (%d)!\n", len); - return -EINVAL; + r = -EINVAL; + goto out; + } + + if (destroyed) { + DRM_ERROR("No other command allowed after destroy!\n"); + r = -EINVAL; + goto out; } switch (cmd) { case 0x00000001: // session handle = amdgpu_get_ib_value(p, ib_idx, idx + 2); + session_idx = amdgpu_vce_validate_handle(p, handle, + &allocated); + if (session_idx < 0) + return session_idx; + size = &p->adev->vce.img_size[session_idx]; break; case 0x00000002: // task info + fb_idx = amdgpu_get_ib_value(p, ib_idx, idx + 6); + bs_idx = amdgpu_get_ib_value(p, ib_idx, idx + 7); + break; + case 0x01000001: // create + created = true; + if (!allocated) { + DRM_ERROR("Handle already in use!\n"); + r = -EINVAL; + goto out; + } + + *size = amdgpu_get_ib_value(p, ib_idx, idx + 8) * + amdgpu_get_ib_value(p, ib_idx, idx + 10) * + 8 * 3 / 2; + break; + case 0x04000001: // config extension case 0x04000002: // pic control case 0x04000005: // rate control @@ -534,60 +623,74 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) break; case 0x03000001: // encode - r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 10, idx + 9); + r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 10, idx + 9, + *size, 0); if (r) - return r; + goto out; - r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 12, idx + 11); + r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 12, idx + 11, + *size / 3, 0); if (r) - return r; + goto out; break; case 0x02000001: // destroy - destroy = true; + destroyed = true; break; case 0x05000001: // context buffer + r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2, + *size * 2, 0); + if (r) + goto out; + break; + case 0x05000004: // video bitstream buffer + tmp = amdgpu_get_ib_value(p, ib_idx, idx + 4); + r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2, + tmp, bs_idx); + if (r) + goto out; + break; + case 0x05000005: // feedback buffer - r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2); + r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2, + 4096, fb_idx); if (r) - return r; + goto out; break; default: DRM_ERROR("invalid VCE command (0x%x)!\n", cmd); - return -EINVAL; + r = -EINVAL; + goto out; } - idx += len / 4; - } - - if (destroy) { - /* IB contains a destroy msg, free the handle */ - for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) - atomic_cmpxchg(&p->adev->vce.handles[i], handle, 0); + if (session_idx == -1) { + DRM_ERROR("no session command at start of IB\n"); + r = -EINVAL; + goto out; + } - return 0; + idx += len / 4; } - /* create or encode, validate the handle */ - for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) { - if (atomic_read(&p->adev->vce.handles[i]) == handle) - return 0; + if (allocated && !created) { + DRM_ERROR("New session without create command!\n"); + r = -ENOENT; } - /* handle not found try to alloc a new one */ - for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) { - if (!atomic_cmpxchg(&p->adev->vce.handles[i], 0, handle)) { - p->adev->vce.filp[i] = p->filp; - return 0; - } +out: + if ((!r && destroyed) || (r && allocated)) { + /* + * IB contains a destroy msg or we have allocated an + * handle and got an error, anyway free the handle + */ + for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) + atomic_cmpxchg(&p->adev->vce.handles[i], handle, 0); } - DRM_ERROR("No more free VCE handles!\n"); - - return -EINVAL; + return r; } /** diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h index b6a9d0956c60..7ccdb5927da5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.h @@ -33,7 +33,6 @@ int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle, int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, struct amdgpu_fence **fence); void amdgpu_vce_free_handles(struct amdgpu_device *adev, struct drm_file *filp); -int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx, int lo, int hi); int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx); bool amdgpu_vce_ring_emit_semaphore(struct amdgpu_ring *ring, struct amdgpu_semaphore *semaphore, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 407882b233c7..9a4e3b63f1cb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -1001,6 +1001,7 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev, list_add(&mapping->list, &bo_va->mappings); interval_tree_insert(&mapping->it, &vm->va); + trace_amdgpu_vm_bo_map(bo_va, mapping); bo_va->addr = 0; @@ -1058,6 +1059,7 @@ error_free: mutex_lock(&vm->mutex); list_del(&mapping->list); interval_tree_remove(&mapping->it, &vm->va); + trace_amdgpu_vm_bo_unmap(bo_va, mapping); kfree(mapping); error_unlock: @@ -1099,6 +1101,7 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev, mutex_lock(&vm->mutex); list_del(&mapping->list); interval_tree_remove(&mapping->it, &vm->va); + trace_amdgpu_vm_bo_unmap(bo_va, mapping); if (bo_va->addr) { /* clear the old address */ @@ -1139,6 +1142,7 @@ void amdgpu_vm_bo_rmv(struct amdgpu_device *adev, list_for_each_entry_safe(mapping, next, &bo_va->mappings, list) { list_del(&mapping->list); interval_tree_remove(&mapping->it, &vm->va); + trace_amdgpu_vm_bo_unmap(bo_va, mapping); if (bo_va->addr) list_add(&mapping->list, &vm->freed); else diff --git a/drivers/gpu/drm/amd/amdgpu/cik.c b/drivers/gpu/drm/amd/amdgpu/cik.c index 5dab578d6462..341c56681841 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik.c +++ b/drivers/gpu/drm/amd/amdgpu/cik.c @@ -2256,10 +2256,6 @@ int cik_set_ip_blocks(struct amdgpu_device *adev) return -EINVAL; } - adev->ip_block_enabled = kcalloc(adev->num_ip_blocks, sizeof(bool), GFP_KERNEL); - if (adev->ip_block_enabled == NULL) - return -ENOMEM; - return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/cikd.h b/drivers/gpu/drm/amd/amdgpu/cikd.h index 220865a44814..d19085a97064 100644 --- a/drivers/gpu/drm/amd/amdgpu/cikd.h +++ b/drivers/gpu/drm/amd/amdgpu/cikd.h @@ -552,4 +552,10 @@ #define VCE_CMD_IB_AUTO 0x00000005 #define VCE_CMD_SEMAPHORE 0x00000006 +/* valid for both DEFAULT_MTYPE and APE1_MTYPE */ +enum { + MTYPE_CACHED = 0, + MTYPE_NONCACHED = 3 +}; + #endif diff --git a/drivers/gpu/drm/amd/amdgpu/cz_dpm.c b/drivers/gpu/drm/amd/amdgpu/cz_dpm.c index e4936a452bc6..f75a31df30bd 100644 --- a/drivers/gpu/drm/amd/amdgpu/cz_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/cz_dpm.c @@ -425,7 +425,7 @@ static int cz_dpm_init(struct amdgpu_device *adev) pi->mgcg_cgtt_local1 = 0x0; pi->clock_slow_down_step = 25000; pi->skip_clock_slow_down = 1; - pi->enable_nb_ps_policy = 1; + pi->enable_nb_ps_policy = 0; pi->caps_power_containment = true; pi->caps_cac = true; pi->didt_enabled = false; diff --git a/drivers/gpu/drm/amd/amdgpu/cz_dpm.h b/drivers/gpu/drm/amd/amdgpu/cz_dpm.h index 782a74107664..99e1afc89629 100644 --- a/drivers/gpu/drm/amd/amdgpu/cz_dpm.h +++ b/drivers/gpu/drm/amd/amdgpu/cz_dpm.h @@ -46,7 +46,7 @@ /* Do not change the following, it is also defined in SMU8.h */ #define SMU_EnabledFeatureScoreboard_AcpDpmOn 0x00000001 -#define SMU_EnabledFeatureScoreboard_SclkDpmOn 0x00100000 +#define SMU_EnabledFeatureScoreboard_SclkDpmOn 0x00200000 #define SMU_EnabledFeatureScoreboard_UvdDpmOn 0x00800000 #define SMU_EnabledFeatureScoreboard_VceDpmOn 0x01000000 diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index 5cde635978f9..6e77964f1b64 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c @@ -3403,19 +3403,25 @@ static int dce_v10_0_crtc_irq(struct amdgpu_device *adev, switch (entry->src_data) { case 0: /* vblank */ - if (disp_int & interrupt_status_offsets[crtc].vblank) { + if (disp_int & interrupt_status_offsets[crtc].vblank) dce_v10_0_crtc_vblank_int_ack(adev, crtc); - if (amdgpu_irq_enabled(adev, source, irq_type)) { - drm_handle_vblank(adev->ddev, crtc); - } - DRM_DEBUG("IH: D%d vblank\n", crtc + 1); + else + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (amdgpu_irq_enabled(adev, source, irq_type)) { + drm_handle_vblank(adev->ddev, crtc); } + DRM_DEBUG("IH: D%d vblank\n", crtc + 1); + break; case 1: /* vline */ - if (disp_int & interrupt_status_offsets[crtc].vline) { + if (disp_int & interrupt_status_offsets[crtc].vline) dce_v10_0_crtc_vline_int_ack(adev, crtc); - DRM_DEBUG("IH: D%d vline\n", crtc + 1); - } + else + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + DRM_DEBUG("IH: D%d vline\n", crtc + 1); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", entry->src_id, entry->src_data); diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c index 95efd98b202d..7f7abb0e0be5 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c @@ -3402,19 +3402,25 @@ static int dce_v11_0_crtc_irq(struct amdgpu_device *adev, switch (entry->src_data) { case 0: /* vblank */ - if (disp_int & interrupt_status_offsets[crtc].vblank) { + if (disp_int & interrupt_status_offsets[crtc].vblank) dce_v11_0_crtc_vblank_int_ack(adev, crtc); - if (amdgpu_irq_enabled(adev, source, irq_type)) { - drm_handle_vblank(adev->ddev, crtc); - } - DRM_DEBUG("IH: D%d vblank\n", crtc + 1); + else + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (amdgpu_irq_enabled(adev, source, irq_type)) { + drm_handle_vblank(adev->ddev, crtc); } + DRM_DEBUG("IH: D%d vblank\n", crtc + 1); + break; case 1: /* vline */ - if (disp_int & interrupt_status_offsets[crtc].vline) { + if (disp_int & interrupt_status_offsets[crtc].vline) dce_v11_0_crtc_vline_int_ack(adev, crtc); - DRM_DEBUG("IH: D%d vline\n", crtc + 1); - } + else + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + DRM_DEBUG("IH: D%d vline\n", crtc + 1); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", entry->src_id, entry->src_data); diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index 72c27ac915f2..08387dfd98a7 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c @@ -3237,19 +3237,25 @@ static int dce_v8_0_crtc_irq(struct amdgpu_device *adev, switch (entry->src_data) { case 0: /* vblank */ - if (disp_int & interrupt_status_offsets[crtc].vblank) { + if (disp_int & interrupt_status_offsets[crtc].vblank) WREG32(mmLB_VBLANK_STATUS + crtc_offsets[crtc], LB_VBLANK_STATUS__VBLANK_ACK_MASK); - if (amdgpu_irq_enabled(adev, source, irq_type)) { - drm_handle_vblank(adev->ddev, crtc); - } - DRM_DEBUG("IH: D%d vblank\n", crtc + 1); + else + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (amdgpu_irq_enabled(adev, source, irq_type)) { + drm_handle_vblank(adev->ddev, crtc); } + DRM_DEBUG("IH: D%d vblank\n", crtc + 1); + break; case 1: /* vline */ - if (disp_int & interrupt_status_offsets[crtc].vline) { + if (disp_int & interrupt_status_offsets[crtc].vline) WREG32(mmLB_VLINE_STATUS + crtc_offsets[crtc], LB_VLINE_STATUS__VLINE_ACK_MASK); - DRM_DEBUG("IH: D%d vline\n", crtc + 1); - } + else + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + DRM_DEBUG("IH: D%d vline\n", crtc + 1); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", entry->src_id, entry->src_data); @@ -3379,7 +3385,7 @@ static int dce_v8_0_hpd_irq(struct amdgpu_device *adev, uint32_t disp_int, mask, int_control, tmp; unsigned hpd; - if (entry->src_data > 6) { + if (entry->src_data >= adev->mode_info.num_hpd) { DRM_DEBUG("Unhandled interrupt: %d %d\n", entry->src_id, entry->src_data); return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c index cb7907447b81..2c188fb9fd22 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c @@ -2010,6 +2010,46 @@ static void gfx_v7_0_setup_rb(struct amdgpu_device *adev, } /** + * gmc_v7_0_init_compute_vmid - gart enable + * + * @rdev: amdgpu_device pointer + * + * Initialize compute vmid sh_mem registers + * + */ +#define DEFAULT_SH_MEM_BASES (0x6000) +#define FIRST_COMPUTE_VMID (8) +#define LAST_COMPUTE_VMID (16) +static void gmc_v7_0_init_compute_vmid(struct amdgpu_device *adev) +{ + int i; + uint32_t sh_mem_config; + uint32_t sh_mem_bases; + + /* + * Configure apertures: + * LDS: 0x60000000'00000000 - 0x60000001'00000000 (4GB) + * Scratch: 0x60000001'00000000 - 0x60000002'00000000 (4GB) + * GPUVM: 0x60010000'00000000 - 0x60020000'00000000 (1TB) + */ + sh_mem_bases = DEFAULT_SH_MEM_BASES | (DEFAULT_SH_MEM_BASES << 16); + sh_mem_config = SH_MEM_ALIGNMENT_MODE_UNALIGNED << + SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT; + sh_mem_config |= MTYPE_NONCACHED << SH_MEM_CONFIG__DEFAULT_MTYPE__SHIFT; + mutex_lock(&adev->srbm_mutex); + for (i = FIRST_COMPUTE_VMID; i < LAST_COMPUTE_VMID; i++) { + cik_srbm_select(adev, 0, 0, 0, i); + /* CP and shaders */ + WREG32(mmSH_MEM_CONFIG, sh_mem_config); + WREG32(mmSH_MEM_APE1_BASE, 1); + WREG32(mmSH_MEM_APE1_LIMIT, 0); + WREG32(mmSH_MEM_BASES, sh_mem_bases); + } + cik_srbm_select(adev, 0, 0, 0, 0); + mutex_unlock(&adev->srbm_mutex); +} + +/** * gfx_v7_0_gpu_init - setup the 3D engine * * @adev: amdgpu_device pointer @@ -2230,6 +2270,8 @@ static void gfx_v7_0_gpu_init(struct amdgpu_device *adev) cik_srbm_select(adev, 0, 0, 0, 0); mutex_unlock(&adev->srbm_mutex); + gmc_v7_0_init_compute_vmid(adev); + WREG32(mmSX_DEBUG_1, 0x20); WREG32(mmTA_CNTL_AUX, 0x00010000); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 14242bd33363..7b683fb2173c 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -1894,6 +1894,51 @@ static void gfx_v8_0_setup_rb(struct amdgpu_device *adev, mutex_unlock(&adev->grbm_idx_mutex); } +/** + * gmc_v8_0_init_compute_vmid - gart enable + * + * @rdev: amdgpu_device pointer + * + * Initialize compute vmid sh_mem registers + * + */ +#define DEFAULT_SH_MEM_BASES (0x6000) +#define FIRST_COMPUTE_VMID (8) +#define LAST_COMPUTE_VMID (16) +static void gmc_v8_0_init_compute_vmid(struct amdgpu_device *adev) +{ + int i; + uint32_t sh_mem_config; + uint32_t sh_mem_bases; + + /* + * Configure apertures: + * LDS: 0x60000000'00000000 - 0x60000001'00000000 (4GB) + * Scratch: 0x60000001'00000000 - 0x60000002'00000000 (4GB) + * GPUVM: 0x60010000'00000000 - 0x60020000'00000000 (1TB) + */ + sh_mem_bases = DEFAULT_SH_MEM_BASES | (DEFAULT_SH_MEM_BASES << 16); + + sh_mem_config = SH_MEM_ADDRESS_MODE_HSA64 << + SH_MEM_CONFIG__ADDRESS_MODE__SHIFT | + SH_MEM_ALIGNMENT_MODE_UNALIGNED << + SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT | + MTYPE_CC << SH_MEM_CONFIG__DEFAULT_MTYPE__SHIFT | + SH_MEM_CONFIG__PRIVATE_ATC_MASK; + + mutex_lock(&adev->srbm_mutex); + for (i = FIRST_COMPUTE_VMID; i < LAST_COMPUTE_VMID; i++) { + vi_srbm_select(adev, 0, 0, 0, i); + /* CP and shaders */ + WREG32(mmSH_MEM_CONFIG, sh_mem_config); + WREG32(mmSH_MEM_APE1_BASE, 1); + WREG32(mmSH_MEM_APE1_LIMIT, 0); + WREG32(mmSH_MEM_BASES, sh_mem_bases); + } + vi_srbm_select(adev, 0, 0, 0, 0); + mutex_unlock(&adev->srbm_mutex); +} + static void gfx_v8_0_gpu_init(struct amdgpu_device *adev) { u32 gb_addr_config; @@ -2113,6 +2158,8 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev) vi_srbm_select(adev, 0, 0, 0, 0); mutex_unlock(&adev->srbm_mutex); + gmc_v8_0_init_compute_vmid(adev); + mutex_lock(&adev->grbm_idx_mutex); /* * making sure that the following register writes will be broadcasted @@ -3081,7 +3128,7 @@ static int gfx_v8_0_cp_compute_resume(struct amdgpu_device *adev) WREG32(mmCP_MEC_DOORBELL_RANGE_LOWER, AMDGPU_DOORBELL_KIQ << 2); WREG32(mmCP_MEC_DOORBELL_RANGE_UPPER, - AMDGPU_DOORBELL_MEC_RING7 << 2); + 0x7FFFF << 2); } tmp = RREG32(mmCP_HQD_PQ_DOORBELL_CONTROL); tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_DOORBELL_CONTROL, @@ -3097,6 +3144,12 @@ static int gfx_v8_0_cp_compute_resume(struct amdgpu_device *adev) WREG32(mmCP_HQD_PQ_DOORBELL_CONTROL, mqd->cp_hqd_pq_doorbell_control); + /* reset read and write pointers, similar to CP_RB0_WPTR/_RPTR */ + ring->wptr = 0; + mqd->cp_hqd_pq_wptr = ring->wptr; + WREG32(mmCP_HQD_PQ_WPTR, mqd->cp_hqd_pq_wptr); + mqd->cp_hqd_pq_rptr = RREG32(mmCP_HQD_PQ_RPTR); + /* set the vmid for the queue */ mqd->cp_hqd_vmid = 0; WREG32(mmCP_HQD_VMID, mqd->cp_hqd_vmid); diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c index e3c1fde75363..7bb37b93993f 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c @@ -439,6 +439,31 @@ static void sdma_v3_0_rlc_stop(struct amdgpu_device *adev) } /** + * sdma_v3_0_ctx_switch_enable - stop the async dma engines context switch + * + * @adev: amdgpu_device pointer + * @enable: enable/disable the DMA MEs context switch. + * + * Halt or unhalt the async dma engines context switch (VI). + */ +static void sdma_v3_0_ctx_switch_enable(struct amdgpu_device *adev, bool enable) +{ + u32 f32_cntl; + int i; + + for (i = 0; i < SDMA_MAX_INSTANCE; i++) { + f32_cntl = RREG32(mmSDMA0_CNTL + sdma_offsets[i]); + if (enable) + f32_cntl = REG_SET_FIELD(f32_cntl, SDMA0_CNTL, + AUTO_CTXSW_ENABLE, 1); + else + f32_cntl = REG_SET_FIELD(f32_cntl, SDMA0_CNTL, + AUTO_CTXSW_ENABLE, 0); + WREG32(mmSDMA0_CNTL + sdma_offsets[i], f32_cntl); + } +} + +/** * sdma_v3_0_enable - stop the async dma engines * * @adev: amdgpu_device pointer @@ -648,6 +673,8 @@ static int sdma_v3_0_start(struct amdgpu_device *adev) /* unhalt the MEs */ sdma_v3_0_enable(adev, true); + /* enable sdma ring preemption */ + sdma_v3_0_ctx_switch_enable(adev, true); /* start the gfx rings and rlc compute queues */ r = sdma_v3_0_gfx_resume(adev); @@ -1079,6 +1106,7 @@ static int sdma_v3_0_hw_fini(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + sdma_v3_0_ctx_switch_enable(adev, false); sdma_v3_0_enable(adev, false); return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c index 90fc93c2c1d0..fa5a4448531d 100644 --- a/drivers/gpu/drm/amd/amdgpu/vi.c +++ b/drivers/gpu/drm/amd/amdgpu/vi.c @@ -1189,10 +1189,6 @@ int vi_set_ip_blocks(struct amdgpu_device *adev) return -EINVAL; } - adev->ip_block_enabled = kcalloc(adev->num_ip_blocks, sizeof(bool), GFP_KERNEL); - if (adev->ip_block_enabled == NULL) - return -ENOMEM; - return 0; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 96c904b3acb7..c991973019d0 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -553,7 +553,7 @@ static int kfd_ioctl_dbg_address_watch(struct file *filep, /* Validate arguments */ if ((args->buf_size_in_bytes > MAX_ALLOWED_AW_BUFF_SIZE) || - (args->buf_size_in_bytes <= sizeof(*args)) || + (args->buf_size_in_bytes <= sizeof(*args) + sizeof(int) * 2) || (cmd_from_user == NULL)) return -EINVAL; @@ -590,7 +590,7 @@ static int kfd_ioctl_dbg_address_watch(struct file *filep, /* skip over the addresses buffer */ args_idx += sizeof(aw_info.watch_address) * aw_info.num_watch_points; - if (args_idx >= args->buf_size_in_bytes) { + if (args_idx >= args->buf_size_in_bytes - sizeof(*args)) { kfree(args_buff); return -EINVAL; } @@ -614,7 +614,7 @@ static int kfd_ioctl_dbg_address_watch(struct file *filep, args_idx += sizeof(aw_info.watch_mask); } - if (args_idx > args->buf_size_in_bytes) { + if (args_idx >= args->buf_size_in_bytes - sizeof(args)) { kfree(args_buff); return -EINVAL; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index 8a1f999daa24..9be007081b72 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -420,6 +420,12 @@ void kfd_unbind_process_from_device(struct kfd_dev *dev, unsigned int pasid) pqm_uninit(&p->pqm); pdd = kfd_get_process_device_data(dev, p); + + if (!pdd) { + mutex_unlock(&p->mutex); + return; + } + if (pdd->reset_wavefronts) { dbgdev_wave_reset_wavefronts(pdd->dev, p); pdd->reset_wavefronts = false; @@ -431,8 +437,7 @@ void kfd_unbind_process_from_device(struct kfd_dev *dev, unsigned int pasid) * We don't call amd_iommu_unbind_pasid() here * because the IOMMU called us. */ - if (pdd) - pdd->bound = false; + pdd->bound = false; mutex_unlock(&p->mutex); } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index e469c4b2e8cc..c25728bc388a 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -684,8 +684,6 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr, dev->node_props.cpu_core_id_base); sysfs_show_32bit_prop(buffer, "simd_id_base", dev->node_props.simd_id_base); - sysfs_show_32bit_prop(buffer, "capability", - dev->node_props.capability); sysfs_show_32bit_prop(buffer, "max_waves_per_simd", dev->node_props.max_waves_per_simd); sysfs_show_32bit_prop(buffer, "lds_size_in_kb", @@ -736,6 +734,8 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr, dev->gpu->kfd2kgd->get_fw_version( dev->gpu->kgd, KGD_ENGINE_MEC1)); + sysfs_show_32bit_prop(buffer, "capability", + dev->node_props.capability); } return sysfs_show_32bit_prop(buffer, "max_engine_clk_ccompute", diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c index 49cafb61d290..816d104ca4da 100644 --- a/drivers/gpu/drm/bridge/dw_hdmi.c +++ b/drivers/gpu/drm/bridge/dw_hdmi.c @@ -1395,7 +1395,7 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector) struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, connector); struct edid *edid; - int ret; + int ret = 0; if (!hdmi->ddc) return 0; @@ -1412,7 +1412,7 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector) dev_dbg(hdmi->dev, "failed to get edid\n"); } - return 0; + return ret; } static enum drm_mode_status @@ -1457,7 +1457,7 @@ static struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = { .best_encoder = dw_hdmi_connector_best_encoder, }; -struct drm_bridge_funcs dw_hdmi_bridge_funcs = { +static struct drm_bridge_funcs dw_hdmi_bridge_funcs = { .enable = dw_hdmi_bridge_enable, .disable = dw_hdmi_bridge_disable, .pre_enable = dw_hdmi_bridge_nop, diff --git a/drivers/gpu/drm/bridge/ps8622.c b/drivers/gpu/drm/bridge/ps8622.c index e895aa7ea353..1a6607beb29f 100644 --- a/drivers/gpu/drm/bridge/ps8622.c +++ b/drivers/gpu/drm/bridge/ps8622.c @@ -18,6 +18,7 @@ #include <linux/err.h> #include <linux/fb.h> #include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/of.h> @@ -31,6 +32,7 @@ #include "drmP.h" #include "drm_crtc.h" #include "drm_crtc_helper.h" +#include "drm_atomic_helper.h" /* Brightness scale on the Parade chip */ #define PS8622_MAX_BRIGHTNESS 0xff @@ -498,10 +500,13 @@ static void ps8622_connector_destroy(struct drm_connector *connector) } static const struct drm_connector_funcs ps8622_connector_funcs = { - .dpms = drm_helper_connector_dpms, + .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = ps8622_detect, .destroy = ps8622_connector_destroy, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; static int ps8622_attach(struct drm_bridge *bridge) @@ -581,31 +586,21 @@ static int ps8622_probe(struct i2c_client *client, ps8622->v12 = NULL; } - ps8622->gpio_slp = devm_gpiod_get(dev, "sleep"); + ps8622->gpio_slp = devm_gpiod_get(dev, "sleep", GPIOD_OUT_HIGH); if (IS_ERR(ps8622->gpio_slp)) { ret = PTR_ERR(ps8622->gpio_slp); dev_err(dev, "cannot get gpio_slp %d\n", ret); return ret; } - ret = gpiod_direction_output(ps8622->gpio_slp, 1); - if (ret) { - dev_err(dev, "cannot configure gpio_slp\n"); - return ret; - } - ps8622->gpio_rst = devm_gpiod_get(dev, "reset"); - if (IS_ERR(ps8622->gpio_rst)) { - ret = PTR_ERR(ps8622->gpio_rst); - dev_err(dev, "cannot get gpio_rst %d\n", ret); - return ret; - } /* * Assert the reset pin high to avoid the bridge being * initialized prematurely */ - ret = gpiod_direction_output(ps8622->gpio_rst, 1); - if (ret) { - dev_err(dev, "cannot configure gpio_rst\n"); + ps8622->gpio_rst = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(ps8622->gpio_rst)) { + ret = PTR_ERR(ps8622->gpio_rst); + dev_err(dev, "cannot get gpio_rst %d\n", ret); return ret; } diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c index 9d2f053382e1..1b1bf2384815 100644 --- a/drivers/gpu/drm/bridge/ptn3460.c +++ b/drivers/gpu/drm/bridge/ptn3460.c @@ -15,6 +15,7 @@ #include <linux/delay.h> #include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/of.h> @@ -23,10 +24,9 @@ #include <drm/drm_panel.h> -#include "bridge/ptn3460.h" - #include "drm_crtc.h" #include "drm_crtc_helper.h" +#include "drm_atomic_helper.h" #include "drm_edid.h" #include "drmP.h" @@ -259,10 +259,13 @@ static void ptn3460_connector_destroy(struct drm_connector *connector) } static struct drm_connector_funcs ptn3460_connector_funcs = { - .dpms = drm_helper_connector_dpms, + .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = ptn3460_detect, .destroy = ptn3460_connector_destroy, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; static int ptn3460_bridge_attach(struct drm_bridge *bridge) @@ -330,32 +333,23 @@ static int ptn3460_probe(struct i2c_client *client, ptn_bridge->client = client; - ptn_bridge->gpio_pd_n = devm_gpiod_get(&client->dev, "powerdown"); + ptn_bridge->gpio_pd_n = devm_gpiod_get(&client->dev, "powerdown", + GPIOD_OUT_HIGH); if (IS_ERR(ptn_bridge->gpio_pd_n)) { ret = PTR_ERR(ptn_bridge->gpio_pd_n); dev_err(dev, "cannot get gpio_pd_n %d\n", ret); return ret; } - ret = gpiod_direction_output(ptn_bridge->gpio_pd_n, 1); - if (ret) { - DRM_ERROR("cannot configure gpio_pd_n\n"); - return ret; - } - - ptn_bridge->gpio_rst_n = devm_gpiod_get(&client->dev, "reset"); - if (IS_ERR(ptn_bridge->gpio_rst_n)) { - ret = PTR_ERR(ptn_bridge->gpio_rst_n); - DRM_ERROR("cannot get gpio_rst_n %d\n", ret); - return ret; - } /* * Request the reset pin low to avoid the bridge being * initialized prematurely */ - ret = gpiod_direction_output(ptn_bridge->gpio_rst_n, 0); - if (ret) { - DRM_ERROR("cannot configure gpio_rst_n\n"); + ptn_bridge->gpio_rst_n = devm_gpiod_get(&client->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(ptn_bridge->gpio_rst_n)) { + ret = PTR_ERR(ptn_bridge->gpio_rst_n); + DRM_ERROR("cannot get gpio_rst_n %d\n", ret); return ret; } @@ -389,7 +383,7 @@ static int ptn3460_remove(struct i2c_client *client) } static const struct i2c_device_id ptn3460_i2c_table[] = { - {"nxp,ptn3460", 0}, + {"ptn3460", 0}, {}, }; MODULE_DEVICE_TABLE(i2c, ptn3460_i2c_table); diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index c7e59b074e62..f6f2fb58eb37 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1216,8 +1216,7 @@ int drm_atomic_check_only(struct drm_atomic_state *state) if (!state->allow_modeset) { for_each_crtc_in_state(state, crtc, crtc_state, i) { - if (crtc_state->mode_changed || - crtc_state->active_changed) { + if (drm_atomic_crtc_needs_modeset(crtc_state)) { DRM_DEBUG_ATOMIC("[CRTC:%d] requires full modeset\n", crtc->base.id); return -EINVAL; diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 536ae4da4665..5b59d5ad7d1c 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -331,12 +331,6 @@ mode_fixup(struct drm_atomic_state *state) return 0; } -static bool -needs_modeset(struct drm_crtc_state *state) -{ - return state->mode_changed || state->active_changed; -} - /** * drm_atomic_helper_check_modeset - validate state object for modeset changes * @dev: DRM device @@ -414,7 +408,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, crtc_state->active_changed = true; } - if (!needs_modeset(crtc_state)) + if (!drm_atomic_crtc_needs_modeset(crtc_state)) continue; DRM_DEBUG_ATOMIC("[CRTC:%d] needs all connectors, enable: %c, active: %c\n", @@ -564,7 +558,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) old_crtc_state = old_state->crtc_states[drm_crtc_index(old_conn_state->crtc)]; if (!old_crtc_state->active || - !needs_modeset(old_conn_state->crtc->state)) + !drm_atomic_crtc_needs_modeset(old_conn_state->crtc->state)) continue; encoder = old_conn_state->best_encoder; @@ -601,7 +595,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) const struct drm_crtc_helper_funcs *funcs; /* Shut down everything that needs a full modeset. */ - if (!needs_modeset(crtc->state)) + if (!drm_atomic_crtc_needs_modeset(crtc->state)) continue; if (!old_crtc_state->active) @@ -792,7 +786,7 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev, const struct drm_crtc_helper_funcs *funcs; /* Need to filter out CRTCs where only planes change. */ - if (!needs_modeset(crtc->state)) + if (!drm_atomic_crtc_needs_modeset(crtc->state)) continue; if (!crtc->state->active) @@ -819,7 +813,7 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev, continue; if (!connector->state->crtc->state->active || - !needs_modeset(connector->state->crtc->state)) + !drm_atomic_crtc_needs_modeset(connector->state->crtc->state)) continue; encoder = connector->state->best_encoder; @@ -1561,10 +1555,14 @@ static int update_output_state(struct drm_atomic_state *state, if (crtc == set->crtc) continue; - crtc_state->enable = - drm_atomic_connectors_for_crtc(state, crtc); - if (!crtc_state->enable) + if (!drm_atomic_connectors_for_crtc(state, crtc)) { + ret = drm_atomic_set_mode_prop_for_crtc(crtc_state, + NULL); + if (ret < 0) + return ret; + crtc_state->active = false; + } } return 0; diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c index 9a62d7a53553..6743ff7dccfa 100644 --- a/drivers/gpu/drm/drm_cache.c +++ b/drivers/gpu/drm/drm_cache.c @@ -130,11 +130,12 @@ drm_clflush_virt_range(void *addr, unsigned long length) { #if defined(CONFIG_X86) if (cpu_has_clflush) { + const int size = boot_cpu_data.x86_clflush_size; void *end = addr + length; + addr = (void *)(((unsigned long)addr) & -size); mb(); - for (; addr < end; addr += boot_cpu_data.x86_clflush_size) + for (; addr < end; addr += size) clflushopt(addr); - clflushopt(end - 1); mb(); return; } diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 77f87b23a6e7..b9ba06176eb1 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -3255,6 +3255,24 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) r->modifier[i], i); return -EINVAL; } + + /* modifier specific checks: */ + switch (r->modifier[i]) { + case DRM_FORMAT_MOD_SAMSUNG_64_32_TILE: + /* NOTE: the pitch restriction may be lifted later if it turns + * out that no hw has this restriction: + */ + if (r->pixel_format != DRM_FORMAT_NV12 || + width % 128 || height % 32 || + r->pitches[i] % 128) { + DRM_DEBUG_KMS("bad modifier data for plane %d\n", i); + return -EINVAL; + } + break; + + default: + break; + } } for (i = num_planes; i < 4; i++) { @@ -4714,7 +4732,7 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector, return 0; if (edid) - size = EDID_LENGTH + (1 + edid->extensions); + size = EDID_LENGTH * (1 + edid->extensions); ret = drm_property_replace_global_blob(dev, &connector->edid_blob_ptr, diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 132581ca4ad8..778bbb6425b8 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -867,8 +867,16 @@ static void drm_dp_destroy_port(struct kref *kref) port->vcpi.num_slots = 0; kfree(port->cached_edid); - if (port->connector) - (*port->mgr->cbs->destroy_connector)(mgr, port->connector); + + /* we can't destroy the connector here, as + we might be holding the mode_config.mutex + from an EDID retrieval */ + if (port->connector) { + mutex_lock(&mgr->destroy_connector_lock); + list_add(&port->connector->destroy_list, &mgr->destroy_connector_list); + mutex_unlock(&mgr->destroy_connector_lock); + schedule_work(&mgr->destroy_connector_work); + } drm_dp_port_teardown_pdt(port, port->pdt); if (!port->input && port->vcpi.vcpi > 0) @@ -1163,6 +1171,8 @@ static struct drm_dp_mst_branch *drm_dp_get_mst_branch_device(struct drm_dp_mst_ struct drm_dp_mst_port *port; int i; /* find the port by iterating down */ + + mutex_lock(&mgr->lock); mstb = mgr->mst_primary; for (i = 0; i < lct - 1; i++) { @@ -1182,6 +1192,7 @@ static struct drm_dp_mst_branch *drm_dp_get_mst_branch_device(struct drm_dp_mst_ } } kref_get(&mstb->kref); + mutex_unlock(&mgr->lock); return mstb; } @@ -1189,7 +1200,7 @@ static void drm_dp_check_and_send_link_address(struct drm_dp_mst_topology_mgr *m struct drm_dp_mst_branch *mstb) { struct drm_dp_mst_port *port; - + struct drm_dp_mst_branch *mstb_child; if (!mstb->link_address_sent) { drm_dp_send_link_address(mgr, mstb); mstb->link_address_sent = true; @@ -1204,17 +1215,31 @@ static void drm_dp_check_and_send_link_address(struct drm_dp_mst_topology_mgr *m if (!port->available_pbn) drm_dp_send_enum_path_resources(mgr, mstb, port); - if (port->mstb) - drm_dp_check_and_send_link_address(mgr, port->mstb); + if (port->mstb) { + mstb_child = drm_dp_get_validated_mstb_ref(mgr, port->mstb); + if (mstb_child) { + drm_dp_check_and_send_link_address(mgr, mstb_child); + drm_dp_put_mst_branch_device(mstb_child); + } + } } } static void drm_dp_mst_link_probe_work(struct work_struct *work) { struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, work); + struct drm_dp_mst_branch *mstb; - drm_dp_check_and_send_link_address(mgr, mgr->mst_primary); - + mutex_lock(&mgr->lock); + mstb = mgr->mst_primary; + if (mstb) { + kref_get(&mstb->kref); + } + mutex_unlock(&mgr->lock); + if (mstb) { + drm_dp_check_and_send_link_address(mgr, mstb); + drm_dp_put_mst_branch_device(mstb); + } } static bool drm_dp_validate_guid(struct drm_dp_mst_topology_mgr *mgr, @@ -2632,6 +2657,30 @@ static void drm_dp_tx_work(struct work_struct *work) mutex_unlock(&mgr->qlock); } +static void drm_dp_destroy_connector_work(struct work_struct *work) +{ + struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work); + struct drm_connector *connector; + + /* + * Not a regular list traverse as we have to drop the destroy + * connector lock before destroying the connector, to avoid AB->BA + * ordering between this lock and the config mutex. + */ + for (;;) { + mutex_lock(&mgr->destroy_connector_lock); + connector = list_first_entry_or_null(&mgr->destroy_connector_list, struct drm_connector, destroy_list); + if (!connector) { + mutex_unlock(&mgr->destroy_connector_lock); + break; + } + list_del(&connector->destroy_list); + mutex_unlock(&mgr->destroy_connector_lock); + + mgr->cbs->destroy_connector(mgr, connector); + } +} + /** * drm_dp_mst_topology_mgr_init - initialise a topology manager * @mgr: manager struct to initialise @@ -2651,10 +2700,13 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, mutex_init(&mgr->lock); mutex_init(&mgr->qlock); mutex_init(&mgr->payload_lock); + mutex_init(&mgr->destroy_connector_lock); INIT_LIST_HEAD(&mgr->tx_msg_upq); INIT_LIST_HEAD(&mgr->tx_msg_downq); + INIT_LIST_HEAD(&mgr->destroy_connector_list); INIT_WORK(&mgr->work, drm_dp_mst_link_probe_work); INIT_WORK(&mgr->tx_work, drm_dp_tx_work); + INIT_WORK(&mgr->destroy_connector_work, drm_dp_destroy_connector_work); init_waitqueue_head(&mgr->tx_waitq); mgr->dev = dev; mgr->aux = aux; @@ -2679,6 +2731,7 @@ EXPORT_SYMBOL(drm_dp_mst_topology_mgr_init); */ void drm_dp_mst_topology_mgr_destroy(struct drm_dp_mst_topology_mgr *mgr) { + flush_work(&mgr->destroy_connector_work); mutex_lock(&mgr->payload_lock); kfree(mgr->payloads); mgr->payloads = NULL; diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 3b3c4f537e95..b7bf4ce8c012 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -46,13 +46,11 @@ MODULE_AUTHOR(CORE_AUTHOR); MODULE_DESCRIPTION(CORE_DESC); MODULE_LICENSE("GPL and additional rights"); MODULE_PARM_DESC(debug, "Enable debug output"); -MODULE_PARM_DESC(atomic, "Enable experimental atomic KMS API"); MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs] (0: never disable, <0: disable immediately)"); MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]"); MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps"); module_param_named(debug, drm_debug, int, 0600); -module_param_named_unsafe(atomic, drm_atomic, bool, 0600); static DEFINE_SPINLOCK(drm_minor_lock); static struct idr drm_minors_idr; diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c index e419eedf751d..bd75f303da63 100644 --- a/drivers/gpu/drm/drm_gem_cma_helper.c +++ b/drivers/gpu/drm/drm_gem_cma_helper.c @@ -110,7 +110,7 @@ struct drm_gem_cma_object *drm_gem_cma_create(struct drm_device *drm, cma_obj->vaddr = dma_alloc_writecombine(drm->dev, size, &cma_obj->paddr, GFP_KERNEL | __GFP_NOWARN); if (!cma_obj->vaddr) { - dev_err(drm->dev, "failed to allocate buffer with size %d\n", + dev_err(drm->dev, "failed to allocate buffer with size %zu\n", size); ret = -ENOMEM; goto error; @@ -388,7 +388,7 @@ void drm_gem_cma_describe(struct drm_gem_cma_object *cma_obj, off = drm_vma_node_start(&obj->vma_node); - seq_printf(m, "%2d (%2d) %08llx %pad %p %d", + seq_printf(m, "%2d (%2d) %08llx %pad %p %zu", obj->name, obj->refcount.refcount.counter, off, &cma_obj->paddr, cma_obj->vaddr, obj->size); diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 9bac1b7479af..b1d303fa2327 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -36,9 +36,6 @@ #include <linux/pci.h> #include <linux/export.h> -#ifdef CONFIG_X86 -#include <asm/mtrr.h> -#endif static int drm_version(struct drm_device *dev, void *data, struct drm_file *file_priv); @@ -197,16 +194,7 @@ static int drm_getmap(struct drm_device *dev, void *data, map->type = r_list->map->type; map->flags = r_list->map->flags; map->handle = (void *)(unsigned long) r_list->user_token; - -#ifdef CONFIG_X86 - /* - * There appears to be exactly one user of the mtrr index: dritest. - * It's easy enough to keep it working on non-PAT systems. - */ - map->mtrr = phys_wc_to_mtrr_index(r_list->map->mtrr); -#else - map->mtrr = -1; -#endif + map->mtrr = arch_phys_wc_index(r_list->map->mtrr); mutex_unlock(&dev->struct_mutex); @@ -350,9 +338,6 @@ drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv) file_priv->universal_planes = req->value; break; case DRM_CLIENT_CAP_ATOMIC: - /* for now, hide behind experimental drm.atomic moduleparam */ - if (!drm_atomic) - return -EINVAL; if (!drm_core_check_feature(dev, DRIVER_ATOMIC)) return -EINVAL; if (req->value > 1) diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index 162dd29b2451..9f935f55d74c 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -309,7 +309,7 @@ static const struct dma_buf_ops drm_gem_prime_dmabuf_ops = { * Drivers can implement @gem_prime_export and @gem_prime_import in terms of * simpler APIs by using the helper functions @drm_gem_prime_export and * @drm_gem_prime_import. These functions implement dma-buf support in terms of - * five lower-level driver callbacks: + * six lower-level driver callbacks: * * Export callbacks: * @@ -321,6 +321,8 @@ static const struct dma_buf_ops drm_gem_prime_dmabuf_ops = { * * - @gem_prime_vunmap: vunmap a buffer exported by your driver * + * - @gem_prime_mmap (optional): mmap a buffer exported by your driver + * * Import callback: * * - @gem_prime_import_sg_table (import): produce a GEM object from another diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index 487ddf5ffe51..0f6cd33b531f 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -217,7 +217,7 @@ static ssize_t status_store(struct device *device, mutex_unlock(&dev->mode_config.mutex); - return ret; + return ret ? ret : count; } static ssize_t status_show(struct device *device, diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index 0a6780367d28..43003c4ad80b 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -24,16 +24,22 @@ config DRM_EXYNOS_FIMD help Choose this option if you want to use Exynos FIMD for DRM. -config DRM_EXYNOS7_DECON - bool "Exynos DRM DECON" +config DRM_EXYNOS5433_DECON + bool "Exynos5433 DRM DECON" depends on DRM_EXYNOS + help + Choose this option if you want to use Exynos5433 DECON for DRM. + +config DRM_EXYNOS7_DECON + bool "Exynos7 DRM DECON" + depends on DRM_EXYNOS && !FB_S3C select FB_MODE_HELPERS help Choose this option if you want to use Exynos DECON for DRM. config DRM_EXYNOS_DPI bool "EXYNOS DRM parallel output support" - depends on (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON) + depends on DRM_EXYNOS && (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON) select DRM_PANEL default n help @@ -41,7 +47,7 @@ config DRM_EXYNOS_DPI config DRM_EXYNOS_DSI bool "EXYNOS DRM MIPI-DSI driver support" - depends on (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON) + depends on DRM_EXYNOS && (DRM_EXYNOS_FIMD || DRM_EXYNOS5433_DECON || DRM_EXYNOS7_DECON) select DRM_MIPI_DSI select DRM_PANEL default n @@ -50,7 +56,7 @@ config DRM_EXYNOS_DSI config DRM_EXYNOS_DP bool "EXYNOS DRM DP driver support" - depends on (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON) && ARCH_EXYNOS && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS) + depends on DRM_EXYNOS && (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON) && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS) default DRM_EXYNOS select DRM_PANEL help @@ -97,3 +103,9 @@ config DRM_EXYNOS_GSC depends on DRM_EXYNOS_IPP && ARCH_EXYNOS5 && !ARCH_MULTIPLATFORM help Choose this option if you want to use Exynos GSC for DRM. + +config DRM_EXYNOS_MIC + bool "Exynos DRM MIC" + depends on (DRM_EXYNOS && DRM_EXYNOS5433_DECON) + help + Choose this option if you want to use Exynos MIC for DRM. diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile index cc90679cfc06..7de0b1084fcd 100644 --- a/drivers/gpu/drm/exynos/Makefile +++ b/drivers/gpu/drm/exynos/Makefile @@ -10,6 +10,7 @@ exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o \ exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o +exynosdrm-$(CONFIG_DRM_EXYNOS5433_DECON) += exynos5433_drm_decon.o exynosdrm-$(CONFIG_DRM_EXYNOS7_DECON) += exynos7_drm_decon.o exynosdrm-$(CONFIG_DRM_EXYNOS_DPI) += exynos_drm_dpi.o exynosdrm-$(CONFIG_DRM_EXYNOS_DSI) += exynos_drm_dsi.o @@ -21,5 +22,6 @@ exynosdrm-$(CONFIG_DRM_EXYNOS_IPP) += exynos_drm_ipp.o exynosdrm-$(CONFIG_DRM_EXYNOS_FIMC) += exynos_drm_fimc.o exynosdrm-$(CONFIG_DRM_EXYNOS_ROTATOR) += exynos_drm_rotator.o exynosdrm-$(CONFIG_DRM_EXYNOS_GSC) += exynos_drm_gsc.o +exynosdrm-$(CONFIG_DRM_EXYNOS_MIC) += exynos_drm_mic.o obj-$(CONFIG_DRM_EXYNOS) += exynosdrm.o diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c new file mode 100644 index 000000000000..8b1225f245fc --- /dev/null +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -0,0 +1,660 @@ +/* drivers/gpu/drm/exynos5433_drm_decon.c + * + * Copyright (C) 2015 Samsung Electronics Co.Ltd + * Authors: + * Joonyoung Shim <jy0922.shim@samsung.com> + * Hyungwon Hwang <human.hwang@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundationr + */ + +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/component.h> +#include <linux/of_gpio.h> +#include <linux/pm_runtime.h> + +#include <video/exynos5433_decon.h> + +#include "exynos_drm_drv.h" +#include "exynos_drm_crtc.h" +#include "exynos_drm_plane.h" +#include "exynos_drm_iommu.h" + +#define WINDOWS_NR 3 +#define MIN_FB_WIDTH_FOR_16WORD_BURST 128 + +struct decon_context { + struct device *dev; + struct drm_device *drm_dev; + struct exynos_drm_crtc *crtc; + struct exynos_drm_plane planes[WINDOWS_NR]; + void __iomem *addr; + struct clk *clks[6]; + unsigned int default_win; + unsigned long irq_flags; + int pipe; + bool suspended; + +#define BIT_CLKS_ENABLED 0 +#define BIT_IRQS_ENABLED 1 + unsigned long enabled; + bool i80_if; + atomic_t win_updated; +}; + +static const char * const decon_clks_name[] = { + "aclk_decon", + "aclk_smmu_decon0x", + "aclk_xiu_decon0x", + "pclk_smmu_decon0x", + "sclk_decon_vclk", + "sclk_decon_eclk", +}; + +static int decon_enable_vblank(struct exynos_drm_crtc *crtc) +{ + struct decon_context *ctx = crtc->ctx; + u32 val; + + if (ctx->suspended) + return -EPERM; + + if (test_and_set_bit(0, &ctx->irq_flags)) { + val = VIDINTCON0_INTEN; + if (ctx->i80_if) + val |= VIDINTCON0_FRAMEDONE; + else + val |= VIDINTCON0_INTFRMEN; + + writel(val, ctx->addr + DECON_VIDINTCON0); + } + + return 0; +} + +static void decon_disable_vblank(struct exynos_drm_crtc *crtc) +{ + struct decon_context *ctx = crtc->ctx; + + if (ctx->suspended) + return; + + if (test_and_clear_bit(0, &ctx->irq_flags)) + writel(0, ctx->addr + DECON_VIDINTCON0); +} + +static void decon_setup_trigger(struct decon_context *ctx) +{ + u32 val = TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F | + TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN; + writel(val, ctx->addr + DECON_TRIGCON); +} + +static void decon_commit(struct exynos_drm_crtc *crtc) +{ + struct decon_context *ctx = crtc->ctx; + struct drm_display_mode *mode = &crtc->base.mode; + u32 val; + + if (ctx->suspended) + return; + + /* enable clock gate */ + val = CMU_CLKGAGE_MODE_SFR_F | CMU_CLKGAGE_MODE_MEM_F; + writel(val, ctx->addr + DECON_CMU); + + /* lcd on and use command if */ + val = VIDOUT_LCD_ON; + if (ctx->i80_if) + val |= VIDOUT_COMMAND_IF; + else + val |= VIDOUT_RGB_IF; + writel(val, ctx->addr + DECON_VIDOUTCON0); + + val = VIDTCON2_LINEVAL(mode->vdisplay - 1) | + VIDTCON2_HOZVAL(mode->hdisplay - 1); + writel(val, ctx->addr + DECON_VIDTCON2); + + if (!ctx->i80_if) { + val = VIDTCON00_VBPD_F( + mode->crtc_vtotal - mode->crtc_vsync_end) | + VIDTCON00_VFPD_F( + mode->crtc_vsync_start - mode->crtc_vdisplay); + writel(val, ctx->addr + DECON_VIDTCON00); + + val = VIDTCON01_VSPW_F( + mode->crtc_vsync_end - mode->crtc_vsync_start); + writel(val, ctx->addr + DECON_VIDTCON01); + + val = VIDTCON10_HBPD_F( + mode->crtc_htotal - mode->crtc_hsync_end) | + VIDTCON10_HFPD_F( + mode->crtc_hsync_start - mode->crtc_hdisplay); + writel(val, ctx->addr + DECON_VIDTCON10); + + val = VIDTCON11_HSPW_F( + mode->crtc_hsync_end - mode->crtc_hsync_start); + writel(val, ctx->addr + DECON_VIDTCON11); + } + + decon_setup_trigger(ctx); + + /* enable output and display signal */ + val = VIDCON0_ENVID | VIDCON0_ENVID_F; + writel(val, ctx->addr + DECON_VIDCON0); +} + +#define COORDINATE_X(x) (((x) & 0xfff) << 12) +#define COORDINATE_Y(x) ((x) & 0xfff) +#define OFFSIZE(x) (((x) & 0x3fff) << 14) +#define PAGEWIDTH(x) ((x) & 0x3fff) + +static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win) +{ + struct exynos_drm_plane *plane = &ctx->planes[win]; + unsigned long val; + + val = readl(ctx->addr + DECON_WINCONx(win)); + val &= ~WINCONx_BPPMODE_MASK; + + switch (plane->pixel_format) { + case DRM_FORMAT_XRGB1555: + val |= WINCONx_BPPMODE_16BPP_I1555; + val |= WINCONx_HAWSWP_F; + val |= WINCONx_BURSTLEN_16WORD; + break; + case DRM_FORMAT_RGB565: + val |= WINCONx_BPPMODE_16BPP_565; + val |= WINCONx_HAWSWP_F; + val |= WINCONx_BURSTLEN_16WORD; + break; + case DRM_FORMAT_XRGB8888: + val |= WINCONx_BPPMODE_24BPP_888; + val |= WINCONx_WSWP_F; + val |= WINCONx_BURSTLEN_16WORD; + break; + case DRM_FORMAT_ARGB8888: + val |= WINCONx_BPPMODE_32BPP_A8888; + val |= WINCONx_WSWP_F | WINCONx_BLD_PIX_F | WINCONx_ALPHA_SEL_F; + val |= WINCONx_BURSTLEN_16WORD; + break; + default: + DRM_ERROR("Proper pixel format is not set\n"); + return; + } + + DRM_DEBUG_KMS("bpp = %u\n", plane->bpp); + + /* + * In case of exynos, setting dma-burst to 16Word causes permanent + * tearing for very small buffers, e.g. cursor buffer. Burst Mode + * switching which is based on plane size is not recommended as + * plane size varies a lot towards the end of the screen and rapid + * movement causes unstable DMA which results into iommu crash/tear. + */ + + if (plane->fb_width < MIN_FB_WIDTH_FOR_16WORD_BURST) { + val &= ~WINCONx_BURSTLEN_MASK; + val |= WINCONx_BURSTLEN_8WORD; + } + + writel(val, ctx->addr + DECON_WINCONx(win)); +} + +static void decon_shadow_protect_win(struct decon_context *ctx, int win, + bool protect) +{ + u32 val; + + val = readl(ctx->addr + DECON_SHADOWCON); + + if (protect) + val |= SHADOWCON_Wx_PROTECT(win); + else + val &= ~SHADOWCON_Wx_PROTECT(win); + + writel(val, ctx->addr + DECON_SHADOWCON); +} + +static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) +{ + struct decon_context *ctx = crtc->ctx; + struct exynos_drm_plane *plane; + u32 val; + + if (win < 0 || win >= WINDOWS_NR) + return; + + plane = &ctx->planes[win]; + + if (ctx->suspended) + return; + + decon_shadow_protect_win(ctx, win, true); + + val = COORDINATE_X(plane->crtc_x) | COORDINATE_Y(plane->crtc_y); + writel(val, ctx->addr + DECON_VIDOSDxA(win)); + + val = COORDINATE_X(plane->crtc_x + plane->crtc_width - 1) | + COORDINATE_Y(plane->crtc_y + plane->crtc_height - 1); + writel(val, ctx->addr + DECON_VIDOSDxB(win)); + + val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) | + VIDOSD_Wx_ALPHA_B_F(0x0); + writel(val, ctx->addr + DECON_VIDOSDxC(win)); + + val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) | + VIDOSD_Wx_ALPHA_B_F(0x0); + writel(val, ctx->addr + DECON_VIDOSDxD(win)); + + writel(plane->dma_addr[0], ctx->addr + DECON_VIDW0xADD0B0(win)); + + val = plane->dma_addr[0] + plane->pitch * plane->crtc_height; + writel(val, ctx->addr + DECON_VIDW0xADD1B0(win)); + + val = OFFSIZE(plane->pitch - plane->crtc_width * (plane->bpp >> 3)) + | PAGEWIDTH(plane->crtc_width * (plane->bpp >> 3)); + writel(val, ctx->addr + DECON_VIDW0xADD2(win)); + + decon_win_set_pixfmt(ctx, win); + + /* window enable */ + val = readl(ctx->addr + DECON_WINCONx(win)); + val |= WINCONx_ENWIN_F; + writel(val, ctx->addr + DECON_WINCONx(win)); + + decon_shadow_protect_win(ctx, win, false); + + /* standalone update */ + val = readl(ctx->addr + DECON_UPDATE); + val |= STANDALONE_UPDATE_F; + writel(val, ctx->addr + DECON_UPDATE); + + if (ctx->i80_if) + atomic_set(&ctx->win_updated, 1); +} + +static void decon_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) +{ + struct decon_context *ctx = crtc->ctx; + struct exynos_drm_plane *plane; + u32 val; + + if (win < 0 || win >= WINDOWS_NR) + return; + + plane = &ctx->planes[win]; + + if (ctx->suspended) + return; + + decon_shadow_protect_win(ctx, win, true); + + /* window disable */ + val = readl(ctx->addr + DECON_WINCONx(win)); + val &= ~WINCONx_ENWIN_F; + writel(val, ctx->addr + DECON_WINCONx(win)); + + decon_shadow_protect_win(ctx, win, false); + + /* standalone update */ + val = readl(ctx->addr + DECON_UPDATE); + val |= STANDALONE_UPDATE_F; + writel(val, ctx->addr + DECON_UPDATE); +} + +static void decon_swreset(struct decon_context *ctx) +{ + unsigned int tries; + + writel(0, ctx->addr + DECON_VIDCON0); + for (tries = 2000; tries; --tries) { + if (~readl(ctx->addr + DECON_VIDCON0) & VIDCON0_STOP_STATUS) + break; + udelay(10); + } + + WARN(tries == 0, "failed to disable DECON\n"); + + writel(VIDCON0_SWRESET, ctx->addr + DECON_VIDCON0); + for (tries = 2000; tries; --tries) { + if (~readl(ctx->addr + DECON_VIDCON0) & VIDCON0_SWRESET) + break; + udelay(10); + } + + WARN(tries == 0, "failed to software reset DECON\n"); +} + +static void decon_enable(struct exynos_drm_crtc *crtc) +{ + struct decon_context *ctx = crtc->ctx; + int ret; + int i; + + if (!ctx->suspended) + return; + + ctx->suspended = false; + + pm_runtime_get_sync(ctx->dev); + + for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) { + ret = clk_prepare_enable(ctx->clks[i]); + if (ret < 0) + goto err; + } + + set_bit(BIT_CLKS_ENABLED, &ctx->enabled); + + /* if vblank was enabled status, enable it again. */ + if (test_and_clear_bit(0, &ctx->irq_flags)) + decon_enable_vblank(ctx->crtc); + + decon_commit(ctx->crtc); + + return; +err: + while (--i >= 0) + clk_disable_unprepare(ctx->clks[i]); + + ctx->suspended = true; +} + +static void decon_disable(struct exynos_drm_crtc *crtc) +{ + struct decon_context *ctx = crtc->ctx; + int i; + + if (ctx->suspended) + return; + + /* + * We need to make sure that all windows are disabled before we + * suspend that connector. Otherwise we might try to scan from + * a destroyed buffer later. + */ + for (i = 0; i < WINDOWS_NR; i++) + decon_win_disable(crtc, i); + + decon_swreset(ctx); + + for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) + clk_disable_unprepare(ctx->clks[i]); + + clear_bit(BIT_CLKS_ENABLED, &ctx->enabled); + + pm_runtime_put_sync(ctx->dev); + + ctx->suspended = true; +} + +void decon_te_irq_handler(struct exynos_drm_crtc *crtc) +{ + struct decon_context *ctx = crtc->ctx; + u32 val; + + if (!test_bit(BIT_CLKS_ENABLED, &ctx->enabled)) + return; + + if (atomic_add_unless(&ctx->win_updated, -1, 0)) { + /* trigger */ + val = readl(ctx->addr + DECON_TRIGCON); + val |= TRIGCON_SWTRIGCMD; + writel(val, ctx->addr + DECON_TRIGCON); + } + + drm_handle_vblank(ctx->drm_dev, ctx->pipe); +} + +static void decon_clear_channels(struct exynos_drm_crtc *crtc) +{ + struct decon_context *ctx = crtc->ctx; + int win, i, ret; + u32 val; + + DRM_DEBUG_KMS("%s\n", __FILE__); + + for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) { + ret = clk_prepare_enable(ctx->clks[i]); + if (ret < 0) + goto err; + } + + for (win = 0; win < WINDOWS_NR; win++) { + /* shadow update disable */ + val = readl(ctx->addr + DECON_SHADOWCON); + val |= SHADOWCON_Wx_PROTECT(win); + writel(val, ctx->addr + DECON_SHADOWCON); + + /* window disable */ + val = readl(ctx->addr + DECON_WINCONx(win)); + val &= ~WINCONx_ENWIN_F; + writel(val, ctx->addr + DECON_WINCONx(win)); + + /* shadow update enable */ + val = readl(ctx->addr + DECON_SHADOWCON); + val &= ~SHADOWCON_Wx_PROTECT(win); + writel(val, ctx->addr + DECON_SHADOWCON); + + /* standalone update */ + val = readl(ctx->addr + DECON_UPDATE); + val |= STANDALONE_UPDATE_F; + writel(val, ctx->addr + DECON_UPDATE); + } + /* TODO: wait for possible vsync */ + msleep(50); + +err: + while (--i >= 0) + clk_disable_unprepare(ctx->clks[i]); +} + +static struct exynos_drm_crtc_ops decon_crtc_ops = { + .enable = decon_enable, + .disable = decon_disable, + .commit = decon_commit, + .enable_vblank = decon_enable_vblank, + .disable_vblank = decon_disable_vblank, + .commit = decon_commit, + .win_commit = decon_win_commit, + .win_disable = decon_win_disable, + .te_handler = decon_te_irq_handler, + .clear_channels = decon_clear_channels, +}; + +static int decon_bind(struct device *dev, struct device *master, void *data) +{ + struct decon_context *ctx = dev_get_drvdata(dev); + struct drm_device *drm_dev = data; + struct exynos_drm_private *priv = drm_dev->dev_private; + struct exynos_drm_plane *exynos_plane; + enum drm_plane_type type; + unsigned int zpos; + int ret; + + ctx->drm_dev = drm_dev; + ctx->pipe = priv->pipe++; + + for (zpos = 0; zpos < WINDOWS_NR; zpos++) { + type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY : + DRM_PLANE_TYPE_OVERLAY; + ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], + 1 << ctx->pipe, type, zpos); + if (ret) + return ret; + } + + exynos_plane = &ctx->planes[ctx->default_win]; + ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, + ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD, + &decon_crtc_ops, ctx); + if (IS_ERR(ctx->crtc)) { + ret = PTR_ERR(ctx->crtc); + goto err; + } + + ret = drm_iommu_attach_device_if_possible(ctx->crtc, drm_dev, dev); + if (ret) + goto err; + + return ret; +err: + priv->pipe--; + return ret; +} + +static void decon_unbind(struct device *dev, struct device *master, void *data) +{ + struct decon_context *ctx = dev_get_drvdata(dev); + + decon_disable(ctx->crtc); + + /* detach this sub driver from iommu mapping if supported. */ + if (is_drm_iommu_supported(ctx->drm_dev)) + drm_iommu_detach_device(ctx->drm_dev, ctx->dev); +} + +static const struct component_ops decon_component_ops = { + .bind = decon_bind, + .unbind = decon_unbind, +}; + +static irqreturn_t decon_vsync_irq_handler(int irq, void *dev_id) +{ + struct decon_context *ctx = dev_id; + u32 val; + + if (!test_bit(BIT_CLKS_ENABLED, &ctx->enabled)) + goto out; + + val = readl(ctx->addr + DECON_VIDINTCON1); + if (val & VIDINTCON1_INTFRMPEND) { + drm_handle_vblank(ctx->drm_dev, ctx->pipe); + + /* clear */ + writel(VIDINTCON1_INTFRMPEND, ctx->addr + DECON_VIDINTCON1); + } + +out: + return IRQ_HANDLED; +} + +static irqreturn_t decon_lcd_sys_irq_handler(int irq, void *dev_id) +{ + struct decon_context *ctx = dev_id; + u32 val; + + if (!test_bit(BIT_CLKS_ENABLED, &ctx->enabled)) + goto out; + + val = readl(ctx->addr + DECON_VIDINTCON1); + if (val & VIDINTCON1_INTFRMDONEPEND) { + exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); + + /* clear */ + writel(VIDINTCON1_INTFRMDONEPEND, + ctx->addr + DECON_VIDINTCON1); + } + +out: + return IRQ_HANDLED; +} + +static int exynos5433_decon_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct decon_context *ctx; + struct resource *res; + int ret; + int i; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->default_win = 0; + ctx->suspended = true; + ctx->dev = dev; + if (of_get_child_by_name(dev->of_node, "i80-if-timings")) + ctx->i80_if = true; + + for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++) { + struct clk *clk; + + clk = devm_clk_get(ctx->dev, decon_clks_name[i]); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + ctx->clks[i] = clk; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "cannot find IO resource\n"); + return -ENXIO; + } + + ctx->addr = devm_ioremap_resource(dev, res); + if (IS_ERR(ctx->addr)) { + dev_err(dev, "ioremap failed\n"); + return PTR_ERR(ctx->addr); + } + + res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, + ctx->i80_if ? "lcd_sys" : "vsync"); + if (!res) { + dev_err(dev, "cannot find IRQ resource\n"); + return -ENXIO; + } + + ret = devm_request_irq(dev, res->start, ctx->i80_if ? + decon_lcd_sys_irq_handler : decon_vsync_irq_handler, 0, + "drm_decon", ctx); + if (ret < 0) { + dev_err(dev, "lcd_sys irq request failed\n"); + return ret; + } + + platform_set_drvdata(pdev, ctx); + + pm_runtime_enable(dev); + + ret = component_add(dev, &decon_component_ops); + if (ret) + goto err_disable_pm_runtime; + + return 0; + +err_disable_pm_runtime: + pm_runtime_disable(dev); + + return ret; +} + +static int exynos5433_decon_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + component_del(&pdev->dev, &decon_component_ops); + + return 0; +} + +static const struct of_device_id exynos5433_decon_driver_dt_match[] = { + { .compatible = "samsung,exynos5433-decon" }, + {}, +}; +MODULE_DEVICE_TABLE(of, exynos5433_decon_driver_dt_match); + +struct platform_driver exynos5433_decon_driver = { + .probe = exynos5433_decon_probe, + .remove = exynos5433_decon_remove, + .driver = { + .name = "exynos5433-decon", + .of_match_table = exynos5433_decon_driver_dt_match, + }, +}; diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index 6714e5b193ea..362532afd1a5 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -89,8 +89,9 @@ static void decon_wait_for_vblank(struct exynos_drm_crtc *crtc) DRM_DEBUG_KMS("vblank wait timed out.\n"); } -static void decon_clear_channel(struct decon_context *ctx) +static void decon_clear_channels(struct exynos_drm_crtc *crtc) { + struct decon_context *ctx = crtc->ctx; unsigned int win, ch_enabled = 0; DRM_DEBUG_KMS("%s\n", __FILE__); @@ -120,27 +121,16 @@ static int decon_ctx_initialize(struct decon_context *ctx, struct drm_device *drm_dev) { struct exynos_drm_private *priv = drm_dev->dev_private; + int ret; ctx->drm_dev = drm_dev; ctx->pipe = priv->pipe++; - /* attach this sub driver to iommu mapping if supported. */ - if (is_drm_iommu_supported(ctx->drm_dev)) { - int ret; - - /* - * If any channel is already active, iommu will throw - * a PAGE FAULT when enabled. So clear any channel if enabled. - */ - decon_clear_channel(ctx); - ret = drm_iommu_attach_device(ctx->drm_dev, ctx->dev); - if (ret) { - DRM_ERROR("drm_iommu_attach failed.\n"); - return ret; - } - } + ret = drm_iommu_attach_device_if_possible(ctx->crtc, drm_dev, ctx->dev); + if (ret) + priv->pipe--; - return 0; + return ret; } static void decon_ctx_remove(struct decon_context *ctx) @@ -175,7 +165,7 @@ static bool decon_mode_fixup(struct exynos_drm_crtc *crtc, static void decon_commit(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = crtc->ctx; - struct drm_display_mode *mode = &crtc->base.mode; + struct drm_display_mode *mode = &crtc->base.state->adjusted_mode; u32 val, clkdiv; if (ctx->suspended) @@ -395,7 +385,7 @@ static void decon_shadow_protect_win(struct decon_context *ctx, static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) { struct decon_context *ctx = crtc->ctx; - struct drm_display_mode *mode = &crtc->base.mode; + struct drm_display_mode *mode = &crtc->base.state->adjusted_mode; struct exynos_drm_plane *plane; int padding; unsigned long val, alpha; @@ -410,11 +400,8 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) plane = &ctx->planes[win]; - /* If suspended, enable this on resume */ - if (ctx->suspended) { - plane->resume = true; + if (ctx->suspended) return; - } /* * SHADOWCON/PRTCON register is used for enabling timing. @@ -506,8 +493,6 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) val = readl(ctx->regs + DECON_UPDATE); val |= DECON_UPDATE_STANDALONE_F; writel(val, ctx->regs + DECON_UPDATE); - - plane->enabled = true; } static void decon_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) @@ -521,11 +506,8 @@ static void decon_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) plane = &ctx->planes[win]; - if (ctx->suspended) { - /* do not resume this window*/ - plane->resume = false; + if (ctx->suspended) return; - } /* protect windows */ decon_shadow_protect_win(ctx, win, true); @@ -541,49 +523,6 @@ static void decon_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) val = readl(ctx->regs + DECON_UPDATE); val |= DECON_UPDATE_STANDALONE_F; writel(val, ctx->regs + DECON_UPDATE); - - plane->enabled = false; -} - -static void decon_window_suspend(struct decon_context *ctx) -{ - struct exynos_drm_plane *plane; - int i; - - for (i = 0; i < WINDOWS_NR; i++) { - plane = &ctx->planes[i]; - plane->resume = plane->enabled; - if (plane->enabled) - decon_win_disable(ctx->crtc, i); - } -} - -static void decon_window_resume(struct decon_context *ctx) -{ - struct exynos_drm_plane *plane; - int i; - - for (i = 0; i < WINDOWS_NR; i++) { - plane = &ctx->planes[i]; - plane->enabled = plane->resume; - plane->resume = false; - } -} - -static void decon_apply(struct decon_context *ctx) -{ - struct exynos_drm_plane *plane; - int i; - - for (i = 0; i < WINDOWS_NR; i++) { - plane = &ctx->planes[i]; - if (plane->enabled) - decon_win_commit(ctx->crtc, i); - else - decon_win_disable(ctx->crtc, i); - } - - decon_commit(ctx->crtc); } static void decon_init(struct decon_context *ctx) @@ -603,12 +542,13 @@ static void decon_init(struct decon_context *ctx) writel(VIDCON1_VCLK_HOLD, ctx->regs + VIDCON1(0)); } -static int decon_poweron(struct decon_context *ctx) +static void decon_enable(struct exynos_drm_crtc *crtc) { + struct decon_context *ctx = crtc->ctx; int ret; if (!ctx->suspended) - return 0; + return; ctx->suspended = false; @@ -617,68 +557,51 @@ static int decon_poweron(struct decon_context *ctx) ret = clk_prepare_enable(ctx->pclk); if (ret < 0) { DRM_ERROR("Failed to prepare_enable the pclk [%d]\n", ret); - goto pclk_err; + return; } ret = clk_prepare_enable(ctx->aclk); if (ret < 0) { DRM_ERROR("Failed to prepare_enable the aclk [%d]\n", ret); - goto aclk_err; + return; } ret = clk_prepare_enable(ctx->eclk); if (ret < 0) { DRM_ERROR("Failed to prepare_enable the eclk [%d]\n", ret); - goto eclk_err; + return; } ret = clk_prepare_enable(ctx->vclk); if (ret < 0) { DRM_ERROR("Failed to prepare_enable the vclk [%d]\n", ret); - goto vclk_err; + return; } decon_init(ctx); /* if vblank was enabled status, enable it again. */ - if (test_and_clear_bit(0, &ctx->irq_flags)) { - ret = decon_enable_vblank(ctx->crtc); - if (ret) { - DRM_ERROR("Failed to re-enable vblank [%d]\n", ret); - goto err; - } - } - - decon_window_resume(ctx); - - decon_apply(ctx); + if (test_and_clear_bit(0, &ctx->irq_flags)) + decon_enable_vblank(ctx->crtc); - return 0; - -err: - clk_disable_unprepare(ctx->vclk); -vclk_err: - clk_disable_unprepare(ctx->eclk); -eclk_err: - clk_disable_unprepare(ctx->aclk); -aclk_err: - clk_disable_unprepare(ctx->pclk); -pclk_err: - ctx->suspended = true; - return ret; + decon_commit(ctx->crtc); } -static int decon_poweroff(struct decon_context *ctx) +static void decon_disable(struct exynos_drm_crtc *crtc) { + struct decon_context *ctx = crtc->ctx; + int i; + if (ctx->suspended) - return 0; + return; /* * We need to make sure that all windows are disabled before we * suspend that connector. Otherwise we might try to scan from * a destroyed buffer later. */ - decon_window_suspend(ctx); + for (i = 0; i < WINDOWS_NR; i++) + decon_win_disable(crtc, i); clk_disable_unprepare(ctx->vclk); clk_disable_unprepare(ctx->eclk); @@ -688,30 +611,11 @@ static int decon_poweroff(struct decon_context *ctx) pm_runtime_put_sync(ctx->dev); ctx->suspended = true; - return 0; -} - -static void decon_dpms(struct exynos_drm_crtc *crtc, int mode) -{ - DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode); - - switch (mode) { - case DRM_MODE_DPMS_ON: - decon_poweron(crtc->ctx); - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - decon_poweroff(crtc->ctx); - break; - default: - DRM_DEBUG_KMS("unspecified mode %d\n", mode); - break; - } } static const struct exynos_drm_crtc_ops decon_crtc_ops = { - .dpms = decon_dpms, + .enable = decon_enable, + .disable = decon_disable, .mode_fixup = decon_mode_fixup, .commit = decon_commit, .enable_vblank = decon_enable_vblank, @@ -719,6 +623,7 @@ static const struct exynos_drm_crtc_ops decon_crtc_ops = { .wait_for_vblank = decon_wait_for_vblank, .win_commit = decon_win_commit, .win_disable = decon_win_disable, + .clear_channels = decon_clear_channels, }; @@ -796,7 +701,7 @@ static void decon_unbind(struct device *dev, struct device *master, { struct decon_context *ctx = dev_get_drvdata(dev); - decon_dpms(ctx->crtc, DRM_MODE_DPMS_OFF); + decon_disable(ctx->crtc); if (ctx->display) exynos_dpi_remove(ctx->display); @@ -824,11 +729,6 @@ static int decon_probe(struct platform_device *pdev) if (!ctx) return -ENOMEM; - ret = exynos_drm_component_add(dev, EXYNOS_DEVICE_TYPE_CRTC, - EXYNOS_DISPLAY_TYPE_LCD); - if (ret) - return ret; - ctx->dev = dev; ctx->suspended = true; @@ -838,10 +738,8 @@ static int decon_probe(struct platform_device *pdev) of_node_put(i80_if_timings); ctx->regs = of_iomap(dev->of_node, 0); - if (!ctx->regs) { - ret = -ENOMEM; - goto err_del_component; - } + if (!ctx->regs) + return -ENOMEM; ctx->pclk = devm_clk_get(dev, "pclk_decon0"); if (IS_ERR(ctx->pclk)) { @@ -911,8 +809,6 @@ err_disable_pm_runtime: err_iounmap: iounmap(ctx->regs); -err_del_component: - exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CRTC); return ret; } @@ -925,7 +821,6 @@ static int decon_remove(struct platform_device *pdev) iounmap(ctx->regs); component_del(&pdev->dev, &decon_component_ops); - exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC); return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index 30feb7d06624..172b8002a2c8 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -28,8 +28,8 @@ #include <drm/drmP.h> #include <drm/drm_crtc.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_panel.h> -#include <drm/bridge/ptn3460.h> #include "exynos_dp_core.h" @@ -953,10 +953,13 @@ static void exynos_dp_connector_destroy(struct drm_connector *connector) } static struct drm_connector_funcs exynos_dp_connector_funcs = { - .dpms = drm_helper_connector_dpms, + .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = exynos_dp_detect, .destroy = exynos_dp_connector_destroy, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; static int exynos_dp_get_modes(struct drm_connector *connector) @@ -1329,7 +1332,6 @@ static int exynos_dp_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *panel_node, *bridge_node, *endpoint; struct exynos_dp_device *dp; - int ret; dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device), GFP_KERNEL); @@ -1340,11 +1342,6 @@ static int exynos_dp_probe(struct platform_device *pdev) dp->display.ops = &exynos_dp_display_ops; platform_set_drvdata(pdev, dp); - ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR, - dp->display.type); - if (ret) - return ret; - panel_node = of_parse_phandle(dev->of_node, "panel", 0); if (panel_node) { dp->panel = of_drm_find_panel(panel_node); @@ -1365,18 +1362,12 @@ static int exynos_dp_probe(struct platform_device *pdev) return -EPROBE_DEFER; } - ret = component_add(&pdev->dev, &exynos_dp_ops); - if (ret) - exynos_drm_component_del(&pdev->dev, - EXYNOS_DEVICE_TYPE_CONNECTOR); - - return ret; + return component_add(&pdev->dev, &exynos_dp_ops); } static int exynos_dp_remove(struct platform_device *pdev) { component_del(&pdev->dev, &exynos_dp_ops); - exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR); return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 9006b947e03c..644b4b76e071 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -14,57 +14,47 @@ #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> #include "exynos_drm_crtc.h" #include "exynos_drm_drv.h" #include "exynos_drm_encoder.h" #include "exynos_drm_plane.h" -static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) +static void exynos_drm_crtc_enable(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); - DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode); - - if (exynos_crtc->dpms == mode) { - DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n"); + if (exynos_crtc->enabled) return; - } - - if (mode > DRM_MODE_DPMS_ON) { - /* wait for the completion of page flip. */ - if (!wait_event_timeout(exynos_crtc->pending_flip_queue, - (exynos_crtc->event == NULL), HZ/20)) - exynos_crtc->event = NULL; - drm_crtc_vblank_off(crtc); - } - - if (exynos_crtc->ops->dpms) - exynos_crtc->ops->dpms(exynos_crtc, mode); - exynos_crtc->dpms = mode; + if (exynos_crtc->ops->enable) + exynos_crtc->ops->enable(exynos_crtc); - if (mode == DRM_MODE_DPMS_ON) - drm_crtc_vblank_on(crtc); -} + exynos_crtc->enabled = true; -static void exynos_drm_crtc_prepare(struct drm_crtc *crtc) -{ - /* drm framework doesn't check NULL. */ + drm_crtc_vblank_on(crtc); } -static void exynos_drm_crtc_commit(struct drm_crtc *crtc) +static void exynos_drm_crtc_disable(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); - struct exynos_drm_plane *exynos_plane = to_exynos_plane(crtc->primary); - exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON); + if (!exynos_crtc->enabled) + return; - if (exynos_crtc->ops->win_commit) - exynos_crtc->ops->win_commit(exynos_crtc, exynos_plane->zpos); + /* wait for the completion of page flip. */ + if (!wait_event_timeout(exynos_crtc->pending_flip_queue, + (exynos_crtc->event == NULL), HZ/20)) + exynos_crtc->event = NULL; - if (exynos_crtc->ops->commit) - exynos_crtc->ops->commit(exynos_crtc); + drm_crtc_vblank_off(crtc); + + if (exynos_crtc->ops->disable) + exynos_crtc->ops->disable(exynos_crtc); + + exynos_crtc->enabled = false; } static bool @@ -81,145 +71,38 @@ exynos_drm_crtc_mode_fixup(struct drm_crtc *crtc, return true; } -static int -exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, int x, int y, - struct drm_framebuffer *old_fb) +static void +exynos_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) { - struct drm_framebuffer *fb = crtc->primary->fb; - unsigned int crtc_w; - unsigned int crtc_h; - int ret; - - /* - * copy the mode data adjusted by mode_fixup() into crtc->mode - * so that hardware can be seet to proper mode. - */ - memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode)); - - ret = exynos_check_plane(crtc->primary, fb); - if (ret < 0) - return ret; - - crtc_w = fb->width - x; - crtc_h = fb->height - y; - exynos_plane_mode_set(crtc->primary, crtc, fb, 0, 0, - crtc_w, crtc_h, x, y, crtc_w, crtc_h); + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); - return 0; + if (exynos_crtc->ops->commit) + exynos_crtc->ops->commit(exynos_crtc); } -static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, - struct drm_framebuffer *old_fb) +static void exynos_crtc_atomic_begin(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); - struct drm_framebuffer *fb = crtc->primary->fb; - unsigned int crtc_w; - unsigned int crtc_h; - /* when framebuffer changing is requested, crtc's dpms should be on */ - if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) { - DRM_ERROR("failed framebuffer changing request.\n"); - return -EPERM; + if (crtc->state->event) { + WARN_ON(drm_crtc_vblank_get(crtc) != 0); + exynos_crtc->event = crtc->state->event; } - - crtc_w = fb->width - x; - crtc_h = fb->height - y; - - return exynos_update_plane(crtc->primary, crtc, fb, 0, 0, - crtc_w, crtc_h, x, y, crtc_w, crtc_h); } -static void exynos_drm_crtc_disable(struct drm_crtc *crtc) +static void exynos_crtc_atomic_flush(struct drm_crtc *crtc) { - struct drm_plane *plane; - int ret; - - exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); - - drm_for_each_legacy_plane(plane, &crtc->dev->mode_config.plane_list) { - if (plane->crtc != crtc) - continue; - - ret = plane->funcs->disable_plane(plane); - if (ret) - DRM_ERROR("Failed to disable plane %d\n", ret); - } } static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { - .dpms = exynos_drm_crtc_dpms, - .prepare = exynos_drm_crtc_prepare, - .commit = exynos_drm_crtc_commit, - .mode_fixup = exynos_drm_crtc_mode_fixup, - .mode_set = exynos_drm_crtc_mode_set, - .mode_set_base = exynos_drm_crtc_mode_set_base, + .enable = exynos_drm_crtc_enable, .disable = exynos_drm_crtc_disable, + .mode_fixup = exynos_drm_crtc_mode_fixup, + .mode_set_nofb = exynos_drm_crtc_mode_set_nofb, + .atomic_begin = exynos_crtc_atomic_begin, + .atomic_flush = exynos_crtc_atomic_flush, }; -static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, - struct drm_framebuffer *fb, - struct drm_pending_vblank_event *event, - uint32_t page_flip_flags) -{ - struct drm_device *dev = crtc->dev; - struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); - struct drm_framebuffer *old_fb = crtc->primary->fb; - unsigned int crtc_w, crtc_h; - int ret; - - /* when the page flip is requested, crtc's dpms should be on */ - if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) { - DRM_ERROR("failed page flip request.\n"); - return -EINVAL; - } - - if (!event) - return -EINVAL; - - spin_lock_irq(&dev->event_lock); - if (exynos_crtc->event) { - ret = -EBUSY; - goto out; - } - - ret = drm_vblank_get(dev, exynos_crtc->pipe); - if (ret) { - DRM_DEBUG("failed to acquire vblank counter\n"); - goto out; - } - - exynos_crtc->event = event; - spin_unlock_irq(&dev->event_lock); - - /* - * the pipe from user always is 0 so we can set pipe number - * of current owner to event. - */ - event->pipe = exynos_crtc->pipe; - - crtc->primary->fb = fb; - crtc_w = fb->width - crtc->x; - crtc_h = fb->height - crtc->y; - ret = exynos_update_plane(crtc->primary, crtc, fb, 0, 0, - crtc_w, crtc_h, crtc->x, crtc->y, - crtc_w, crtc_h); - if (ret) { - crtc->primary->fb = old_fb; - spin_lock_irq(&dev->event_lock); - exynos_crtc->event = NULL; - drm_vblank_put(dev, exynos_crtc->pipe); - spin_unlock_irq(&dev->event_lock); - return ret; - } - - return 0; - -out: - spin_unlock_irq(&dev->event_lock); - return ret; -} - static void exynos_drm_crtc_destroy(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); @@ -232,9 +115,12 @@ static void exynos_drm_crtc_destroy(struct drm_crtc *crtc) } static struct drm_crtc_funcs exynos_crtc_funcs = { - .set_config = drm_crtc_helper_set_config, - .page_flip = exynos_drm_crtc_page_flip, + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, .destroy = exynos_drm_crtc_destroy, + .reset = drm_atomic_helper_crtc_reset, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, }; struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, @@ -255,7 +141,6 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, init_waitqueue_head(&exynos_crtc->pending_flip_queue); - exynos_crtc->dpms = DRM_MODE_DPMS_OFF; exynos_crtc->pipe = pipe; exynos_crtc->type = type; exynos_crtc->ops = ops; @@ -286,7 +171,7 @@ int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe) struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(private->crtc[pipe]); - if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) + if (!exynos_crtc->enabled) return -EPERM; if (exynos_crtc->ops->enable_vblank) @@ -301,7 +186,7 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe) struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(private->crtc[pipe]); - if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) + if (!exynos_crtc->enabled) return; if (exynos_crtc->ops->disable_vblank) diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c index 37678cf4425a..7cb6595c1894 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c @@ -13,6 +13,7 @@ #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_panel.h> +#include <drm/drm_atomic_helper.h> #include <linux/regulator/consumer.h> @@ -59,10 +60,13 @@ static void exynos_dpi_connector_destroy(struct drm_connector *connector) } static struct drm_connector_funcs exynos_dpi_connector_funcs = { - .dpms = drm_helper_connector_dpms, + .dpms = drm_atomic_helper_connector_dpms, .detect = exynos_dpi_detect, .fill_modes = drm_helper_probe_single_connector_modes, .destroy = exynos_dpi_connector_destroy, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; static int exynos_dpi_get_modes(struct drm_connector *connector) @@ -309,33 +313,19 @@ struct exynos_drm_display *exynos_dpi_probe(struct device *dev) ctx->dev = dev; ctx->dpms_mode = DRM_MODE_DPMS_OFF; - ret = exynos_drm_component_add(dev, - EXYNOS_DEVICE_TYPE_CONNECTOR, - ctx->display.type); - if (ret) - return ERR_PTR(ret); - ret = exynos_dpi_parse_dt(ctx); if (ret < 0) { devm_kfree(dev, ctx); - goto err_del_component; + return NULL; } if (ctx->panel_node) { ctx->panel = of_drm_find_panel(ctx->panel_node); - if (!ctx->panel) { - exynos_drm_component_del(dev, - EXYNOS_DEVICE_TYPE_CONNECTOR); + if (!ctx->panel) return ERR_PTR(-EPROBE_DEFER); - } } return &ctx->display; - -err_del_component: - exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CONNECTOR); - - return NULL; } int exynos_dpi_remove(struct exynos_drm_display *display) @@ -347,7 +337,5 @@ int exynos_dpi_remove(struct exynos_drm_display *display) if (ctx->panel) drm_panel_detach(ctx->panel); - exynos_drm_component_del(ctx->dev, EXYNOS_DEVICE_TYPE_CONNECTOR); - return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 8ac465208eae..63a68c60a353 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -38,19 +38,6 @@ #define DRIVER_MAJOR 1 #define DRIVER_MINOR 0 -static struct platform_device *exynos_drm_pdev; - -static DEFINE_MUTEX(drm_component_lock); -static LIST_HEAD(drm_component_list); - -struct component_dev { - struct list_head list; - struct device *crtc_dev; - struct device *conn_dev; - enum exynos_drm_output_type out_type; - unsigned int dev_type_flag; -}; - static int exynos_drm_load(struct drm_device *dev, unsigned long flags) { struct exynos_drm_private *private; @@ -98,6 +85,8 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags) if (ret) goto err_cleanup_vblank; + drm_mode_config_reset(dev); + /* * enable drm irq mode. * - with irq_enabled = true, we can use the vblank feature. @@ -348,190 +337,29 @@ static const struct dev_pm_ops exynos_drm_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(exynos_drm_sys_suspend, exynos_drm_sys_resume) }; -int exynos_drm_component_add(struct device *dev, - enum exynos_drm_device_type dev_type, - enum exynos_drm_output_type out_type) -{ - struct component_dev *cdev; - - if (dev_type != EXYNOS_DEVICE_TYPE_CRTC && - dev_type != EXYNOS_DEVICE_TYPE_CONNECTOR) { - DRM_ERROR("invalid device type.\n"); - return -EINVAL; - } - - mutex_lock(&drm_component_lock); - - /* - * Make sure to check if there is a component which has two device - * objects, for connector and for encoder/connector. - * It should make sure that crtc and encoder/connector drivers are - * ready before exynos drm core binds them. - */ - list_for_each_entry(cdev, &drm_component_list, list) { - if (cdev->out_type == out_type) { - /* - * If crtc and encoder/connector device objects are - * added already just return. - */ - if (cdev->dev_type_flag == (EXYNOS_DEVICE_TYPE_CRTC | - EXYNOS_DEVICE_TYPE_CONNECTOR)) { - mutex_unlock(&drm_component_lock); - return 0; - } - - if (dev_type == EXYNOS_DEVICE_TYPE_CRTC) { - cdev->crtc_dev = dev; - cdev->dev_type_flag |= dev_type; - } - - if (dev_type == EXYNOS_DEVICE_TYPE_CONNECTOR) { - cdev->conn_dev = dev; - cdev->dev_type_flag |= dev_type; - } - - mutex_unlock(&drm_component_lock); - return 0; - } - } - - mutex_unlock(&drm_component_lock); - - cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); - if (!cdev) - return -ENOMEM; - - if (dev_type == EXYNOS_DEVICE_TYPE_CRTC) - cdev->crtc_dev = dev; - if (dev_type == EXYNOS_DEVICE_TYPE_CONNECTOR) - cdev->conn_dev = dev; - - cdev->out_type = out_type; - cdev->dev_type_flag = dev_type; - - mutex_lock(&drm_component_lock); - list_add_tail(&cdev->list, &drm_component_list); - mutex_unlock(&drm_component_lock); - - return 0; -} - -void exynos_drm_component_del(struct device *dev, - enum exynos_drm_device_type dev_type) -{ - struct component_dev *cdev, *next; - - mutex_lock(&drm_component_lock); - - list_for_each_entry_safe(cdev, next, &drm_component_list, list) { - if (dev_type == EXYNOS_DEVICE_TYPE_CRTC) { - if (cdev->crtc_dev == dev) { - cdev->crtc_dev = NULL; - cdev->dev_type_flag &= ~dev_type; - } - } - - if (dev_type == EXYNOS_DEVICE_TYPE_CONNECTOR) { - if (cdev->conn_dev == dev) { - cdev->conn_dev = NULL; - cdev->dev_type_flag &= ~dev_type; - } - } - - /* - * Release cdev object only in case that both of crtc and - * encoder/connector device objects are NULL. - */ - if (!cdev->crtc_dev && !cdev->conn_dev) { - list_del(&cdev->list); - kfree(cdev); - } - } - - mutex_unlock(&drm_component_lock); -} - -static int compare_dev(struct device *dev, void *data) -{ - return dev == (struct device *)data; -} - -static struct component_match *exynos_drm_match_add(struct device *dev) -{ - struct component_match *match = NULL; - struct component_dev *cdev; - unsigned int attach_cnt = 0; - - mutex_lock(&drm_component_lock); - - /* Do not retry to probe if there is no any kms driver regitered. */ - if (list_empty(&drm_component_list)) { - mutex_unlock(&drm_component_lock); - return ERR_PTR(-ENODEV); - } - - list_for_each_entry(cdev, &drm_component_list, list) { - /* - * Add components to master only in case that crtc and - * encoder/connector device objects exist. - */ - if (!cdev->crtc_dev || !cdev->conn_dev) - continue; - - attach_cnt++; - - mutex_unlock(&drm_component_lock); - - /* - * fimd and dpi modules have same device object so add - * only crtc device object in this case. - */ - if (cdev->crtc_dev == cdev->conn_dev) { - component_match_add(dev, &match, compare_dev, - cdev->crtc_dev); - goto out_lock; - } - - /* - * Do not chage below call order. - * crtc device first should be added to master because - * connector/encoder need pipe number of crtc when they - * are created. - */ - component_match_add(dev, &match, compare_dev, cdev->crtc_dev); - component_match_add(dev, &match, compare_dev, cdev->conn_dev); - -out_lock: - mutex_lock(&drm_component_lock); - } - - mutex_unlock(&drm_component_lock); - - return attach_cnt ? match : ERR_PTR(-EPROBE_DEFER); -} - -static int exynos_drm_bind(struct device *dev) -{ - return drm_platform_init(&exynos_drm_driver, to_platform_device(dev)); -} - -static void exynos_drm_unbind(struct device *dev) -{ - drm_put_dev(dev_get_drvdata(dev)); -} - -static const struct component_master_ops exynos_drm_ops = { - .bind = exynos_drm_bind, - .unbind = exynos_drm_unbind, -}; +/* forward declaration */ +static struct platform_driver exynos_drm_platform_driver; +/* + * Connector drivers should not be placed before associated crtc drivers, + * because connector requires pipe number of its crtc during initialization. + */ static struct platform_driver *const exynos_drm_kms_drivers[] = { +#ifdef CONFIG_DRM_EXYNOS_VIDI + &vidi_driver, +#endif #ifdef CONFIG_DRM_EXYNOS_FIMD &fimd_driver, #endif +#ifdef CONFIG_DRM_EXYNOS5433_DECON + &exynos5433_decon_driver, +#endif #ifdef CONFIG_DRM_EXYNOS7_DECON &decon_driver, #endif +#ifdef CONFIG_DRM_EXYNOS_MIC + &mic_driver, +#endif #ifdef CONFIG_DRM_EXYNOS_DP &dp_driver, #endif @@ -560,6 +388,59 @@ static struct platform_driver *const exynos_drm_non_kms_drivers[] = { #ifdef CONFIG_DRM_EXYNOS_IPP &ipp_driver, #endif + &exynos_drm_platform_driver, +}; + +static struct platform_driver *const exynos_drm_drv_with_simple_dev[] = { +#ifdef CONFIG_DRM_EXYNOS_VIDI + &vidi_driver, +#endif +#ifdef CONFIG_DRM_EXYNOS_IPP + &ipp_driver, +#endif + &exynos_drm_platform_driver, +}; +#define PDEV_COUNT ARRAY_SIZE(exynos_drm_drv_with_simple_dev) + +static int compare_dev(struct device *dev, void *data) +{ + return dev == (struct device *)data; +} + +static struct component_match *exynos_drm_match_add(struct device *dev) +{ + struct component_match *match = NULL; + int i; + + for (i = 0; i < ARRAY_SIZE(exynos_drm_kms_drivers); ++i) { + struct device_driver *drv = &exynos_drm_kms_drivers[i]->driver; + struct device *p = NULL, *d; + + while ((d = bus_find_device(&platform_bus_type, p, drv, + (void *)platform_bus_type.match))) { + put_device(p); + component_match_add(dev, &match, compare_dev, d); + p = d; + } + put_device(p); + } + + return match ?: ERR_PTR(-ENODEV); +} + +static int exynos_drm_bind(struct device *dev) +{ + return drm_platform_init(&exynos_drm_driver, to_platform_device(dev)); +} + +static void exynos_drm_unbind(struct device *dev) +{ + drm_put_dev(dev_get_drvdata(dev)); +} + +static const struct component_master_ops exynos_drm_ops = { + .bind = exynos_drm_bind, + .unbind = exynos_drm_unbind, }; static int exynos_drm_platform_probe(struct platform_device *pdev) @@ -570,9 +451,8 @@ static int exynos_drm_platform_probe(struct platform_device *pdev) exynos_drm_driver.num_ioctls = ARRAY_SIZE(exynos_ioctls); match = exynos_drm_match_add(&pdev->dev); - if (IS_ERR(match)) { + if (IS_ERR(match)) return PTR_ERR(match); - } return component_master_add_with_match(&pdev->dev, &exynos_drm_ops, match); @@ -584,13 +464,6 @@ static int exynos_drm_platform_remove(struct platform_device *pdev) return 0; } -static const char * const strings[] = { - "samsung,exynos3", - "samsung,exynos4", - "samsung,exynos5", - "samsung,exynos7", -}; - static struct platform_driver exynos_drm_platform_driver = { .probe = exynos_drm_platform_probe, .remove = exynos_drm_platform_remove, @@ -600,101 +473,125 @@ static struct platform_driver exynos_drm_platform_driver = { }, }; -static int exynos_drm_init(void) +static struct platform_device *exynos_drm_pdevs[PDEV_COUNT]; + +static void exynos_drm_unregister_devices(void) { - bool is_exynos = false; - int ret, i, j; + int i = PDEV_COUNT; - /* - * Register device object only in case of Exynos SoC. - * - * Below codes resolves temporarily infinite loop issue incurred - * by Exynos drm driver when using multi-platform kernel. - * So these codes will be replaced with more generic way later. - */ - for (i = 0; i < ARRAY_SIZE(strings); i++) { - if (of_machine_is_compatible(strings[i])) { - is_exynos = true; - break; - } + while (--i >= 0) { + platform_device_unregister(exynos_drm_pdevs[i]); + exynos_drm_pdevs[i] = NULL; } +} - if (!is_exynos) - return -ENODEV; +static int exynos_drm_register_devices(void) +{ + int i; - exynos_drm_pdev = platform_device_register_simple("exynos-drm", -1, - NULL, 0); - if (IS_ERR(exynos_drm_pdev)) - return PTR_ERR(exynos_drm_pdev); + for (i = 0; i < PDEV_COUNT; ++i) { + struct platform_driver *d = exynos_drm_drv_with_simple_dev[i]; + struct platform_device *pdev = + platform_device_register_simple(d->driver.name, -1, + NULL, 0); - ret = exynos_drm_probe_vidi(); - if (ret < 0) - goto err_unregister_pd; + if (!IS_ERR(pdev)) { + exynos_drm_pdevs[i] = pdev; + continue; + } + while (--i >= 0) { + platform_device_unregister(exynos_drm_pdevs[i]); + exynos_drm_pdevs[i] = NULL; + } - for (i = 0; i < ARRAY_SIZE(exynos_drm_kms_drivers); ++i) { - ret = platform_driver_register(exynos_drm_kms_drivers[i]); - if (ret < 0) - goto err_unregister_kms_drivers; + return PTR_ERR(pdev); } - for (j = 0; j < ARRAY_SIZE(exynos_drm_non_kms_drivers); ++j) { - ret = platform_driver_register(exynos_drm_non_kms_drivers[j]); - if (ret < 0) - goto err_unregister_non_kms_drivers; - } + return 0; +} -#ifdef CONFIG_DRM_EXYNOS_IPP - ret = exynos_platform_device_ipp_register(); - if (ret < 0) - goto err_unregister_non_kms_drivers; -#endif +static void exynos_drm_unregister_drivers(struct platform_driver * const *drv, + int count) +{ + while (--count >= 0) + platform_driver_unregister(drv[count]); +} - ret = platform_driver_register(&exynos_drm_platform_driver); - if (ret) - goto err_unregister_resources; +static int exynos_drm_register_drivers(struct platform_driver * const *drv, + int count) +{ + int i, ret; - return 0; + for (i = 0; i < count; ++i) { + ret = platform_driver_register(drv[i]); + if (!ret) + continue; -err_unregister_resources: -#ifdef CONFIG_DRM_EXYNOS_IPP - exynos_platform_device_ipp_unregister(); -#endif + while (--i >= 0) + platform_driver_unregister(drv[i]); -err_unregister_non_kms_drivers: - while (--j >= 0) - platform_driver_unregister(exynos_drm_non_kms_drivers[j]); + return ret; + } -err_unregister_kms_drivers: - while (--i >= 0) - platform_driver_unregister(exynos_drm_kms_drivers[i]); + return 0; +} - exynos_drm_remove_vidi(); +static inline int exynos_drm_register_kms_drivers(void) +{ + return exynos_drm_register_drivers(exynos_drm_kms_drivers, + ARRAY_SIZE(exynos_drm_kms_drivers)); +} -err_unregister_pd: - platform_device_unregister(exynos_drm_pdev); +static inline int exynos_drm_register_non_kms_drivers(void) +{ + return exynos_drm_register_drivers(exynos_drm_non_kms_drivers, + ARRAY_SIZE(exynos_drm_non_kms_drivers)); +} - return ret; +static inline void exynos_drm_unregister_kms_drivers(void) +{ + exynos_drm_unregister_drivers(exynos_drm_kms_drivers, + ARRAY_SIZE(exynos_drm_kms_drivers)); } -static void exynos_drm_exit(void) +static inline void exynos_drm_unregister_non_kms_drivers(void) { - int i; + exynos_drm_unregister_drivers(exynos_drm_non_kms_drivers, + ARRAY_SIZE(exynos_drm_non_kms_drivers)); +} -#ifdef CONFIG_DRM_EXYNOS_IPP - exynos_platform_device_ipp_unregister(); -#endif +static int exynos_drm_init(void) +{ + int ret; - for (i = ARRAY_SIZE(exynos_drm_non_kms_drivers) - 1; i >= 0; --i) - platform_driver_unregister(exynos_drm_non_kms_drivers[i]); + ret = exynos_drm_register_devices(); + if (ret) + return ret; - for (i = ARRAY_SIZE(exynos_drm_kms_drivers) - 1; i >= 0; --i) - platform_driver_unregister(exynos_drm_kms_drivers[i]); + ret = exynos_drm_register_kms_drivers(); + if (ret) + goto err_unregister_pdevs; - platform_driver_unregister(&exynos_drm_platform_driver); + ret = exynos_drm_register_non_kms_drivers(); + if (ret) + goto err_unregister_kms_drivers; + + return 0; + +err_unregister_kms_drivers: + exynos_drm_unregister_kms_drivers(); - exynos_drm_remove_vidi(); +err_unregister_pdevs: + exynos_drm_unregister_devices(); - platform_device_unregister(exynos_drm_pdev); + return ret; +} + +static void exynos_drm_exit(void) +{ + exynos_drm_unregister_non_kms_drivers(); + exynos_drm_unregister_kms_drivers(); + exynos_drm_unregister_devices(); } module_init(exynos_drm_init); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 29e3fb78c615..dd00f160c1e5 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -25,13 +25,6 @@ #define to_exynos_crtc(x) container_of(x, struct exynos_drm_crtc, base) #define to_exynos_plane(x) container_of(x, struct exynos_drm_plane, base) -/* This enumerates device type. */ -enum exynos_drm_device_type { - EXYNOS_DEVICE_TYPE_NONE, - EXYNOS_DEVICE_TYPE_CRTC, - EXYNOS_DEVICE_TYPE_CONNECTOR, -}; - /* this enumerates display type. */ enum exynos_drm_output_type { EXYNOS_DISPLAY_TYPE_NONE, @@ -71,8 +64,6 @@ enum exynos_drm_output_type { * @dma_addr: array of bus(accessed by dma) address to the memory region * allocated for a overlay. * @zpos: order of overlay layer(z position). - * @enabled: enabled or not. - * @resume: to resume or not. * * this structure is common to exynos SoC and its contents would be copied * to hardware specific overlay info. @@ -101,9 +92,6 @@ struct exynos_drm_plane { uint32_t pixel_format; dma_addr_t dma_addr[MAX_FB_BUFFER]; unsigned int zpos; - - bool enabled:1; - bool resume:1; }; /* @@ -157,7 +145,8 @@ struct exynos_drm_display { /* * Exynos drm crtc ops * - * @dpms: control device power. + * @enable: enable the device + * @disable: disable the device * @mode_fixup: fix mode data before applying it * @commit: set current hw specific display mode to hw. * @enable_vblank: specific driver callback for enabling vblank interrupt. @@ -175,7 +164,8 @@ struct exynos_drm_display { */ struct exynos_drm_crtc; struct exynos_drm_crtc_ops { - void (*dpms)(struct exynos_drm_crtc *crtc, int mode); + void (*enable)(struct exynos_drm_crtc *crtc); + void (*disable)(struct exynos_drm_crtc *crtc); bool (*mode_fixup)(struct exynos_drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); @@ -187,6 +177,7 @@ struct exynos_drm_crtc_ops { void (*win_disable)(struct exynos_drm_crtc *crtc, unsigned int zpos); void (*te_handler)(struct exynos_drm_crtc *crtc); void (*clock_enable)(struct exynos_drm_crtc *crtc, bool enable); + void (*clear_channels)(struct exynos_drm_crtc *crtc); }; /* @@ -201,7 +192,7 @@ struct exynos_drm_crtc_ops { * drm framework doesn't support multiple irq yet. * we can refer to the crtc to current hardware interrupt occurred through * this pipe value. - * @dpms: store the crtc dpms value + * @enabled: if the crtc is enabled or not * @event: vblank event that is currently queued for flip * @ops: pointer to callbacks for exynos drm specific functionality * @ctx: A pointer to the crtc's implementation specific context @@ -210,7 +201,7 @@ struct exynos_drm_crtc { struct drm_crtc base; enum exynos_drm_output_type type; unsigned int pipe; - unsigned int dpms; + bool enabled; wait_queue_head_t pending_flip_queue; struct drm_pending_vblank_event *event; const struct exynos_drm_crtc_ops *ops; @@ -293,15 +284,6 @@ int exynos_drm_device_subdrv_remove(struct drm_device *dev); int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file); void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file); -#ifdef CONFIG_DRM_EXYNOS_IPP -int exynos_platform_device_ipp_register(void); -void exynos_platform_device_ipp_unregister(void); -#else -static inline int exynos_platform_device_ipp_register(void) { return 0; } -static inline void exynos_platform_device_ipp_unregister(void) {} -#endif - - #ifdef CONFIG_DRM_EXYNOS_DPI struct exynos_drm_display * exynos_dpi_probe(struct device *dev); int exynos_dpi_remove(struct exynos_drm_display *display); @@ -314,26 +296,12 @@ static inline int exynos_dpi_remove(struct exynos_drm_display *display) } #endif -#ifdef CONFIG_DRM_EXYNOS_VIDI -int exynos_drm_probe_vidi(void); -void exynos_drm_remove_vidi(void); -#else -static inline int exynos_drm_probe_vidi(void) { return 0; } -static inline void exynos_drm_remove_vidi(void) {} -#endif - /* This function creates a encoder and a connector, and initializes them. */ int exynos_drm_create_enc_conn(struct drm_device *dev, struct exynos_drm_display *display); -int exynos_drm_component_add(struct device *dev, - enum exynos_drm_device_type dev_type, - enum exynos_drm_output_type out_type); - -void exynos_drm_component_del(struct device *dev, - enum exynos_drm_device_type dev_type); - extern struct platform_driver fimd_driver; +extern struct platform_driver exynos5433_decon_driver; extern struct platform_driver decon_driver; extern struct platform_driver dp_driver; extern struct platform_driver dsi_driver; @@ -346,4 +314,5 @@ extern struct platform_driver fimc_driver; extern struct platform_driver rotator_driver; extern struct platform_driver gsc_driver; extern struct platform_driver ipp_driver; +extern struct platform_driver mic_driver; #endif diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 04927153bf38..0e58b36cb8c2 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -14,12 +14,14 @@ #include <drm/drm_crtc_helper.h> #include <drm/drm_mipi_dsi.h> #include <drm/drm_panel.h> +#include <drm/drm_atomic_helper.h> #include <linux/clk.h> #include <linux/gpio/consumer.h> #include <linux/irq.h> #include <linux/of_device.h> #include <linux/of_gpio.h> +#include <linux/of_graph.h> #include <linux/phy/phy.h> #include <linux/regulator/consumer.h> #include <linux/component.h> @@ -33,38 +35,6 @@ /* returns true iff both arguments logically differs */ #define NEQV(a, b) (!(a) ^ !(b)) -#define DSIM_STATUS_REG 0x0 /* Status register */ -#define DSIM_SWRST_REG 0x4 /* Software reset register */ -#define DSIM_CLKCTRL_REG 0x8 /* Clock control register */ -#define DSIM_TIMEOUT_REG 0xc /* Time out register */ -#define DSIM_CONFIG_REG 0x10 /* Configuration register */ -#define DSIM_ESCMODE_REG 0x14 /* Escape mode register */ - -/* Main display image resolution register */ -#define DSIM_MDRESOL_REG 0x18 -#define DSIM_MVPORCH_REG 0x1c /* Main display Vporch register */ -#define DSIM_MHPORCH_REG 0x20 /* Main display Hporch register */ -#define DSIM_MSYNC_REG 0x24 /* Main display sync area register */ - -/* Sub display image resolution register */ -#define DSIM_SDRESOL_REG 0x28 -#define DSIM_INTSRC_REG 0x2c /* Interrupt source register */ -#define DSIM_INTMSK_REG 0x30 /* Interrupt mask register */ -#define DSIM_PKTHDR_REG 0x34 /* Packet Header FIFO register */ -#define DSIM_PAYLOAD_REG 0x38 /* Payload FIFO register */ -#define DSIM_RXFIFO_REG 0x3c /* Read FIFO register */ -#define DSIM_FIFOTHLD_REG 0x40 /* FIFO threshold level register */ -#define DSIM_FIFOCTRL_REG 0x44 /* FIFO status and control register */ - -/* FIFO memory AC characteristic register */ -#define DSIM_PLLCTRL_REG 0x4c /* PLL control register */ -#define DSIM_PHYACCHR_REG 0x54 /* D-PHY AC characteristic register */ -#define DSIM_PHYACCHR1_REG 0x58 /* D-PHY AC characteristic register1 */ -#define DSIM_PHYCTRL_REG 0x5c -#define DSIM_PHYTIMING_REG 0x64 -#define DSIM_PHYTIMING1_REG 0x68 -#define DSIM_PHYTIMING2_REG 0x6c - /* DSIM_STATUS */ #define DSIM_STOP_STATE_DAT(x) (((x) & 0xf) << 0) #define DSIM_STOP_STATE_CLK (1 << 8) @@ -128,8 +98,8 @@ /* DSIM_MDRESOL */ #define DSIM_MAIN_STAND_BY (1 << 31) -#define DSIM_MAIN_VRESOL(x) (((x) & 0x7ff) << 16) -#define DSIM_MAIN_HRESOL(x) (((x) & 0X7ff) << 0) +#define DSIM_MAIN_VRESOL(x, num_bits) (((x) & ((1 << (num_bits)) - 1)) << 16) +#define DSIM_MAIN_HRESOL(x, num_bits) (((x) & ((1 << (num_bits)) - 1)) << 0) /* DSIM_MVPORCH */ #define DSIM_CMD_ALLOW(x) ((x) << 28) @@ -163,6 +133,7 @@ #define DSIM_INT_PLL_STABLE (1 << 31) #define DSIM_INT_SW_RST_RELEASE (1 << 30) #define DSIM_INT_SFR_FIFO_EMPTY (1 << 29) +#define DSIM_INT_SFR_HDR_FIFO_EMPTY (1 << 28) #define DSIM_INT_BTA (1 << 25) #define DSIM_INT_FRAME_DONE (1 << 24) #define DSIM_INT_RX_TIMEOUT (1 << 21) @@ -211,6 +182,8 @@ /* DSIM_PHYCTRL */ #define DSIM_PHYCTRL_ULPS_EXIT(x) (((x) & 0x1ff) << 0) +#define DSIM_PHYCTRL_B_DPHYCTL_VREG_LP (1 << 30) +#define DSIM_PHYCTRL_B_DPHYCTL_SLEW_UP (1 << 14) /* DSIM_PHYTIMING */ #define DSIM_PHYTIMING_LPX(x) ((x) << 8) @@ -234,6 +207,18 @@ #define DSI_XFER_TIMEOUT_MS 100 #define DSI_RX_FIFO_EMPTY 0x30800002 +#define OLD_SCLK_MIPI_CLK_NAME "pll_clk" + +#define REG_ADDR(dsi, reg_idx) ((dsi)->reg_base + \ + dsi->driver_data->reg_ofs[(reg_idx)]) +#define DSI_WRITE(dsi, reg_idx, val) writel((val), \ + REG_ADDR((dsi), (reg_idx))) +#define DSI_READ(dsi, reg_idx) readl(REG_ADDR((dsi), (reg_idx))) + +static char *clk_names[5] = { "bus_clk", "sclk_mipi", + "phyclk_mipidphy0_bitclkdiv8", "phyclk_mipidphy0_rxclkesc0", + "sclk_rgb_vclk_to_dsim0" }; + enum exynos_dsi_transfer_type { EXYNOS_DSI_TX, EXYNOS_DSI_RX, @@ -259,12 +244,18 @@ struct exynos_dsi_transfer { #define DSIM_STATE_ENABLED BIT(0) #define DSIM_STATE_INITIALIZED BIT(1) #define DSIM_STATE_CMD_LPM BIT(2) +#define DSIM_STATE_VIDOUT_AVAILABLE BIT(3) struct exynos_dsi_driver_data { + unsigned int *reg_ofs; unsigned int plltmr_reg; - unsigned int has_freqband:1; unsigned int has_clklane_stop:1; + unsigned int num_clks; + unsigned int max_freq; + unsigned int wait_for_reset; + unsigned int num_bits_resol; + unsigned int *reg_values; }; struct exynos_dsi { @@ -277,8 +268,7 @@ struct exynos_dsi { void __iomem *reg_base; struct phy *phy; - struct clk *pll_clk; - struct clk *bus_clk; + struct clk **clks; struct regulator_bulk_data supplies[2]; int irq; int te_gpio; @@ -299,6 +289,7 @@ struct exynos_dsi { struct list_head transfer_list; struct exynos_dsi_driver_data *driver_data; + struct device_node *bridge_node; }; #define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host) @@ -309,25 +300,186 @@ static inline struct exynos_dsi *display_to_dsi(struct exynos_drm_display *d) return container_of(d, struct exynos_dsi, display); } +enum reg_idx { + DSIM_STATUS_REG, /* Status register */ + DSIM_SWRST_REG, /* Software reset register */ + DSIM_CLKCTRL_REG, /* Clock control register */ + DSIM_TIMEOUT_REG, /* Time out register */ + DSIM_CONFIG_REG, /* Configuration register */ + DSIM_ESCMODE_REG, /* Escape mode register */ + DSIM_MDRESOL_REG, + DSIM_MVPORCH_REG, /* Main display Vporch register */ + DSIM_MHPORCH_REG, /* Main display Hporch register */ + DSIM_MSYNC_REG, /* Main display sync area register */ + DSIM_INTSRC_REG, /* Interrupt source register */ + DSIM_INTMSK_REG, /* Interrupt mask register */ + DSIM_PKTHDR_REG, /* Packet Header FIFO register */ + DSIM_PAYLOAD_REG, /* Payload FIFO register */ + DSIM_RXFIFO_REG, /* Read FIFO register */ + DSIM_FIFOCTRL_REG, /* FIFO status and control register */ + DSIM_PLLCTRL_REG, /* PLL control register */ + DSIM_PHYCTRL_REG, + DSIM_PHYTIMING_REG, + DSIM_PHYTIMING1_REG, + DSIM_PHYTIMING2_REG, + NUM_REGS +}; +static unsigned int exynos_reg_ofs[] = { + [DSIM_STATUS_REG] = 0x00, + [DSIM_SWRST_REG] = 0x04, + [DSIM_CLKCTRL_REG] = 0x08, + [DSIM_TIMEOUT_REG] = 0x0c, + [DSIM_CONFIG_REG] = 0x10, + [DSIM_ESCMODE_REG] = 0x14, + [DSIM_MDRESOL_REG] = 0x18, + [DSIM_MVPORCH_REG] = 0x1c, + [DSIM_MHPORCH_REG] = 0x20, + [DSIM_MSYNC_REG] = 0x24, + [DSIM_INTSRC_REG] = 0x2c, + [DSIM_INTMSK_REG] = 0x30, + [DSIM_PKTHDR_REG] = 0x34, + [DSIM_PAYLOAD_REG] = 0x38, + [DSIM_RXFIFO_REG] = 0x3c, + [DSIM_FIFOCTRL_REG] = 0x44, + [DSIM_PLLCTRL_REG] = 0x4c, + [DSIM_PHYCTRL_REG] = 0x5c, + [DSIM_PHYTIMING_REG] = 0x64, + [DSIM_PHYTIMING1_REG] = 0x68, + [DSIM_PHYTIMING2_REG] = 0x6c, +}; + +static unsigned int exynos5433_reg_ofs[] = { + [DSIM_STATUS_REG] = 0x04, + [DSIM_SWRST_REG] = 0x0C, + [DSIM_CLKCTRL_REG] = 0x10, + [DSIM_TIMEOUT_REG] = 0x14, + [DSIM_CONFIG_REG] = 0x18, + [DSIM_ESCMODE_REG] = 0x1C, + [DSIM_MDRESOL_REG] = 0x20, + [DSIM_MVPORCH_REG] = 0x24, + [DSIM_MHPORCH_REG] = 0x28, + [DSIM_MSYNC_REG] = 0x2C, + [DSIM_INTSRC_REG] = 0x34, + [DSIM_INTMSK_REG] = 0x38, + [DSIM_PKTHDR_REG] = 0x3C, + [DSIM_PAYLOAD_REG] = 0x40, + [DSIM_RXFIFO_REG] = 0x44, + [DSIM_FIFOCTRL_REG] = 0x4C, + [DSIM_PLLCTRL_REG] = 0x94, + [DSIM_PHYCTRL_REG] = 0xA4, + [DSIM_PHYTIMING_REG] = 0xB4, + [DSIM_PHYTIMING1_REG] = 0xB8, + [DSIM_PHYTIMING2_REG] = 0xBC, +}; + +enum reg_value_idx { + RESET_TYPE, + PLL_TIMER, + STOP_STATE_CNT, + PHYCTRL_ULPS_EXIT, + PHYCTRL_VREG_LP, + PHYCTRL_SLEW_UP, + PHYTIMING_LPX, + PHYTIMING_HS_EXIT, + PHYTIMING_CLK_PREPARE, + PHYTIMING_CLK_ZERO, + PHYTIMING_CLK_POST, + PHYTIMING_CLK_TRAIL, + PHYTIMING_HS_PREPARE, + PHYTIMING_HS_ZERO, + PHYTIMING_HS_TRAIL +}; + +static unsigned int reg_values[] = { + [RESET_TYPE] = DSIM_SWRST, + [PLL_TIMER] = 500, + [STOP_STATE_CNT] = 0xf, + [PHYCTRL_ULPS_EXIT] = DSIM_PHYCTRL_ULPS_EXIT(0x0af), + [PHYCTRL_VREG_LP] = 0, + [PHYCTRL_SLEW_UP] = 0, + [PHYTIMING_LPX] = DSIM_PHYTIMING_LPX(0x06), + [PHYTIMING_HS_EXIT] = DSIM_PHYTIMING_HS_EXIT(0x0b), + [PHYTIMING_CLK_PREPARE] = DSIM_PHYTIMING1_CLK_PREPARE(0x07), + [PHYTIMING_CLK_ZERO] = DSIM_PHYTIMING1_CLK_ZERO(0x27), + [PHYTIMING_CLK_POST] = DSIM_PHYTIMING1_CLK_POST(0x0d), + [PHYTIMING_CLK_TRAIL] = DSIM_PHYTIMING1_CLK_TRAIL(0x08), + [PHYTIMING_HS_PREPARE] = DSIM_PHYTIMING2_HS_PREPARE(0x09), + [PHYTIMING_HS_ZERO] = DSIM_PHYTIMING2_HS_ZERO(0x0d), + [PHYTIMING_HS_TRAIL] = DSIM_PHYTIMING2_HS_TRAIL(0x0b), +}; + +static unsigned int exynos5433_reg_values[] = { + [RESET_TYPE] = DSIM_FUNCRST, + [PLL_TIMER] = 22200, + [STOP_STATE_CNT] = 0xa, + [PHYCTRL_ULPS_EXIT] = DSIM_PHYCTRL_ULPS_EXIT(0x190), + [PHYCTRL_VREG_LP] = DSIM_PHYCTRL_B_DPHYCTL_VREG_LP, + [PHYCTRL_SLEW_UP] = DSIM_PHYCTRL_B_DPHYCTL_SLEW_UP, + [PHYTIMING_LPX] = DSIM_PHYTIMING_LPX(0x07), + [PHYTIMING_HS_EXIT] = DSIM_PHYTIMING_HS_EXIT(0x0c), + [PHYTIMING_CLK_PREPARE] = DSIM_PHYTIMING1_CLK_PREPARE(0x09), + [PHYTIMING_CLK_ZERO] = DSIM_PHYTIMING1_CLK_ZERO(0x2d), + [PHYTIMING_CLK_POST] = DSIM_PHYTIMING1_CLK_POST(0x0e), + [PHYTIMING_CLK_TRAIL] = DSIM_PHYTIMING1_CLK_TRAIL(0x09), + [PHYTIMING_HS_PREPARE] = DSIM_PHYTIMING2_HS_PREPARE(0x0b), + [PHYTIMING_HS_ZERO] = DSIM_PHYTIMING2_HS_ZERO(0x10), + [PHYTIMING_HS_TRAIL] = DSIM_PHYTIMING2_HS_TRAIL(0x0c), +}; + static struct exynos_dsi_driver_data exynos3_dsi_driver_data = { + .reg_ofs = exynos_reg_ofs, .plltmr_reg = 0x50, .has_freqband = 1, .has_clklane_stop = 1, + .num_clks = 2, + .max_freq = 1000, + .wait_for_reset = 1, + .num_bits_resol = 11, + .reg_values = reg_values, }; static struct exynos_dsi_driver_data exynos4_dsi_driver_data = { + .reg_ofs = exynos_reg_ofs, .plltmr_reg = 0x50, .has_freqband = 1, .has_clklane_stop = 1, + .num_clks = 2, + .max_freq = 1000, + .wait_for_reset = 1, + .num_bits_resol = 11, + .reg_values = reg_values, }; static struct exynos_dsi_driver_data exynos4415_dsi_driver_data = { + .reg_ofs = exynos_reg_ofs, .plltmr_reg = 0x58, .has_clklane_stop = 1, + .num_clks = 2, + .max_freq = 1000, + .wait_for_reset = 1, + .num_bits_resol = 11, + .reg_values = reg_values, }; static struct exynos_dsi_driver_data exynos5_dsi_driver_data = { + .reg_ofs = exynos_reg_ofs, .plltmr_reg = 0x58, + .num_clks = 2, + .max_freq = 1000, + .wait_for_reset = 1, + .num_bits_resol = 11, + .reg_values = reg_values, +}; + +static struct exynos_dsi_driver_data exynos5433_dsi_driver_data = { + .reg_ofs = exynos5433_reg_ofs, + .plltmr_reg = 0xa0, + .has_clklane_stop = 1, + .num_clks = 5, + .max_freq = 1500, + .wait_for_reset = 0, + .num_bits_resol = 12, + .reg_values = exynos5433_reg_values, }; static struct of_device_id exynos_dsi_of_match[] = { @@ -339,6 +491,8 @@ static struct of_device_id exynos_dsi_of_match[] = { .data = &exynos4415_dsi_driver_data }, { .compatible = "samsung,exynos5410-mipi-dsi", .data = &exynos5_dsi_driver_data }, + { .compatible = "samsung,exynos5433-mipi-dsi", + .data = &exynos5433_dsi_driver_data }, { } }; @@ -361,8 +515,10 @@ static void exynos_dsi_wait_for_reset(struct exynos_dsi *dsi) static void exynos_dsi_reset(struct exynos_dsi *dsi) { + struct exynos_dsi_driver_data *driver_data = dsi->driver_data; + reinit_completion(&dsi->completed); - writel(DSIM_SWRST, dsi->reg_base + DSIM_SWRST_REG); + DSI_WRITE(dsi, DSIM_SWRST_REG, driver_data->reg_values[RESET_TYPE]); } #ifndef MHZ @@ -372,6 +528,7 @@ static void exynos_dsi_reset(struct exynos_dsi *dsi) static unsigned long exynos_dsi_pll_find_pms(struct exynos_dsi *dsi, unsigned long fin, unsigned long fout, u8 *p, u16 *m, u8 *s) { + struct exynos_dsi_driver_data *driver_data = dsi->driver_data; unsigned long best_freq = 0; u32 min_delta = 0xffffffff; u8 p_min, p_max; @@ -395,7 +552,8 @@ static unsigned long exynos_dsi_pll_find_pms(struct exynos_dsi *dsi, tmp = (u64)_m * fin; do_div(tmp, _p); - if (tmp < 500 * MHZ || tmp > 1000 * MHZ) + if (tmp < 500 * MHZ || + tmp > driver_data->max_freq * MHZ) continue; tmp = (u64)_m * fin; @@ -431,16 +589,7 @@ static unsigned long exynos_dsi_set_pll(struct exynos_dsi *dsi, u16 m; u32 reg; - clk_set_rate(dsi->pll_clk, dsi->pll_clk_rate); - - fin = clk_get_rate(dsi->pll_clk); - if (!fin) { - dev_err(dsi->dev, "failed to get PLL clock frequency\n"); - return 0; - } - - dev_dbg(dsi->dev, "PLL input frequency: %lu\n", fin); - + fin = dsi->pll_clk_rate; fout = exynos_dsi_pll_find_pms(dsi, fin, freq, &p, &m, &s); if (!fout) { dev_err(dsi->dev, @@ -449,7 +598,8 @@ static unsigned long exynos_dsi_set_pll(struct exynos_dsi *dsi, } dev_dbg(dsi->dev, "PLL freq %lu, (p %d, m %d, s %d)\n", fout, p, m, s); - writel(500, dsi->reg_base + driver_data->plltmr_reg); + writel(driver_data->reg_values[PLL_TIMER], + dsi->reg_base + driver_data->plltmr_reg); reg = DSIM_PLL_EN | DSIM_PLL_P(p) | DSIM_PLL_M(m) | DSIM_PLL_S(s); @@ -471,7 +621,7 @@ static unsigned long exynos_dsi_set_pll(struct exynos_dsi *dsi, reg |= DSIM_FREQ_BAND(band); } - writel(reg, dsi->reg_base + DSIM_PLLCTRL_REG); + DSI_WRITE(dsi, DSIM_PLLCTRL_REG, reg); timeout = 1000; do { @@ -479,7 +629,7 @@ static unsigned long exynos_dsi_set_pll(struct exynos_dsi *dsi, dev_err(dsi->dev, "PLL failed to stabilize\n"); return 0; } - reg = readl(dsi->reg_base + DSIM_STATUS_REG); + reg = DSI_READ(dsi, DSIM_STATUS_REG); } while ((reg & DSIM_PLL_STABLE) == 0); return fout; @@ -509,7 +659,7 @@ static int exynos_dsi_enable_clock(struct exynos_dsi *dsi) dev_dbg(dsi->dev, "hs_clk = %lu, byte_clk = %lu, esc_clk = %lu\n", hs_clk, byte_clk, esc_clk); - reg = readl(dsi->reg_base + DSIM_CLKCTRL_REG); + reg = DSI_READ(dsi, DSIM_CLKCTRL_REG); reg &= ~(DSIM_ESC_PRESCALER_MASK | DSIM_LANE_ESC_CLK_EN_CLK | DSIM_LANE_ESC_CLK_EN_DATA_MASK | DSIM_PLL_BYPASS | DSIM_BYTE_CLK_SRC_MASK); @@ -519,7 +669,7 @@ static int exynos_dsi_enable_clock(struct exynos_dsi *dsi) | DSIM_LANE_ESC_CLK_EN_DATA(BIT(dsi->lanes) - 1) | DSIM_BYTE_CLK_SRC(0) | DSIM_TX_REQUEST_HSCLK; - writel(reg, dsi->reg_base + DSIM_CLKCTRL_REG); + DSI_WRITE(dsi, DSIM_CLKCTRL_REG, reg); return 0; } @@ -527,22 +677,24 @@ static int exynos_dsi_enable_clock(struct exynos_dsi *dsi) static void exynos_dsi_set_phy_ctrl(struct exynos_dsi *dsi) { struct exynos_dsi_driver_data *driver_data = dsi->driver_data; + unsigned int *reg_values = driver_data->reg_values; u32 reg; if (driver_data->has_freqband) return; /* B D-PHY: D-PHY Master & Slave Analog Block control */ - reg = DSIM_PHYCTRL_ULPS_EXIT(0x0af); - writel(reg, dsi->reg_base + DSIM_PHYCTRL_REG); + reg = reg_values[PHYCTRL_ULPS_EXIT] | reg_values[PHYCTRL_VREG_LP] | + reg_values[PHYCTRL_SLEW_UP]; + DSI_WRITE(dsi, DSIM_PHYCTRL_REG, reg); /* * T LPX: Transmitted length of any Low-Power state period * T HS-EXIT: Time that the transmitter drives LP-11 following a HS * burst */ - reg = DSIM_PHYTIMING_LPX(0x06) | DSIM_PHYTIMING_HS_EXIT(0x0b); - writel(reg, dsi->reg_base + DSIM_PHYTIMING_REG); + reg = reg_values[PHYTIMING_LPX] | reg_values[PHYTIMING_HS_EXIT]; + DSI_WRITE(dsi, DSIM_PHYTIMING_REG, reg); /* * T CLK-PREPARE: Time that the transmitter drives the Clock Lane LP-00 @@ -557,11 +709,12 @@ static void exynos_dsi_set_phy_ctrl(struct exynos_dsi *dsi) * T CLK-TRAIL: Time that the transmitter drives the HS-0 state after * the last payload clock bit of a HS transmission burst */ - reg = DSIM_PHYTIMING1_CLK_PREPARE(0x07) | - DSIM_PHYTIMING1_CLK_ZERO(0x27) | - DSIM_PHYTIMING1_CLK_POST(0x0d) | - DSIM_PHYTIMING1_CLK_TRAIL(0x08); - writel(reg, dsi->reg_base + DSIM_PHYTIMING1_REG); + reg = reg_values[PHYTIMING_CLK_PREPARE] | + reg_values[PHYTIMING_CLK_ZERO] | + reg_values[PHYTIMING_CLK_POST] | + reg_values[PHYTIMING_CLK_TRAIL]; + + DSI_WRITE(dsi, DSIM_PHYTIMING1_REG, reg); /* * T HS-PREPARE: Time that the transmitter drives the Data Lane LP-00 @@ -572,23 +725,31 @@ static void exynos_dsi_set_phy_ctrl(struct exynos_dsi *dsi) * T HS-TRAIL: Time that the transmitter drives the flipped differential * state after last payload data bit of a HS transmission burst */ - reg = DSIM_PHYTIMING2_HS_PREPARE(0x09) | DSIM_PHYTIMING2_HS_ZERO(0x0d) | - DSIM_PHYTIMING2_HS_TRAIL(0x0b); - writel(reg, dsi->reg_base + DSIM_PHYTIMING2_REG); + reg = reg_values[PHYTIMING_HS_PREPARE] | reg_values[PHYTIMING_HS_ZERO] | + reg_values[PHYTIMING_HS_TRAIL]; + DSI_WRITE(dsi, DSIM_PHYTIMING2_REG, reg); } static void exynos_dsi_disable_clock(struct exynos_dsi *dsi) { u32 reg; - reg = readl(dsi->reg_base + DSIM_CLKCTRL_REG); + reg = DSI_READ(dsi, DSIM_CLKCTRL_REG); reg &= ~(DSIM_LANE_ESC_CLK_EN_CLK | DSIM_LANE_ESC_CLK_EN_DATA_MASK | DSIM_ESC_CLKEN | DSIM_BYTE_CLKEN); - writel(reg, dsi->reg_base + DSIM_CLKCTRL_REG); + DSI_WRITE(dsi, DSIM_CLKCTRL_REG, reg); - reg = readl(dsi->reg_base + DSIM_PLLCTRL_REG); + reg = DSI_READ(dsi, DSIM_PLLCTRL_REG); reg &= ~DSIM_PLL_EN; - writel(reg, dsi->reg_base + DSIM_PLLCTRL_REG); + DSI_WRITE(dsi, DSIM_PLLCTRL_REG, reg); +} + +static void exynos_dsi_enable_lane(struct exynos_dsi *dsi, u32 lane) +{ + u32 reg = DSI_READ(dsi, DSIM_CONFIG_REG); + reg |= (DSIM_NUM_OF_DATA_LANE(dsi->lanes - 1) | DSIM_LANE_EN_CLK | + DSIM_LANE_EN(lane)); + DSI_WRITE(dsi, DSIM_CONFIG_REG, reg); } static int exynos_dsi_init_link(struct exynos_dsi *dsi) @@ -599,15 +760,14 @@ static int exynos_dsi_init_link(struct exynos_dsi *dsi) u32 lanes_mask; /* Initialize FIFO pointers */ - reg = readl(dsi->reg_base + DSIM_FIFOCTRL_REG); + reg = DSI_READ(dsi, DSIM_FIFOCTRL_REG); reg &= ~0x1f; - writel(reg, dsi->reg_base + DSIM_FIFOCTRL_REG); + DSI_WRITE(dsi, DSIM_FIFOCTRL_REG, reg); usleep_range(9000, 11000); reg |= 0x1f; - writel(reg, dsi->reg_base + DSIM_FIFOCTRL_REG); - + DSI_WRITE(dsi, DSIM_FIFOCTRL_REG, reg); usleep_range(9000, 11000); /* DSI configuration */ @@ -664,17 +824,6 @@ static int exynos_dsi_init_link(struct exynos_dsi *dsi) return -EINVAL; } - reg |= DSIM_NUM_OF_DATA_LANE(dsi->lanes - 1); - - writel(reg, dsi->reg_base + DSIM_CONFIG_REG); - - reg |= DSIM_LANE_EN_CLK; - writel(reg, dsi->reg_base + DSIM_CONFIG_REG); - - lanes_mask = BIT(dsi->lanes) - 1; - reg |= DSIM_LANE_EN(lanes_mask); - writel(reg, dsi->reg_base + DSIM_CONFIG_REG); - /* * Use non-continuous clock mode if the periparal wants and * host controller supports @@ -686,8 +835,11 @@ static int exynos_dsi_init_link(struct exynos_dsi *dsi) if (driver_data->has_clklane_stop && dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) { reg |= DSIM_CLKLANE_STOP; - writel(reg, dsi->reg_base + DSIM_CONFIG_REG); } + DSI_WRITE(dsi, DSIM_CONFIG_REG, reg); + + lanes_mask = BIT(dsi->lanes) - 1; + exynos_dsi_enable_lane(dsi, lanes_mask); /* Check clock and data lane state are stop state */ timeout = 100; @@ -697,19 +849,19 @@ static int exynos_dsi_init_link(struct exynos_dsi *dsi) return -EFAULT; } - reg = readl(dsi->reg_base + DSIM_STATUS_REG); + reg = DSI_READ(dsi, DSIM_STATUS_REG); if ((reg & DSIM_STOP_STATE_DAT(lanes_mask)) != DSIM_STOP_STATE_DAT(lanes_mask)) continue; } while (!(reg & (DSIM_STOP_STATE_CLK | DSIM_TX_READY_HS_CLK))); - reg = readl(dsi->reg_base + DSIM_ESCMODE_REG); + reg = DSI_READ(dsi, DSIM_ESCMODE_REG); reg &= ~DSIM_STOP_STATE_CNT_MASK; - reg |= DSIM_STOP_STATE_CNT(0xf); - writel(reg, dsi->reg_base + DSIM_ESCMODE_REG); + reg |= DSIM_STOP_STATE_CNT(driver_data->reg_values[STOP_STATE_CNT]); + DSI_WRITE(dsi, DSIM_ESCMODE_REG, reg); reg = DSIM_BTA_TIMEOUT(0xff) | DSIM_LPDR_TIMEOUT(0xffff); - writel(reg, dsi->reg_base + DSIM_TIMEOUT_REG); + DSI_WRITE(dsi, DSIM_TIMEOUT_REG, reg); return 0; } @@ -717,25 +869,27 @@ static int exynos_dsi_init_link(struct exynos_dsi *dsi) static void exynos_dsi_set_display_mode(struct exynos_dsi *dsi) { struct videomode *vm = &dsi->vm; + unsigned int num_bits_resol = dsi->driver_data->num_bits_resol; u32 reg; if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { reg = DSIM_CMD_ALLOW(0xf) | DSIM_STABLE_VFP(vm->vfront_porch) | DSIM_MAIN_VBP(vm->vback_porch); - writel(reg, dsi->reg_base + DSIM_MVPORCH_REG); + DSI_WRITE(dsi, DSIM_MVPORCH_REG, reg); reg = DSIM_MAIN_HFP(vm->hfront_porch) | DSIM_MAIN_HBP(vm->hback_porch); - writel(reg, dsi->reg_base + DSIM_MHPORCH_REG); + DSI_WRITE(dsi, DSIM_MHPORCH_REG, reg); reg = DSIM_MAIN_VSA(vm->vsync_len) | DSIM_MAIN_HSA(vm->hsync_len); - writel(reg, dsi->reg_base + DSIM_MSYNC_REG); + DSI_WRITE(dsi, DSIM_MSYNC_REG, reg); } + reg = DSIM_MAIN_HRESOL(vm->hactive, num_bits_resol) | + DSIM_MAIN_VRESOL(vm->vactive, num_bits_resol); - reg = DSIM_MAIN_HRESOL(vm->hactive) | DSIM_MAIN_VRESOL(vm->vactive); - writel(reg, dsi->reg_base + DSIM_MDRESOL_REG); + DSI_WRITE(dsi, DSIM_MDRESOL_REG, reg); dev_dbg(dsi->dev, "LCD size = %dx%d\n", vm->hactive, vm->vactive); } @@ -744,12 +898,12 @@ static void exynos_dsi_set_display_enable(struct exynos_dsi *dsi, bool enable) { u32 reg; - reg = readl(dsi->reg_base + DSIM_MDRESOL_REG); + reg = DSI_READ(dsi, DSIM_MDRESOL_REG); if (enable) reg |= DSIM_MAIN_STAND_BY; else reg &= ~DSIM_MAIN_STAND_BY; - writel(reg, dsi->reg_base + DSIM_MDRESOL_REG); + DSI_WRITE(dsi, DSIM_MDRESOL_REG, reg); } static int exynos_dsi_wait_for_hdr_fifo(struct exynos_dsi *dsi) @@ -757,7 +911,7 @@ static int exynos_dsi_wait_for_hdr_fifo(struct exynos_dsi *dsi) int timeout = 2000; do { - u32 reg = readl(dsi->reg_base + DSIM_FIFOCTRL_REG); + u32 reg = DSI_READ(dsi, DSIM_FIFOCTRL_REG); if (!(reg & DSIM_SFR_HEADER_FULL)) return 0; @@ -771,22 +925,21 @@ static int exynos_dsi_wait_for_hdr_fifo(struct exynos_dsi *dsi) static void exynos_dsi_set_cmd_lpm(struct exynos_dsi *dsi, bool lpm) { - u32 v = readl(dsi->reg_base + DSIM_ESCMODE_REG); + u32 v = DSI_READ(dsi, DSIM_ESCMODE_REG); if (lpm) v |= DSIM_CMD_LPDT_LP; else v &= ~DSIM_CMD_LPDT_LP; - writel(v, dsi->reg_base + DSIM_ESCMODE_REG); + DSI_WRITE(dsi, DSIM_ESCMODE_REG, v); } static void exynos_dsi_force_bta(struct exynos_dsi *dsi) { - u32 v = readl(dsi->reg_base + DSIM_ESCMODE_REG); - + u32 v = DSI_READ(dsi, DSIM_ESCMODE_REG); v |= DSIM_FORCE_BTA; - writel(v, dsi->reg_base + DSIM_ESCMODE_REG); + DSI_WRITE(dsi, DSIM_ESCMODE_REG, v); } static void exynos_dsi_send_to_fifo(struct exynos_dsi *dsi, @@ -810,7 +963,7 @@ static void exynos_dsi_send_to_fifo(struct exynos_dsi *dsi, while (length >= 4) { reg = (payload[3] << 24) | (payload[2] << 16) | (payload[1] << 8) | payload[0]; - writel(reg, dsi->reg_base + DSIM_PAYLOAD_REG); + DSI_WRITE(dsi, DSIM_PAYLOAD_REG, reg); payload += 4; length -= 4; } @@ -825,7 +978,7 @@ static void exynos_dsi_send_to_fifo(struct exynos_dsi *dsi, /* Fall through */ case 1: reg |= payload[0]; - writel(reg, dsi->reg_base + DSIM_PAYLOAD_REG); + DSI_WRITE(dsi, DSIM_PAYLOAD_REG, reg); break; case 0: /* Do nothing */ @@ -848,7 +1001,7 @@ static void exynos_dsi_send_to_fifo(struct exynos_dsi *dsi, dsi->state ^= DSIM_STATE_CMD_LPM; } - writel(reg, dsi->reg_base + DSIM_PKTHDR_REG); + DSI_WRITE(dsi, DSIM_PKTHDR_REG, reg); if (xfer->flags & MIPI_DSI_MSG_REQ_ACK) exynos_dsi_force_bta(dsi); @@ -864,7 +1017,7 @@ static void exynos_dsi_read_from_fifo(struct exynos_dsi *dsi, u32 reg; if (first) { - reg = readl(dsi->reg_base + DSIM_RXFIFO_REG); + reg = DSI_READ(dsi, DSIM_RXFIFO_REG); switch (reg & 0x3f) { case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE: @@ -903,7 +1056,7 @@ static void exynos_dsi_read_from_fifo(struct exynos_dsi *dsi, /* Receive payload */ while (length >= 4) { - reg = readl(dsi->reg_base + DSIM_RXFIFO_REG); + reg = DSI_READ(dsi, DSIM_RXFIFO_REG); payload[0] = (reg >> 0) & 0xff; payload[1] = (reg >> 8) & 0xff; payload[2] = (reg >> 16) & 0xff; @@ -913,7 +1066,7 @@ static void exynos_dsi_read_from_fifo(struct exynos_dsi *dsi, } if (length) { - reg = readl(dsi->reg_base + DSIM_RXFIFO_REG); + reg = DSI_READ(dsi, DSIM_RXFIFO_REG); switch (length) { case 3: payload[2] = (reg >> 16) & 0xff; @@ -932,7 +1085,7 @@ static void exynos_dsi_read_from_fifo(struct exynos_dsi *dsi, clear_fifo: length = DSI_RX_FIFO_SIZE / 4; do { - reg = readl(dsi->reg_base + DSIM_RXFIFO_REG); + reg = DSI_READ(dsi, DSIM_RXFIFO_REG); if (reg == DSI_RX_FIFO_EMPTY) break; } while (--length); @@ -1088,23 +1241,26 @@ static irqreturn_t exynos_dsi_irq(int irq, void *dev_id) struct exynos_dsi *dsi = dev_id; u32 status; - status = readl(dsi->reg_base + DSIM_INTSRC_REG); + status = DSI_READ(dsi, DSIM_INTSRC_REG); if (!status) { static unsigned long int j; if (printk_timed_ratelimit(&j, 500)) dev_warn(dsi->dev, "spurious interrupt\n"); return IRQ_HANDLED; } - writel(status, dsi->reg_base + DSIM_INTSRC_REG); + DSI_WRITE(dsi, DSIM_INTSRC_REG, status); if (status & DSIM_INT_SW_RST_RELEASE) { - u32 mask = ~(DSIM_INT_RX_DONE | DSIM_INT_SFR_FIFO_EMPTY); - writel(mask, dsi->reg_base + DSIM_INTMSK_REG); + u32 mask = ~(DSIM_INT_RX_DONE | DSIM_INT_SFR_FIFO_EMPTY | + DSIM_INT_SFR_HDR_FIFO_EMPTY | DSIM_INT_FRAME_DONE | + DSIM_INT_RX_ECC_ERR | DSIM_INT_SW_RST_RELEASE); + DSI_WRITE(dsi, DSIM_INTMSK_REG, mask); complete(&dsi->completed); return IRQ_HANDLED; } - if (!(status & (DSIM_INT_RX_DONE | DSIM_INT_SFR_FIFO_EMPTY))) + if (!(status & (DSIM_INT_RX_DONE | DSIM_INT_SFR_FIFO_EMPTY | + DSIM_INT_FRAME_DONE | DSIM_INT_PLL_STABLE))) return IRQ_HANDLED; if (exynos_dsi_transfer_finish(dsi)) @@ -1118,7 +1274,7 @@ static irqreturn_t exynos_dsi_te_irq_handler(int irq, void *dev_id) struct exynos_dsi *dsi = (struct exynos_dsi *)dev_id; struct drm_encoder *encoder = dsi->display.encoder; - if (dsi->state & DSIM_STATE_ENABLED) + if (dsi->state & DSIM_STATE_VIDOUT_AVAILABLE) exynos_drm_crtc_te_handler(encoder->crtc); return IRQ_HANDLED; @@ -1142,10 +1298,17 @@ static void exynos_dsi_disable_irq(struct exynos_dsi *dsi) static int exynos_dsi_init(struct exynos_dsi *dsi) { + struct exynos_dsi_driver_data *driver_data = dsi->driver_data; + exynos_dsi_reset(dsi); exynos_dsi_enable_irq(dsi); + + if (driver_data->reg_values[RESET_TYPE] == DSIM_FUNCRST) + exynos_dsi_enable_lane(dsi, BIT(dsi->lanes) - 1); + exynos_dsi_enable_clock(dsi); - exynos_dsi_wait_for_reset(dsi); + if (driver_data->wait_for_reset) + exynos_dsi_wait_for_reset(dsi); exynos_dsi_set_phy_ctrl(dsi); exynos_dsi_init_link(dsi); @@ -1164,15 +1327,15 @@ static int exynos_dsi_register_te_irq(struct exynos_dsi *dsi) goto out; } - ret = gpio_request_one(dsi->te_gpio, GPIOF_IN, "te_gpio"); + ret = gpio_request(dsi->te_gpio, "te_gpio"); if (ret) { dev_err(dsi->dev, "gpio request failed with %d\n", ret); goto out; } te_gpio_irq = gpio_to_irq(dsi->te_gpio); - irq_set_status_flags(te_gpio_irq, IRQ_NOAUTOEN); + ret = request_threaded_irq(te_gpio_irq, exynos_dsi_te_irq_handler, NULL, IRQF_TRIGGER_RISING, "TE", dsi); if (ret) { @@ -1251,6 +1414,9 @@ static ssize_t exynos_dsi_host_transfer(struct mipi_dsi_host *host, struct exynos_dsi_transfer xfer; int ret; + if (!(dsi->state & DSIM_STATE_ENABLED)) + return -EINVAL; + if (!(dsi->state & DSIM_STATE_INITIALIZED)) { ret = exynos_dsi_init(dsi); if (ret) @@ -1294,7 +1460,8 @@ static const struct mipi_dsi_host_ops exynos_dsi_ops = { static int exynos_dsi_poweron(struct exynos_dsi *dsi) { - int ret; + struct exynos_dsi_driver_data *driver_data = dsi->driver_data; + int ret, i; ret = regulator_bulk_enable(ARRAY_SIZE(dsi->supplies), dsi->supplies); if (ret < 0) { @@ -1302,31 +1469,23 @@ static int exynos_dsi_poweron(struct exynos_dsi *dsi) return ret; } - ret = clk_prepare_enable(dsi->bus_clk); - if (ret < 0) { - dev_err(dsi->dev, "cannot enable bus clock %d\n", ret); - goto err_bus_clk; - } - - ret = clk_prepare_enable(dsi->pll_clk); - if (ret < 0) { - dev_err(dsi->dev, "cannot enable pll clock %d\n", ret); - goto err_pll_clk; + for (i = 0; i < driver_data->num_clks; i++) { + ret = clk_prepare_enable(dsi->clks[i]); + if (ret < 0) + goto err_clk; } ret = phy_power_on(dsi->phy); if (ret < 0) { dev_err(dsi->dev, "cannot enable phy %d\n", ret); - goto err_phy; + goto err_clk; } return 0; -err_phy: - clk_disable_unprepare(dsi->pll_clk); -err_pll_clk: - clk_disable_unprepare(dsi->bus_clk); -err_bus_clk: +err_clk: + while (--i > -1) + clk_disable_unprepare(dsi->clks[i]); regulator_bulk_disable(ARRAY_SIZE(dsi->supplies), dsi->supplies); return ret; @@ -1334,7 +1493,8 @@ err_bus_clk: static void exynos_dsi_poweroff(struct exynos_dsi *dsi) { - int ret; + struct exynos_dsi_driver_data *driver_data = dsi->driver_data; + int ret, i; usleep_range(10000, 20000); @@ -1350,8 +1510,8 @@ static void exynos_dsi_poweroff(struct exynos_dsi *dsi) phy_power_off(dsi->phy); - clk_disable_unprepare(dsi->pll_clk); - clk_disable_unprepare(dsi->bus_clk); + for (i = driver_data->num_clks - 1; i > -1; i--) + clk_disable_unprepare(dsi->clks[i]); ret = regulator_bulk_disable(ARRAY_SIZE(dsi->supplies), dsi->supplies); if (ret < 0) @@ -1369,8 +1529,11 @@ static int exynos_dsi_enable(struct exynos_dsi *dsi) if (ret < 0) return ret; + dsi->state |= DSIM_STATE_ENABLED; + ret = drm_panel_prepare(dsi->panel); if (ret < 0) { + dsi->state &= ~DSIM_STATE_ENABLED; exynos_dsi_poweroff(dsi); return ret; } @@ -1378,8 +1541,6 @@ static int exynos_dsi_enable(struct exynos_dsi *dsi) exynos_dsi_set_display_mode(dsi); exynos_dsi_set_display_enable(dsi, true); - dsi->state |= DSIM_STATE_ENABLED; - ret = drm_panel_enable(dsi->panel); if (ret < 0) { dsi->state &= ~DSIM_STATE_ENABLED; @@ -1389,6 +1550,8 @@ static int exynos_dsi_enable(struct exynos_dsi *dsi) return ret; } + dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE; + return 0; } @@ -1397,12 +1560,15 @@ static void exynos_dsi_disable(struct exynos_dsi *dsi) if (!(dsi->state & DSIM_STATE_ENABLED)) return; + dsi->state &= ~DSIM_STATE_VIDOUT_AVAILABLE; + drm_panel_disable(dsi->panel); exynos_dsi_set_display_enable(dsi, false); drm_panel_unprepare(dsi->panel); - exynos_dsi_poweroff(dsi); dsi->state &= ~DSIM_STATE_ENABLED; + + exynos_dsi_poweroff(dsi); } static void exynos_dsi_dpms(struct exynos_drm_display *display, int mode) @@ -1457,10 +1623,13 @@ static void exynos_dsi_connector_destroy(struct drm_connector *connector) } static struct drm_connector_funcs exynos_dsi_connector_funcs = { - .dpms = drm_helper_connector_dpms, + .dpms = drm_atomic_helper_connector_dpms, .detect = exynos_dsi_detect, .fill_modes = drm_helper_probe_single_connector_modes, .destroy = exynos_dsi_connector_destroy, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; static int exynos_dsi_get_modes(struct drm_connector *connector) @@ -1627,7 +1796,22 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi) ret = exynos_dsi_of_read_u32(ep, "samsung,esc-clock-frequency", &dsi->esc_clk_rate); + if (ret < 0) + goto end; + + of_node_put(ep); + + ep = of_graph_get_next_endpoint(node, NULL); + if (!ep) { + ret = -ENXIO; + goto end; + } + dsi->bridge_node = of_graph_get_remote_port_parent(ep); + if (!dsi->bridge_node) { + ret = -ENXIO; + goto end; + } end: of_node_put(ep); @@ -1640,6 +1824,7 @@ static int exynos_dsi_bind(struct device *dev, struct device *master, struct exynos_drm_display *display = dev_get_drvdata(dev); struct exynos_dsi *dsi = display_to_dsi(display); struct drm_device *drm_dev = data; + struct drm_bridge *bridge; int ret; ret = exynos_drm_create_enc_conn(drm_dev, display); @@ -1649,6 +1834,12 @@ static int exynos_dsi_bind(struct device *dev, struct device *master, return ret; } + bridge = of_drm_find_bridge(dsi->bridge_node); + if (bridge) { + display->encoder->bridge = bridge; + drm_bridge_attach(drm_dev, bridge); + } + return mipi_dsi_host_register(&dsi->dsi_host); } @@ -1673,7 +1864,7 @@ static int exynos_dsi_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct resource *res; struct exynos_dsi *dsi; - int ret; + int ret, i; dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL); if (!dsi) @@ -1682,11 +1873,6 @@ static int exynos_dsi_probe(struct platform_device *pdev) dsi->display.type = EXYNOS_DISPLAY_TYPE_LCD; dsi->display.ops = &exynos_dsi_display_ops; - ret = exynos_drm_component_add(dev, EXYNOS_DEVICE_TYPE_CONNECTOR, - dsi->display.type); - if (ret) - return ret; - /* To be checked as invalid one */ dsi->te_gpio = -ENOENT; @@ -1702,7 +1888,7 @@ static int exynos_dsi_probe(struct platform_device *pdev) ret = exynos_dsi_parse_dt(dsi); if (ret) - goto err_del_component; + return ret; dsi->supplies[0].supply = "vddcore"; dsi->supplies[1].supply = "vddio"; @@ -1713,40 +1899,44 @@ static int exynos_dsi_probe(struct platform_device *pdev) return -EPROBE_DEFER; } - dsi->pll_clk = devm_clk_get(dev, "pll_clk"); - if (IS_ERR(dsi->pll_clk)) { - dev_info(dev, "failed to get dsi pll input clock\n"); - ret = PTR_ERR(dsi->pll_clk); - goto err_del_component; - } + dsi->clks = devm_kzalloc(dev, + sizeof(*dsi->clks) * dsi->driver_data->num_clks, + GFP_KERNEL); + if (!dsi->clks) + return -ENOMEM; + + for (i = 0; i < dsi->driver_data->num_clks; i++) { + dsi->clks[i] = devm_clk_get(dev, clk_names[i]); + if (IS_ERR(dsi->clks[i])) { + if (strcmp(clk_names[i], "sclk_mipi") == 0) { + strcpy(clk_names[i], OLD_SCLK_MIPI_CLK_NAME); + i--; + continue; + } - dsi->bus_clk = devm_clk_get(dev, "bus_clk"); - if (IS_ERR(dsi->bus_clk)) { - dev_info(dev, "failed to get dsi bus clock\n"); - ret = PTR_ERR(dsi->bus_clk); - goto err_del_component; + dev_info(dev, "failed to get the clock: %s\n", + clk_names[i]); + return PTR_ERR(dsi->clks[i]); + } } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); dsi->reg_base = devm_ioremap_resource(dev, res); if (IS_ERR(dsi->reg_base)) { dev_err(dev, "failed to remap io region\n"); - ret = PTR_ERR(dsi->reg_base); - goto err_del_component; + return PTR_ERR(dsi->reg_base); } dsi->phy = devm_phy_get(dev, "dsim"); if (IS_ERR(dsi->phy)) { dev_info(dev, "failed to get dsim phy\n"); - ret = PTR_ERR(dsi->phy); - goto err_del_component; + return PTR_ERR(dsi->phy); } dsi->irq = platform_get_irq(pdev, 0); if (dsi->irq < 0) { dev_err(dev, "failed to request dsi irq resource\n"); - ret = dsi->irq; - goto err_del_component; + return dsi->irq; } irq_set_status_flags(dsi->irq, IRQ_NOAUTOEN); @@ -1755,26 +1945,17 @@ static int exynos_dsi_probe(struct platform_device *pdev) dev_name(dev), dsi); if (ret) { dev_err(dev, "failed to request dsi irq\n"); - goto err_del_component; + return ret; } platform_set_drvdata(pdev, &dsi->display); - ret = component_add(dev, &exynos_dsi_component_ops); - if (ret) - goto err_del_component; - - return ret; - -err_del_component: - exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CONNECTOR); - return ret; + return component_add(dev, &exynos_dsi_component_ops); } static int exynos_dsi_remove(struct platform_device *pdev) { component_del(&pdev->dev, &exynos_dsi_component_ops); - exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR); return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c index 57de0bdc5a3b..7b89fd520e45 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c @@ -32,17 +32,6 @@ struct exynos_drm_encoder { struct exynos_drm_display *display; }; -static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode) -{ - struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); - struct exynos_drm_display *display = exynos_encoder->display; - - DRM_DEBUG_KMS("encoder dpms: %d\n", mode); - - if (display->ops->dpms) - display->ops->dpms(display, mode); -} - static bool exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, @@ -76,12 +65,7 @@ static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder, display->ops->mode_set(display, adjusted_mode); } -static void exynos_drm_encoder_prepare(struct drm_encoder *encoder) -{ - /* drm framework doesn't check NULL. */ -} - -static void exynos_drm_encoder_commit(struct drm_encoder *encoder) +static void exynos_drm_encoder_enable(struct drm_encoder *encoder) { struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); struct exynos_drm_display *display = exynos_encoder->display; @@ -95,24 +79,17 @@ static void exynos_drm_encoder_commit(struct drm_encoder *encoder) static void exynos_drm_encoder_disable(struct drm_encoder *encoder) { - struct drm_plane *plane; - struct drm_device *dev = encoder->dev; - - exynos_drm_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); + struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); + struct exynos_drm_display *display = exynos_encoder->display; - /* all planes connected to this encoder should be also disabled. */ - drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) { - if (plane->crtc && (plane->crtc == encoder->crtc)) - plane->funcs->disable_plane(plane); - } + if (display->ops->dpms) + display->ops->dpms(display, DRM_MODE_DPMS_OFF); } static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = { - .dpms = exynos_drm_encoder_dpms, .mode_fixup = exynos_drm_encoder_mode_fixup, .mode_set = exynos_drm_encoder_mode_set, - .prepare = exynos_drm_encoder_prepare, - .commit = exynos_drm_encoder_commit, + .enable = exynos_drm_encoder_enable, .disable = exynos_drm_encoder_disable, }; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 142eb4e3f59e..2b6320e6eae2 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -16,6 +16,8 @@ #include <drm/drm_crtc.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_fb_helper.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> #include <uapi/drm/exynos_drm.h> #include "exynos_drm_drv.h" @@ -265,9 +267,46 @@ static void exynos_drm_output_poll_changed(struct drm_device *dev) exynos_drm_fbdev_init(dev); } +static int exynos_atomic_commit(struct drm_device *dev, + struct drm_atomic_state *state, + bool async) +{ + int ret; + + ret = drm_atomic_helper_prepare_planes(dev, state); + if (ret) + return ret; + + /* This is the point of no return */ + + drm_atomic_helper_swap_state(dev, state); + + drm_atomic_helper_commit_modeset_disables(dev, state); + + drm_atomic_helper_commit_modeset_enables(dev, state); + + /* + * Exynos can't update planes with CRTCs and encoders disabled, + * its updates routines, specially for FIMD, requires the clocks + * to be enabled. So it is necessary to handle the modeset operations + * *before* the commit_planes() step, this way it will always + * have the relevant clocks enabled to perform the update. + */ + + drm_atomic_helper_commit_planes(dev, state); + + drm_atomic_helper_cleanup_planes(dev, state); + + drm_atomic_state_free(state); + + return 0; +} + static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = { .fb_create = exynos_user_fb_create, .output_poll_changed = exynos_drm_output_poll_changed, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = exynos_atomic_commit, }; void exynos_drm_mode_config_init(struct drm_device *dev) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index e71e331f0188..e0b085b4bdfa 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -275,9 +275,6 @@ int exynos_drm_fbdev_init(struct drm_device *dev) } - /* disable all the possible outputs/crtcs before entering KMS mode */ - drm_helper_disable_unused_functions(dev); - ret = drm_fb_helper_initial_config(helper, PREFERRED_BPP); if (ret < 0) { DRM_ERROR("failed to set up hw configuration.\n"); diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index a0edab833148..794e56c8798e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -196,6 +196,62 @@ static inline struct fimd_driver_data *drm_fimd_get_driver_data( return (struct fimd_driver_data *)of_id->data; } +static int fimd_enable_vblank(struct exynos_drm_crtc *crtc) +{ + struct fimd_context *ctx = crtc->ctx; + u32 val; + + if (ctx->suspended) + return -EPERM; + + if (!test_and_set_bit(0, &ctx->irq_flags)) { + val = readl(ctx->regs + VIDINTCON0); + + val |= VIDINTCON0_INT_ENABLE; + + if (ctx->i80_if) { + val |= VIDINTCON0_INT_I80IFDONE; + val |= VIDINTCON0_INT_SYSMAINCON; + val &= ~VIDINTCON0_INT_SYSSUBCON; + } else { + val |= VIDINTCON0_INT_FRAME; + + val &= ~VIDINTCON0_FRAMESEL0_MASK; + val |= VIDINTCON0_FRAMESEL0_VSYNC; + val &= ~VIDINTCON0_FRAMESEL1_MASK; + val |= VIDINTCON0_FRAMESEL1_NONE; + } + + writel(val, ctx->regs + VIDINTCON0); + } + + return 0; +} + +static void fimd_disable_vblank(struct exynos_drm_crtc *crtc) +{ + struct fimd_context *ctx = crtc->ctx; + u32 val; + + if (ctx->suspended) + return; + + if (test_and_clear_bit(0, &ctx->irq_flags)) { + val = readl(ctx->regs + VIDINTCON0); + + val &= ~VIDINTCON0_INT_ENABLE; + + if (ctx->i80_if) { + val &= ~VIDINTCON0_INT_I80IFDONE; + val &= ~VIDINTCON0_INT_SYSMAINCON; + val &= ~VIDINTCON0_INT_SYSSUBCON; + } else + val &= ~VIDINTCON0_INT_FRAME; + + writel(val, ctx->regs + VIDINTCON0); + } +} + static void fimd_wait_for_vblank(struct exynos_drm_crtc *crtc) { struct fimd_context *ctx = crtc->ctx; @@ -242,12 +298,19 @@ static void fimd_enable_shadow_channel_path(struct fimd_context *ctx, writel(val, ctx->regs + SHADOWCON); } -static void fimd_clear_channel(struct fimd_context *ctx) +static void fimd_clear_channels(struct exynos_drm_crtc *crtc) { + struct fimd_context *ctx = crtc->ctx; unsigned int win, ch_enabled = 0; DRM_DEBUG_KMS("%s\n", __FILE__); + /* Hardware is in unknown state, so ensure it gets enabled properly */ + pm_runtime_get_sync(ctx->dev); + + clk_prepare_enable(ctx->bus_clk); + clk_prepare_enable(ctx->lcd_clk); + /* Check if any channel is enabled. */ for (win = 0; win < WINDOWS_NR; win++) { u32 val = readl(ctx->regs + WINCON(win)); @@ -265,36 +328,24 @@ static void fimd_clear_channel(struct fimd_context *ctx) /* Wait for vsync, as disable channel takes effect at next vsync */ if (ch_enabled) { - unsigned int state = ctx->suspended; + int pipe = ctx->pipe; - ctx->suspended = 0; - fimd_wait_for_vblank(ctx->crtc); - ctx->suspended = state; - } -} + /* ensure that vblank interrupt won't be reported to core */ + ctx->suspended = false; + ctx->pipe = -1; -static int fimd_iommu_attach_devices(struct fimd_context *ctx, - struct drm_device *drm_dev) -{ - - /* attach this sub driver to iommu mapping if supported. */ - if (is_drm_iommu_supported(ctx->drm_dev)) { - int ret; - - /* - * If any channel is already active, iommu will throw - * a PAGE FAULT when enabled. So clear any channel if enabled. - */ - fimd_clear_channel(ctx); - ret = drm_iommu_attach_device(ctx->drm_dev, ctx->dev); - if (ret) { - DRM_ERROR("drm_iommu_attach failed.\n"); - return ret; - } + fimd_enable_vblank(ctx->crtc); + fimd_wait_for_vblank(ctx->crtc); + fimd_disable_vblank(ctx->crtc); + ctx->suspended = true; + ctx->pipe = pipe; } - return 0; + clk_disable_unprepare(ctx->lcd_clk); + clk_disable_unprepare(ctx->bus_clk); + + pm_runtime_put(ctx->dev); } static void fimd_iommu_detach_devices(struct fimd_context *ctx) @@ -337,7 +388,7 @@ static bool fimd_mode_fixup(struct exynos_drm_crtc *crtc, static void fimd_commit(struct exynos_drm_crtc *crtc) { struct fimd_context *ctx = crtc->ctx; - struct drm_display_mode *mode = &crtc->base.mode; + struct drm_display_mode *mode = &crtc->base.state->adjusted_mode; struct fimd_driver_data *driver_data = ctx->driver_data; void *timing_base = ctx->regs + driver_data->timing_base; u32 val, clkdiv; @@ -434,61 +485,6 @@ static void fimd_commit(struct exynos_drm_crtc *crtc) writel(val, ctx->regs + VIDCON0); } -static int fimd_enable_vblank(struct exynos_drm_crtc *crtc) -{ - struct fimd_context *ctx = crtc->ctx; - u32 val; - - if (ctx->suspended) - return -EPERM; - - if (!test_and_set_bit(0, &ctx->irq_flags)) { - val = readl(ctx->regs + VIDINTCON0); - - val |= VIDINTCON0_INT_ENABLE; - - if (ctx->i80_if) { - val |= VIDINTCON0_INT_I80IFDONE; - val |= VIDINTCON0_INT_SYSMAINCON; - val &= ~VIDINTCON0_INT_SYSSUBCON; - } else { - val |= VIDINTCON0_INT_FRAME; - - val &= ~VIDINTCON0_FRAMESEL0_MASK; - val |= VIDINTCON0_FRAMESEL0_VSYNC; - val &= ~VIDINTCON0_FRAMESEL1_MASK; - val |= VIDINTCON0_FRAMESEL1_NONE; - } - - writel(val, ctx->regs + VIDINTCON0); - } - - return 0; -} - -static void fimd_disable_vblank(struct exynos_drm_crtc *crtc) -{ - struct fimd_context *ctx = crtc->ctx; - u32 val; - - if (ctx->suspended) - return; - - if (test_and_clear_bit(0, &ctx->irq_flags)) { - val = readl(ctx->regs + VIDINTCON0); - - val &= ~VIDINTCON0_INT_ENABLE; - - if (ctx->i80_if) { - val &= ~VIDINTCON0_INT_I80IFDONE; - val &= ~VIDINTCON0_INT_SYSMAINCON; - val &= ~VIDINTCON0_INT_SYSSUBCON; - } else - val &= ~VIDINTCON0_INT_FRAME; - - writel(val, ctx->regs + VIDINTCON0); - } -} static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win) { @@ -634,11 +630,8 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) plane = &ctx->planes[win]; - /* If suspended, enable this on resume */ - if (ctx->suspended) { - plane->resume = true; + if (ctx->suspended) return; - } /* * SHADOWCON/PRTCON register is used for enabling timing. @@ -728,8 +721,6 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) /* Enable DMA channel and unprotect windows */ fimd_shadow_protect_win(ctx, win, false); - plane->enabled = true; - if (ctx->i80_if) atomic_set(&ctx->win_updated, 1); } @@ -744,11 +735,8 @@ static void fimd_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) plane = &ctx->planes[win]; - if (ctx->suspended) { - /* do not resume this window*/ - plane->resume = false; + if (ctx->suspended) return; - } /* protect windows */ fimd_shadow_protect_win(ctx, win, true); @@ -760,57 +748,15 @@ static void fimd_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) /* unprotect windows */ fimd_shadow_protect_win(ctx, win, false); - - plane->enabled = false; -} - -static void fimd_window_suspend(struct fimd_context *ctx) -{ - struct exynos_drm_plane *plane; - int i; - - for (i = 0; i < WINDOWS_NR; i++) { - plane = &ctx->planes[i]; - plane->resume = plane->enabled; - if (plane->enabled) - fimd_win_disable(ctx->crtc, i); - } -} - -static void fimd_window_resume(struct fimd_context *ctx) -{ - struct exynos_drm_plane *plane; - int i; - - for (i = 0; i < WINDOWS_NR; i++) { - plane = &ctx->planes[i]; - plane->enabled = plane->resume; - plane->resume = false; - } } -static void fimd_apply(struct fimd_context *ctx) -{ - struct exynos_drm_plane *plane; - int i; - - for (i = 0; i < WINDOWS_NR; i++) { - plane = &ctx->planes[i]; - if (plane->enabled) - fimd_win_commit(ctx->crtc, i); - else - fimd_win_disable(ctx->crtc, i); - } - - fimd_commit(ctx->crtc); -} - -static int fimd_poweron(struct fimd_context *ctx) +static void fimd_enable(struct exynos_drm_crtc *crtc) { + struct fimd_context *ctx = crtc->ctx; int ret; if (!ctx->suspended) - return 0; + return; ctx->suspended = false; @@ -819,50 +765,43 @@ static int fimd_poweron(struct fimd_context *ctx) ret = clk_prepare_enable(ctx->bus_clk); if (ret < 0) { DRM_ERROR("Failed to prepare_enable the bus clk [%d]\n", ret); - goto bus_clk_err; + return; } ret = clk_prepare_enable(ctx->lcd_clk); if (ret < 0) { DRM_ERROR("Failed to prepare_enable the lcd clk [%d]\n", ret); - goto lcd_clk_err; + return; } /* if vblank was enabled status, enable it again. */ - if (test_and_clear_bit(0, &ctx->irq_flags)) { - ret = fimd_enable_vblank(ctx->crtc); - if (ret) { - DRM_ERROR("Failed to re-enable vblank [%d]\n", ret); - goto enable_vblank_err; - } - } - - fimd_window_resume(ctx); - - fimd_apply(ctx); + if (test_and_clear_bit(0, &ctx->irq_flags)) + fimd_enable_vblank(ctx->crtc); - return 0; - -enable_vblank_err: - clk_disable_unprepare(ctx->lcd_clk); -lcd_clk_err: - clk_disable_unprepare(ctx->bus_clk); -bus_clk_err: - ctx->suspended = true; - return ret; + fimd_commit(ctx->crtc); } -static int fimd_poweroff(struct fimd_context *ctx) +static void fimd_disable(struct exynos_drm_crtc *crtc) { + struct fimd_context *ctx = crtc->ctx; + int i; + if (ctx->suspended) - return 0; + return; /* * We need to make sure that all windows are disabled before we * suspend that connector. Otherwise we might try to scan from * a destroyed buffer later. */ - fimd_window_suspend(ctx); + for (i = 0; i < WINDOWS_NR; i++) + fimd_win_disable(crtc, i); + + fimd_enable_vblank(crtc); + fimd_wait_for_vblank(crtc); + fimd_disable_vblank(crtc); + + writel(0, ctx->regs + VIDCON0); clk_disable_unprepare(ctx->lcd_clk); clk_disable_unprepare(ctx->bus_clk); @@ -870,26 +809,6 @@ static int fimd_poweroff(struct fimd_context *ctx) pm_runtime_put_sync(ctx->dev); ctx->suspended = true; - return 0; -} - -static void fimd_dpms(struct exynos_drm_crtc *crtc, int mode) -{ - DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode); - - switch (mode) { - case DRM_MODE_DPMS_ON: - fimd_poweron(crtc->ctx); - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - fimd_poweroff(crtc->ctx); - break; - default: - DRM_DEBUG_KMS("unspecified mode %d\n", mode); - break; - } } static void fimd_trigger(struct device *dev) @@ -964,7 +883,8 @@ static void fimd_dp_clock_enable(struct exynos_drm_crtc *crtc, bool enable) } static const struct exynos_drm_crtc_ops fimd_crtc_ops = { - .dpms = fimd_dpms, + .enable = fimd_enable, + .disable = fimd_disable, .mode_fixup = fimd_mode_fixup, .commit = fimd_commit, .enable_vblank = fimd_enable_vblank, @@ -974,6 +894,7 @@ static const struct exynos_drm_crtc_ops fimd_crtc_ops = { .win_disable = fimd_win_disable, .te_handler = fimd_te_handler, .clock_enable = fimd_dp_clock_enable, + .clear_channels = fimd_clear_channels, }; static irqreturn_t fimd_irq_handler(int irq, void *dev_id) @@ -1043,7 +964,11 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) if (ctx->display) exynos_drm_create_enc_conn(drm_dev, ctx->display); - return fimd_iommu_attach_devices(ctx, drm_dev); + ret = drm_iommu_attach_device_if_possible(ctx->crtc, drm_dev, dev); + if (ret) + priv->pipe--; + + return ret; } static void fimd_unbind(struct device *dev, struct device *master, @@ -1051,7 +976,7 @@ static void fimd_unbind(struct device *dev, struct device *master, { struct fimd_context *ctx = dev_get_drvdata(dev); - fimd_dpms(ctx->crtc, DRM_MODE_DPMS_OFF); + fimd_disable(ctx->crtc); fimd_iommu_detach_devices(ctx); @@ -1079,11 +1004,6 @@ static int fimd_probe(struct platform_device *pdev) if (!ctx) return -ENOMEM; - ret = exynos_drm_component_add(dev, EXYNOS_DEVICE_TYPE_CRTC, - EXYNOS_DISPLAY_TYPE_LCD); - if (ret) - return ret; - ctx->dev = dev; ctx->suspended = true; ctx->driver_data = drm_fimd_get_driver_data(pdev); @@ -1134,38 +1054,33 @@ static int fimd_probe(struct platform_device *pdev) ctx->bus_clk = devm_clk_get(dev, "fimd"); if (IS_ERR(ctx->bus_clk)) { dev_err(dev, "failed to get bus clock\n"); - ret = PTR_ERR(ctx->bus_clk); - goto err_del_component; + return PTR_ERR(ctx->bus_clk); } ctx->lcd_clk = devm_clk_get(dev, "sclk_fimd"); if (IS_ERR(ctx->lcd_clk)) { dev_err(dev, "failed to get lcd clock\n"); - ret = PTR_ERR(ctx->lcd_clk); - goto err_del_component; + return PTR_ERR(ctx->lcd_clk); } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ctx->regs = devm_ioremap_resource(dev, res); - if (IS_ERR(ctx->regs)) { - ret = PTR_ERR(ctx->regs); - goto err_del_component; - } + if (IS_ERR(ctx->regs)) + return PTR_ERR(ctx->regs); res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, ctx->i80_if ? "lcd_sys" : "vsync"); if (!res) { dev_err(dev, "irq request failed.\n"); - ret = -ENXIO; - goto err_del_component; + return -ENXIO; } ret = devm_request_irq(dev, res->start, fimd_irq_handler, 0, "drm_fimd", ctx); if (ret) { dev_err(dev, "irq request failed.\n"); - goto err_del_component; + return ret; } init_waitqueue_head(&ctx->wait_vsync_queue); @@ -1175,8 +1090,7 @@ static int fimd_probe(struct platform_device *pdev) ctx->display = exynos_dpi_probe(dev); if (IS_ERR(ctx->display)) { - ret = PTR_ERR(ctx->display); - goto err_del_component; + return PTR_ERR(ctx->display); } pm_runtime_enable(dev); @@ -1190,8 +1104,6 @@ static int fimd_probe(struct platform_device *pdev) err_disable_pm_runtime: pm_runtime_disable(dev); -err_del_component: - exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CRTC); return ret; } @@ -1200,7 +1112,6 @@ static int fimd_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); component_del(&pdev->dev, &fimd_component_ops); - exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC); return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h index 308173cb4f0a..6f42e2248288 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.h +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h @@ -61,7 +61,6 @@ struct exynos_drm_gem_buf { * or at framebuffer creation. * @size: size requested from user, in bytes and this size is aligned * in page unit. - * @vma: a pointer to vm_area. * @flags: indicate memory type to allocated buffer and cache attruibute. * * P.S. this object would be transferred to user as kms_bo.handle so @@ -71,7 +70,6 @@ struct exynos_drm_gem_obj { struct drm_gem_object base; struct exynos_drm_gem_buf *buffer; unsigned long size; - struct vm_area_struct *vma; unsigned int flags; }; diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.c b/drivers/gpu/drm/exynos/exynos_drm_iommu.c index b32b291f88ff..d4ec7465e9cc 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_iommu.c +++ b/drivers/gpu/drm/exynos/exynos_drm_iommu.c @@ -100,6 +100,9 @@ int drm_iommu_attach_device(struct drm_device *drm_dev, dma_set_max_seg_size(subdrv_dev, 0xffffffffu); + if (subdrv_dev->archdata.mapping) + arm_iommu_detach_device(subdrv_dev); + ret = arm_iommu_attach_device(subdrv_dev, dev->archdata.mapping); if (ret < 0) { DRM_DEBUG_KMS("failed iommu attach.\n"); @@ -114,8 +117,8 @@ int drm_iommu_attach_device(struct drm_device *drm_dev, * If iommu attach succeeded, the sub driver would have dma_ops * for iommu and also all sub drivers have same dma_ops. */ - if (!dev->archdata.dma_ops) - dev->archdata.dma_ops = subdrv_dev->archdata.dma_ops; + if (get_dma_ops(dev) == get_dma_ops(NULL)) + set_dma_ops(dev, get_dma_ops(subdrv_dev)); return 0; } @@ -141,3 +144,17 @@ void drm_iommu_detach_device(struct drm_device *drm_dev, iommu_detach_device(mapping->domain, subdrv_dev); drm_release_iommu_mapping(drm_dev); } + +int drm_iommu_attach_device_if_possible(struct exynos_drm_crtc *exynos_crtc, + struct drm_device *drm_dev, struct device *subdrv_dev) +{ + int ret = 0; + + if (is_drm_iommu_supported(drm_dev)) { + if (exynos_crtc->ops->clear_channels) + exynos_crtc->ops->clear_channels(exynos_crtc); + return drm_iommu_attach_device(drm_dev, subdrv_dev); + } + + return ret; +} diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.h b/drivers/gpu/drm/exynos/exynos_drm_iommu.h index 35d25889b476..8341c7a475b4 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_iommu.h +++ b/drivers/gpu/drm/exynos/exynos_drm_iommu.h @@ -38,6 +38,10 @@ static inline bool is_drm_iommu_supported(struct drm_device *drm_dev) #endif } +int drm_iommu_attach_device_if_possible( + struct exynos_drm_crtc *exynos_crtc, struct drm_device *drm_dev, + struct device *subdrv_dev); + #else static inline int drm_create_iommu_mapping(struct drm_device *drm_dev) @@ -65,5 +69,12 @@ static inline bool is_drm_iommu_supported(struct drm_device *drm_dev) return false; } +static inline int drm_iommu_attach_device_if_possible( + struct exynos_drm_crtc *exynos_crtc, struct drm_device *drm_dev, + struct device *subdrv_dev) +{ + return 0; +} + #endif #endif diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c index b7f1cbc46cc2..67e5451e066f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c @@ -45,9 +45,6 @@ #define get_ipp_context(dev) platform_get_drvdata(to_platform_device(dev)) #define ipp_is_m2m_cmd(c) (c == IPP_CMD_M2M) -/* platform device pointer for ipp device. */ -static struct platform_device *exynos_drm_ipp_pdev; - /* * A structure of event. * @@ -102,30 +99,6 @@ static LIST_HEAD(exynos_drm_ippdrv_list); static DEFINE_MUTEX(exynos_drm_ippdrv_lock); static BLOCKING_NOTIFIER_HEAD(exynos_drm_ippnb_list); -int exynos_platform_device_ipp_register(void) -{ - struct platform_device *pdev; - - if (exynos_drm_ipp_pdev) - return -EEXIST; - - pdev = platform_device_register_simple("exynos-drm-ipp", -1, NULL, 0); - if (IS_ERR(pdev)) - return PTR_ERR(pdev); - - exynos_drm_ipp_pdev = pdev; - - return 0; -} - -void exynos_platform_device_ipp_unregister(void) -{ - if (exynos_drm_ipp_pdev) { - platform_device_unregister(exynos_drm_ipp_pdev); - exynos_drm_ipp_pdev = NULL; - } -} - int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv) { mutex_lock(&exynos_drm_ippdrv_lock); @@ -482,12 +455,11 @@ static int ipp_validate_mem_node(struct drm_device *drm_dev, { struct drm_exynos_ipp_config *ipp_cfg; unsigned int num_plane; - unsigned long min_size, size; - unsigned int bpp; + unsigned long size, buf_size = 0, plane_size, img_size = 0; + unsigned int bpp, width, height; int i; - /* The property id should already be varified */ - ipp_cfg = &c_node->property.config[m_node->prop_id]; + ipp_cfg = &c_node->property.config[m_node->ops_id]; num_plane = drm_format_num_planes(ipp_cfg->fmt); /** @@ -498,20 +470,45 @@ static int ipp_validate_mem_node(struct drm_device *drm_dev, * but it seems more than enough */ for (i = 0; i < num_plane; ++i) { - if (!m_node->buf_info.handles[i]) { - DRM_ERROR("invalid handle for plane %d\n", i); - return -EINVAL; - } + width = ipp_cfg->sz.hsize; + height = ipp_cfg->sz.vsize; bpp = drm_format_plane_cpp(ipp_cfg->fmt, i); - min_size = (ipp_cfg->sz.hsize * ipp_cfg->sz.vsize * bpp) >> 3; - size = exynos_drm_gem_get_size(drm_dev, - m_node->buf_info.handles[i], - c_node->filp); - if (min_size > size) { - DRM_ERROR("invalid size for plane %d\n", i); - return -EINVAL; + + /* + * The result of drm_format_plane_cpp() for chroma planes must + * be used with drm_format_xxxx_chroma_subsampling() for + * correct result. + */ + if (i > 0) { + width /= drm_format_horz_chroma_subsampling( + ipp_cfg->fmt); + height /= drm_format_vert_chroma_subsampling( + ipp_cfg->fmt); } + plane_size = width * height * bpp; + img_size += plane_size; + + if (m_node->buf_info.handles[i]) { + size = exynos_drm_gem_get_size(drm_dev, + m_node->buf_info.handles[i], + c_node->filp); + if (plane_size > size) { + DRM_ERROR( + "buffer %d is smaller than required\n", + i); + return -EINVAL; + } + + buf_size += size; + } + } + + if (buf_size < img_size) { + DRM_ERROR("size of buffers(%lu) is smaller than image(%lu)\n", + buf_size, img_size); + return -EINVAL; } + return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_mic.c b/drivers/gpu/drm/exynos/exynos_drm_mic.c new file mode 100644 index 000000000000..8994eab56ba8 --- /dev/null +++ b/drivers/gpu/drm/exynos/exynos_drm_mic.c @@ -0,0 +1,490 @@ +/* + * Copyright (C) 2015 Samsung Electronics Co.Ltd + * Authors: + * Hyungwon Hwang <human.hwang@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundationr + */ + +#include <linux/platform_device.h> +#include <video/of_videomode.h> +#include <linux/of_address.h> +#include <video/videomode.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/of_graph.h> +#include <linux/clk.h> +#include <drm/drmP.h> +#include <linux/mfd/syscon.h> +#include <linux/regmap.h> + +/* Sysreg registers for MIC */ +#define DSD_CFG_MUX 0x1004 +#define MIC0_RGB_MUX (1 << 0) +#define MIC0_I80_MUX (1 << 1) +#define MIC0_ON_MUX (1 << 5) + +/* MIC registers */ +#define MIC_OP 0x0 +#define MIC_IP_VER 0x0004 +#define MIC_V_TIMING_0 0x0008 +#define MIC_V_TIMING_1 0x000C +#define MIC_IMG_SIZE 0x0010 +#define MIC_INPUT_TIMING_0 0x0014 +#define MIC_INPUT_TIMING_1 0x0018 +#define MIC_2D_OUTPUT_TIMING_0 0x001C +#define MIC_2D_OUTPUT_TIMING_1 0x0020 +#define MIC_2D_OUTPUT_TIMING_2 0x0024 +#define MIC_3D_OUTPUT_TIMING_0 0x0028 +#define MIC_3D_OUTPUT_TIMING_1 0x002C +#define MIC_3D_OUTPUT_TIMING_2 0x0030 +#define MIC_CORE_PARA_0 0x0034 +#define MIC_CORE_PARA_1 0x0038 +#define MIC_CTC_CTRL 0x0040 +#define MIC_RD_DATA 0x0044 + +#define MIC_UPD_REG (1 << 31) +#define MIC_ON_REG (1 << 30) +#define MIC_TD_ON_REG (1 << 29) +#define MIC_BS_CHG_OUT (1 << 16) +#define MIC_VIDEO_TYPE(x) (((x) & 0xf) << 12) +#define MIC_PSR_EN (1 << 5) +#define MIC_SW_RST (1 << 4) +#define MIC_ALL_RST (1 << 3) +#define MIC_CORE_VER_CONTROL (1 << 2) +#define MIC_MODE_SEL_COMMAND_MODE (1 << 1) +#define MIC_MODE_SEL_MASK (1 << 1) +#define MIC_CORE_EN (1 << 0) + +#define MIC_V_PULSE_WIDTH(x) (((x) & 0x3fff) << 16) +#define MIC_V_PERIOD_LINE(x) ((x) & 0x3fff) + +#define MIC_VBP_SIZE(x) (((x) & 0x3fff) << 16) +#define MIC_VFP_SIZE(x) ((x) & 0x3fff) + +#define MIC_IMG_V_SIZE(x) (((x) & 0x3fff) << 16) +#define MIC_IMG_H_SIZE(x) ((x) & 0x3fff) + +#define MIC_H_PULSE_WIDTH_IN(x) (((x) & 0x3fff) << 16) +#define MIC_H_PERIOD_PIXEL_IN(x) ((x) & 0x3fff) + +#define MIC_HBP_SIZE_IN(x) (((x) & 0x3fff) << 16) +#define MIC_HFP_SIZE_IN(x) ((x) & 0x3fff) + +#define MIC_H_PULSE_WIDTH_2D(x) (((x) & 0x3fff) << 16) +#define MIC_H_PERIOD_PIXEL_2D(x) ((x) & 0x3fff) + +#define MIC_HBP_SIZE_2D(x) (((x) & 0x3fff) << 16) +#define MIC_HFP_SIZE_2D(x) ((x) & 0x3fff) + +#define MIC_BS_SIZE_2D(x) ((x) & 0x3fff) + +enum { + ENDPOINT_DECON_NODE, + ENDPOINT_DSI_NODE, + NUM_ENDPOINTS +}; + +static char *clk_names[] = { "pclk_mic0", "sclk_rgb_vclk_to_mic0" }; +#define NUM_CLKS ARRAY_SIZE(clk_names) +static DEFINE_MUTEX(mic_mutex); + +struct exynos_mic { + struct device *dev; + void __iomem *reg; + struct regmap *sysreg; + struct clk *clks[NUM_CLKS]; + + bool i80_mode; + struct videomode vm; + struct drm_encoder *encoder; + struct drm_bridge bridge; + + bool enabled; +}; + +static void mic_set_path(struct exynos_mic *mic, bool enable) +{ + int ret; + unsigned int val; + + ret = regmap_read(mic->sysreg, DSD_CFG_MUX, &val); + if (ret) { + DRM_ERROR("mic: Failed to read system register\n"); + return; + } + + if (enable) { + if (mic->i80_mode) + val |= MIC0_I80_MUX; + else + val |= MIC0_RGB_MUX; + + val |= MIC0_ON_MUX; + } else + val &= ~(MIC0_RGB_MUX | MIC0_I80_MUX | MIC0_ON_MUX); + + regmap_write(mic->sysreg, DSD_CFG_MUX, val); + if (ret) + DRM_ERROR("mic: Failed to read system register\n"); +} + +static int mic_sw_reset(struct exynos_mic *mic) +{ + unsigned int retry = 100; + int ret; + + writel(MIC_SW_RST, mic->reg + MIC_OP); + + while (retry-- > 0) { + ret = readl(mic->reg + MIC_OP); + if (!(ret & MIC_SW_RST)) + return 0; + + udelay(10); + } + + return -ETIMEDOUT; +} + +static void mic_set_porch_timing(struct exynos_mic *mic) +{ + struct videomode vm = mic->vm; + u32 reg; + + reg = MIC_V_PULSE_WIDTH(vm.vsync_len) + + MIC_V_PERIOD_LINE(vm.vsync_len + vm.vactive + + vm.vback_porch + vm.vfront_porch); + writel(reg, mic->reg + MIC_V_TIMING_0); + + reg = MIC_VBP_SIZE(vm.vback_porch) + + MIC_VFP_SIZE(vm.vfront_porch); + writel(reg, mic->reg + MIC_V_TIMING_1); + + reg = MIC_V_PULSE_WIDTH(vm.hsync_len) + + MIC_V_PERIOD_LINE(vm.hsync_len + vm.hactive + + vm.hback_porch + vm.hfront_porch); + writel(reg, mic->reg + MIC_INPUT_TIMING_0); + + reg = MIC_VBP_SIZE(vm.hback_porch) + + MIC_VFP_SIZE(vm.hfront_porch); + writel(reg, mic->reg + MIC_INPUT_TIMING_1); +} + +static void mic_set_img_size(struct exynos_mic *mic) +{ + struct videomode *vm = &mic->vm; + u32 reg; + + reg = MIC_IMG_H_SIZE(vm->hactive) + + MIC_IMG_V_SIZE(vm->vactive); + + writel(reg, mic->reg + MIC_IMG_SIZE); +} + +static void mic_set_output_timing(struct exynos_mic *mic) +{ + struct videomode vm = mic->vm; + u32 reg, bs_size_2d; + + DRM_DEBUG("w: %u, h: %u\n", vm.hactive, vm.vactive); + bs_size_2d = ((vm.hactive >> 2) << 1) + (vm.vactive % 4); + reg = MIC_BS_SIZE_2D(bs_size_2d); + writel(reg, mic->reg + MIC_2D_OUTPUT_TIMING_2); + + if (!mic->i80_mode) { + reg = MIC_H_PULSE_WIDTH_2D(vm.hsync_len) + + MIC_H_PERIOD_PIXEL_2D(vm.hsync_len + bs_size_2d + + vm.hback_porch + vm.hfront_porch); + writel(reg, mic->reg + MIC_2D_OUTPUT_TIMING_0); + + reg = MIC_HBP_SIZE_2D(vm.hback_porch) + + MIC_H_PERIOD_PIXEL_2D(vm.hfront_porch); + writel(reg, mic->reg + MIC_2D_OUTPUT_TIMING_1); + } +} + +static void mic_set_reg_on(struct exynos_mic *mic, bool enable) +{ + u32 reg = readl(mic->reg + MIC_OP); + + if (enable) { + reg &= ~(MIC_MODE_SEL_MASK | MIC_CORE_VER_CONTROL | MIC_PSR_EN); + reg |= (MIC_CORE_EN | MIC_BS_CHG_OUT | MIC_ON_REG); + + reg &= ~MIC_MODE_SEL_COMMAND_MODE; + if (mic->i80_mode) + reg |= MIC_MODE_SEL_COMMAND_MODE; + } else { + reg &= ~MIC_CORE_EN; + } + + reg |= MIC_UPD_REG; + writel(reg, mic->reg + MIC_OP); +} + +static struct device_node *get_remote_node(struct device_node *from, int reg) +{ + struct device_node *endpoint = NULL, *remote_node = NULL; + + endpoint = of_graph_get_endpoint_by_regs(from, reg, -1); + if (!endpoint) { + DRM_ERROR("mic: Failed to find remote port from %s", + from->full_name); + goto exit; + } + + remote_node = of_graph_get_remote_port_parent(endpoint); + if (!remote_node) { + DRM_ERROR("mic: Failed to find remote port parent from %s", + from->full_name); + goto exit; + } + +exit: + of_node_put(endpoint); + return remote_node; +} + +static int parse_dt(struct exynos_mic *mic) +{ + int ret = 0, i, j; + struct device_node *remote_node; + struct device_node *nodes[3]; + + /* + * The order of endpoints does matter. + * The first node must be for decon and the second one must be for dsi. + */ + for (i = 0, j = 0; i < NUM_ENDPOINTS; i++) { + remote_node = get_remote_node(mic->dev->of_node, i); + if (!remote_node) { + ret = -EPIPE; + goto exit; + } + nodes[j++] = remote_node; + + switch (i) { + case ENDPOINT_DECON_NODE: + /* decon node */ + if (of_get_child_by_name(remote_node, + "i80-if-timings")) + mic->i80_mode = 1; + + break; + case ENDPOINT_DSI_NODE: + /* panel node */ + remote_node = get_remote_node(remote_node, 1); + if (!remote_node) { + ret = -EPIPE; + goto exit; + } + nodes[j++] = remote_node; + + ret = of_get_videomode(remote_node, + &mic->vm, 0); + if (ret) { + DRM_ERROR("mic: failed to get videomode"); + goto exit; + } + + break; + default: + DRM_ERROR("mic: Unknown endpoint from MIC"); + break; + } + } + +exit: + while (--j > -1) + of_node_put(nodes[j]); + + return ret; +} + +void mic_disable(struct drm_bridge *bridge) { } + +void mic_post_disable(struct drm_bridge *bridge) +{ + struct exynos_mic *mic = bridge->driver_private; + int i; + + mutex_lock(&mic_mutex); + if (!mic->enabled) + goto already_disabled; + + mic_set_path(mic, 0); + + for (i = NUM_CLKS - 1; i > -1; i--) + clk_disable_unprepare(mic->clks[i]); + + mic->enabled = 0; + +already_disabled: + mutex_unlock(&mic_mutex); +} + +void mic_pre_enable(struct drm_bridge *bridge) +{ + struct exynos_mic *mic = bridge->driver_private; + int ret, i; + + mutex_lock(&mic_mutex); + if (mic->enabled) + goto already_enabled; + + for (i = 0; i < NUM_CLKS; i++) { + ret = clk_prepare_enable(mic->clks[i]); + if (ret < 0) { + DRM_ERROR("Failed to enable clock (%s)\n", + clk_names[i]); + goto turn_off_clks; + } + } + + mic_set_path(mic, 1); + + ret = mic_sw_reset(mic); + if (ret) { + DRM_ERROR("Failed to reset\n"); + goto turn_off_clks; + } + + if (!mic->i80_mode) + mic_set_porch_timing(mic); + mic_set_img_size(mic); + mic_set_output_timing(mic); + mic_set_reg_on(mic, 1); + mic->enabled = 1; + mutex_unlock(&mic_mutex); + + return; + +turn_off_clks: + while (--i > -1) + clk_disable_unprepare(mic->clks[i]); +already_enabled: + mutex_unlock(&mic_mutex); +} + +void mic_enable(struct drm_bridge *bridge) { } + +void mic_destroy(struct drm_bridge *bridge) +{ + struct exynos_mic *mic = bridge->driver_private; + int i; + + mutex_lock(&mic_mutex); + if (!mic->enabled) + goto already_disabled; + + for (i = NUM_CLKS - 1; i > -1; i--) + clk_disable_unprepare(mic->clks[i]); + +already_disabled: + mutex_unlock(&mic_mutex); +} + +struct drm_bridge_funcs mic_bridge_funcs = { + .disable = mic_disable, + .post_disable = mic_post_disable, + .pre_enable = mic_pre_enable, + .enable = mic_enable, +}; + +int exynos_mic_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct exynos_mic *mic; + struct resource res; + int ret, i; + + mic = devm_kzalloc(dev, sizeof(*mic), GFP_KERNEL); + if (!mic) { + DRM_ERROR("mic: Failed to allocate memory for MIC object\n"); + ret = -ENOMEM; + goto err; + } + + mic->dev = dev; + + ret = parse_dt(mic); + if (ret) + goto err; + + ret = of_address_to_resource(dev->of_node, 0, &res); + if (ret) { + DRM_ERROR("mic: Failed to get mem region for MIC\n"); + goto err; + } + mic->reg = devm_ioremap(dev, res.start, resource_size(&res)); + if (!mic->reg) { + DRM_ERROR("mic: Failed to remap for MIC\n"); + ret = -ENOMEM; + goto err; + } + + mic->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node, + "samsung,disp-syscon"); + if (IS_ERR(mic->sysreg)) { + DRM_ERROR("mic: Failed to get system register.\n"); + goto err; + } + + mic->bridge.funcs = &mic_bridge_funcs; + mic->bridge.of_node = dev->of_node; + mic->bridge.driver_private = mic; + ret = drm_bridge_add(&mic->bridge); + if (ret) { + DRM_ERROR("mic: Failed to add MIC to the global bridge list\n"); + goto err; + } + + for (i = 0; i < NUM_CLKS; i++) { + mic->clks[i] = of_clk_get_by_name(dev->of_node, clk_names[i]); + if (IS_ERR(mic->clks[i])) { + DRM_ERROR("mic: Failed to get clock (%s)\n", + clk_names[i]); + ret = PTR_ERR(mic->clks[i]); + goto err; + } + } + + DRM_DEBUG_KMS("MIC has been probed\n"); + +err: + return ret; +} + +static int exynos_mic_remove(struct platform_device *pdev) +{ + struct exynos_mic *mic = platform_get_drvdata(pdev); + int i; + + drm_bridge_remove(&mic->bridge); + + for (i = NUM_CLKS - 1; i > -1; i--) + clk_put(mic->clks[i]); + + return 0; +} + +static const struct of_device_id exynos_mic_of_match[] = { + { .compatible = "samsung,exynos5433-mic" }, + { } +}; +MODULE_DEVICE_TABLE(of, exynos_mic_of_match); + +struct platform_driver mic_driver = { + .probe = exynos_mic_probe, + .remove = exynos_mic_remove, + .driver = { + .name = "exynos-mic", + .owner = THIS_MODULE, + .of_match_table = exynos_mic_of_match, + }, +}; diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index b1180fbe7546..a729980d3c2f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -13,6 +13,7 @@ #include <drm/exynos_drm.h> #include <drm/drm_plane_helper.h> +#include <drm/drm_atomic_helper.h> #include "exynos_drm_drv.h" #include "exynos_drm_crtc.h" #include "exynos_drm_fb.h" @@ -61,42 +62,21 @@ static int exynos_plane_get_size(int start, unsigned length, unsigned last) return size; } -int exynos_check_plane(struct drm_plane *plane, struct drm_framebuffer *fb) -{ - struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); - int nr; - int i; - - nr = exynos_drm_fb_get_buf_cnt(fb); - for (i = 0; i < nr; i++) { - struct exynos_drm_gem_buf *buffer = exynos_drm_fb_buffer(fb, i); - - if (!buffer) { - DRM_DEBUG_KMS("buffer is null\n"); - return -EFAULT; - } - - exynos_plane->dma_addr[i] = buffer->dma_addr + fb->offsets[i]; - - DRM_DEBUG_KMS("buffer: %d, dma_addr = 0x%lx\n", - i, (unsigned long)exynos_plane->dma_addr[i]); - } - - return 0; -} - -void exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, - struct drm_framebuffer *fb, int crtc_x, int crtc_y, - unsigned int crtc_w, unsigned int crtc_h, - uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) +static void exynos_plane_mode_set(struct drm_plane *plane, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + int crtc_x, int crtc_y, + unsigned int crtc_w, unsigned int crtc_h, + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h) { struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); + struct drm_display_mode *mode = &crtc->state->adjusted_mode; unsigned int actual_w; unsigned int actual_h; - actual_w = exynos_plane_get_size(crtc_x, crtc_w, crtc->mode.hdisplay); - actual_h = exynos_plane_get_size(crtc_y, crtc_h, crtc->mode.vdisplay); + actual_w = exynos_plane_get_size(crtc_x, crtc_w, mode->hdisplay); + actual_h = exynos_plane_get_size(crtc_y, crtc_h, mode->vdisplay); if (crtc_x < 0) { if (actual_w) @@ -132,10 +112,10 @@ void exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, exynos_plane->crtc_height = actual_h; /* set drm mode data. */ - exynos_plane->mode_width = crtc->mode.hdisplay; - exynos_plane->mode_height = crtc->mode.vdisplay; - exynos_plane->refresh = crtc->mode.vrefresh; - exynos_plane->scan_flag = crtc->mode.flags; + exynos_plane->mode_width = mode->hdisplay; + exynos_plane->mode_height = mode->vdisplay; + exynos_plane->refresh = mode->vrefresh; + exynos_plane->scan_flag = mode->flags; DRM_DEBUG_KMS("plane : offset_x/y(%d,%d), width/height(%d,%d)", exynos_plane->crtc_x, exynos_plane->crtc_y, @@ -144,48 +124,83 @@ void exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, plane->crtc = crtc; } -int -exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, - struct drm_framebuffer *fb, int crtc_x, int crtc_y, - unsigned int crtc_w, unsigned int crtc_h, - uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) +static struct drm_plane_funcs exynos_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = drm_plane_cleanup, + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +}; + +static int exynos_plane_atomic_check(struct drm_plane *plane, + struct drm_plane_state *state) { + struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); + int nr; + int i; + + if (!state->fb) + return 0; + + nr = exynos_drm_fb_get_buf_cnt(state->fb); + for (i = 0; i < nr; i++) { + struct exynos_drm_gem_buf *buffer = + exynos_drm_fb_buffer(state->fb, i); + + if (!buffer) { + DRM_DEBUG_KMS("buffer is null\n"); + return -EFAULT; + } + + exynos_plane->dma_addr[i] = buffer->dma_addr + + state->fb->offsets[i]; + + DRM_DEBUG_KMS("buffer: %d, dma_addr = 0x%lx\n", + i, (unsigned long)exynos_plane->dma_addr[i]); + } + + return 0; +} - struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); +static void exynos_plane_atomic_update(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct drm_plane_state *state = plane->state; + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(state->crtc); struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); - int ret; - ret = exynos_check_plane(plane, fb); - if (ret < 0) - return ret; + if (!state->crtc) + return; - exynos_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y, - crtc_w, crtc_h, src_x >> 16, src_y >> 16, - src_w >> 16, src_h >> 16); + exynos_plane_mode_set(plane, state->crtc, state->fb, + state->crtc_x, state->crtc_y, + state->crtc_w, state->crtc_h, + state->src_x >> 16, state->src_y >> 16, + state->src_w >> 16, state->src_h >> 16); if (exynos_crtc->ops->win_commit) exynos_crtc->ops->win_commit(exynos_crtc, exynos_plane->zpos); - - return 0; } -static int exynos_disable_plane(struct drm_plane *plane) +static void exynos_plane_atomic_disable(struct drm_plane *plane, + struct drm_plane_state *old_state) { struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); - struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(plane->crtc); + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(old_state->crtc); - if (exynos_crtc && exynos_crtc->ops->win_disable) + if (!old_state->crtc) + return; + + if (exynos_crtc->ops->win_disable) exynos_crtc->ops->win_disable(exynos_crtc, exynos_plane->zpos); - - return 0; } -static struct drm_plane_funcs exynos_plane_funcs = { - .update_plane = exynos_update_plane, - .disable_plane = exynos_disable_plane, - .destroy = drm_plane_cleanup, +static const struct drm_plane_helper_funcs plane_helper_funcs = { + .atomic_check = exynos_plane_atomic_check, + .atomic_update = exynos_plane_atomic_update, + .atomic_disable = exynos_plane_atomic_disable, }; static void exynos_plane_attach_zpos_property(struct drm_plane *plane, @@ -223,6 +238,8 @@ int exynos_plane_init(struct drm_device *dev, return err; } + drm_plane_helper_add(&exynos_plane->base, &plane_helper_funcs); + exynos_plane->zpos = zpos; if (type == DRM_PLANE_TYPE_OVERLAY) diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.h b/drivers/gpu/drm/exynos/exynos_drm_plane.h index f360590d1412..8c88ae983c38 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.h +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.h @@ -9,17 +9,6 @@ * */ -int exynos_check_plane(struct drm_plane *plane, struct drm_framebuffer *fb); -void exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, - struct drm_framebuffer *fb, int crtc_x, int crtc_y, - unsigned int crtc_w, unsigned int crtc_h, - uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h); -int exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, - struct drm_framebuffer *fb, int crtc_x, int crtc_y, - unsigned int crtc_w, unsigned int crtc_h, - uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h); int exynos_plane_init(struct drm_device *dev, struct exynos_drm_plane *exynos_plane, unsigned long possible_crtcs, enum drm_plane_type type, diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 1b3479a8db5f..3413393d8a16 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -20,6 +20,7 @@ #include <drm/drm_edid.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_atomic_helper.h> #include "exynos_drm_drv.h" #include "exynos_drm_crtc.h" @@ -130,78 +131,34 @@ static void vidi_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) plane = &ctx->planes[win]; - plane->enabled = true; - DRM_DEBUG_KMS("dma_addr = %pad\n", plane->dma_addr); if (ctx->vblank_on) schedule_work(&ctx->work); } -static void vidi_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) +static void vidi_enable(struct exynos_drm_crtc *crtc) { struct vidi_context *ctx = crtc->ctx; - struct exynos_drm_plane *plane; - - if (win < 0 || win >= WINDOWS_NR) - return; - - plane = &ctx->planes[win]; - plane->enabled = false; - - /* TODO. */ -} - -static int vidi_power_on(struct vidi_context *ctx, bool enable) -{ - struct exynos_drm_plane *plane; - int i; - - DRM_DEBUG_KMS("%s\n", __FILE__); - if (enable != false && enable != true) - return -EINVAL; - - if (enable) { - ctx->suspended = false; + mutex_lock(&ctx->lock); - /* if vblank was enabled status, enable it again. */ - if (test_and_clear_bit(0, &ctx->irq_flags)) - vidi_enable_vblank(ctx->crtc); + ctx->suspended = false; - for (i = 0; i < WINDOWS_NR; i++) { - plane = &ctx->planes[i]; - if (plane->enabled) - vidi_win_commit(ctx->crtc, i); - } - } else { - ctx->suspended = true; - } + /* if vblank was enabled status, enable it again. */ + if (test_and_clear_bit(0, &ctx->irq_flags)) + vidi_enable_vblank(ctx->crtc); - return 0; + mutex_unlock(&ctx->lock); } -static void vidi_dpms(struct exynos_drm_crtc *crtc, int mode) +static void vidi_disable(struct exynos_drm_crtc *crtc) { struct vidi_context *ctx = crtc->ctx; - DRM_DEBUG_KMS("%d\n", mode); - mutex_lock(&ctx->lock); - switch (mode) { - case DRM_MODE_DPMS_ON: - vidi_power_on(ctx, true); - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - vidi_power_on(ctx, false); - break; - default: - DRM_DEBUG_KMS("unspecified mode %d\n", mode); - break; - } + ctx->suspended = true; mutex_unlock(&ctx->lock); } @@ -218,11 +175,11 @@ static int vidi_ctx_initialize(struct vidi_context *ctx, } static const struct exynos_drm_crtc_ops vidi_crtc_ops = { - .dpms = vidi_dpms, + .enable = vidi_enable, + .disable = vidi_disable, .enable_vblank = vidi_enable_vblank, .disable_vblank = vidi_disable_vblank, .win_commit = vidi_win_commit, - .win_disable = vidi_win_disable, }; static void vidi_fake_vblank_handler(struct work_struct *work) @@ -384,10 +341,13 @@ static void vidi_connector_destroy(struct drm_connector *connector) } static struct drm_connector_funcs vidi_connector_funcs = { - .dpms = drm_helper_connector_dpms, + .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = vidi_detect, .destroy = vidi_connector_destroy, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; static int vidi_get_modes(struct drm_connector *connector) @@ -520,16 +480,6 @@ static int vidi_probe(struct platform_device *pdev) ctx->default_win = 0; ctx->pdev = pdev; - ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC, - EXYNOS_DISPLAY_TYPE_VIDI); - if (ret) - return ret; - - ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR, - ctx->display.type); - if (ret) - goto err_del_crtc_component; - INIT_WORK(&ctx->work, vidi_fake_vblank_handler); mutex_init(&ctx->lock); @@ -539,7 +489,7 @@ static int vidi_probe(struct platform_device *pdev) ret = device_create_file(&pdev->dev, &dev_attr_connection); if (ret < 0) { DRM_ERROR("failed to create connection sysfs.\n"); - goto err_del_conn_component; + return ret; } ret = component_add(&pdev->dev, &vidi_component_ops); @@ -550,10 +500,6 @@ static int vidi_probe(struct platform_device *pdev) err_remove_file: device_remove_file(&pdev->dev, &dev_attr_connection); -err_del_conn_component: - exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR); -err_del_crtc_component: - exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC); return ret; } @@ -570,8 +516,6 @@ static int vidi_remove(struct platform_device *pdev) } component_del(&pdev->dev, &vidi_component_ops); - exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR); - exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC); return 0; } @@ -584,38 +528,3 @@ struct platform_driver vidi_driver = { .owner = THIS_MODULE, }, }; - -int exynos_drm_probe_vidi(void) -{ - struct platform_device *pdev; - int ret; - - pdev = platform_device_register_simple("exynos-drm-vidi", -1, NULL, 0); - if (IS_ERR(pdev)) - return PTR_ERR(pdev); - - ret = platform_driver_register(&vidi_driver); - if (ret) { - platform_device_unregister(pdev); - return ret; - } - - return ret; -} - -static int exynos_drm_remove_vidi_device(struct device *dev, void *data) -{ - platform_device_unregister(to_platform_device(dev)); - - return 0; -} - -void exynos_drm_remove_vidi(void) -{ - int ret = driver_for_each_device(&vidi_driver.driver, NULL, NULL, - exynos_drm_remove_vidi_device); - /* silence compiler warning */ - (void)ret; - - platform_driver_unregister(&vidi_driver); -} diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 5eba971f394a..99e286489031 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -17,6 +17,7 @@ #include <drm/drmP.h> #include <drm/drm_edid.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_atomic_helper.h> #include "regs-hdmi.h" @@ -1050,10 +1051,13 @@ static void hdmi_connector_destroy(struct drm_connector *connector) } static struct drm_connector_funcs hdmi_connector_funcs = { - .dpms = drm_helper_connector_dpms, + .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = hdmi_detect, .destroy = hdmi_connector_destroy, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; static int hdmi_get_modes(struct drm_connector *connector) @@ -2123,8 +2127,8 @@ static void hdmi_dpms(struct exynos_drm_display *display, int mode) */ if (crtc) funcs = crtc->helper_private; - if (funcs && funcs->dpms) - (*funcs->dpms)(crtc, mode); + if (funcs && funcs->disable) + (*funcs->disable)(crtc); hdmi_poweroff(hdata); break; @@ -2356,20 +2360,13 @@ static int hdmi_probe(struct platform_device *pdev) hdata->display.type = EXYNOS_DISPLAY_TYPE_HDMI; hdata->display.ops = &hdmi_display_ops; - ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR, - hdata->display.type); - if (ret) - return ret; - mutex_init(&hdata->hdmi_mutex); platform_set_drvdata(pdev, hdata); match = of_match_node(hdmi_match_types, dev->of_node); - if (!match) { - ret = -ENODEV; - goto err_del_component; - } + if (!match) + return -ENODEV; drv_data = (struct hdmi_driver_data *)match->data; hdata->type = drv_data->type; @@ -2389,13 +2386,13 @@ static int hdmi_probe(struct platform_device *pdev) hdata->regs = devm_ioremap_resource(dev, res); if (IS_ERR(hdata->regs)) { ret = PTR_ERR(hdata->regs); - goto err_del_component; + return ret; } ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD"); if (ret) { DRM_ERROR("failed to request HPD gpio\n"); - goto err_del_component; + return ret; } ddc_node = hdmi_legacy_ddc_dt_binding(dev); @@ -2406,8 +2403,7 @@ static int hdmi_probe(struct platform_device *pdev) ddc_node = of_parse_phandle(dev->of_node, "ddc", 0); if (!ddc_node) { DRM_ERROR("Failed to find ddc node in device tree\n"); - ret = -ENODEV; - goto err_del_component; + return -ENODEV; } out_get_ddc_adpt: @@ -2491,9 +2487,6 @@ err_hdmiphy: err_ddc: put_device(&hdata->ddc_adpt->dev); -err_del_component: - exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR); - return ret; } @@ -2513,7 +2506,6 @@ static int hdmi_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); component_del(&pdev->dev, &hdmi_component_ops); - exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR); return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 8874c1fcb3ab..cae98db33062 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -882,10 +882,12 @@ static int mixer_initialize(struct mixer_context *mixer_ctx, } } - if (!is_drm_iommu_supported(mixer_ctx->drm_dev)) - return 0; + ret = drm_iommu_attach_device_if_possible(mixer_ctx->crtc, drm_dev, + mixer_ctx->dev); + if (ret) + priv->pipe--; - return drm_iommu_attach_device(mixer_ctx->drm_dev, mixer_ctx->dev); + return ret; } static void mixer_ctx_remove(struct mixer_context *mixer_ctx) @@ -937,8 +939,6 @@ static void mixer_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) vp_video_buffer(mixer_ctx, win); else mixer_graph_buffer(mixer_ctx, win); - - mixer_ctx->planes[win].enabled = true; } static void mixer_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) @@ -952,7 +952,6 @@ static void mixer_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) mutex_lock(&mixer_ctx->mixer_mutex); if (!mixer_ctx->powered) { mutex_unlock(&mixer_ctx->mixer_mutex); - mixer_ctx->planes[win].resume = false; return; } mutex_unlock(&mixer_ctx->mixer_mutex); @@ -964,8 +963,6 @@ static void mixer_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) mixer_vsync_set_update(mixer_ctx, true); spin_unlock_irqrestore(&res->reg_slock, flags); - - mixer_ctx->planes[win].enabled = false; } static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc) @@ -1000,36 +997,11 @@ static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc) drm_vblank_put(mixer_ctx->drm_dev, mixer_ctx->pipe); } -static void mixer_window_suspend(struct mixer_context *ctx) -{ - struct exynos_drm_plane *plane; - int i; - - for (i = 0; i < MIXER_WIN_NR; i++) { - plane = &ctx->planes[i]; - plane->resume = plane->enabled; - mixer_win_disable(ctx->crtc, i); - } - mixer_wait_for_vblank(ctx->crtc); -} - -static void mixer_window_resume(struct mixer_context *ctx) -{ - struct exynos_drm_plane *plane; - int i; - - for (i = 0; i < MIXER_WIN_NR; i++) { - plane = &ctx->planes[i]; - plane->enabled = plane->resume; - plane->resume = false; - if (plane->enabled) - mixer_win_commit(ctx->crtc, i); - } -} - -static void mixer_poweron(struct mixer_context *ctx) +static void mixer_enable(struct exynos_drm_crtc *crtc) { + struct mixer_context *ctx = crtc->ctx; struct mixer_resources *res = &ctx->mixer_res; + int ret; mutex_lock(&ctx->mixer_mutex); if (ctx->powered) { @@ -1041,12 +1013,32 @@ static void mixer_poweron(struct mixer_context *ctx) pm_runtime_get_sync(ctx->dev); - clk_prepare_enable(res->mixer); - clk_prepare_enable(res->hdmi); + ret = clk_prepare_enable(res->mixer); + if (ret < 0) { + DRM_ERROR("Failed to prepare_enable the mixer clk [%d]\n", ret); + return; + } + ret = clk_prepare_enable(res->hdmi); + if (ret < 0) { + DRM_ERROR("Failed to prepare_enable the hdmi clk [%d]\n", ret); + return; + } if (ctx->vp_enabled) { - clk_prepare_enable(res->vp); - if (ctx->has_sclk) - clk_prepare_enable(res->sclk_mixer); + ret = clk_prepare_enable(res->vp); + if (ret < 0) { + DRM_ERROR("Failed to prepare_enable the vp clk [%d]\n", + ret); + return; + } + if (ctx->has_sclk) { + ret = clk_prepare_enable(res->sclk_mixer); + if (ret < 0) { + DRM_ERROR("Failed to prepare_enable the " \ + "sclk_mixer clk [%d]\n", + ret); + return; + } + } } mutex_lock(&ctx->mixer_mutex); @@ -1057,13 +1049,13 @@ static void mixer_poweron(struct mixer_context *ctx) mixer_reg_write(res, MXR_INT_EN, ctx->int_en); mixer_win_reset(ctx); - - mixer_window_resume(ctx); } -static void mixer_poweroff(struct mixer_context *ctx) +static void mixer_disable(struct exynos_drm_crtc *crtc) { + struct mixer_context *ctx = crtc->ctx; struct mixer_resources *res = &ctx->mixer_res; + int i; mutex_lock(&ctx->mixer_mutex); if (!ctx->powered) { @@ -1074,7 +1066,9 @@ static void mixer_poweroff(struct mixer_context *ctx) mixer_stop(ctx); mixer_regs_dump(ctx); - mixer_window_suspend(ctx); + + for (i = 0; i < MIXER_WIN_NR; i++) + mixer_win_disable(crtc, i); ctx->int_en = mixer_reg_read(res, MXR_INT_EN); @@ -1093,23 +1087,6 @@ static void mixer_poweroff(struct mixer_context *ctx) pm_runtime_put_sync(ctx->dev); } -static void mixer_dpms(struct exynos_drm_crtc *crtc, int mode) -{ - switch (mode) { - case DRM_MODE_DPMS_ON: - mixer_poweron(crtc->ctx); - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - mixer_poweroff(crtc->ctx); - break; - default: - DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode); - break; - } -} - /* Only valid for Mixer version 16.0.33.0 */ int mixer_check_mode(struct drm_display_mode *mode) { @@ -1131,7 +1108,8 @@ int mixer_check_mode(struct drm_display_mode *mode) } static const struct exynos_drm_crtc_ops mixer_crtc_ops = { - .dpms = mixer_dpms, + .enable = mixer_enable, + .disable = mixer_disable, .enable_vblank = mixer_enable_vblank, .disable_vblank = mixer_disable_vblank, .wait_for_vblank = mixer_wait_for_vblank, @@ -1280,18 +1258,9 @@ static int mixer_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ctx); - ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC, - EXYNOS_DISPLAY_TYPE_HDMI); - if (ret) - return ret; - ret = component_add(&pdev->dev, &mixer_component_ops); - if (ret) { - exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC); - return ret; - } - - pm_runtime_enable(dev); + if (!ret) + pm_runtime_enable(dev); return ret; } @@ -1301,7 +1270,6 @@ static int mixer_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); component_del(&pdev->dev, &mixer_component_ops); - exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC); return 0; } diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 9605ff8f2fcd..306d9e4e5cf3 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -123,7 +123,7 @@ static const struct drm_i915_cmd_descriptor common_cmds[] = { CMD( MI_SEMAPHORE_MBOX, SMI, !F, 0xFF, R ), CMD( MI_STORE_DWORD_INDEX, SMI, !F, 0xFF, R ), CMD( MI_LOAD_REGISTER_IMM(1), SMI, !F, 0xFF, W, - .reg = { .offset = 1, .mask = 0x007FFFFC } ), + .reg = { .offset = 1, .mask = 0x007FFFFC, .step = 2 } ), CMD( MI_STORE_REGISTER_MEM(1), SMI, !F, 0xFF, W | B, .reg = { .offset = 1, .mask = 0x007FFFFC }, .bits = {{ @@ -395,16 +395,38 @@ static const struct drm_i915_cmd_table hsw_blt_ring_cmds[] = { /* * Register whitelists, sorted by increasing register offset. + */ + +/* + * An individual whitelist entry granting access to register addr. If + * mask is non-zero the argument of immediate register writes will be + * AND-ed with mask, and the command will be rejected if the result + * doesn't match value. + * + * Registers with non-zero mask are only allowed to be written using + * LRI. + */ +struct drm_i915_reg_descriptor { + u32 addr; + u32 mask; + u32 value; +}; + +/* Convenience macro for adding 32-bit registers. */ +#define REG32(address, ...) \ + { .addr = address, __VA_ARGS__ } + +/* + * Convenience macro for adding 64-bit registers. * * Some registers that userspace accesses are 64 bits. The register * access commands only allow 32-bit accesses. Hence, we have to include * entries for both halves of the 64-bit registers. */ +#define REG64(addr) \ + REG32(addr), REG32(addr + sizeof(u32)) -/* Convenience macro for adding 64-bit registers */ -#define REG64(addr) (addr), (addr + sizeof(u32)) - -static const u32 gen7_render_regs[] = { +static const struct drm_i915_reg_descriptor gen7_render_regs[] = { REG64(GPGPU_THREADS_DISPATCHED), REG64(HS_INVOCATION_COUNT), REG64(DS_INVOCATION_COUNT), @@ -417,15 +439,15 @@ static const u32 gen7_render_regs[] = { REG64(CL_PRIMITIVES_COUNT), REG64(PS_INVOCATION_COUNT), REG64(PS_DEPTH_COUNT), - OACONTROL, /* Only allowed for LRI and SRM. See below. */ + REG32(OACONTROL), /* Only allowed for LRI and SRM. See below. */ REG64(MI_PREDICATE_SRC0), REG64(MI_PREDICATE_SRC1), - GEN7_3DPRIM_END_OFFSET, - GEN7_3DPRIM_START_VERTEX, - GEN7_3DPRIM_VERTEX_COUNT, - GEN7_3DPRIM_INSTANCE_COUNT, - GEN7_3DPRIM_START_INSTANCE, - GEN7_3DPRIM_BASE_VERTEX, + REG32(GEN7_3DPRIM_END_OFFSET), + REG32(GEN7_3DPRIM_START_VERTEX), + REG32(GEN7_3DPRIM_VERTEX_COUNT), + REG32(GEN7_3DPRIM_INSTANCE_COUNT), + REG32(GEN7_3DPRIM_START_INSTANCE), + REG32(GEN7_3DPRIM_BASE_VERTEX), REG64(GEN7_SO_NUM_PRIMS_WRITTEN(0)), REG64(GEN7_SO_NUM_PRIMS_WRITTEN(1)), REG64(GEN7_SO_NUM_PRIMS_WRITTEN(2)), @@ -434,33 +456,41 @@ static const u32 gen7_render_regs[] = { REG64(GEN7_SO_PRIM_STORAGE_NEEDED(1)), REG64(GEN7_SO_PRIM_STORAGE_NEEDED(2)), REG64(GEN7_SO_PRIM_STORAGE_NEEDED(3)), - GEN7_SO_WRITE_OFFSET(0), - GEN7_SO_WRITE_OFFSET(1), - GEN7_SO_WRITE_OFFSET(2), - GEN7_SO_WRITE_OFFSET(3), - GEN7_L3SQCREG1, - GEN7_L3CNTLREG2, - GEN7_L3CNTLREG3, + REG32(GEN7_SO_WRITE_OFFSET(0)), + REG32(GEN7_SO_WRITE_OFFSET(1)), + REG32(GEN7_SO_WRITE_OFFSET(2)), + REG32(GEN7_SO_WRITE_OFFSET(3)), + REG32(GEN7_L3SQCREG1), + REG32(GEN7_L3CNTLREG2), + REG32(GEN7_L3CNTLREG3), + REG32(HSW_SCRATCH1, + .mask = ~HSW_SCRATCH1_L3_DATA_ATOMICS_DISABLE, + .value = 0), + REG32(HSW_ROW_CHICKEN3, + .mask = ~(HSW_ROW_CHICKEN3_L3_GLOBAL_ATOMICS_DISABLE << 16 | + HSW_ROW_CHICKEN3_L3_GLOBAL_ATOMICS_DISABLE), + .value = 0), }; -static const u32 gen7_blt_regs[] = { - BCS_SWCTRL, +static const struct drm_i915_reg_descriptor gen7_blt_regs[] = { + REG32(BCS_SWCTRL), }; -static const u32 ivb_master_regs[] = { - FORCEWAKE_MT, - DERRMR, - GEN7_PIPE_DE_LOAD_SL(PIPE_A), - GEN7_PIPE_DE_LOAD_SL(PIPE_B), - GEN7_PIPE_DE_LOAD_SL(PIPE_C), +static const struct drm_i915_reg_descriptor ivb_master_regs[] = { + REG32(FORCEWAKE_MT), + REG32(DERRMR), + REG32(GEN7_PIPE_DE_LOAD_SL(PIPE_A)), + REG32(GEN7_PIPE_DE_LOAD_SL(PIPE_B)), + REG32(GEN7_PIPE_DE_LOAD_SL(PIPE_C)), }; -static const u32 hsw_master_regs[] = { - FORCEWAKE_MT, - DERRMR, +static const struct drm_i915_reg_descriptor hsw_master_regs[] = { + REG32(FORCEWAKE_MT), + REG32(DERRMR), }; #undef REG64 +#undef REG32 static u32 gen7_render_get_cmd_length_mask(u32 cmd_header) { @@ -550,14 +580,16 @@ static bool validate_cmds_sorted(struct intel_engine_cs *ring, return ret; } -static bool check_sorted(int ring_id, const u32 *reg_table, int reg_count) +static bool check_sorted(int ring_id, + const struct drm_i915_reg_descriptor *reg_table, + int reg_count) { int i; u32 previous = 0; bool ret = true; for (i = 0; i < reg_count; i++) { - u32 curr = reg_table[i]; + u32 curr = reg_table[i].addr; if (curr < previous) { DRM_ERROR("CMD: table not sorted ring=%d entry=%d reg=0x%08X prev=0x%08X\n", @@ -804,18 +836,20 @@ find_cmd(struct intel_engine_cs *ring, return default_desc; } -static bool valid_reg(const u32 *table, int count, u32 addr) +static const struct drm_i915_reg_descriptor * +find_reg(const struct drm_i915_reg_descriptor *table, + int count, u32 addr) { - if (table && count != 0) { + if (table) { int i; for (i = 0; i < count; i++) { - if (table[i] == addr) - return true; + if (table[i].addr == addr) + return &table[i]; } } - return false; + return NULL; } static u32 *vmap_batch(struct drm_i915_gem_object *obj, @@ -934,7 +968,7 @@ bool i915_needs_cmd_parser(struct intel_engine_cs *ring) static bool check_cmd(const struct intel_engine_cs *ring, const struct drm_i915_cmd_descriptor *desc, - const u32 *cmd, + const u32 *cmd, u32 length, const bool is_master, bool *oacontrol_set) { @@ -950,38 +984,70 @@ static bool check_cmd(const struct intel_engine_cs *ring, } if (desc->flags & CMD_DESC_REGISTER) { - u32 reg_addr = cmd[desc->reg.offset] & desc->reg.mask; - /* - * OACONTROL requires some special handling for writes. We - * want to make sure that any batch which enables OA also - * disables it before the end of the batch. The goal is to - * prevent one process from snooping on the perf data from - * another process. To do that, we need to check the value - * that will be written to the register. Hence, limit - * OACONTROL writes to only MI_LOAD_REGISTER_IMM commands. + * Get the distance between individual register offset + * fields if the command can perform more than one + * access at a time. */ - if (reg_addr == OACONTROL) { - if (desc->cmd.value == MI_LOAD_REGISTER_MEM) { - DRM_DEBUG_DRIVER("CMD: Rejected LRM to OACONTROL\n"); + const u32 step = desc->reg.step ? desc->reg.step : length; + u32 offset; + + for (offset = desc->reg.offset; offset < length; + offset += step) { + const u32 reg_addr = cmd[offset] & desc->reg.mask; + const struct drm_i915_reg_descriptor *reg = + find_reg(ring->reg_table, ring->reg_count, + reg_addr); + + if (!reg && is_master) + reg = find_reg(ring->master_reg_table, + ring->master_reg_count, + reg_addr); + + if (!reg) { + DRM_DEBUG_DRIVER("CMD: Rejected register 0x%08X in command: 0x%08X (ring=%d)\n", + reg_addr, *cmd, ring->id); return false; } - if (desc->cmd.value == MI_LOAD_REGISTER_IMM(1)) - *oacontrol_set = (cmd[2] != 0); - } + /* + * OACONTROL requires some special handling for + * writes. We want to make sure that any batch which + * enables OA also disables it before the end of the + * batch. The goal is to prevent one process from + * snooping on the perf data from another process. To do + * that, we need to check the value that will be written + * to the register. Hence, limit OACONTROL writes to + * only MI_LOAD_REGISTER_IMM commands. + */ + if (reg_addr == OACONTROL) { + if (desc->cmd.value == MI_LOAD_REGISTER_MEM) { + DRM_DEBUG_DRIVER("CMD: Rejected LRM to OACONTROL\n"); + return false; + } + + if (desc->cmd.value == MI_LOAD_REGISTER_IMM(1)) + *oacontrol_set = (cmd[offset + 1] != 0); + } - if (!valid_reg(ring->reg_table, - ring->reg_count, reg_addr)) { - if (!is_master || - !valid_reg(ring->master_reg_table, - ring->master_reg_count, - reg_addr)) { - DRM_DEBUG_DRIVER("CMD: Rejected register 0x%08X in command: 0x%08X (ring=%d)\n", - reg_addr, - *cmd, - ring->id); - return false; + /* + * Check the value written to the register against the + * allowed mask/value pair given in the whitelist entry. + */ + if (reg->mask) { + if (desc->cmd.value == MI_LOAD_REGISTER_MEM) { + DRM_DEBUG_DRIVER("CMD: Rejected LRM to masked register 0x%08X\n", + reg_addr); + return false; + } + + if (desc->cmd.value == MI_LOAD_REGISTER_IMM(1) && + (offset + 2 > length || + (cmd[offset + 1] & reg->mask) != reg->value)) { + DRM_DEBUG_DRIVER("CMD: Rejected LRI to masked register 0x%08X\n", + reg_addr); + return false; + } } } } @@ -1105,7 +1171,8 @@ int i915_parse_cmds(struct intel_engine_cs *ring, break; } - if (!check_cmd(ring, desc, cmd, is_master, &oacontrol_set)) { + if (!check_cmd(ring, desc, cmd, length, is_master, + &oacontrol_set)) { ret = -EINVAL; break; } diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 88cc793c46d3..82bbe3f2a7e1 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1725,12 +1725,15 @@ static int i915_sr_status(struct seq_file *m, void *unused) if (HAS_PCH_SPLIT(dev)) sr_enabled = I915_READ(WM1_LP_ILK) & WM1_LP_SR_EN; - else if (IS_CRESTLINE(dev) || IS_I945G(dev) || IS_I945GM(dev)) + else if (IS_CRESTLINE(dev) || IS_G4X(dev) || + IS_I945G(dev) || IS_I945GM(dev)) sr_enabled = I915_READ(FW_BLC_SELF) & FW_BLC_SELF_EN; else if (IS_I915GM(dev)) sr_enabled = I915_READ(INSTPM) & INSTPM_SELF_EN; else if (IS_PINEVIEW(dev)) sr_enabled = I915_READ(DSPFW3) & PINEVIEW_SELF_REFRESH_EN; + else if (IS_VALLEYVIEW(dev)) + sr_enabled = I915_READ(FW_BLC_SELF_VLV) & FW_CSPWRDWNEN; intel_runtime_pm_put(dev_priv); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 72f5a3f9dbf2..542fac628b28 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2300,10 +2300,15 @@ struct drm_i915_cmd_descriptor { * Describes where to find a register address in the command to check * against the ring's register whitelist. Only valid if flags has the * CMD_DESC_REGISTER bit set. + * + * A non-zero step value implies that the command may access multiple + * registers in sequence (e.g. LRI), in that case step gives the + * distance in dwords between individual offset fields. */ struct { u32 offset; u32 mask; + u32 step; } reg; #define MAX_CMD_DESC_BITMASKS 3 diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index be35f0486202..248fd1ac7b3a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2813,9 +2813,6 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring) { WARN_ON(i915_verify_lists(ring->dev)); - if (list_empty(&ring->active_list)) - return; - /* Retire requests first as we use it above for the early return. * If we retire requests last, we may use a later seqno and so clear * the requests lists without clearing the active list, leading to @@ -3241,8 +3238,8 @@ int i915_vma_unbind(struct i915_vma *vma) } else if (vma->ggtt_view.pages) { sg_free_table(vma->ggtt_view.pages); kfree(vma->ggtt_view.pages); - vma->ggtt_view.pages = NULL; } + vma->ggtt_view.pages = NULL; } drm_mm_remove_node(&vma->node); diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 8867818b1401..d65cbe6afb92 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -157,9 +157,7 @@ i915_gem_alloc_context_obj(struct drm_device *dev, size_t size) struct drm_i915_gem_object *obj; int ret; - obj = i915_gem_object_create_stolen(dev, size); - if (obj == NULL) - obj = i915_gem_alloc_object(dev, size); + obj = i915_gem_alloc_object(dev, size); if (obj == NULL) return ERR_PTR(-ENOMEM); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index bd0e4bda2c64..a7fa14516cda 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -32,6 +32,7 @@ #include "i915_trace.h" #include "intel_drv.h" #include <linux/dma_remapping.h> +#include <linux/uaccess.h> #define __EXEC_OBJECT_HAS_PIN (1<<31) #define __EXEC_OBJECT_HAS_FENCE (1<<30) @@ -458,7 +459,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, } /* We can't wait for rendering with pagefaults disabled */ - if (obj->active && in_atomic()) + if (obj->active && pagefault_disabled()) return -EFAULT; if (use_cpu_reloc(obj)) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 619dad1b2386..dcc6a88c560e 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -516,17 +516,17 @@ static void gen8_ppgtt_clear_range(struct i915_address_space *vm, struct page *page_table; if (WARN_ON(!ppgtt->pdp.page_directory[pdpe])) - continue; + break; pd = ppgtt->pdp.page_directory[pdpe]; if (WARN_ON(!pd->page_table[pde])) - continue; + break; pt = pd->page_table[pde]; if (WARN_ON(!pt->page)) - continue; + break; page_table = pt->page; @@ -2546,6 +2546,8 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj; struct i915_address_space *vm; + struct i915_vma *vma; + bool flush; i915_check_and_clear_faults(dev); @@ -2555,16 +2557,23 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) dev_priv->gtt.base.total, true); + /* Cache flush objects bound into GGTT and rebind them. */ + vm = &dev_priv->gtt.base; list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { - struct i915_vma *vma = i915_gem_obj_to_vma(obj, - &dev_priv->gtt.base); - if (!vma) - continue; + flush = false; + list_for_each_entry(vma, &obj->vma_list, vma_link) { + if (vma->vm != vm) + continue; - i915_gem_clflush_object(obj, obj->pin_display); - WARN_ON(i915_vma_bind(vma, obj->cache_level, PIN_UPDATE)); - } + WARN_ON(i915_vma_bind(vma, obj->cache_level, + PIN_UPDATE)); + flush = true; + } + + if (flush) + i915_gem_clflush_object(obj, obj->pin_display); + } if (INTEL_INFO(dev)->gen >= 8) { if (IS_CHERRYVIEW(dev) || IS_BROXTON(dev)) diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index 633bd1fcab69..d61e74a08f82 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -183,8 +183,18 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev) if (IS_GEN4(dev)) { uint32_t ddc2 = I915_READ(DCC2); - if (!(ddc2 & DCC2_MODIFIED_ENHANCED_DISABLE)) + if (!(ddc2 & DCC2_MODIFIED_ENHANCED_DISABLE)) { + /* Since the swizzling may vary within an + * object, we have no idea what the swizzling + * is for any page in particular. Thus we + * cannot migrate tiled pages using the GPU, + * nor can we tell userspace what the exact + * swizzling is for any object. + */ dev_priv->quirks |= QUIRK_PIN_SWIZZLED_PAGES; + swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; + swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; + } } if (dcc == 0xffffffff) { diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 6d3fead3a358..2030f602cbf8 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3491,6 +3491,7 @@ enum skl_disp_power_wells { #define BLM_POLARITY_PNV (1 << 0) /* pnv only */ #define BLC_HIST_CTL (dev_priv->info.display_mmio_offset + 0x61260) +#define BLM_HISTOGRAM_ENABLE (1 << 31) /* New registers for PCH-split platforms. Safe where new bits show up, the * register layout machtes with gen4 BLC_PWM_CTL[12]. */ @@ -6941,6 +6942,9 @@ enum skl_disp_power_wells { #define AUDIO_CP_READY(trans) ((1 << 1) << ((trans) * 4)) #define AUDIO_ELD_VALID(trans) ((1 << 0) << ((trans) * 4)) +#define HSW_AUD_CHICKENBIT 0x65f10 +#define SKL_AUD_CODEC_WAKE_SIGNAL (1 << 15) + /* HSW Power Wells */ #define HSW_PWR_WELL_BIOS 0x45400 /* CTL1 */ #define HSW_PWR_WELL_DRIVER 0x45404 /* CTL2 */ diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index c4312177b0ee..3da9b8409f20 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -470,6 +470,32 @@ static void i915_audio_component_put_power(struct device *dev) intel_display_power_put(dev_to_i915(dev), POWER_DOMAIN_AUDIO); } +static void i915_audio_component_codec_wake_override(struct device *dev, + bool enable) +{ + struct drm_i915_private *dev_priv = dev_to_i915(dev); + u32 tmp; + + if (!IS_SKYLAKE(dev_priv)) + return; + + /* + * Enable/disable generating the codec wake signal, overriding the + * internal logic to generate the codec wake to controller. + */ + tmp = I915_READ(HSW_AUD_CHICKENBIT); + tmp &= ~SKL_AUD_CODEC_WAKE_SIGNAL; + I915_WRITE(HSW_AUD_CHICKENBIT, tmp); + usleep_range(1000, 1500); + + if (enable) { + tmp = I915_READ(HSW_AUD_CHICKENBIT); + tmp |= SKL_AUD_CODEC_WAKE_SIGNAL; + I915_WRITE(HSW_AUD_CHICKENBIT, tmp); + usleep_range(1000, 1500); + } +} + /* Get CDCLK in kHz */ static int i915_audio_component_get_cdclk_freq(struct device *dev) { @@ -491,6 +517,7 @@ static const struct i915_audio_component_ops i915_audio_component_ops = { .owner = THIS_MODULE, .get_power = i915_audio_component_get_power, .put_power = i915_audio_component_put_power, + .codec_wake_override = i915_audio_component_codec_wake_override, .get_cdclk_freq = i915_audio_component_get_cdclk_freq, }; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4e3f302d86f7..ba9321998a41 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -87,7 +87,8 @@ static void ironlake_pch_clock_get(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config); static int intel_set_mode(struct drm_crtc *crtc, - struct drm_atomic_state *state); + struct drm_atomic_state *state, + bool force_restore); static int intel_framebuffer_init(struct drm_device *dev, struct intel_framebuffer *ifb, struct drm_mode_fb_cmd2 *mode_cmd, @@ -4853,6 +4854,9 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc) struct intel_plane *intel_plane; int pipe = intel_crtc->pipe; + if (!intel_crtc->active) + return; + intel_crtc_wait_for_pending_flips(crtc); intel_pre_disable_primary(crtc); @@ -7886,7 +7890,7 @@ static void chv_crtc_clock_get(struct intel_crtc *crtc, int pipe = pipe_config->cpu_transcoder; enum dpio_channel port = vlv_pipe_to_channel(pipe); intel_clock_t clock; - u32 cmn_dw13, pll_dw0, pll_dw1, pll_dw2; + u32 cmn_dw13, pll_dw0, pll_dw1, pll_dw2, pll_dw3; int refclk = 100000; mutex_lock(&dev_priv->sb_lock); @@ -7894,10 +7898,13 @@ static void chv_crtc_clock_get(struct intel_crtc *crtc, pll_dw0 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW0(port)); pll_dw1 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW1(port)); pll_dw2 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW2(port)); + pll_dw3 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW3(port)); mutex_unlock(&dev_priv->sb_lock); clock.m1 = (pll_dw1 & 0x7) == DPIO_CHV_M1_DIV_BY_2 ? 2 : 0; - clock.m2 = ((pll_dw0 & 0xff) << 22) | (pll_dw2 & 0x3fffff); + clock.m2 = (pll_dw0 & 0xff) << 22; + if (pll_dw3 & DPIO_CHV_FRAC_DIV_EN) + clock.m2 |= pll_dw2 & 0x3fffff; clock.n = (pll_dw1 >> DPIO_CHV_N_DIV_SHIFT) & 0xf; clock.p1 = (cmn_dw13 >> DPIO_CHV_P1_DIV_SHIFT) & 0x7; clock.p2 = (cmn_dw13 >> DPIO_CHV_P2_DIV_SHIFT) & 0x1f; @@ -10096,7 +10103,7 @@ retry: drm_mode_copy(&crtc_state->base.mode, mode); - if (intel_set_mode(crtc, state)) { + if (intel_set_mode(crtc, state, true)) { DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n"); if (old->release_fb) old->release_fb->funcs->destroy(old->release_fb); @@ -10170,7 +10177,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, if (ret) goto fail; - ret = intel_set_mode(crtc, state); + ret = intel_set_mode(crtc, state, true); if (ret) goto fail; @@ -11385,10 +11392,6 @@ static void intel_modeset_fixup_state(struct drm_atomic_state *state) crtc->base.enabled = crtc->base.state->enable; crtc->config = to_intel_crtc_state(crtc->base.state); } - - /* Copy the new configuration to the staged state, to keep the few - * pieces of code that haven't been converted yet happy */ - intel_modeset_update_staged_output_state(state->dev); } static void @@ -11870,15 +11873,15 @@ intel_modeset_update_state(struct drm_atomic_state *state) if (!intel_encoder->base.crtc) continue; - for_each_crtc_in_state(state, crtc, crtc_state, i) - if (crtc == intel_encoder->base.crtc) - break; + for_each_crtc_in_state(state, crtc, crtc_state, i) { + if (crtc != intel_encoder->base.crtc) + continue; - if (crtc != intel_encoder->base.crtc) - continue; + if (crtc_state->enable && needs_modeset(crtc_state)) + intel_encoder->connectors_active = false; - if (crtc_state->enable && needs_modeset(crtc_state)) - intel_encoder->connectors_active = false; + break; + } } drm_atomic_helper_swap_state(state->dev, state); @@ -11893,24 +11896,24 @@ intel_modeset_update_state(struct drm_atomic_state *state) if (!connector->encoder || !connector->encoder->crtc) continue; - for_each_crtc_in_state(state, crtc, crtc_state, i) - if (crtc == connector->encoder->crtc) - break; + for_each_crtc_in_state(state, crtc, crtc_state, i) { + if (crtc != connector->encoder->crtc) + continue; - if (crtc != connector->encoder->crtc) - continue; + if (crtc->state->enable && needs_modeset(crtc->state)) { + struct drm_property *dpms_property = + dev->mode_config.dpms_property; - if (crtc->state->enable && needs_modeset(crtc->state)) { - struct drm_property *dpms_property = - dev->mode_config.dpms_property; + connector->dpms = DRM_MODE_DPMS_ON; + drm_object_property_set_value(&connector->base, + dpms_property, + DRM_MODE_DPMS_ON); - connector->dpms = DRM_MODE_DPMS_ON; - drm_object_property_set_value(&connector->base, - dpms_property, - DRM_MODE_DPMS_ON); + intel_encoder = to_intel_encoder(connector->encoder); + intel_encoder->connectors_active = true; + } - intel_encoder = to_intel_encoder(connector->encoder); - intel_encoder->connectors_active = true; + break; } } @@ -12646,20 +12649,24 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc, } static int intel_set_mode_with_config(struct drm_crtc *crtc, - struct intel_crtc_state *pipe_config) + struct intel_crtc_state *pipe_config, + bool force_restore) { int ret; ret = __intel_set_mode(crtc, pipe_config); - if (ret == 0) + if (ret == 0 && force_restore) { + intel_modeset_update_staged_output_state(crtc->dev); intel_modeset_check_state(crtc->dev); + } return ret; } static int intel_set_mode(struct drm_crtc *crtc, - struct drm_atomic_state *state) + struct drm_atomic_state *state, + bool force_restore) { struct intel_crtc_state *pipe_config; int ret = 0; @@ -12670,7 +12677,7 @@ static int intel_set_mode(struct drm_crtc *crtc, goto out; } - ret = intel_set_mode_with_config(crtc, pipe_config); + ret = intel_set_mode_with_config(crtc, pipe_config, force_restore); if (ret) goto out; @@ -12682,7 +12689,6 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_atomic_state *state; - struct intel_crtc *intel_crtc; struct intel_encoder *encoder; struct intel_connector *connector; struct drm_connector_state *connector_state; @@ -12725,29 +12731,23 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) } } - for_each_intel_crtc(dev, intel_crtc) { - if (intel_crtc->new_enabled == intel_crtc->base.enabled) - continue; - - crtc_state = intel_atomic_get_crtc_state(state, intel_crtc); - if (IS_ERR(crtc_state)) { - DRM_DEBUG_KMS("Failed to add [CRTC:%d] to state: %ld\n", - intel_crtc->base.base.id, - PTR_ERR(crtc_state)); - continue; - } + crtc_state = intel_atomic_get_crtc_state(state, to_intel_crtc(crtc)); + if (IS_ERR(crtc_state)) { + DRM_DEBUG_KMS("Failed to add [CRTC:%d] to state: %ld\n", + crtc->base.id, PTR_ERR(crtc_state)); + drm_atomic_state_free(state); + return; + } - crtc_state->base.active = crtc_state->base.enable = - intel_crtc->new_enabled; + crtc_state->base.active = crtc_state->base.enable = + to_intel_crtc(crtc)->new_enabled; - if (&intel_crtc->base == crtc) - drm_mode_copy(&crtc_state->base.mode, &crtc->mode); - } + drm_mode_copy(&crtc_state->base.mode, &crtc->mode); intel_modeset_setup_plane_state(state, crtc, &crtc->mode, crtc->primary->fb, crtc->x, crtc->y); - ret = intel_set_mode(crtc, state); + ret = intel_set_mode(crtc, state, false); if (ret) drm_atomic_state_free(state); } @@ -12947,7 +12947,7 @@ static int intel_crtc_set_config(struct drm_mode_set *set) primary_plane_was_visible = primary_plane_visible(set->crtc); - ret = intel_set_mode_with_config(set->crtc, pipe_config); + ret = intel_set_mode_with_config(set->crtc, pipe_config, true); if (ret == 0 && pipe_config->base.enable && @@ -13276,7 +13276,7 @@ intel_check_primary_plane(struct drm_plane *plane, if (ret) return ret; - if (intel_crtc->active) { + if (crtc_state->base.active) { struct intel_plane_state *old_state = to_intel_plane_state(plane->state); @@ -13309,6 +13309,16 @@ intel_check_primary_plane(struct drm_plane *plane, intel_crtc->atomic.wait_vblank = true; } + /* + * FIXME: Actually if we will still have any other plane enabled + * on the pipe we could let IPS enabled still, but for + * now lets consider that when we make primary invisible + * by setting DSPCNTR to 0 on update_primary_plane function + * IPS needs to be disable. + */ + if (!state->visible || !fb) + intel_crtc->atomic.disable_ips = true; + intel_crtc->atomic.fb_bits |= INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe); @@ -13406,6 +13416,9 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc) if (intel_crtc->atomic.disable_fbc) intel_fbc_disable(dev); + if (intel_crtc->atomic.disable_ips) + hsw_disable_ips(intel_crtc); + if (intel_crtc->atomic.pre_disable_primary) intel_pre_disable_primary(crtc); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 280c282da9bd..6e8faa253792 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -893,10 +893,8 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, continue; } if (status & DP_AUX_CH_CTL_DONE) - break; + goto done; } - if (status & DP_AUX_CH_CTL_DONE) - break; } if ((status & DP_AUX_CH_CTL_DONE) == 0) { @@ -905,6 +903,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, goto out; } +done: /* Check for timeout or receive error. * Timeouts occur when the sink is not connected */ @@ -1141,6 +1140,9 @@ skl_edp_set_pll_config(struct intel_crtc_state *pipe_config, int link_clock) static void hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config, int link_bw) { + memset(&pipe_config->dpll_hw_state, 0, + sizeof(pipe_config->dpll_hw_state)); + switch (link_bw) { case DP_LINK_BW_1_62: pipe_config->ddi_pll_sel = PORT_CLK_SEL_LCPLL_810; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2afb31a46275..105928382e21 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -485,6 +485,7 @@ struct intel_crtc_atomic_commit { /* Sleepable operations to perform before commit */ bool wait_for_flips; bool disable_fbc; + bool disable_ips; bool pre_disable_primary; bool update_wm; unsigned disabled_planes; diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 92072f56e418..a64f26c670af 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -486,7 +486,7 @@ gmbus_xfer(struct i2c_adapter *adapter, struct intel_gmbus, adapter); struct drm_i915_private *dev_priv = bus->dev_priv; - int i, reg_offset; + int i = 0, inc, try = 0, reg_offset; int ret = 0; intel_aux_display_runtime_get(dev_priv); @@ -499,12 +499,14 @@ gmbus_xfer(struct i2c_adapter *adapter, reg_offset = dev_priv->gpio_mmio_base; +retry: I915_WRITE(GMBUS0 + reg_offset, bus->reg0); - for (i = 0; i < num; i++) { + for (; i < num; i += inc) { + inc = 1; if (gmbus_is_index_read(msgs, i, num)) { ret = gmbus_xfer_index_read(dev_priv, &msgs[i]); - i += 1; /* set i to the index of the read xfer */ + inc = 2; /* an index read is two msgs */ } else if (msgs[i].flags & I2C_M_RD) { ret = gmbus_xfer_read(dev_priv, &msgs[i], 0); } else { @@ -576,6 +578,18 @@ clear_err: adapter->name, msgs[i].addr, (msgs[i].flags & I2C_M_RD) ? 'r' : 'w', msgs[i].len); + /* + * Passive adapters sometimes NAK the first probe. Retry the first + * message once on -ENXIO for GMBUS transfers; the bit banging algorithm + * has retries internally. See also the retry loop in + * drm_do_probe_ddc_edid, which bails out on the first -ENXIO. + */ + if (ret == -ENXIO && i == 0 && try++ == 0) { + DRM_DEBUG_KMS("GMBUS [%s] NAK on first message, retry\n", + adapter->name); + goto retry; + } + goto out; timeout: diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 9f5485ddcbe6..9b74ffae5f5a 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1085,6 +1085,12 @@ static int gen8_init_common_ring(struct intel_engine_cs *ring) I915_WRITE_IMR(ring, ~(ring->irq_enable_mask | ring->irq_keep_mask)); I915_WRITE(RING_HWSTAM(ring->mmio_base), 0xffffffff); + if (ring->status_page.obj) { + I915_WRITE(RING_HWS_PGA(ring->mmio_base), + (u32)ring->status_page.gfx_addr); + POSTING_READ(RING_HWS_PGA(ring->mmio_base)); + } + I915_WRITE(RING_MODE_GEN7(ring), _MASKED_BIT_DISABLE(GFX_REPLAY_MODE) | _MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE)); diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 71e87abdcae7..481337436f72 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -396,16 +396,6 @@ int intel_opregion_notify_adapter(struct drm_device *dev, pci_power_t state) return -EINVAL; } -/* - * If the vendor backlight interface is not in use and ACPI backlight interface - * is broken, do not bother processing backlight change requests from firmware. - */ -static bool should_ignore_backlight_request(void) -{ - return acpi_video_backlight_support() && - !acpi_video_verify_backlight_support(); -} - static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -414,7 +404,7 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) DRM_DEBUG_DRIVER("bclp = 0x%08x\n", bclp); - if (should_ignore_backlight_request()) { + if (acpi_video_get_backlight_type() == acpi_backlight_native) { DRM_DEBUG_KMS("opregion backlight request ignored\n"); return 0; } diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 7d83527f95f7..55aad2322e10 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -907,6 +907,14 @@ static void i9xx_enable_backlight(struct intel_connector *connector) /* XXX: combine this into above write? */ intel_panel_actually_set_backlight(connector, panel->backlight.level); + + /* + * Needed to enable backlight on some 855gm models. BLC_HIST_CTL is + * 855gm only, but checking for gen2 is safe, as 855gm is the only gen2 + * that has backlight. + */ + if (IS_GEN2(dev)) + I915_WRITE(BLC_HIST_CTL, BLM_HISTOGRAM_ENABLE); } static void i965_enable_backlight(struct intel_connector *connector) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index d934f857394d..3817a6f00d9e 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -901,13 +901,6 @@ static int chv_init_workarounds(struct intel_engine_cs *ring) GEN6_WIZ_HASHING_MASK, GEN6_WIZ_HASHING_16x4); - if (INTEL_REVID(dev) == SKL_REVID_C0 || - INTEL_REVID(dev) == SKL_REVID_D0) - /* WaBarrierPerformanceFixDisable:skl */ - WA_SET_BIT_MASKED(HDC_CHICKEN0, - HDC_FENCE_DEST_SLM_DISABLE | - HDC_BARRIER_PERFORMANCE_DISABLE); - return 0; } @@ -1030,6 +1023,13 @@ static int skl_init_workarounds(struct intel_engine_cs *ring) WA_SET_BIT_MASKED(HIZ_CHICKEN, BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE); + if (INTEL_REVID(dev) == SKL_REVID_C0 || + INTEL_REVID(dev) == SKL_REVID_D0) + /* WaBarrierPerformanceFixDisable:skl */ + WA_SET_BIT_MASKED(HDC_CHICKEN0, + HDC_FENCE_DEST_SLM_DISABLE | + HDC_BARRIER_PERFORMANCE_DISABLE); + if (INTEL_REVID(dev) <= SKL_REVID_D0) { /* *Use Force Non-Coherent whenever executing a 3D context. This diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 39f6dfc0ee54..e539314ae87e 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -118,6 +118,7 @@ struct intel_ringbuffer { }; struct intel_context; +struct drm_i915_reg_descriptor; struct intel_engine_cs { const char *name; @@ -300,14 +301,14 @@ struct intel_engine_cs { /* * Table of registers allowed in commands that read/write registers. */ - const u32 *reg_table; + const struct drm_i915_reg_descriptor *reg_table; int reg_count; /* * Table of registers allowed in commands that read/write registers, but * only from the DRM master. */ - const u32 *master_reg_table; + const struct drm_i915_reg_descriptor *master_reg_table; int master_reg_count; /* diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index d24ef75596a1..aa2fd751609c 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -2554,7 +2554,7 @@ intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device) DRM_DEBUG_KMS("initialising analog device %d\n", device); - intel_sdvo_connector = kzalloc(sizeof(*intel_sdvo_connector), GFP_KERNEL); + intel_sdvo_connector = intel_sdvo_connector_alloc(); if (!intel_sdvo_connector) return false; diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 6e84df9369a6..ad4b9010dfb0 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -1526,6 +1526,11 @@ static int mga_vga_mode_valid(struct drm_connector *connector, return MODE_BANDWIDTH; } + if ((mode->hdisplay % 8) != 0 || (mode->hsync_start % 8) != 0 || + (mode->hsync_end % 8) != 0 || (mode->htotal % 8) != 0) { + return MODE_H_ILLEGAL; + } + if (mode->crtc_hdisplay > 2048 || mode->crtc_hsync_start > 4096 || mode->crtc_hsync_end > 4096 || mode->crtc_htotal > 4096 || mode->crtc_vdisplay > 2048 || mode->crtc_vsync_start > 4096 || diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index 0a6f6764a37c..08ba8d0d93f5 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -46,3 +46,10 @@ config DRM_MSM_DSI Choose this option if you have a need for MIPI DSI connector support. +config DRM_MSM_DSI_PLL + bool "Enable DSI PLL driver in MSM DRM" + depends on DRM_MSM_DSI && COMMON_CLK + default y + help + Choose this option to enable DSI PLL driver which provides DSI + source clocks under common clock framework. diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index ab2086783fee..16a81b94d6f0 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -1,4 +1,5 @@ ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/msm +ccflags-$(CONFIG_DRM_MSM_DSI_PLL) += -Idrivers/gpu/drm/msm/dsi msm-y := \ adreno/adreno_device.o \ @@ -50,10 +51,14 @@ msm-y := \ msm-$(CONFIG_DRM_MSM_FBDEV) += msm_fbdev.o msm-$(CONFIG_COMMON_CLK) += mdp/mdp4/mdp4_lvds_pll.o + msm-$(CONFIG_DRM_MSM_DSI) += dsi/dsi.o \ dsi/dsi_host.o \ dsi/dsi_manager.o \ dsi/dsi_phy.o \ mdp/mdp5/mdp5_cmd_encoder.o +msm-$(CONFIG_DRM_MSM_DSI_PLL) += dsi/pll/dsi_pll.o \ + dsi/pll/dsi_pll_28nm.o + obj-$(CONFIG_DRM_MSM) += msm.o diff --git a/drivers/gpu/drm/msm/adreno/a2xx.xml.h b/drivers/gpu/drm/msm/adreno/a2xx.xml.h index edc845fffdf4..23176e402796 100644 --- a/drivers/gpu/drm/msm/adreno/a2xx.xml.h +++ b/drivers/gpu/drm/msm/adreno/a2xx.xml.h @@ -12,9 +12,9 @@ The rules-ng-ng source files this header was generated from are: - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) - /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2014-06-02 15:21:30) - /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2014-11-13 22:44:30) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 15085 bytes, from 2014-12-20 21:49:41) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 64344 bytes, from 2014-12-12 20:22:26) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 51069 bytes, from 2014-12-21 15:51:54) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14895 bytes, from 2015-04-19 15:23:28) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 66709 bytes, from 2015-04-12 18:16:35) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 60633 bytes, from 2015-05-20 14:48:19) Copyright (C) 2013-2014 by the following authors: - Rob Clark <robdclark@gmail.com> (robclark) diff --git a/drivers/gpu/drm/msm/adreno/a3xx.xml.h b/drivers/gpu/drm/msm/adreno/a3xx.xml.h index e91a739452d7..1c599e5cf318 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx.xml.h +++ b/drivers/gpu/drm/msm/adreno/a3xx.xml.h @@ -12,11 +12,11 @@ The rules-ng-ng source files this header was generated from are: - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) - /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2014-06-02 15:21:30) - /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2014-11-13 22:44:30) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 15085 bytes, from 2014-12-20 21:49:41) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 64344 bytes, from 2014-12-12 20:22:26) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 51069 bytes, from 2014-12-21 15:51:54) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14895 bytes, from 2015-04-19 15:23:28) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 66709 bytes, from 2015-04-12 18:16:35) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 60633 bytes, from 2015-05-20 14:48:19) -Copyright (C) 2013-2014 by the following authors: +Copyright (C) 2013-2015 by the following authors: - Rob Clark <robdclark@gmail.com> (robclark) Permission is hereby granted, free of charge, to any person obtaining @@ -130,6 +130,10 @@ enum a3xx_tex_fmt { TFMT_I420_Y = 24, TFMT_I420_U = 26, TFMT_I420_V = 27, + TFMT_ATC_RGB = 32, + TFMT_ATC_RGBA_EXPLICIT = 33, + TFMT_ETC1 = 34, + TFMT_ATC_RGBA_INTERPOLATED = 35, TFMT_DXT1 = 36, TFMT_DXT3 = 37, TFMT_DXT5 = 38, @@ -178,10 +182,13 @@ enum a3xx_tex_fmt { TFMT_32_SINT = 92, TFMT_32_32_SINT = 93, TFMT_32_32_32_32_SINT = 95, - TFMT_RGTC2_SNORM = 112, - TFMT_RGTC2_UNORM = 113, - TFMT_RGTC1_SNORM = 114, - TFMT_RGTC1_UNORM = 115, + TFMT_ETC2_RG11_SNORM = 112, + TFMT_ETC2_RG11_UNORM = 113, + TFMT_ETC2_R11_SNORM = 114, + TFMT_ETC2_R11_UNORM = 115, + TFMT_ETC2_RGBA8 = 116, + TFMT_ETC2_RGB8A1 = 117, + TFMT_ETC2_RGB8 = 118, }; enum a3xx_tex_fetchsize { @@ -209,14 +216,24 @@ enum a3xx_color_fmt { RB_R10G10B10A2_UNORM = 16, RB_A8_UNORM = 20, RB_R8_UNORM = 21, + RB_R16_FLOAT = 24, + RB_R16G16_FLOAT = 25, RB_R16G16B16A16_FLOAT = 27, RB_R11G11B10_FLOAT = 28, + RB_R16_SNORM = 32, + RB_R16G16_SNORM = 33, + RB_R16G16B16A16_SNORM = 35, + RB_R16_UNORM = 36, + RB_R16G16_UNORM = 37, + RB_R16G16B16A16_UNORM = 39, RB_R16_SINT = 40, RB_R16G16_SINT = 41, RB_R16G16B16A16_SINT = 43, RB_R16_UINT = 44, RB_R16G16_UINT = 45, RB_R16G16B16A16_UINT = 47, + RB_R32_FLOAT = 48, + RB_R32G32_FLOAT = 49, RB_R32G32B32A32_FLOAT = 51, RB_R32_SINT = 52, RB_R32G32_SINT = 53, @@ -265,6 +282,12 @@ enum a3xx_intp_mode { FLAT = 1, }; +enum a3xx_repl_mode { + S = 1, + T = 2, + ONE_T = 3, +}; + enum a3xx_tex_filter { A3XX_TEX_NEAREST = 0, A3XX_TEX_LINEAR = 1, @@ -751,7 +774,7 @@ static inline uint32_t A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL(float val) #define A3XX_GRAS_SU_POLY_OFFSET_OFFSET__SHIFT 0 static inline uint32_t A3XX_GRAS_SU_POLY_OFFSET_OFFSET(float val) { - return ((((int32_t)(val * 16384.0))) << A3XX_GRAS_SU_POLY_OFFSET_OFFSET__SHIFT) & A3XX_GRAS_SU_POLY_OFFSET_OFFSET__MASK; + return ((((int32_t)(val * 64.0))) << A3XX_GRAS_SU_POLY_OFFSET_OFFSET__SHIFT) & A3XX_GRAS_SU_POLY_OFFSET_OFFSET__MASK; } #define REG_A3XX_GRAS_SU_MODE_CONTROL 0x00002070 @@ -854,6 +877,12 @@ static inline uint32_t A3XX_RB_MODE_CONTROL_RENDER_MODE(enum a3xx_render_mode va { return ((val) << A3XX_RB_MODE_CONTROL_RENDER_MODE__SHIFT) & A3XX_RB_MODE_CONTROL_RENDER_MODE__MASK; } +#define A3XX_RB_MODE_CONTROL_MRT__MASK 0x00003000 +#define A3XX_RB_MODE_CONTROL_MRT__SHIFT 12 +static inline uint32_t A3XX_RB_MODE_CONTROL_MRT(uint32_t val) +{ + return ((val) << A3XX_RB_MODE_CONTROL_MRT__SHIFT) & A3XX_RB_MODE_CONTROL_MRT__MASK; +} #define A3XX_RB_MODE_CONTROL_MARB_CACHE_SPLIT_MODE 0x00008000 #define A3XX_RB_MODE_CONTROL_PACKER_TIMER_ENABLE 0x00010000 @@ -1246,9 +1275,21 @@ static inline uint32_t A3XX_RB_STENCIL_CONTROL_ZFAIL_BF(enum adreno_stencil_op v #define REG_A3XX_RB_STENCIL_CLEAR 0x00002105 -#define REG_A3XX_RB_STENCIL_BUF_INFO 0x00002106 +#define REG_A3XX_RB_STENCIL_INFO 0x00002106 +#define A3XX_RB_STENCIL_INFO_STENCIL_BASE__MASK 0xfffff800 +#define A3XX_RB_STENCIL_INFO_STENCIL_BASE__SHIFT 11 +static inline uint32_t A3XX_RB_STENCIL_INFO_STENCIL_BASE(uint32_t val) +{ + return ((val >> 12) << A3XX_RB_STENCIL_INFO_STENCIL_BASE__SHIFT) & A3XX_RB_STENCIL_INFO_STENCIL_BASE__MASK; +} -#define REG_A3XX_RB_STENCIL_BUF_PITCH 0x00002107 +#define REG_A3XX_RB_STENCIL_PITCH 0x00002107 +#define A3XX_RB_STENCIL_PITCH__MASK 0xffffffff +#define A3XX_RB_STENCIL_PITCH__SHIFT 0 +static inline uint32_t A3XX_RB_STENCIL_PITCH(uint32_t val) +{ + return ((val >> 3) << A3XX_RB_STENCIL_PITCH__SHIFT) & A3XX_RB_STENCIL_PITCH__MASK; +} #define REG_A3XX_RB_STENCILREFMASK 0x00002108 #define A3XX_RB_STENCILREFMASK_STENCILREF__MASK 0x000000ff @@ -1356,6 +1397,7 @@ static inline uint32_t A3XX_PC_PRIM_VTX_CNTL_POLYMODE_BACK_PTYPE(enum adreno_pa_ { return ((val) << A3XX_PC_PRIM_VTX_CNTL_POLYMODE_BACK_PTYPE__SHIFT) & A3XX_PC_PRIM_VTX_CNTL_POLYMODE_BACK_PTYPE__MASK; } +#define A3XX_PC_PRIM_VTX_CNTL_POLYMODE_ENABLE 0x00001000 #define A3XX_PC_PRIM_VTX_CNTL_PRIMITIVE_RESTART 0x00100000 #define A3XX_PC_PRIM_VTX_CNTL_PROVOKING_VTX_LAST 0x02000000 #define A3XX_PC_PRIM_VTX_CNTL_PSIZE 0x04000000 @@ -1805,6 +1847,102 @@ static inline uint32_t A3XX_VPC_VARYING_INTERP_MODE_CF(enum a3xx_intp_mode val) static inline uint32_t REG_A3XX_VPC_VARYING_PS_REPL(uint32_t i0) { return 0x00002286 + 0x1*i0; } static inline uint32_t REG_A3XX_VPC_VARYING_PS_REPL_MODE(uint32_t i0) { return 0x00002286 + 0x1*i0; } +#define A3XX_VPC_VARYING_PS_REPL_MODE_C0__MASK 0x00000003 +#define A3XX_VPC_VARYING_PS_REPL_MODE_C0__SHIFT 0 +static inline uint32_t A3XX_VPC_VARYING_PS_REPL_MODE_C0(enum a3xx_repl_mode val) +{ + return ((val) << A3XX_VPC_VARYING_PS_REPL_MODE_C0__SHIFT) & A3XX_VPC_VARYING_PS_REPL_MODE_C0__MASK; +} +#define A3XX_VPC_VARYING_PS_REPL_MODE_C1__MASK 0x0000000c +#define A3XX_VPC_VARYING_PS_REPL_MODE_C1__SHIFT 2 +static inline uint32_t A3XX_VPC_VARYING_PS_REPL_MODE_C1(enum a3xx_repl_mode val) +{ + return ((val) << A3XX_VPC_VARYING_PS_REPL_MODE_C1__SHIFT) & A3XX_VPC_VARYING_PS_REPL_MODE_C1__MASK; +} +#define A3XX_VPC_VARYING_PS_REPL_MODE_C2__MASK 0x00000030 +#define A3XX_VPC_VARYING_PS_REPL_MODE_C2__SHIFT 4 +static inline uint32_t A3XX_VPC_VARYING_PS_REPL_MODE_C2(enum a3xx_repl_mode val) +{ + return ((val) << A3XX_VPC_VARYING_PS_REPL_MODE_C2__SHIFT) & A3XX_VPC_VARYING_PS_REPL_MODE_C2__MASK; +} +#define A3XX_VPC_VARYING_PS_REPL_MODE_C3__MASK 0x000000c0 +#define A3XX_VPC_VARYING_PS_REPL_MODE_C3__SHIFT 6 +static inline uint32_t A3XX_VPC_VARYING_PS_REPL_MODE_C3(enum a3xx_repl_mode val) +{ + return ((val) << A3XX_VPC_VARYING_PS_REPL_MODE_C3__SHIFT) & A3XX_VPC_VARYING_PS_REPL_MODE_C3__MASK; +} +#define A3XX_VPC_VARYING_PS_REPL_MODE_C4__MASK 0x00000300 +#define A3XX_VPC_VARYING_PS_REPL_MODE_C4__SHIFT 8 +static inline uint32_t A3XX_VPC_VARYING_PS_REPL_MODE_C4(enum a3xx_repl_mode val) +{ + return ((val) << A3XX_VPC_VARYING_PS_REPL_MODE_C4__SHIFT) & A3XX_VPC_VARYING_PS_REPL_MODE_C4__MASK; +} +#define A3XX_VPC_VARYING_PS_REPL_MODE_C5__MASK 0x00000c00 +#define A3XX_VPC_VARYING_PS_REPL_MODE_C5__SHIFT 10 +static inline uint32_t A3XX_VPC_VARYING_PS_REPL_MODE_C5(enum a3xx_repl_mode val) +{ + return ((val) << A3XX_VPC_VARYING_PS_REPL_MODE_C5__SHIFT) & A3XX_VPC_VARYING_PS_REPL_MODE_C5__MASK; +} +#define A3XX_VPC_VARYING_PS_REPL_MODE_C6__MASK 0x00003000 +#define A3XX_VPC_VARYING_PS_REPL_MODE_C6__SHIFT 12 +static inline uint32_t A3XX_VPC_VARYING_PS_REPL_MODE_C6(enum a3xx_repl_mode val) +{ + return ((val) << A3XX_VPC_VARYING_PS_REPL_MODE_C6__SHIFT) & A3XX_VPC_VARYING_PS_REPL_MODE_C6__MASK; +} +#define A3XX_VPC_VARYING_PS_REPL_MODE_C7__MASK 0x0000c000 +#define A3XX_VPC_VARYING_PS_REPL_MODE_C7__SHIFT 14 +static inline uint32_t A3XX_VPC_VARYING_PS_REPL_MODE_C7(enum a3xx_repl_mode val) +{ + return ((val) << A3XX_VPC_VARYING_PS_REPL_MODE_C7__SHIFT) & A3XX_VPC_VARYING_PS_REPL_MODE_C7__MASK; +} +#define A3XX_VPC_VARYING_PS_REPL_MODE_C8__MASK 0x00030000 +#define A3XX_VPC_VARYING_PS_REPL_MODE_C8__SHIFT 16 +static inline uint32_t A3XX_VPC_VARYING_PS_REPL_MODE_C8(enum a3xx_repl_mode val) +{ + return ((val) << A3XX_VPC_VARYING_PS_REPL_MODE_C8__SHIFT) & A3XX_VPC_VARYING_PS_REPL_MODE_C8__MASK; +} +#define A3XX_VPC_VARYING_PS_REPL_MODE_C9__MASK 0x000c0000 +#define A3XX_VPC_VARYING_PS_REPL_MODE_C9__SHIFT 18 +static inline uint32_t A3XX_VPC_VARYING_PS_REPL_MODE_C9(enum a3xx_repl_mode val) +{ + return ((val) << A3XX_VPC_VARYING_PS_REPL_MODE_C9__SHIFT) & A3XX_VPC_VARYING_PS_REPL_MODE_C9__MASK; +} +#define A3XX_VPC_VARYING_PS_REPL_MODE_CA__MASK 0x00300000 +#define A3XX_VPC_VARYING_PS_REPL_MODE_CA__SHIFT 20 +static inline uint32_t A3XX_VPC_VARYING_PS_REPL_MODE_CA(enum a3xx_repl_mode val) +{ + return ((val) << A3XX_VPC_VARYING_PS_REPL_MODE_CA__SHIFT) & A3XX_VPC_VARYING_PS_REPL_MODE_CA__MASK; +} +#define A3XX_VPC_VARYING_PS_REPL_MODE_CB__MASK 0x00c00000 +#define A3XX_VPC_VARYING_PS_REPL_MODE_CB__SHIFT 22 +static inline uint32_t A3XX_VPC_VARYING_PS_REPL_MODE_CB(enum a3xx_repl_mode val) +{ + return ((val) << A3XX_VPC_VARYING_PS_REPL_MODE_CB__SHIFT) & A3XX_VPC_VARYING_PS_REPL_MODE_CB__MASK; +} +#define A3XX_VPC_VARYING_PS_REPL_MODE_CC__MASK 0x03000000 +#define A3XX_VPC_VARYING_PS_REPL_MODE_CC__SHIFT 24 +static inline uint32_t A3XX_VPC_VARYING_PS_REPL_MODE_CC(enum a3xx_repl_mode val) +{ + return ((val) << A3XX_VPC_VARYING_PS_REPL_MODE_CC__SHIFT) & A3XX_VPC_VARYING_PS_REPL_MODE_CC__MASK; +} +#define A3XX_VPC_VARYING_PS_REPL_MODE_CD__MASK 0x0c000000 +#define A3XX_VPC_VARYING_PS_REPL_MODE_CD__SHIFT 26 +static inline uint32_t A3XX_VPC_VARYING_PS_REPL_MODE_CD(enum a3xx_repl_mode val) +{ + return ((val) << A3XX_VPC_VARYING_PS_REPL_MODE_CD__SHIFT) & A3XX_VPC_VARYING_PS_REPL_MODE_CD__MASK; +} +#define A3XX_VPC_VARYING_PS_REPL_MODE_CE__MASK 0x30000000 +#define A3XX_VPC_VARYING_PS_REPL_MODE_CE__SHIFT 28 +static inline uint32_t A3XX_VPC_VARYING_PS_REPL_MODE_CE(enum a3xx_repl_mode val) +{ + return ((val) << A3XX_VPC_VARYING_PS_REPL_MODE_CE__SHIFT) & A3XX_VPC_VARYING_PS_REPL_MODE_CE__MASK; +} +#define A3XX_VPC_VARYING_PS_REPL_MODE_CF__MASK 0xc0000000 +#define A3XX_VPC_VARYING_PS_REPL_MODE_CF__SHIFT 30 +static inline uint32_t A3XX_VPC_VARYING_PS_REPL_MODE_CF(enum a3xx_repl_mode val) +{ + return ((val) << A3XX_VPC_VARYING_PS_REPL_MODE_CF__SHIFT) & A3XX_VPC_VARYING_PS_REPL_MODE_CF__MASK; +} #define REG_A3XX_VPC_VARY_CYLWRAP_ENABLE_0 0x0000228a @@ -2107,6 +2245,12 @@ static inline uint32_t A3XX_SP_FS_OBJ_OFFSET_REG_SHADEROBJOFFSET(uint32_t val) #define REG_A3XX_SP_FS_FLAT_SHAD_MODE_REG_1 0x000022e9 #define REG_A3XX_SP_FS_OUTPUT_REG 0x000022ec +#define A3XX_SP_FS_OUTPUT_REG_MRT__MASK 0x00000003 +#define A3XX_SP_FS_OUTPUT_REG_MRT__SHIFT 0 +static inline uint32_t A3XX_SP_FS_OUTPUT_REG_MRT(uint32_t val) +{ + return ((val) << A3XX_SP_FS_OUTPUT_REG_MRT__SHIFT) & A3XX_SP_FS_OUTPUT_REG_MRT__MASK; +} #define A3XX_SP_FS_OUTPUT_REG_DEPTH_ENABLE 0x00000080 #define A3XX_SP_FS_OUTPUT_REG_DEPTH_REGID__MASK 0x0000ff00 #define A3XX_SP_FS_OUTPUT_REG_DEPTH_REGID__SHIFT 8 @@ -2661,7 +2805,7 @@ static inline uint32_t A3XX_TEX_CONST_2_SWAP(enum a3xx_color_swap val) } #define REG_A3XX_TEX_CONST_3 0x00000003 -#define A3XX_TEX_CONST_3_LAYERSZ1__MASK 0x0000000f +#define A3XX_TEX_CONST_3_LAYERSZ1__MASK 0x00007fff #define A3XX_TEX_CONST_3_LAYERSZ1__SHIFT 0 static inline uint32_t A3XX_TEX_CONST_3_LAYERSZ1(uint32_t val) { diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index b66c53bdc039..fd266ed963b6 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c @@ -93,7 +93,10 @@ static int a3xx_hw_init(struct msm_gpu *gpu) /* Set up AOOO: */ gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003c); gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003c003c); - + } else if (adreno_is_a306(adreno_gpu)) { + gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0003); + gpu_write(gpu, REG_A3XX_VBIF_OUT_RD_LIM_CONF0, 0x0000000a); + gpu_write(gpu, REG_A3XX_VBIF_OUT_WR_LIM_CONF0, 0x0000000a); } else if (adreno_is_a320(adreno_gpu)) { /* Set up 16 deep read/write request queues: */ gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x10101010); @@ -186,7 +189,9 @@ static int a3xx_hw_init(struct msm_gpu *gpu) gpu_write(gpu, REG_A3XX_UCHE_CACHE_MODE_CONTROL_REG, 0x00000001); /* Enable Clock gating: */ - if (adreno_is_a320(adreno_gpu)) + if (adreno_is_a306(adreno_gpu)) + gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xaaaaaaaa); + else if (adreno_is_a320(adreno_gpu)) gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xbfffffff); else if (adreno_is_a330v2(adreno_gpu)) gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xaaaaaaaa); @@ -271,7 +276,8 @@ static int a3xx_hw_init(struct msm_gpu *gpu) gpu_write(gpu, REG_A3XX_CP_PFP_UCODE_DATA, ptr[i]); /* CP ROQ queue sizes (bytes) - RB:16, ST:16, IB1:32, IB2:64 */ - if (adreno_is_a305(adreno_gpu) || adreno_is_a320(adreno_gpu)) { + if (adreno_is_a305(adreno_gpu) || adreno_is_a306(adreno_gpu) || + adreno_is_a320(adreno_gpu)) { gpu_write(gpu, REG_AXXX_CP_QUEUE_THRESHOLDS, AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB1_START(2) | AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB2_START(6) | @@ -295,9 +301,12 @@ static int a3xx_hw_init(struct msm_gpu *gpu) static void a3xx_recover(struct msm_gpu *gpu) { + adreno_dump_info(gpu); + /* dump registers before resetting gpu, if enabled: */ if (hang_debug) a3xx_dump(gpu); + gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 1); gpu_read(gpu, REG_A3XX_RBBM_SW_RESET_CMD); gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 0); diff --git a/drivers/gpu/drm/msm/adreno/a4xx.xml.h b/drivers/gpu/drm/msm/adreno/a4xx.xml.h index 755723fd8ba5..3f06ecf62583 100644 --- a/drivers/gpu/drm/msm/adreno/a4xx.xml.h +++ b/drivers/gpu/drm/msm/adreno/a4xx.xml.h @@ -12,11 +12,11 @@ The rules-ng-ng source files this header was generated from are: - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) - /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2014-06-02 15:21:30) - /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2014-11-13 22:44:30) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 15085 bytes, from 2014-12-20 21:49:41) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 64344 bytes, from 2014-12-12 20:22:26) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 51069 bytes, from 2014-12-21 15:51:54) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14895 bytes, from 2015-04-19 15:23:28) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 66709 bytes, from 2015-04-12 18:16:35) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 60633 bytes, from 2015-05-20 14:48:19) -Copyright (C) 2013-2014 by the following authors: +Copyright (C) 2013-2015 by the following authors: - Rob Clark <robdclark@gmail.com> (robclark) Permission is hereby granted, free of charge, to any person obtaining @@ -43,10 +43,40 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. enum a4xx_color_fmt { RB4_A8_UNORM = 1, + RB4_R8_UNORM = 2, + RB4_R4G4B4A4_UNORM = 8, + RB4_R5G5B5A1_UNORM = 10, RB4_R5G6R5_UNORM = 14, - RB4_Z16_UNORM = 15, + RB4_R8G8_UNORM = 15, + RB4_R8G8_SNORM = 16, + RB4_R8G8_UINT = 17, + RB4_R8G8_SINT = 18, + RB4_R16_FLOAT = 21, + RB4_R16_UINT = 22, + RB4_R16_SINT = 23, RB4_R8G8B8_UNORM = 25, RB4_R8G8B8A8_UNORM = 26, + RB4_R8G8B8A8_SNORM = 28, + RB4_R8G8B8A8_UINT = 29, + RB4_R8G8B8A8_SINT = 30, + RB4_R10G10B10A2_UNORM = 31, + RB4_R10G10B10A2_UINT = 34, + RB4_R11G11B10_FLOAT = 39, + RB4_R16G16_FLOAT = 42, + RB4_R16G16_UINT = 43, + RB4_R16G16_SINT = 44, + RB4_R32_FLOAT = 45, + RB4_R32_UINT = 46, + RB4_R32_SINT = 47, + RB4_R16G16B16A16_FLOAT = 54, + RB4_R16G16B16A16_UINT = 55, + RB4_R16G16B16A16_SINT = 56, + RB4_R32G32_FLOAT = 57, + RB4_R32G32_UINT = 58, + RB4_R32G32_SINT = 59, + RB4_R32G32B32A32_FLOAT = 60, + RB4_R32G32B32A32_UINT = 61, + RB4_R32G32B32A32_SINT = 62, }; enum a4xx_tile_mode { @@ -91,7 +121,14 @@ enum a4xx_vtx_fmt { VFMT4_16_16_UNORM = 29, VFMT4_16_16_16_UNORM = 30, VFMT4_16_16_16_16_UNORM = 31, + VFMT4_32_UINT = 32, + VFMT4_32_32_UINT = 33, + VFMT4_32_32_32_UINT = 34, + VFMT4_32_32_32_32_UINT = 35, + VFMT4_32_SINT = 36, VFMT4_32_32_SINT = 37, + VFMT4_32_32_32_SINT = 38, + VFMT4_32_32_32_32_SINT = 39, VFMT4_8_UINT = 40, VFMT4_8_8_UINT = 41, VFMT4_8_8_8_UINT = 42, @@ -125,12 +162,57 @@ enum a4xx_tex_fmt { TFMT4_8_UNORM = 4, TFMT4_8_8_UNORM = 14, TFMT4_8_8_8_8_UNORM = 28, + TFMT4_8_8_SNORM = 15, + TFMT4_8_8_8_8_SNORM = 29, + TFMT4_8_8_UINT = 16, + TFMT4_8_8_8_8_UINT = 30, + TFMT4_8_8_SINT = 17, + TFMT4_8_8_8_8_SINT = 31, + TFMT4_16_UINT = 21, + TFMT4_16_16_UINT = 41, + TFMT4_16_16_16_16_UINT = 54, + TFMT4_16_SINT = 22, + TFMT4_16_16_SINT = 42, + TFMT4_16_16_16_16_SINT = 55, + TFMT4_32_UINT = 44, + TFMT4_32_32_UINT = 57, + TFMT4_32_32_32_32_UINT = 64, + TFMT4_32_SINT = 45, + TFMT4_32_32_SINT = 58, + TFMT4_32_32_32_32_SINT = 65, TFMT4_16_FLOAT = 20, TFMT4_16_16_FLOAT = 40, TFMT4_16_16_16_16_FLOAT = 53, TFMT4_32_FLOAT = 43, TFMT4_32_32_FLOAT = 56, TFMT4_32_32_32_32_FLOAT = 63, + TFMT4_9_9_9_E5_FLOAT = 32, + TFMT4_11_11_10_FLOAT = 37, + TFMT4_ATC_RGB = 100, + TFMT4_ATC_RGBA_EXPLICIT = 101, + TFMT4_ATC_RGBA_INTERPOLATED = 102, + TFMT4_ETC2_RG11_UNORM = 103, + TFMT4_ETC2_RG11_SNORM = 104, + TFMT4_ETC2_R11_UNORM = 105, + TFMT4_ETC2_R11_SNORM = 106, + TFMT4_ETC1 = 107, + TFMT4_ETC2_RGB8 = 108, + TFMT4_ETC2_RGBA8 = 109, + TFMT4_ETC2_RGB8A1 = 110, + TFMT4_ASTC_4x4 = 111, + TFMT4_ASTC_5x4 = 112, + TFMT4_ASTC_5x5 = 113, + TFMT4_ASTC_6x5 = 114, + TFMT4_ASTC_6x6 = 115, + TFMT4_ASTC_8x5 = 116, + TFMT4_ASTC_8x6 = 117, + TFMT4_ASTC_8x8 = 118, + TFMT4_ASTC_10x5 = 119, + TFMT4_ASTC_10x6 = 120, + TFMT4_ASTC_10x8 = 121, + TFMT4_ASTC_10x10 = 122, + TFMT4_ASTC_12x10 = 123, + TFMT4_ASTC_12x12 = 124, }; enum a4xx_tex_fetchsize { @@ -147,9 +229,16 @@ enum a4xx_depth_format { DEPTH4_24_8 = 2, }; +enum a4xx_tess_spacing { + EQUAL_SPACING = 0, + ODD_SPACING = 2, + EVEN_SPACING = 3, +}; + enum a4xx_tex_filter { A4XX_TEX_NEAREST = 0, A4XX_TEX_LINEAR = 1, + A4XX_TEX_ANISO = 2, }; enum a4xx_tex_clamp { @@ -159,6 +248,14 @@ enum a4xx_tex_clamp { A4XX_TEX_CLAMP_NONE = 3, }; +enum a4xx_tex_aniso { + A4XX_TEX_ANISO_1 = 0, + A4XX_TEX_ANISO_2 = 1, + A4XX_TEX_ANISO_4 = 2, + A4XX_TEX_ANISO_8 = 3, + A4XX_TEX_ANISO_16 = 4, +}; + enum a4xx_tex_swiz { A4XX_TEX_X = 0, A4XX_TEX_Y = 1, @@ -279,13 +376,16 @@ static inline uint32_t A4XX_RB_MSAA_CONTROL_SAMPLES(uint32_t val) #define A4XX_RB_RENDER_CONTROL2_YCOORD 0x00000002 #define A4XX_RB_RENDER_CONTROL2_ZCOORD 0x00000004 #define A4XX_RB_RENDER_CONTROL2_WCOORD 0x00000008 +#define A4XX_RB_RENDER_CONTROL2_SAMPLEMASK 0x00000010 #define A4XX_RB_RENDER_CONTROL2_FACENESS 0x00000020 +#define A4XX_RB_RENDER_CONTROL2_SAMPLEID 0x00000040 #define A4XX_RB_RENDER_CONTROL2_MSAA_SAMPLES__MASK 0x00000380 #define A4XX_RB_RENDER_CONTROL2_MSAA_SAMPLES__SHIFT 7 static inline uint32_t A4XX_RB_RENDER_CONTROL2_MSAA_SAMPLES(uint32_t val) { return ((val) << A4XX_RB_RENDER_CONTROL2_MSAA_SAMPLES__SHIFT) & A4XX_RB_RENDER_CONTROL2_MSAA_SAMPLES__MASK; } +#define A4XX_RB_RENDER_CONTROL2_SAMPLEID_HR 0x00000800 #define A4XX_RB_RENDER_CONTROL2_VARYING 0x00001000 static inline uint32_t REG_A4XX_RB_MRT(uint32_t i0) { return 0x000020a4 + 0x5*i0; } @@ -310,6 +410,12 @@ static inline uint32_t A4XX_RB_MRT_BUF_INFO_COLOR_FORMAT(enum a4xx_color_fmt val { return ((val) << A4XX_RB_MRT_BUF_INFO_COLOR_FORMAT__SHIFT) & A4XX_RB_MRT_BUF_INFO_COLOR_FORMAT__MASK; } +#define A4XX_RB_MRT_BUF_INFO_COLOR_TILE_MODE__MASK 0x000000c0 +#define A4XX_RB_MRT_BUF_INFO_COLOR_TILE_MODE__SHIFT 6 +static inline uint32_t A4XX_RB_MRT_BUF_INFO_COLOR_TILE_MODE(enum a4xx_tile_mode val) +{ + return ((val) << A4XX_RB_MRT_BUF_INFO_COLOR_TILE_MODE__SHIFT) & A4XX_RB_MRT_BUF_INFO_COLOR_TILE_MODE__MASK; +} #define A4XX_RB_MRT_BUF_INFO_DITHER_MODE__MASK 0x00000600 #define A4XX_RB_MRT_BUF_INFO_DITHER_MODE__SHIFT 9 static inline uint32_t A4XX_RB_MRT_BUF_INFO_DITHER_MODE(enum adreno_rb_dither_mode val) @@ -322,6 +428,7 @@ static inline uint32_t A4XX_RB_MRT_BUF_INFO_COLOR_SWAP(enum a3xx_color_swap val) { return ((val) << A4XX_RB_MRT_BUF_INFO_COLOR_SWAP__SHIFT) & A4XX_RB_MRT_BUF_INFO_COLOR_SWAP__MASK; } +#define A4XX_RB_MRT_BUF_INFO_COLOR_SRGB 0x00002000 #define A4XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH__MASK 0x007fc000 #define A4XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH__SHIFT 14 static inline uint32_t A4XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH(uint32_t val) @@ -449,7 +556,12 @@ static inline uint32_t A4XX_RB_ALPHA_CONTROL_ALPHA_TEST_FUNC(enum adreno_compare } #define REG_A4XX_RB_FS_OUTPUT 0x000020f9 -#define A4XX_RB_FS_OUTPUT_ENABLE_BLEND 0x00000001 +#define A4XX_RB_FS_OUTPUT_ENABLE_BLEND__MASK 0x000000ff +#define A4XX_RB_FS_OUTPUT_ENABLE_BLEND__SHIFT 0 +static inline uint32_t A4XX_RB_FS_OUTPUT_ENABLE_BLEND(uint32_t val) +{ + return ((val) << A4XX_RB_FS_OUTPUT_ENABLE_BLEND__SHIFT) & A4XX_RB_FS_OUTPUT_ENABLE_BLEND__MASK; +} #define A4XX_RB_FS_OUTPUT_FAST_CLEAR 0x00000100 #define A4XX_RB_FS_OUTPUT_SAMPLE_MASK__MASK 0xffff0000 #define A4XX_RB_FS_OUTPUT_SAMPLE_MASK__SHIFT 16 @@ -458,12 +570,54 @@ static inline uint32_t A4XX_RB_FS_OUTPUT_SAMPLE_MASK(uint32_t val) return ((val) << A4XX_RB_FS_OUTPUT_SAMPLE_MASK__SHIFT) & A4XX_RB_FS_OUTPUT_SAMPLE_MASK__MASK; } -#define REG_A4XX_RB_RENDER_CONTROL3 0x000020fb -#define A4XX_RB_RENDER_CONTROL3_COMPONENT_ENABLE__MASK 0x0000001f -#define A4XX_RB_RENDER_CONTROL3_COMPONENT_ENABLE__SHIFT 0 -static inline uint32_t A4XX_RB_RENDER_CONTROL3_COMPONENT_ENABLE(uint32_t val) +#define REG_A4XX_RB_RENDER_COMPONENTS 0x000020fb +#define A4XX_RB_RENDER_COMPONENTS_RT0__MASK 0x0000000f +#define A4XX_RB_RENDER_COMPONENTS_RT0__SHIFT 0 +static inline uint32_t A4XX_RB_RENDER_COMPONENTS_RT0(uint32_t val) { - return ((val) << A4XX_RB_RENDER_CONTROL3_COMPONENT_ENABLE__SHIFT) & A4XX_RB_RENDER_CONTROL3_COMPONENT_ENABLE__MASK; + return ((val) << A4XX_RB_RENDER_COMPONENTS_RT0__SHIFT) & A4XX_RB_RENDER_COMPONENTS_RT0__MASK; +} +#define A4XX_RB_RENDER_COMPONENTS_RT1__MASK 0x000000f0 +#define A4XX_RB_RENDER_COMPONENTS_RT1__SHIFT 4 +static inline uint32_t A4XX_RB_RENDER_COMPONENTS_RT1(uint32_t val) +{ + return ((val) << A4XX_RB_RENDER_COMPONENTS_RT1__SHIFT) & A4XX_RB_RENDER_COMPONENTS_RT1__MASK; +} +#define A4XX_RB_RENDER_COMPONENTS_RT2__MASK 0x00000f00 +#define A4XX_RB_RENDER_COMPONENTS_RT2__SHIFT 8 +static inline uint32_t A4XX_RB_RENDER_COMPONENTS_RT2(uint32_t val) +{ + return ((val) << A4XX_RB_RENDER_COMPONENTS_RT2__SHIFT) & A4XX_RB_RENDER_COMPONENTS_RT2__MASK; +} +#define A4XX_RB_RENDER_COMPONENTS_RT3__MASK 0x0000f000 +#define A4XX_RB_RENDER_COMPONENTS_RT3__SHIFT 12 +static inline uint32_t A4XX_RB_RENDER_COMPONENTS_RT3(uint32_t val) +{ + return ((val) << A4XX_RB_RENDER_COMPONENTS_RT3__SHIFT) & A4XX_RB_RENDER_COMPONENTS_RT3__MASK; +} +#define A4XX_RB_RENDER_COMPONENTS_RT4__MASK 0x000f0000 +#define A4XX_RB_RENDER_COMPONENTS_RT4__SHIFT 16 +static inline uint32_t A4XX_RB_RENDER_COMPONENTS_RT4(uint32_t val) +{ + return ((val) << A4XX_RB_RENDER_COMPONENTS_RT4__SHIFT) & A4XX_RB_RENDER_COMPONENTS_RT4__MASK; +} +#define A4XX_RB_RENDER_COMPONENTS_RT5__MASK 0x00f00000 +#define A4XX_RB_RENDER_COMPONENTS_RT5__SHIFT 20 +static inline uint32_t A4XX_RB_RENDER_COMPONENTS_RT5(uint32_t val) +{ + return ((val) << A4XX_RB_RENDER_COMPONENTS_RT5__SHIFT) & A4XX_RB_RENDER_COMPONENTS_RT5__MASK; +} +#define A4XX_RB_RENDER_COMPONENTS_RT6__MASK 0x0f000000 +#define A4XX_RB_RENDER_COMPONENTS_RT6__SHIFT 24 +static inline uint32_t A4XX_RB_RENDER_COMPONENTS_RT6(uint32_t val) +{ + return ((val) << A4XX_RB_RENDER_COMPONENTS_RT6__SHIFT) & A4XX_RB_RENDER_COMPONENTS_RT6__MASK; +} +#define A4XX_RB_RENDER_COMPONENTS_RT7__MASK 0xf0000000 +#define A4XX_RB_RENDER_COMPONENTS_RT7__SHIFT 28 +static inline uint32_t A4XX_RB_RENDER_COMPONENTS_RT7(uint32_t val) +{ + return ((val) << A4XX_RB_RENDER_COMPONENTS_RT7__SHIFT) & A4XX_RB_RENDER_COMPONENTS_RT7__MASK; } #define REG_A4XX_RB_COPY_CONTROL 0x000020fc @@ -547,7 +701,12 @@ static inline uint32_t A4XX_RB_COPY_DEST_INFO_TILE(enum a4xx_tile_mode val) } #define REG_A4XX_RB_FS_OUTPUT_REG 0x00002100 -#define A4XX_RB_FS_OUTPUT_REG_COLOR_PIPE_ENABLE 0x00000001 +#define A4XX_RB_FS_OUTPUT_REG_MRT__MASK 0x0000000f +#define A4XX_RB_FS_OUTPUT_REG_MRT__SHIFT 0 +static inline uint32_t A4XX_RB_FS_OUTPUT_REG_MRT(uint32_t val) +{ + return ((val) << A4XX_RB_FS_OUTPUT_REG_MRT__SHIFT) & A4XX_RB_FS_OUTPUT_REG_MRT__MASK; +} #define A4XX_RB_FS_OUTPUT_REG_FRAG_WRITES_Z 0x00000020 #define REG_A4XX_RB_DEPTH_CONTROL 0x00002101 @@ -930,6 +1089,10 @@ static inline uint32_t REG_A4XX_RBBM_CLOCK_DELAY_RB_MARB_CCU_L1_REG(uint32_t i0) #define REG_A4XX_CP_IB2_BUFSZ 0x00000209 +#define REG_A4XX_CP_ME_NRT_ADDR 0x0000020c + +#define REG_A4XX_CP_ME_NRT_DATA 0x0000020d + #define REG_A4XX_CP_ME_RB_DONE_DATA 0x00000217 #define REG_A4XX_CP_QUEUE_THRESH2 0x00000219 @@ -940,9 +1103,9 @@ static inline uint32_t REG_A4XX_RBBM_CLOCK_DELAY_RB_MARB_CCU_L1_REG(uint32_t i0) #define REG_A4XX_CP_ROQ_DATA 0x0000021d -#define REG_A4XX_CP_MEQ_ADDR 0x0000021e +#define REG_A4XX_CP_MEQ_ADDR 0x0000021e -#define REG_A4XX_CP_MEQ_DATA 0x0000021f +#define REG_A4XX_CP_MEQ_DATA 0x0000021f #define REG_A4XX_CP_MERCIU_ADDR 0x00000220 @@ -1004,12 +1167,17 @@ static inline uint32_t REG_A4XX_CP_SCRATCH_REG(uint32_t i0) { return 0x00000578 #define REG_A4XX_SP_VS_STATUS 0x00000ec0 +#define REG_A4XX_SP_MODE_CONTROL 0x00000ec3 + #define REG_A4XX_SP_PERFCTR_SP_SEL_11 0x00000ecf #define REG_A4XX_SP_SP_CTRL_REG 0x000022c0 #define A4XX_SP_SP_CTRL_REG_BINNING_PASS 0x00080000 #define REG_A4XX_SP_INSTR_CACHE_CTRL 0x000022c1 +#define A4XX_SP_INSTR_CACHE_CTRL_VS_BUFFER 0x00000080 +#define A4XX_SP_INSTR_CACHE_CTRL_FS_BUFFER 0x00000100 +#define A4XX_SP_INSTR_CACHE_CTRL_INSTR_BUFFER 0x00000400 #define REG_A4XX_SP_VS_CTRL_REG0 0x000022c4 #define A4XX_SP_VS_CTRL_REG0_THREADMODE__MASK 0x00000001 @@ -1229,6 +1397,12 @@ static inline uint32_t A4XX_SP_FS_OBJ_OFFSET_REG_SHADEROBJOFFSET(uint32_t val) #define REG_A4XX_SP_FS_LENGTH_REG 0x000022ef #define REG_A4XX_SP_FS_OUTPUT_REG 0x000022f0 +#define A4XX_SP_FS_OUTPUT_REG_MRT__MASK 0x0000000f +#define A4XX_SP_FS_OUTPUT_REG_MRT__SHIFT 0 +static inline uint32_t A4XX_SP_FS_OUTPUT_REG_MRT(uint32_t val) +{ + return ((val) << A4XX_SP_FS_OUTPUT_REG_MRT__SHIFT) & A4XX_SP_FS_OUTPUT_REG_MRT__MASK; +} #define A4XX_SP_FS_OUTPUT_REG_DEPTH_ENABLE 0x00000080 #define A4XX_SP_FS_OUTPUT_REG_DEPTH_REGID__MASK 0x0000ff00 #define A4XX_SP_FS_OUTPUT_REG_DEPTH_REGID__SHIFT 8 @@ -1236,6 +1410,12 @@ static inline uint32_t A4XX_SP_FS_OUTPUT_REG_DEPTH_REGID(uint32_t val) { return ((val) << A4XX_SP_FS_OUTPUT_REG_DEPTH_REGID__SHIFT) & A4XX_SP_FS_OUTPUT_REG_DEPTH_REGID__MASK; } +#define A4XX_SP_FS_OUTPUT_REG_SAMPLEMASK_REGID__MASK 0xff000000 +#define A4XX_SP_FS_OUTPUT_REG_SAMPLEMASK_REGID__SHIFT 24 +static inline uint32_t A4XX_SP_FS_OUTPUT_REG_SAMPLEMASK_REGID(uint32_t val) +{ + return ((val) << A4XX_SP_FS_OUTPUT_REG_SAMPLEMASK_REGID__SHIFT) & A4XX_SP_FS_OUTPUT_REG_SAMPLEMASK_REGID__MASK; +} static inline uint32_t REG_A4XX_SP_FS_MRT(uint32_t i0) { return 0x000022f1 + 0x1*i0; } @@ -1254,6 +1434,20 @@ static inline uint32_t A4XX_SP_FS_MRT_REG_MRTFORMAT(enum a4xx_color_fmt val) return ((val) << A4XX_SP_FS_MRT_REG_MRTFORMAT__SHIFT) & A4XX_SP_FS_MRT_REG_MRTFORMAT__MASK; } +#define REG_A4XX_SP_CS_CTRL_REG0 0x00002300 + +#define REG_A4XX_SP_CS_OBJ_OFFSET_REG 0x00002301 + +#define REG_A4XX_SP_CS_OBJ_START 0x00002302 + +#define REG_A4XX_SP_CS_PVT_MEM_PARAM 0x00002303 + +#define REG_A4XX_SP_CS_PVT_MEM_ADDR 0x00002304 + +#define REG_A4XX_SP_CS_PVT_MEM_SIZE 0x00002305 + +#define REG_A4XX_SP_CS_LENGTH_REG 0x00002306 + #define REG_A4XX_SP_HS_OBJ_OFFSET_REG 0x0000230d #define A4XX_SP_HS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__MASK 0x01ff0000 #define A4XX_SP_HS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__SHIFT 16 @@ -1268,6 +1462,14 @@ static inline uint32_t A4XX_SP_HS_OBJ_OFFSET_REG_SHADEROBJOFFSET(uint32_t val) return ((val) << A4XX_SP_HS_OBJ_OFFSET_REG_SHADEROBJOFFSET__SHIFT) & A4XX_SP_HS_OBJ_OFFSET_REG_SHADEROBJOFFSET__MASK; } +#define REG_A4XX_SP_HS_OBJ_START 0x0000230e + +#define REG_A4XX_SP_HS_PVT_MEM_PARAM 0x0000230f + +#define REG_A4XX_SP_HS_PVT_MEM_ADDR 0x00002310 + +#define REG_A4XX_SP_HS_LENGTH_REG 0x00002312 + #define REG_A4XX_SP_DS_OBJ_OFFSET_REG 0x00002334 #define A4XX_SP_DS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__MASK 0x01ff0000 #define A4XX_SP_DS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__SHIFT 16 @@ -1282,6 +1484,14 @@ static inline uint32_t A4XX_SP_DS_OBJ_OFFSET_REG_SHADEROBJOFFSET(uint32_t val) return ((val) << A4XX_SP_DS_OBJ_OFFSET_REG_SHADEROBJOFFSET__SHIFT) & A4XX_SP_DS_OBJ_OFFSET_REG_SHADEROBJOFFSET__MASK; } +#define REG_A4XX_SP_DS_OBJ_START 0x00002335 + +#define REG_A4XX_SP_DS_PVT_MEM_PARAM 0x00002336 + +#define REG_A4XX_SP_DS_PVT_MEM_ADDR 0x00002337 + +#define REG_A4XX_SP_DS_LENGTH_REG 0x00002339 + #define REG_A4XX_SP_GS_OBJ_OFFSET_REG 0x0000235b #define A4XX_SP_GS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__MASK 0x01ff0000 #define A4XX_SP_GS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__SHIFT 16 @@ -1296,6 +1506,12 @@ static inline uint32_t A4XX_SP_GS_OBJ_OFFSET_REG_SHADEROBJOFFSET(uint32_t val) return ((val) << A4XX_SP_GS_OBJ_OFFSET_REG_SHADEROBJOFFSET__SHIFT) & A4XX_SP_GS_OBJ_OFFSET_REG_SHADEROBJOFFSET__MASK; } +#define REG_A4XX_SP_GS_OBJ_START 0x0000235c + +#define REG_A4XX_SP_GS_PVT_MEM_PARAM 0x0000235d + +#define REG_A4XX_SP_GS_PVT_MEM_ADDR 0x0000235e + #define REG_A4XX_SP_GS_LENGTH_REG 0x00002360 #define REG_A4XX_VPC_DEBUG_RAM_SEL 0x00000e60 @@ -1418,6 +1634,10 @@ static inline uint32_t REG_A4XX_VSC_PIPE_DATA_LENGTH_REG(uint32_t i0) { return 0 #define REG_A4XX_VFD_PERFCTR_VFD_SEL_7 0x00000e4a +#define REG_A4XX_VGT_CL_INITIATOR 0x000021d0 + +#define REG_A4XX_VGT_EVENT_INITIATOR 0x000021d9 + #define REG_A4XX_VFD_CONTROL_0 0x00002200 #define A4XX_VFD_CONTROL_0_TOTALATTRTOVS__MASK 0x000000ff #define A4XX_VFD_CONTROL_0_TOTALATTRTOVS__SHIFT 0 @@ -1554,10 +1774,54 @@ static inline uint32_t A4XX_VFD_DECODE_INSTR_SHIFTCNT(uint32_t val) #define REG_A4XX_TPL1_DEBUG_ECO_CONTROL 0x00000f00 +#define REG_A4XX_TPL1_TP_MODE_CONTROL 0x00000f03 + #define REG_A4XX_TPL1_PERFCTR_TP_SEL_7 0x00000f0b #define REG_A4XX_TPL1_TP_TEX_OFFSET 0x00002380 +#define REG_A4XX_TPL1_TP_TEX_COUNT 0x00002381 +#define A4XX_TPL1_TP_TEX_COUNT_VS__MASK 0x000000ff +#define A4XX_TPL1_TP_TEX_COUNT_VS__SHIFT 0 +static inline uint32_t A4XX_TPL1_TP_TEX_COUNT_VS(uint32_t val) +{ + return ((val) << A4XX_TPL1_TP_TEX_COUNT_VS__SHIFT) & A4XX_TPL1_TP_TEX_COUNT_VS__MASK; +} +#define A4XX_TPL1_TP_TEX_COUNT_HS__MASK 0x0000ff00 +#define A4XX_TPL1_TP_TEX_COUNT_HS__SHIFT 8 +static inline uint32_t A4XX_TPL1_TP_TEX_COUNT_HS(uint32_t val) +{ + return ((val) << A4XX_TPL1_TP_TEX_COUNT_HS__SHIFT) & A4XX_TPL1_TP_TEX_COUNT_HS__MASK; +} +#define A4XX_TPL1_TP_TEX_COUNT_DS__MASK 0x00ff0000 +#define A4XX_TPL1_TP_TEX_COUNT_DS__SHIFT 16 +static inline uint32_t A4XX_TPL1_TP_TEX_COUNT_DS(uint32_t val) +{ + return ((val) << A4XX_TPL1_TP_TEX_COUNT_DS__SHIFT) & A4XX_TPL1_TP_TEX_COUNT_DS__MASK; +} +#define A4XX_TPL1_TP_TEX_COUNT_GS__MASK 0xff000000 +#define A4XX_TPL1_TP_TEX_COUNT_GS__SHIFT 24 +static inline uint32_t A4XX_TPL1_TP_TEX_COUNT_GS(uint32_t val) +{ + return ((val) << A4XX_TPL1_TP_TEX_COUNT_GS__SHIFT) & A4XX_TPL1_TP_TEX_COUNT_GS__MASK; +} + +#define REG_A4XX_TPL1_TP_VS_BORDER_COLOR_BASE_ADDR 0x00002384 + +#define REG_A4XX_TPL1_TP_HS_BORDER_COLOR_BASE_ADDR 0x00002387 + +#define REG_A4XX_TPL1_TP_DS_BORDER_COLOR_BASE_ADDR 0x0000238a + +#define REG_A4XX_TPL1_TP_GS_BORDER_COLOR_BASE_ADDR 0x0000238d + +#define REG_A4XX_TPL1_TP_FS_TEX_COUNT 0x000023a0 + +#define REG_A4XX_TPL1_TP_FS_BORDER_COLOR_BASE_ADDR 0x000023a1 + +#define REG_A4XX_TPL1_TP_CS_BORDER_COLOR_BASE_ADDR 0x000023a4 + +#define REG_A4XX_TPL1_TP_CS_SAMPLER_BASE_ADDR 0x000023a5 + #define REG_A4XX_TPL1_TP_CS_TEXMEMOBJ_BASE_ADDR 0x000023a6 #define REG_A4XX_GRAS_TSE_STATUS 0x00000c80 @@ -1676,6 +1940,14 @@ static inline uint32_t A4XX_GRAS_SU_POLY_OFFSET_OFFSET(float val) return ((fui(val)) << A4XX_GRAS_SU_POLY_OFFSET_OFFSET__SHIFT) & A4XX_GRAS_SU_POLY_OFFSET_OFFSET__MASK; } +#define REG_A4XX_GRAS_SU_POLY_OFFSET_CLAMP 0x00002076 +#define A4XX_GRAS_SU_POLY_OFFSET_CLAMP__MASK 0xffffffff +#define A4XX_GRAS_SU_POLY_OFFSET_CLAMP__SHIFT 0 +static inline uint32_t A4XX_GRAS_SU_POLY_OFFSET_CLAMP(float val) +{ + return ((fui(val)) << A4XX_GRAS_SU_POLY_OFFSET_CLAMP__SHIFT) & A4XX_GRAS_SU_POLY_OFFSET_CLAMP__MASK; +} + #define REG_A4XX_GRAS_DEPTH_CONTROL 0x00002077 #define A4XX_GRAS_DEPTH_CONTROL_FORMAT__MASK 0x00000003 #define A4XX_GRAS_DEPTH_CONTROL_FORMAT__SHIFT 0 @@ -1828,6 +2100,8 @@ static inline uint32_t A4XX_GRAS_SC_EXTENT_WINDOW_TL_Y(uint32_t val) #define REG_A4XX_HLSQ_DEBUG_ECO_CONTROL 0x00000e04 +#define REG_A4XX_HLSQ_MODE_CONTROL 0x00000e05 + #define REG_A4XX_HLSQ_PERF_PIPE_MASK 0x00000e0e #define REG_A4XX_HLSQ_CONTROL_0_REG 0x000023c0 @@ -1867,7 +2141,12 @@ static inline uint32_t A4XX_HLSQ_CONTROL_1_REG_COORDREGID(uint32_t val) { return ((val) << A4XX_HLSQ_CONTROL_1_REG_COORDREGID__SHIFT) & A4XX_HLSQ_CONTROL_1_REG_COORDREGID__MASK; } -#define A4XX_HLSQ_CONTROL_1_REG_ZWCOORD 0x02000000 +#define A4XX_HLSQ_CONTROL_1_REG_ZWCOORDREGID__MASK 0xff000000 +#define A4XX_HLSQ_CONTROL_1_REG_ZWCOORDREGID__SHIFT 24 +static inline uint32_t A4XX_HLSQ_CONTROL_1_REG_ZWCOORDREGID(uint32_t val) +{ + return ((val) << A4XX_HLSQ_CONTROL_1_REG_ZWCOORDREGID__SHIFT) & A4XX_HLSQ_CONTROL_1_REG_ZWCOORDREGID__MASK; +} #define REG_A4XX_HLSQ_CONTROL_2_REG 0x000023c2 #define A4XX_HLSQ_CONTROL_2_REG_PRIMALLOCTHRESHOLD__MASK 0xfc000000 @@ -1882,6 +2161,18 @@ static inline uint32_t A4XX_HLSQ_CONTROL_2_REG_FACEREGID(uint32_t val) { return ((val) << A4XX_HLSQ_CONTROL_2_REG_FACEREGID__SHIFT) & A4XX_HLSQ_CONTROL_2_REG_FACEREGID__MASK; } +#define A4XX_HLSQ_CONTROL_2_REG_SAMPLEID_REGID__MASK 0x0003fc00 +#define A4XX_HLSQ_CONTROL_2_REG_SAMPLEID_REGID__SHIFT 10 +static inline uint32_t A4XX_HLSQ_CONTROL_2_REG_SAMPLEID_REGID(uint32_t val) +{ + return ((val) << A4XX_HLSQ_CONTROL_2_REG_SAMPLEID_REGID__SHIFT) & A4XX_HLSQ_CONTROL_2_REG_SAMPLEID_REGID__MASK; +} +#define A4XX_HLSQ_CONTROL_2_REG_SAMPLEMASK_REGID__MASK 0x03fc0000 +#define A4XX_HLSQ_CONTROL_2_REG_SAMPLEMASK_REGID__SHIFT 18 +static inline uint32_t A4XX_HLSQ_CONTROL_2_REG_SAMPLEMASK_REGID(uint32_t val) +{ + return ((val) << A4XX_HLSQ_CONTROL_2_REG_SAMPLEMASK_REGID__SHIFT) & A4XX_HLSQ_CONTROL_2_REG_SAMPLEMASK_REGID__MASK; +} #define REG_A4XX_HLSQ_CONTROL_3_REG 0x000023c3 #define A4XX_HLSQ_CONTROL_3_REG_REGID__MASK 0x000000ff @@ -1891,6 +2182,8 @@ static inline uint32_t A4XX_HLSQ_CONTROL_3_REG_REGID(uint32_t val) return ((val) << A4XX_HLSQ_CONTROL_3_REG_REGID__SHIFT) & A4XX_HLSQ_CONTROL_3_REG_REGID__MASK; } +#define REG_A4XX_HLSQ_CONTROL_4_REG 0x000023c4 + #define REG_A4XX_HLSQ_VS_CONTROL_REG 0x000023c5 #define A4XX_HLSQ_VS_CONTROL_REG_CONSTLENGTH__MASK 0x000000ff #define A4XX_HLSQ_VS_CONTROL_REG_CONSTLENGTH__SHIFT 0 @@ -1904,6 +2197,7 @@ static inline uint32_t A4XX_HLSQ_VS_CONTROL_REG_CONSTOBJECTOFFSET(uint32_t val) { return ((val) << A4XX_HLSQ_VS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT) & A4XX_HLSQ_VS_CONTROL_REG_CONSTOBJECTOFFSET__MASK; } +#define A4XX_HLSQ_VS_CONTROL_REG_ENABLED 0x00010000 #define A4XX_HLSQ_VS_CONTROL_REG_SHADEROBJOFFSET__MASK 0x00fe0000 #define A4XX_HLSQ_VS_CONTROL_REG_SHADEROBJOFFSET__SHIFT 17 static inline uint32_t A4XX_HLSQ_VS_CONTROL_REG_SHADEROBJOFFSET(uint32_t val) @@ -1930,6 +2224,7 @@ static inline uint32_t A4XX_HLSQ_FS_CONTROL_REG_CONSTOBJECTOFFSET(uint32_t val) { return ((val) << A4XX_HLSQ_FS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT) & A4XX_HLSQ_FS_CONTROL_REG_CONSTOBJECTOFFSET__MASK; } +#define A4XX_HLSQ_FS_CONTROL_REG_ENABLED 0x00010000 #define A4XX_HLSQ_FS_CONTROL_REG_SHADEROBJOFFSET__MASK 0x00fe0000 #define A4XX_HLSQ_FS_CONTROL_REG_SHADEROBJOFFSET__SHIFT 17 static inline uint32_t A4XX_HLSQ_FS_CONTROL_REG_SHADEROBJOFFSET(uint32_t val) @@ -1956,6 +2251,7 @@ static inline uint32_t A4XX_HLSQ_HS_CONTROL_REG_CONSTOBJECTOFFSET(uint32_t val) { return ((val) << A4XX_HLSQ_HS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT) & A4XX_HLSQ_HS_CONTROL_REG_CONSTOBJECTOFFSET__MASK; } +#define A4XX_HLSQ_HS_CONTROL_REG_ENABLED 0x00010000 #define A4XX_HLSQ_HS_CONTROL_REG_SHADEROBJOFFSET__MASK 0x00fe0000 #define A4XX_HLSQ_HS_CONTROL_REG_SHADEROBJOFFSET__SHIFT 17 static inline uint32_t A4XX_HLSQ_HS_CONTROL_REG_SHADEROBJOFFSET(uint32_t val) @@ -1982,6 +2278,7 @@ static inline uint32_t A4XX_HLSQ_DS_CONTROL_REG_CONSTOBJECTOFFSET(uint32_t val) { return ((val) << A4XX_HLSQ_DS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT) & A4XX_HLSQ_DS_CONTROL_REG_CONSTOBJECTOFFSET__MASK; } +#define A4XX_HLSQ_DS_CONTROL_REG_ENABLED 0x00010000 #define A4XX_HLSQ_DS_CONTROL_REG_SHADEROBJOFFSET__MASK 0x00fe0000 #define A4XX_HLSQ_DS_CONTROL_REG_SHADEROBJOFFSET__SHIFT 17 static inline uint32_t A4XX_HLSQ_DS_CONTROL_REG_SHADEROBJOFFSET(uint32_t val) @@ -2008,6 +2305,7 @@ static inline uint32_t A4XX_HLSQ_GS_CONTROL_REG_CONSTOBJECTOFFSET(uint32_t val) { return ((val) << A4XX_HLSQ_GS_CONTROL_REG_CONSTOBJECTOFFSET__SHIFT) & A4XX_HLSQ_GS_CONTROL_REG_CONSTOBJECTOFFSET__MASK; } +#define A4XX_HLSQ_GS_CONTROL_REG_ENABLED 0x00010000 #define A4XX_HLSQ_GS_CONTROL_REG_SHADEROBJOFFSET__MASK 0x00fe0000 #define A4XX_HLSQ_GS_CONTROL_REG_SHADEROBJOFFSET__SHIFT 17 static inline uint32_t A4XX_HLSQ_GS_CONTROL_REG_SHADEROBJOFFSET(uint32_t val) @@ -2021,6 +2319,36 @@ static inline uint32_t A4XX_HLSQ_GS_CONTROL_REG_INSTRLENGTH(uint32_t val) return ((val) << A4XX_HLSQ_GS_CONTROL_REG_INSTRLENGTH__SHIFT) & A4XX_HLSQ_GS_CONTROL_REG_INSTRLENGTH__MASK; } +#define REG_A4XX_HLSQ_CS_CONTROL 0x000023ca + +#define REG_A4XX_HLSQ_CL_NDRANGE_0 0x000023cd + +#define REG_A4XX_HLSQ_CL_NDRANGE_1 0x000023ce + +#define REG_A4XX_HLSQ_CL_NDRANGE_2 0x000023cf + +#define REG_A4XX_HLSQ_CL_NDRANGE_3 0x000023d0 + +#define REG_A4XX_HLSQ_CL_NDRANGE_4 0x000023d1 + +#define REG_A4XX_HLSQ_CL_NDRANGE_5 0x000023d2 + +#define REG_A4XX_HLSQ_CL_NDRANGE_6 0x000023d3 + +#define REG_A4XX_HLSQ_CL_CONTROL_0 0x000023d4 + +#define REG_A4XX_HLSQ_CL_CONTROL_1 0x000023d5 + +#define REG_A4XX_HLSQ_CL_KERNEL_CONST 0x000023d6 + +#define REG_A4XX_HLSQ_CL_KERNEL_GROUP_X 0x000023d7 + +#define REG_A4XX_HLSQ_CL_KERNEL_GROUP_Y 0x000023d8 + +#define REG_A4XX_HLSQ_CL_KERNEL_GROUP_Z 0x000023d9 + +#define REG_A4XX_HLSQ_CL_WG_OFFSET 0x000023da + #define REG_A4XX_HLSQ_UPDATE_CONTROL 0x000023db #define REG_A4XX_PC_BINNING_COMMAND 0x00000d00 @@ -2035,7 +2363,13 @@ static inline uint32_t A4XX_HLSQ_GS_CONTROL_REG_INSTRLENGTH(uint32_t val) #define REG_A4XX_PC_BIN_BASE 0x000021c0 #define REG_A4XX_PC_PRIM_VTX_CNTL 0x000021c4 -#define A4XX_PC_PRIM_VTX_CNTL_VAROUT 0x00000001 +#define A4XX_PC_PRIM_VTX_CNTL_VAROUT__MASK 0x0000000f +#define A4XX_PC_PRIM_VTX_CNTL_VAROUT__SHIFT 0 +static inline uint32_t A4XX_PC_PRIM_VTX_CNTL_VAROUT(uint32_t val) +{ + return ((val) << A4XX_PC_PRIM_VTX_CNTL_VAROUT__SHIFT) & A4XX_PC_PRIM_VTX_CNTL_VAROUT__MASK; +} +#define A4XX_PC_PRIM_VTX_CNTL_PRIMITIVE_RESTART 0x00100000 #define A4XX_PC_PRIM_VTX_CNTL_PROVOKING_VTX_LAST 0x02000000 #define A4XX_PC_PRIM_VTX_CNTL_PSIZE 0x04000000 @@ -2044,8 +2378,45 @@ static inline uint32_t A4XX_HLSQ_GS_CONTROL_REG_INSTRLENGTH(uint32_t val) #define REG_A4XX_PC_RESTART_INDEX 0x000021c6 #define REG_A4XX_PC_GS_PARAM 0x000021e5 +#define A4XX_PC_GS_PARAM_MAX_VERTICES__MASK 0x000003ff +#define A4XX_PC_GS_PARAM_MAX_VERTICES__SHIFT 0 +static inline uint32_t A4XX_PC_GS_PARAM_MAX_VERTICES(uint32_t val) +{ + return ((val) << A4XX_PC_GS_PARAM_MAX_VERTICES__SHIFT) & A4XX_PC_GS_PARAM_MAX_VERTICES__MASK; +} +#define A4XX_PC_GS_PARAM_INVOCATIONS__MASK 0x0000f800 +#define A4XX_PC_GS_PARAM_INVOCATIONS__SHIFT 11 +static inline uint32_t A4XX_PC_GS_PARAM_INVOCATIONS(uint32_t val) +{ + return ((val) << A4XX_PC_GS_PARAM_INVOCATIONS__SHIFT) & A4XX_PC_GS_PARAM_INVOCATIONS__MASK; +} +#define A4XX_PC_GS_PARAM_PRIMTYPE__MASK 0x01800000 +#define A4XX_PC_GS_PARAM_PRIMTYPE__SHIFT 23 +static inline uint32_t A4XX_PC_GS_PARAM_PRIMTYPE(enum adreno_pa_su_sc_draw val) +{ + return ((val) << A4XX_PC_GS_PARAM_PRIMTYPE__SHIFT) & A4XX_PC_GS_PARAM_PRIMTYPE__MASK; +} +#define A4XX_PC_GS_PARAM_LAYER 0x80000000 #define REG_A4XX_PC_HS_PARAM 0x000021e7 +#define A4XX_PC_HS_PARAM_VERTICES_OUT__MASK 0x0000003f +#define A4XX_PC_HS_PARAM_VERTICES_OUT__SHIFT 0 +static inline uint32_t A4XX_PC_HS_PARAM_VERTICES_OUT(uint32_t val) +{ + return ((val) << A4XX_PC_HS_PARAM_VERTICES_OUT__SHIFT) & A4XX_PC_HS_PARAM_VERTICES_OUT__MASK; +} +#define A4XX_PC_HS_PARAM_SPACING__MASK 0x00600000 +#define A4XX_PC_HS_PARAM_SPACING__SHIFT 21 +static inline uint32_t A4XX_PC_HS_PARAM_SPACING(enum a4xx_tess_spacing val) +{ + return ((val) << A4XX_PC_HS_PARAM_SPACING__SHIFT) & A4XX_PC_HS_PARAM_SPACING__MASK; +} +#define A4XX_PC_HS_PARAM_PRIMTYPE__MASK 0x01800000 +#define A4XX_PC_HS_PARAM_PRIMTYPE__SHIFT 23 +static inline uint32_t A4XX_PC_HS_PARAM_PRIMTYPE(enum adreno_pa_su_sc_draw val) +{ + return ((val) << A4XX_PC_HS_PARAM_PRIMTYPE__SHIFT) & A4XX_PC_HS_PARAM_PRIMTYPE__MASK; +} #define REG_A4XX_VBIF_VERSION 0x00003000 @@ -2074,16 +2445,10 @@ static inline uint32_t A4XX_HLSQ_GS_CONTROL_REG_INSTRLENGTH(uint32_t val) #define REG_A4XX_UNKNOWN_0D01 0x00000d01 -#define REG_A4XX_UNKNOWN_0E05 0x00000e05 - #define REG_A4XX_UNKNOWN_0E42 0x00000e42 #define REG_A4XX_UNKNOWN_0EC2 0x00000ec2 -#define REG_A4XX_UNKNOWN_0EC3 0x00000ec3 - -#define REG_A4XX_UNKNOWN_0F03 0x00000f03 - #define REG_A4XX_UNKNOWN_2001 0x00002001 #define REG_A4XX_UNKNOWN_209B 0x0000209b @@ -2124,10 +2489,6 @@ static inline uint32_t A4XX_UNKNOWN_20F7(float val) #define REG_A4XX_UNKNOWN_22D7 0x000022d7 -#define REG_A4XX_UNKNOWN_2381 0x00002381 - -#define REG_A4XX_UNKNOWN_23A0 0x000023a0 - #define REG_A4XX_TEX_SAMP_0 0x00000000 #define A4XX_TEX_SAMP_0_MIPFILTER_LINEAR_NEAR 0x00000001 #define A4XX_TEX_SAMP_0_XY_MAG__MASK 0x00000006 @@ -2160,6 +2521,12 @@ static inline uint32_t A4XX_TEX_SAMP_0_WRAP_R(enum a4xx_tex_clamp val) { return ((val) << A4XX_TEX_SAMP_0_WRAP_R__SHIFT) & A4XX_TEX_SAMP_0_WRAP_R__MASK; } +#define A4XX_TEX_SAMP_0_ANISO__MASK 0x0001c000 +#define A4XX_TEX_SAMP_0_ANISO__SHIFT 14 +static inline uint32_t A4XX_TEX_SAMP_0_ANISO(enum a4xx_tex_aniso val) +{ + return ((val) << A4XX_TEX_SAMP_0_ANISO__SHIFT) & A4XX_TEX_SAMP_0_ANISO__MASK; +} #define REG_A4XX_TEX_SAMP_1 0x00000001 #define A4XX_TEX_SAMP_1_COMPARE_FUNC__MASK 0x0000000e @@ -2185,6 +2552,7 @@ static inline uint32_t A4XX_TEX_SAMP_1_MIN_LOD(float val) #define REG_A4XX_TEX_CONST_0 0x00000000 #define A4XX_TEX_CONST_0_TILED 0x00000001 +#define A4XX_TEX_CONST_0_SRGB 0x00000004 #define A4XX_TEX_CONST_0_SWIZ_X__MASK 0x00000070 #define A4XX_TEX_CONST_0_SWIZ_X__SHIFT 4 static inline uint32_t A4XX_TEX_CONST_0_SWIZ_X(enum a4xx_tex_swiz val) diff --git a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c index 91221836c5ad..a53f1be05f75 100644 --- a/drivers/gpu/drm/msm/adreno/a4xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a4xx_gpu.c @@ -268,6 +268,8 @@ static int a4xx_hw_init(struct msm_gpu *gpu) static void a4xx_recover(struct msm_gpu *gpu) { + adreno_dump_info(gpu); + /* dump registers before resetting gpu, if enabled: */ if (hang_debug) a4xx_dump(gpu); @@ -505,7 +507,6 @@ static const unsigned int a4xx_register_offsets[REG_ADRENO_REGISTER_MAX] = { static void a4xx_dump(struct msm_gpu *gpu) { - adreno_dump(gpu); printk("status: %08x\n", gpu_read(gpu, REG_A4XX_RBBM_STATUS)); adreno_dump(gpu); diff --git a/drivers/gpu/drm/msm/adreno/adreno_common.xml.h b/drivers/gpu/drm/msm/adreno/adreno_common.xml.h index 8531beb982e7..9562a1fa552b 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_common.xml.h +++ b/drivers/gpu/drm/msm/adreno/adreno_common.xml.h @@ -12,9 +12,9 @@ The rules-ng-ng source files this header was generated from are: - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) - /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2014-06-02 15:21:30) - /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2014-11-13 22:44:30) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 15085 bytes, from 2014-12-20 21:49:41) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 64344 bytes, from 2014-12-12 20:22:26) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 51069 bytes, from 2014-12-21 15:51:54) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14895 bytes, from 2015-04-19 15:23:28) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 66709 bytes, from 2015-04-12 18:16:35) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 60633 bytes, from 2015-05-20 14:48:19) Copyright (C) 2013-2014 by the following authors: - Rob Clark <robdclark@gmail.com> (robclark) diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c index be83dee83d08..1ea2df524fac 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_device.c +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c @@ -19,7 +19,7 @@ #include "adreno_gpu.h" -#if defined(CONFIG_MSM_BUS_SCALING) && !defined(CONFIG_OF) +#if defined(DOWNSTREAM_CONFIG_MSM_BUS_SCALING) && !defined(CONFIG_OF) # include <mach/kgsl.h> #endif @@ -42,6 +42,14 @@ static const struct adreno_info gpulist[] = { .gmem = SZ_256K, .init = a3xx_gpu_init, }, { + .rev = ADRENO_REV(3, 0, 6, 0), + .revn = 307, /* because a305c is revn==306 */ + .name = "A306", + .pm4fw = "a300_pm4.fw", + .pfpfw = "a300_pfp.fw", + .gmem = SZ_128K, + .init = a3xx_gpu_init, + }, { .rev = ADRENO_REV(3, 2, ANY_ID, ANY_ID), .revn = 320, .name = "A320", @@ -240,7 +248,7 @@ static int adreno_bind(struct device *dev, struct device *master, void *data) config.rev = ADRENO_REV(3, 0, 5, 0); } -# ifdef CONFIG_MSM_BUS_SCALING +# ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING config.bus_scale_table = pdata->bus_scale_table; # endif #endif diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index bbdcab0a56c1..a3b54cc76495 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -176,6 +176,17 @@ int adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, OUT_PKT3(ring, CP_INTERRUPT, 1); OUT_RING(ring, 0x80000000); + /* Workaround for missing irq issue on 8x16/a306. Unsure if the + * root cause is a platform issue or some a306 quirk, but this + * keeps things humming along: + */ + if (adreno_is_a306(adreno_gpu)) { + OUT_PKT3(ring, CP_WAIT_FOR_IDLE, 1); + OUT_RING(ring, 0x00000000); + OUT_PKT3(ring, CP_INTERRUPT, 1); + OUT_RING(ring, 0x80000000); + } + #if 0 if (adreno_is_a3xx(adreno_gpu)) { /* Dummy set-constant to trigger context rollover */ @@ -249,8 +260,13 @@ void adreno_show(struct msm_gpu *gpu, struct seq_file *m) } #endif -/* would be nice to not have to duplicate the _show() stuff with printk(): */ -void adreno_dump(struct msm_gpu *gpu) +/* Dump common gpu status and scratch registers on any hang, to make + * the hangcheck logs more useful. The scratch registers seem always + * safe to read when GPU has hung (unlike some other regs, depending + * on how the GPU hung), and they are useful to match up to cmdstream + * dumps when debugging hangs: + */ +void adreno_dump_info(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); int i; @@ -266,6 +282,18 @@ void adreno_dump(struct msm_gpu *gpu) printk("wptr: %d\n", adreno_gpu->memptrs->wptr); printk("rb wptr: %d\n", get_wptr(gpu->rb)); + for (i = 0; i < 8; i++) { + printk("CP_SCRATCH_REG%d: %u\n", i, + gpu_read(gpu, REG_AXXX_CP_SCRATCH_REG0 + i)); + } +} + +/* would be nice to not have to duplicate the _show() stuff with printk(): */ +void adreno_dump(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + int i; + /* dump these out in a form that can be parsed by demsm: */ printk("IO:region %s 00000000 00020000\n", gpu->name); for (i = 0; adreno_gpu->registers[i] != ~0; i += 2) { @@ -317,7 +345,7 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, gpu->fast_rate = config->fast_rate; gpu->slow_rate = config->slow_rate; gpu->bus_freq = config->bus_freq; -#ifdef CONFIG_MSM_BUS_SCALING +#ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING gpu->bus_scale_table = config->bus_scale_table; #endif diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index a0cc30977e67..0a312e9d3afd 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -167,7 +167,7 @@ struct adreno_gpu { struct adreno_platform_config { struct adreno_rev rev; uint32_t fast_rate, slow_rate, bus_freq; -#ifdef CONFIG_MSM_BUS_SCALING +#ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING struct msm_bus_scale_pdata *bus_scale_table; #endif }; @@ -197,6 +197,12 @@ static inline bool adreno_is_a305(struct adreno_gpu *gpu) return gpu->revn == 305; } +static inline bool adreno_is_a306(struct adreno_gpu *gpu) +{ + /* yes, 307, because a305c is 306 */ + return gpu->revn == 307; +} + static inline bool adreno_is_a320(struct adreno_gpu *gpu) { return gpu->revn == 320; @@ -233,6 +239,7 @@ void adreno_idle(struct msm_gpu *gpu); #ifdef CONFIG_DEBUG_FS void adreno_show(struct msm_gpu *gpu, struct seq_file *m); #endif +void adreno_dump_info(struct msm_gpu *gpu); void adreno_dump(struct msm_gpu *gpu); void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords); diff --git a/drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h b/drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h index 6ffc4f6c8af1..bd5b23bf9041 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h +++ b/drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h @@ -12,11 +12,11 @@ The rules-ng-ng source files this header was generated from are: - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) - /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2014-06-02 15:21:30) - /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2014-11-13 22:44:30) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 15085 bytes, from 2014-12-20 21:49:41) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 64344 bytes, from 2014-12-12 20:22:26) -- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 51069 bytes, from 2014-12-21 15:51:54) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14895 bytes, from 2015-04-19 15:23:28) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 66709 bytes, from 2015-04-12 18:16:35) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 60633 bytes, from 2015-05-20 14:48:19) -Copyright (C) 2013-2014 by the following authors: +Copyright (C) 2013-2015 by the following authors: - Rob Clark <robdclark@gmail.com> (robclark) Permission is hereby granted, free of charge, to any person obtaining @@ -76,16 +76,11 @@ enum pc_di_primtype { DI_PT_LINELOOP = 7, DI_PT_RECTLIST = 8, DI_PT_POINTLIST_A3XX = 9, - DI_PT_QUADLIST = 13, - DI_PT_QUADSTRIP = 14, - DI_PT_POLYGON = 15, - DI_PT_2D_COPY_RECT_LIST_V0 = 16, - DI_PT_2D_COPY_RECT_LIST_V1 = 17, - DI_PT_2D_COPY_RECT_LIST_V2 = 18, - DI_PT_2D_COPY_RECT_LIST_V3 = 19, - DI_PT_2D_FILL_RECT_LIST = 20, - DI_PT_2D_LINE_STRIP = 21, - DI_PT_2D_TRI_STRIP = 22, + DI_PT_LINE_ADJ = 10, + DI_PT_LINESTRIP_ADJ = 11, + DI_PT_TRI_ADJ = 12, + DI_PT_TRISTRIP_ADJ = 13, + DI_PT_PATCHES = 34, }; enum pc_di_src_sel { @@ -192,6 +187,7 @@ enum adreno_state_block { SB_FRAG_TEX = 2, SB_FRAG_MIPADDR = 3, SB_VERT_SHADER = 4, + SB_GEOM_SHADER = 5, SB_FRAG_SHADER = 6, }; @@ -382,12 +378,19 @@ static inline uint32_t CP_DRAW_INDX_OFFSET_0_SOURCE_SELECT(enum pc_di_src_sel va { return ((val) << CP_DRAW_INDX_OFFSET_0_SOURCE_SELECT__SHIFT) & CP_DRAW_INDX_OFFSET_0_SOURCE_SELECT__MASK; } +#define CP_DRAW_INDX_OFFSET_0_TESSELLATE 0x00000100 #define CP_DRAW_INDX_OFFSET_0_INDEX_SIZE__MASK 0x00000c00 #define CP_DRAW_INDX_OFFSET_0_INDEX_SIZE__SHIFT 10 static inline uint32_t CP_DRAW_INDX_OFFSET_0_INDEX_SIZE(enum a4xx_index_size val) { return ((val) << CP_DRAW_INDX_OFFSET_0_INDEX_SIZE__SHIFT) & CP_DRAW_INDX_OFFSET_0_INDEX_SIZE__MASK; } +#define CP_DRAW_INDX_OFFSET_0_TESS_MODE__MASK 0x01f00000 +#define CP_DRAW_INDX_OFFSET_0_TESS_MODE__SHIFT 20 +static inline uint32_t CP_DRAW_INDX_OFFSET_0_TESS_MODE(uint32_t val) +{ + return ((val) << CP_DRAW_INDX_OFFSET_0_TESS_MODE__SHIFT) & CP_DRAW_INDX_OFFSET_0_TESS_MODE__MASK; +} #define REG_CP_DRAW_INDX_OFFSET_1 0x00000001 #define CP_DRAW_INDX_OFFSET_1_NUM_INSTANCES__MASK 0xffffffff diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c index ad50b80225f5..1f2561e2ff71 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.c +++ b/drivers/gpu/drm/msm/dsi/dsi.c @@ -23,12 +23,47 @@ struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi) msm_dsi->encoders[MSM_DSI_CMD_ENCODER_ID]; } +static int dsi_get_phy(struct msm_dsi *msm_dsi) +{ + struct platform_device *pdev = msm_dsi->pdev; + struct platform_device *phy_pdev; + struct device_node *phy_node; + + phy_node = of_parse_phandle(pdev->dev.of_node, "qcom,dsi-phy", 0); + if (!phy_node) { + dev_err(&pdev->dev, "cannot find phy device\n"); + return -ENXIO; + } + + phy_pdev = of_find_device_by_node(phy_node); + if (phy_pdev) + msm_dsi->phy = platform_get_drvdata(phy_pdev); + + of_node_put(phy_node); + + if (!phy_pdev || !msm_dsi->phy) { + dev_err(&pdev->dev, "%s: phy driver is not ready\n", __func__); + return -EPROBE_DEFER; + } + + msm_dsi->phy_dev = get_device(&phy_pdev->dev); + + return 0; +} + static void dsi_destroy(struct msm_dsi *msm_dsi) { if (!msm_dsi) return; msm_dsi_manager_unregister(msm_dsi); + + if (msm_dsi->phy_dev) { + put_device(msm_dsi->phy_dev); + msm_dsi->phy = NULL; + msm_dsi->phy_dev = NULL; + } + if (msm_dsi->host) { msm_dsi_host_destroy(msm_dsi->host); msm_dsi->host = NULL; @@ -43,7 +78,6 @@ static struct msm_dsi *dsi_init(struct platform_device *pdev) int ret; if (!pdev) { - dev_err(&pdev->dev, "no dsi device\n"); ret = -ENXIO; goto fail; } @@ -63,6 +97,11 @@ static struct msm_dsi *dsi_init(struct platform_device *pdev) if (ret) goto fail; + /* GET dsi PHY */ + ret = dsi_get_phy(msm_dsi); + if (ret) + goto fail; + /* Register to dsi manager */ ret = msm_dsi_manager_register(msm_dsi); if (ret) @@ -142,12 +181,14 @@ static struct platform_driver dsi_driver = { void __init msm_dsi_register(void) { DBG(""); + msm_dsi_phy_driver_register(); platform_driver_register(&dsi_driver); } void __exit msm_dsi_unregister(void) { DBG(""); + msm_dsi_phy_driver_unregister(); platform_driver_unregister(&dsi_driver); } diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h index 10f54d4e379a..92d697de4858 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.h +++ b/drivers/gpu/drm/msm/dsi/dsi.h @@ -14,6 +14,7 @@ #ifndef __DSI_CONNECTOR_H__ #define __DSI_CONNECTOR_H__ +#include <linux/of_platform.h> #include <linux/platform_device.h> #include "drm_crtc.h" @@ -38,6 +39,28 @@ #define DSI_ENCODER_MASTER DSI_1 #define DSI_ENCODER_SLAVE DSI_0 +enum msm_dsi_phy_type { + MSM_DSI_PHY_28NM_HPM, + MSM_DSI_PHY_28NM_LP, + MSM_DSI_PHY_MAX +}; + +#define DSI_DEV_REGULATOR_MAX 8 + +/* Regulators for DSI devices */ +struct dsi_reg_entry { + char name[32]; + int min_voltage; + int max_voltage; + int enable_load; + int disable_load; +}; + +struct dsi_reg_config { + int num; + struct dsi_reg_entry regs[DSI_DEV_REGULATOR_MAX]; +}; + struct msm_dsi { struct drm_device *dev; struct platform_device *pdev; @@ -49,6 +72,8 @@ struct msm_dsi { struct msm_dsi_phy *phy; struct drm_panel *panel; unsigned long panel_flags; + + struct device *phy_dev; bool phy_enabled; /* the encoders we are hooked to (outside of dsi block) */ @@ -73,6 +98,29 @@ void msm_dsi_manager_unregister(struct msm_dsi *msm_dsi); /* msm dsi */ struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi); +/* dsi pll */ +struct msm_dsi_pll; +#ifdef CONFIG_DRM_MSM_DSI_PLL +struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev, + enum msm_dsi_phy_type type, int dsi_id); +void msm_dsi_pll_destroy(struct msm_dsi_pll *pll); +int msm_dsi_pll_get_clk_provider(struct msm_dsi_pll *pll, + struct clk **byte_clk_provider, struct clk **pixel_clk_provider); +#else +static inline struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev, + enum msm_dsi_phy_type type, int id) { + return ERR_PTR(-ENODEV); +} +static inline void msm_dsi_pll_destroy(struct msm_dsi_pll *pll) +{ +} +static inline int msm_dsi_pll_get_clk_provider(struct msm_dsi_pll *pll, + struct clk **byte_clk_provider, struct clk **pixel_clk_provider) +{ + return -ENODEV; +} +#endif + /* dsi host */ int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host, const struct mipi_dsi_msg *msg); @@ -94,6 +142,8 @@ struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host, unsigned long *panel_flags); int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer); void msm_dsi_host_unregister(struct mipi_dsi_host *host); +int msm_dsi_host_set_src_pll(struct mipi_dsi_host *host, + struct msm_dsi_pll *src_pll); void msm_dsi_host_destroy(struct mipi_dsi_host *host); int msm_dsi_host_modeset_init(struct mipi_dsi_host *host, struct drm_device *dev); @@ -101,17 +151,14 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi); /* dsi phy */ struct msm_dsi_phy; -enum msm_dsi_phy_type { - MSM_DSI_PHY_UNKNOWN, - MSM_DSI_PHY_28NM, - MSM_DSI_PHY_MAX -}; -struct msm_dsi_phy *msm_dsi_phy_init(struct platform_device *pdev, - enum msm_dsi_phy_type type, int id); +void msm_dsi_phy_driver_register(void); +void msm_dsi_phy_driver_unregister(void); int msm_dsi_phy_enable(struct msm_dsi_phy *phy, bool is_dual_panel, const unsigned long bit_rate, const unsigned long esc_rate); int msm_dsi_phy_disable(struct msm_dsi_phy *phy); void msm_dsi_phy_get_clk_pre_post(struct msm_dsi_phy *phy, u32 *clk_pre, u32 *clk_post); +struct msm_dsi_pll *msm_dsi_phy_get_pll(struct msm_dsi_phy *phy); + #endif /* __DSI_CONNECTOR_H__ */ diff --git a/drivers/gpu/drm/msm/dsi/dsi.xml.h b/drivers/gpu/drm/msm/dsi/dsi.xml.h index 1dcfae265e98..9791ea04bcbc 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.xml.h +++ b/drivers/gpu/drm/msm/dsi/dsi.xml.h @@ -8,8 +8,17 @@ http://github.com/freedreno/envytools/ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: -- /usr2/hali/local/envytools/envytools/rnndb/dsi/dsi.xml ( 18681 bytes, from 2015-03-04 23:08:31) -- /usr2/hali/local/envytools/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-01-28 21:43:22) +- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2014-12-05 15:34:49) +- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2015-03-24 22:05:22) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2352 bytes, from 2015-04-12 15:02:42) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 35083 bytes, from 2015-04-12 15:04:03) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 22094 bytes, from 2015-05-12 12:45:23) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2014-10-31 16:48:57) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 29012 bytes, from 2015-05-12 12:45:23) +- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2015-05-12 12:45:23) Copyright (C) 2013-2015 by the following authors: - Rob Clark <robdclark@gmail.com> (robclark) @@ -394,6 +403,9 @@ static inline uint32_t DSI_CLKOUT_TIMING_CTRL_T_CLK_POST(uint32_t val) #define DSI_EOT_PACKET_CTRL_TX_EOT_APPEND 0x00000001 #define DSI_EOT_PACKET_CTRL_RX_EOT_IGNORE 0x00000010 +#define REG_DSI_LANE_CTRL 0x000000a8 +#define DSI_LANE_CTRL_CLKLN_HS_FORCE_REQUEST 0x10000000 + #define REG_DSI_LANE_SWAP_CTRL 0x000000ac #define DSI_LANE_SWAP_CTRL_DLN_SWAP_SEL__MASK 0x00000007 #define DSI_LANE_SWAP_CTRL_DLN_SWAP_SEL__SHIFT 0 @@ -835,5 +847,152 @@ static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD(uint32_t val) #define REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG 0x00000018 +#define REG_DSI_28nm_PHY_PLL_REFCLK_CFG 0x00000000 +#define DSI_28nm_PHY_PLL_REFCLK_CFG_DBLR 0x00000001 + +#define REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG 0x00000004 + +#define REG_DSI_28nm_PHY_PLL_CHGPUMP_CFG 0x00000008 + +#define REG_DSI_28nm_PHY_PLL_VCOLPF_CFG 0x0000000c + +#define REG_DSI_28nm_PHY_PLL_VREG_CFG 0x00000010 +#define DSI_28nm_PHY_PLL_VREG_CFG_POSTDIV1_BYPASS_B 0x00000002 + +#define REG_DSI_28nm_PHY_PLL_PWRGEN_CFG 0x00000014 + +#define REG_DSI_28nm_PHY_PLL_DMUX_CFG 0x00000018 + +#define REG_DSI_28nm_PHY_PLL_AMUX_CFG 0x0000001c + +#define REG_DSI_28nm_PHY_PLL_GLB_CFG 0x00000020 +#define DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B 0x00000001 +#define DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B 0x00000002 +#define DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B 0x00000004 +#define DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE 0x00000008 + +#define REG_DSI_28nm_PHY_PLL_POSTDIV2_CFG 0x00000024 + +#define REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG 0x00000028 + +#define REG_DSI_28nm_PHY_PLL_LPFR_CFG 0x0000002c + +#define REG_DSI_28nm_PHY_PLL_LPFC1_CFG 0x00000030 + +#define REG_DSI_28nm_PHY_PLL_LPFC2_CFG 0x00000034 + +#define REG_DSI_28nm_PHY_PLL_SDM_CFG0 0x00000038 +#define DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV__MASK 0x0000003f +#define DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV__SHIFT 0 +static inline uint32_t DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV(uint32_t val) +{ + return ((val) << DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV__SHIFT) & DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV__MASK; +} +#define DSI_28nm_PHY_PLL_SDM_CFG0_BYP 0x00000040 + +#define REG_DSI_28nm_PHY_PLL_SDM_CFG1 0x0000003c +#define DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET__MASK 0x0000003f +#define DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET__SHIFT 0 +static inline uint32_t DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET(uint32_t val) +{ + return ((val) << DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET__SHIFT) & DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET__MASK; +} +#define DSI_28nm_PHY_PLL_SDM_CFG1_DITHER_EN__MASK 0x00000040 +#define DSI_28nm_PHY_PLL_SDM_CFG1_DITHER_EN__SHIFT 6 +static inline uint32_t DSI_28nm_PHY_PLL_SDM_CFG1_DITHER_EN(uint32_t val) +{ + return ((val) << DSI_28nm_PHY_PLL_SDM_CFG1_DITHER_EN__SHIFT) & DSI_28nm_PHY_PLL_SDM_CFG1_DITHER_EN__MASK; +} + +#define REG_DSI_28nm_PHY_PLL_SDM_CFG2 0x00000040 +#define DSI_28nm_PHY_PLL_SDM_CFG2_FREQ_SEED_7_0__MASK 0x000000ff +#define DSI_28nm_PHY_PLL_SDM_CFG2_FREQ_SEED_7_0__SHIFT 0 +static inline uint32_t DSI_28nm_PHY_PLL_SDM_CFG2_FREQ_SEED_7_0(uint32_t val) +{ + return ((val) << DSI_28nm_PHY_PLL_SDM_CFG2_FREQ_SEED_7_0__SHIFT) & DSI_28nm_PHY_PLL_SDM_CFG2_FREQ_SEED_7_0__MASK; +} + +#define REG_DSI_28nm_PHY_PLL_SDM_CFG3 0x00000044 +#define DSI_28nm_PHY_PLL_SDM_CFG3_FREQ_SEED_15_8__MASK 0x000000ff +#define DSI_28nm_PHY_PLL_SDM_CFG3_FREQ_SEED_15_8__SHIFT 0 +static inline uint32_t DSI_28nm_PHY_PLL_SDM_CFG3_FREQ_SEED_15_8(uint32_t val) +{ + return ((val) << DSI_28nm_PHY_PLL_SDM_CFG3_FREQ_SEED_15_8__SHIFT) & DSI_28nm_PHY_PLL_SDM_CFG3_FREQ_SEED_15_8__MASK; +} + +#define REG_DSI_28nm_PHY_PLL_SDM_CFG4 0x00000048 + +#define REG_DSI_28nm_PHY_PLL_SSC_CFG0 0x0000004c + +#define REG_DSI_28nm_PHY_PLL_SSC_CFG1 0x00000050 + +#define REG_DSI_28nm_PHY_PLL_SSC_CFG2 0x00000054 + +#define REG_DSI_28nm_PHY_PLL_SSC_CFG3 0x00000058 + +#define REG_DSI_28nm_PHY_PLL_LKDET_CFG0 0x0000005c + +#define REG_DSI_28nm_PHY_PLL_LKDET_CFG1 0x00000060 + +#define REG_DSI_28nm_PHY_PLL_LKDET_CFG2 0x00000064 + +#define REG_DSI_28nm_PHY_PLL_TEST_CFG 0x00000068 +#define DSI_28nm_PHY_PLL_TEST_CFG_PLL_SW_RESET 0x00000001 + +#define REG_DSI_28nm_PHY_PLL_CAL_CFG0 0x0000006c + +#define REG_DSI_28nm_PHY_PLL_CAL_CFG1 0x00000070 + +#define REG_DSI_28nm_PHY_PLL_CAL_CFG2 0x00000074 + +#define REG_DSI_28nm_PHY_PLL_CAL_CFG3 0x00000078 + +#define REG_DSI_28nm_PHY_PLL_CAL_CFG4 0x0000007c + +#define REG_DSI_28nm_PHY_PLL_CAL_CFG5 0x00000080 + +#define REG_DSI_28nm_PHY_PLL_CAL_CFG6 0x00000084 + +#define REG_DSI_28nm_PHY_PLL_CAL_CFG7 0x00000088 + +#define REG_DSI_28nm_PHY_PLL_CAL_CFG8 0x0000008c + +#define REG_DSI_28nm_PHY_PLL_CAL_CFG9 0x00000090 + +#define REG_DSI_28nm_PHY_PLL_CAL_CFG10 0x00000094 + +#define REG_DSI_28nm_PHY_PLL_CAL_CFG11 0x00000098 + +#define REG_DSI_28nm_PHY_PLL_EFUSE_CFG 0x0000009c + +#define REG_DSI_28nm_PHY_PLL_DEBUG_BUS_SEL 0x000000a0 + +#define REG_DSI_28nm_PHY_PLL_CTRL_42 0x000000a4 + +#define REG_DSI_28nm_PHY_PLL_CTRL_43 0x000000a8 + +#define REG_DSI_28nm_PHY_PLL_CTRL_44 0x000000ac + +#define REG_DSI_28nm_PHY_PLL_CTRL_45 0x000000b0 + +#define REG_DSI_28nm_PHY_PLL_CTRL_46 0x000000b4 + +#define REG_DSI_28nm_PHY_PLL_CTRL_47 0x000000b8 + +#define REG_DSI_28nm_PHY_PLL_CTRL_48 0x000000bc + +#define REG_DSI_28nm_PHY_PLL_STATUS 0x000000c0 +#define DSI_28nm_PHY_PLL_STATUS_PLL_RDY 0x00000001 + +#define REG_DSI_28nm_PHY_PLL_DEBUG_BUS0 0x000000c4 + +#define REG_DSI_28nm_PHY_PLL_DEBUG_BUS1 0x000000c8 + +#define REG_DSI_28nm_PHY_PLL_DEBUG_BUS2 0x000000cc + +#define REG_DSI_28nm_PHY_PLL_DEBUG_BUS3 0x000000d0 + +#define REG_DSI_28nm_PHY_PLL_CTRL_54 0x000000d4 + #endif /* DSI_XML */ diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 649d20d29f92..de0400923303 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -15,6 +15,7 @@ #include <linux/delay.h> #include <linux/err.h> #include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/interrupt.h> #include <linux/of_device.h> #include <linux/of_gpio.h> @@ -36,35 +37,19 @@ #define DSI_6G_REG_SHIFT 4 -#define DSI_REGULATOR_MAX 8 -struct dsi_reg_entry { - char name[32]; - int min_voltage; - int max_voltage; - int enable_load; - int disable_load; -}; - -struct dsi_reg_config { - int num; - struct dsi_reg_entry regs[DSI_REGULATOR_MAX]; -}; - struct dsi_config { u32 major; u32 minor; u32 io_offset; - enum msm_dsi_phy_type phy_type; struct dsi_reg_config reg_cfg; }; static const struct dsi_config dsi_cfgs[] = { - {MSM_DSI_VER_MAJOR_V2, 0, 0, MSM_DSI_PHY_UNKNOWN}, + {MSM_DSI_VER_MAJOR_V2, 0, 0, {0,} }, { /* 8974 v1 */ .major = MSM_DSI_VER_MAJOR_6G, .minor = MSM_DSI_6G_VER_MINOR_V1_0, .io_offset = DSI_6G_REG_SHIFT, - .phy_type = MSM_DSI_PHY_28NM, .reg_cfg = { .num = 4, .regs = { @@ -79,7 +64,6 @@ static const struct dsi_config dsi_cfgs[] = { .major = MSM_DSI_VER_MAJOR_6G, .minor = MSM_DSI_6G_VER_MINOR_V1_1, .io_offset = DSI_6G_REG_SHIFT, - .phy_type = MSM_DSI_PHY_28NM, .reg_cfg = { .num = 4, .regs = { @@ -94,7 +78,6 @@ static const struct dsi_config dsi_cfgs[] = { .major = MSM_DSI_VER_MAJOR_6G, .minor = MSM_DSI_6G_VER_MINOR_V1_1_1, .io_offset = DSI_6G_REG_SHIFT, - .phy_type = MSM_DSI_PHY_28NM, .reg_cfg = { .num = 4, .regs = { @@ -109,7 +92,6 @@ static const struct dsi_config dsi_cfgs[] = { .major = MSM_DSI_VER_MAJOR_6G, .minor = MSM_DSI_6G_VER_MINOR_V1_2, .io_offset = DSI_6G_REG_SHIFT, - .phy_type = MSM_DSI_PHY_28NM, .reg_cfg = { .num = 4, .regs = { @@ -124,7 +106,6 @@ static const struct dsi_config dsi_cfgs[] = { .major = MSM_DSI_VER_MAJOR_6G, .minor = MSM_DSI_6G_VER_MINOR_V1_3_1, .io_offset = DSI_6G_REG_SHIFT, - .phy_type = MSM_DSI_PHY_28NM, .reg_cfg = { .num = 4, .regs = { @@ -197,7 +178,7 @@ struct msm_dsi_host { int id; void __iomem *ctrl_base; - struct regulator_bulk_data supplies[DSI_REGULATOR_MAX]; + struct regulator_bulk_data supplies[DSI_DEV_REGULATOR_MAX]; struct clk *mdp_core_clk; struct clk *ahb_clk; struct clk *axi_clk; @@ -205,6 +186,9 @@ struct msm_dsi_host { struct clk *byte_clk; struct clk *esc_clk; struct clk *pixel_clk; + struct clk *byte_clk_src; + struct clk *pixel_clk_src; + u32 byte_clk_rate; struct gpio_desc *disp_en_gpio; @@ -273,7 +257,7 @@ static const struct dsi_config *dsi_get_config(struct msm_dsi_host *msm_host) u32 major = 0, minor = 0; gdsc_reg = regulator_get(&msm_host->pdev->dev, "gdsc"); - if (IS_ERR_OR_NULL(gdsc_reg)) { + if (IS_ERR(gdsc_reg)) { pr_err("%s: cannot get gdsc\n", __func__); goto fail; } @@ -463,6 +447,22 @@ static int dsi_clk_init(struct msm_dsi_host *msm_host) goto exit; } + msm_host->byte_clk_src = devm_clk_get(dev, "byte_clk_src"); + if (IS_ERR(msm_host->byte_clk_src)) { + ret = PTR_ERR(msm_host->byte_clk_src); + pr_err("%s: can't find byte_clk_src. ret=%d\n", __func__, ret); + msm_host->byte_clk_src = NULL; + goto exit; + } + + msm_host->pixel_clk_src = devm_clk_get(dev, "pixel_clk_src"); + if (IS_ERR(msm_host->pixel_clk_src)) { + ret = PTR_ERR(msm_host->pixel_clk_src); + pr_err("%s: can't find pixel_clk_src. ret=%d\n", __func__, ret); + msm_host->pixel_clk_src = NULL; + goto exit; + } + exit: return ret; } @@ -787,6 +787,11 @@ static void dsi_ctrl_config(struct msm_dsi_host *msm_host, bool enable, dsi_write(msm_host, REG_DSI_LANE_SWAP_CTRL, DSI_LANE_SWAP_CTRL_DLN_SWAP_SEL(LANE_SWAP_0123)); } + + if (!(flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)) + dsi_write(msm_host, REG_DSI_LANE_CTRL, + DSI_LANE_CTRL_CLKLN_HS_FORCE_REQUEST); + data |= DSI_CTRL_ENABLE; dsi_write(msm_host, REG_DSI_CTRL, data); @@ -1345,36 +1350,19 @@ static irqreturn_t dsi_host_irq(int irq, void *ptr) static int dsi_host_init_panel_gpios(struct msm_dsi_host *msm_host, struct device *panel_device) { - int ret; - - msm_host->disp_en_gpio = devm_gpiod_get(panel_device, - "disp-enable"); + msm_host->disp_en_gpio = devm_gpiod_get_optional(panel_device, + "disp-enable", + GPIOD_OUT_LOW); if (IS_ERR(msm_host->disp_en_gpio)) { DBG("cannot get disp-enable-gpios %ld", PTR_ERR(msm_host->disp_en_gpio)); - msm_host->disp_en_gpio = NULL; - } - if (msm_host->disp_en_gpio) { - ret = gpiod_direction_output(msm_host->disp_en_gpio, 0); - if (ret) { - pr_err("cannot set dir to disp-en-gpios %d\n", ret); - return ret; - } + return PTR_ERR(msm_host->disp_en_gpio); } - msm_host->te_gpio = devm_gpiod_get(panel_device, "disp-te"); + msm_host->te_gpio = devm_gpiod_get(panel_device, "disp-te", GPIOD_IN); if (IS_ERR(msm_host->te_gpio)) { DBG("cannot get disp-te-gpios %ld", PTR_ERR(msm_host->te_gpio)); - msm_host->te_gpio = NULL; - } - - if (msm_host->te_gpio) { - ret = gpiod_direction_input(msm_host->te_gpio); - if (ret) { - pr_err("%s: cannot set dir to disp-te-gpios, %d\n", - __func__, ret); - return ret; - } + return PTR_ERR(msm_host->te_gpio); } return 0; @@ -1508,13 +1496,6 @@ int msm_dsi_host_init(struct msm_dsi *msm_dsi) msm_host->workqueue = alloc_ordered_workqueue("dsi_drm_work", 0); INIT_WORK(&msm_host->err_work, dsi_err_worker); - msm_dsi->phy = msm_dsi_phy_init(pdev, msm_host->cfg->phy_type, - msm_host->id); - if (!msm_dsi->phy) { - ret = -EINVAL; - pr_err("%s: phy init failed\n", __func__); - goto fail; - } msm_dsi->host = &msm_host->base; msm_dsi->id = msm_host->id; @@ -1824,6 +1805,39 @@ void msm_dsi_host_cmd_xfer_commit(struct mipi_dsi_host *host, u32 iova, u32 len) wmb(); } +int msm_dsi_host_set_src_pll(struct mipi_dsi_host *host, + struct msm_dsi_pll *src_pll) +{ + struct msm_dsi_host *msm_host = to_msm_dsi_host(host); + struct clk *byte_clk_provider, *pixel_clk_provider; + int ret; + + ret = msm_dsi_pll_get_clk_provider(src_pll, + &byte_clk_provider, &pixel_clk_provider); + if (ret) { + pr_info("%s: can't get provider from pll, don't set parent\n", + __func__); + return 0; + } + + ret = clk_set_parent(msm_host->byte_clk_src, byte_clk_provider); + if (ret) { + pr_err("%s: can't set parent to byte_clk_src. ret=%d\n", + __func__, ret); + goto exit; + } + + ret = clk_set_parent(msm_host->pixel_clk_src, pixel_clk_provider); + if (ret) { + pr_err("%s: can't set parent to pixel_clk_src. ret=%d\n", + __func__, ret); + goto exit; + } + +exit: + return ret; +} + int msm_dsi_host_enable(struct mipi_dsi_host *host) { struct msm_dsi_host *msm_host = to_msm_dsi_host(host); diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index 0a40f3c64e8b..87ac6612b6f8 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -60,6 +60,53 @@ static int dsi_mgr_parse_dual_panel(struct device_node *np, int id) return 0; } +static int dsi_mgr_host_register(int id) +{ + struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); + struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id); + struct msm_dsi *clk_master_dsi = dsi_mgr_get_dsi(DSI_CLOCK_MASTER); + struct msm_dsi_pll *src_pll; + int ret; + + if (!IS_DUAL_PANEL()) { + ret = msm_dsi_host_register(msm_dsi->host, true); + if (ret) + return ret; + + src_pll = msm_dsi_phy_get_pll(msm_dsi->phy); + ret = msm_dsi_host_set_src_pll(msm_dsi->host, src_pll); + } else if (!other_dsi) { + ret = 0; + } else { + struct msm_dsi *mdsi = IS_MASTER_PANEL(id) ? + msm_dsi : other_dsi; + struct msm_dsi *sdsi = IS_MASTER_PANEL(id) ? + other_dsi : msm_dsi; + /* Register slave host first, so that slave DSI device + * has a chance to probe, and do not block the master + * DSI device's probe. + * Also, do not check defer for the slave host, + * because only master DSI device adds the panel to global + * panel list. The panel's device is the master DSI device. + */ + ret = msm_dsi_host_register(sdsi->host, false); + if (ret) + return ret; + ret = msm_dsi_host_register(mdsi->host, true); + if (ret) + return ret; + + /* PLL0 is to drive both 2 DSI link clocks in Dual DSI mode. */ + src_pll = msm_dsi_phy_get_pll(clk_master_dsi->phy); + ret = msm_dsi_host_set_src_pll(msm_dsi->host, src_pll); + if (ret) + return ret; + ret = msm_dsi_host_set_src_pll(other_dsi->host, src_pll); + } + + return ret; +} + struct dsi_connector { struct drm_connector base; int id; @@ -652,7 +699,6 @@ int msm_dsi_manager_register(struct msm_dsi *msm_dsi) { struct msm_dsi_manager *msm_dsim = &msm_dsim_glb; int id = msm_dsi->id; - struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id); int ret; if (id > DSI_MAX) { @@ -670,31 +716,20 @@ int msm_dsi_manager_register(struct msm_dsi *msm_dsi) ret = dsi_mgr_parse_dual_panel(msm_dsi->pdev->dev.of_node, id); if (ret) { pr_err("%s: failed to parse dual panel info\n", __func__); - return ret; + goto fail; } - if (!IS_DUAL_PANEL()) { - ret = msm_dsi_host_register(msm_dsi->host, true); - } else if (!other_dsi) { - return 0; - } else { - struct msm_dsi *mdsi = IS_MASTER_PANEL(id) ? - msm_dsi : other_dsi; - struct msm_dsi *sdsi = IS_MASTER_PANEL(id) ? - other_dsi : msm_dsi; - /* Register slave host first, so that slave DSI device - * has a chance to probe, and do not block the master - * DSI device's probe. - * Also, do not check defer for the slave host, - * because only master DSI device adds the panel to global - * panel list. The panel's device is the master DSI device. - */ - ret = msm_dsi_host_register(sdsi->host, false); - if (ret) - return ret; - ret = msm_dsi_host_register(mdsi->host, true); + ret = dsi_mgr_host_register(id); + if (ret) { + pr_err("%s: failed to register mipi dsi host for DSI %d\n", + __func__, id); + goto fail; } + return 0; + +fail: + msm_dsim->dsi[id] = NULL; return ret; } diff --git a/drivers/gpu/drm/msm/dsi/dsi_phy.c b/drivers/gpu/drm/msm/dsi/dsi_phy.c index f0cea8927388..2d3b33ce1cc5 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi/dsi_phy.c @@ -11,12 +11,27 @@ * GNU General Public License for more details. */ +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> + #include "dsi.h" #include "dsi.xml.h" #define dsi_phy_read(offset) msm_readl((offset)) #define dsi_phy_write(offset, data) msm_writel((data), (offset)) +struct dsi_phy_ops { + int (*enable)(struct msm_dsi_phy *phy, bool is_dual_panel, + const unsigned long bit_rate, const unsigned long esc_rate); + int (*disable)(struct msm_dsi_phy *phy); +}; + +struct dsi_phy_cfg { + enum msm_dsi_phy_type type; + struct dsi_reg_config reg_cfg; + struct dsi_phy_ops ops; +}; + struct dsi_dphy_timing { u32 clk_pre; u32 clk_post; @@ -34,15 +49,106 @@ struct dsi_dphy_timing { }; struct msm_dsi_phy { + struct platform_device *pdev; void __iomem *base; void __iomem *reg_base; int id; + + struct clk *ahb_clk; + struct regulator_bulk_data supplies[DSI_DEV_REGULATOR_MAX]; + struct dsi_dphy_timing timing; - int (*enable)(struct msm_dsi_phy *phy, bool is_dual_panel, - const unsigned long bit_rate, const unsigned long esc_rate); - int (*disable)(struct msm_dsi_phy *phy); + const struct dsi_phy_cfg *cfg; + + struct msm_dsi_pll *pll; }; +static int dsi_phy_regulator_init(struct msm_dsi_phy *phy) +{ + struct regulator_bulk_data *s = phy->supplies; + const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs; + struct device *dev = &phy->pdev->dev; + int num = phy->cfg->reg_cfg.num; + int i, ret; + + for (i = 0; i < num; i++) + s[i].supply = regs[i].name; + + ret = devm_regulator_bulk_get(&phy->pdev->dev, num, s); + if (ret < 0) { + dev_err(dev, "%s: failed to init regulator, ret=%d\n", + __func__, ret); + return ret; + } + + for (i = 0; i < num; i++) { + if ((regs[i].min_voltage >= 0) && (regs[i].max_voltage >= 0)) { + ret = regulator_set_voltage(s[i].consumer, + regs[i].min_voltage, regs[i].max_voltage); + if (ret < 0) { + dev_err(dev, + "regulator %d set voltage failed, %d\n", + i, ret); + return ret; + } + } + } + + return 0; +} + +static void dsi_phy_regulator_disable(struct msm_dsi_phy *phy) +{ + struct regulator_bulk_data *s = phy->supplies; + const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs; + int num = phy->cfg->reg_cfg.num; + int i; + + DBG(""); + for (i = num - 1; i >= 0; i--) + if (regs[i].disable_load >= 0) + regulator_set_load(s[i].consumer, + regs[i].disable_load); + + regulator_bulk_disable(num, s); +} + +static int dsi_phy_regulator_enable(struct msm_dsi_phy *phy) +{ + struct regulator_bulk_data *s = phy->supplies; + const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs; + struct device *dev = &phy->pdev->dev; + int num = phy->cfg->reg_cfg.num; + int ret, i; + + DBG(""); + for (i = 0; i < num; i++) { + if (regs[i].enable_load >= 0) { + ret = regulator_set_load(s[i].consumer, + regs[i].enable_load); + if (ret < 0) { + dev_err(dev, + "regulator %d set op mode failed, %d\n", + i, ret); + goto fail; + } + } + } + + ret = regulator_bulk_enable(num, s); + if (ret < 0) { + dev_err(dev, "regulator enable failed, %d\n", ret); + goto fail; + } + + return 0; + +fail: + for (i--; i >= 0; i--) + regulator_set_load(s[i].consumer, regs[i].disable_load); + return ret; +} + #define S_DIV_ROUND_UP(n, d) \ (((n) >= 0) ? (((n) + (d) - 1) / (d)) : (((n) - (d) + 1) / (d))) @@ -284,59 +390,200 @@ static int dsi_28nm_phy_disable(struct msm_dsi_phy *phy) return 0; } -#define dsi_phy_func_init(name) \ - do { \ - phy->enable = dsi_##name##_phy_enable; \ - phy->disable = dsi_##name##_phy_disable; \ - } while (0) +static int dsi_phy_enable_resource(struct msm_dsi_phy *phy) +{ + int ret; + + pm_runtime_get_sync(&phy->pdev->dev); -struct msm_dsi_phy *msm_dsi_phy_init(struct platform_device *pdev, - enum msm_dsi_phy_type type, int id) + ret = clk_prepare_enable(phy->ahb_clk); + if (ret) { + pr_err("%s: can't enable ahb clk, %d\n", __func__, ret); + pm_runtime_put_sync(&phy->pdev->dev); + } + + return ret; +} + +static void dsi_phy_disable_resource(struct msm_dsi_phy *phy) +{ + clk_disable_unprepare(phy->ahb_clk); + pm_runtime_put_sync(&phy->pdev->dev); +} + +static const struct dsi_phy_cfg dsi_phy_cfgs[MSM_DSI_PHY_MAX] = { + [MSM_DSI_PHY_28NM_HPM] = { + .type = MSM_DSI_PHY_28NM_HPM, + .reg_cfg = { + .num = 1, + .regs = { + {"vddio", 1800000, 1800000, 100000, 100}, + }, + }, + .ops = { + .enable = dsi_28nm_phy_enable, + .disable = dsi_28nm_phy_disable, + } + }, + [MSM_DSI_PHY_28NM_LP] = { + .type = MSM_DSI_PHY_28NM_LP, + .reg_cfg = { + .num = 1, + .regs = { + {"vddio", 1800000, 1800000, 100000, 100}, + }, + }, + .ops = { + .enable = dsi_28nm_phy_enable, + .disable = dsi_28nm_phy_disable, + } + }, +}; + +static const struct of_device_id dsi_phy_dt_match[] = { + { .compatible = "qcom,dsi-phy-28nm-hpm", + .data = &dsi_phy_cfgs[MSM_DSI_PHY_28NM_HPM],}, + { .compatible = "qcom,dsi-phy-28nm-lp", + .data = &dsi_phy_cfgs[MSM_DSI_PHY_28NM_LP],}, + {} +}; + +static int dsi_phy_driver_probe(struct platform_device *pdev) { struct msm_dsi_phy *phy; + const struct of_device_id *match; + int ret; phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL); if (!phy) - return NULL; + return -ENOMEM; + + match = of_match_node(dsi_phy_dt_match, pdev->dev.of_node); + if (!match) + return -ENODEV; + + phy->cfg = match->data; + phy->pdev = pdev; + + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,dsi-phy-index", &phy->id); + if (ret) { + dev_err(&pdev->dev, + "%s: PHY index not specified, ret=%d\n", + __func__, ret); + goto fail; + } phy->base = msm_ioremap(pdev, "dsi_phy", "DSI_PHY"); - if (IS_ERR_OR_NULL(phy->base)) { - pr_err("%s: failed to map phy base\n", __func__); - return NULL; + if (IS_ERR(phy->base)) { + dev_err(&pdev->dev, "%s: failed to map phy base\n", __func__); + ret = -ENOMEM; + goto fail; } phy->reg_base = msm_ioremap(pdev, "dsi_phy_regulator", "DSI_PHY_REG"); - if (IS_ERR_OR_NULL(phy->reg_base)) { - pr_err("%s: failed to map phy regulator base\n", __func__); - return NULL; + if (IS_ERR(phy->reg_base)) { + dev_err(&pdev->dev, + "%s: failed to map phy regulator base\n", __func__); + ret = -ENOMEM; + goto fail; } - switch (type) { - case MSM_DSI_PHY_28NM: - dsi_phy_func_init(28nm); - break; - default: - pr_err("%s: unsupported type, %d\n", __func__, type); - return NULL; + ret = dsi_phy_regulator_init(phy); + if (ret) { + dev_err(&pdev->dev, "%s: failed to init regulator\n", __func__); + goto fail; + } + + phy->ahb_clk = devm_clk_get(&pdev->dev, "iface_clk"); + if (IS_ERR(phy->ahb_clk)) { + pr_err("%s: Unable to get ahb clk\n", __func__); + ret = PTR_ERR(phy->ahb_clk); + goto fail; } - phy->id = id; + /* PLL init will call into clk_register which requires + * register access, so we need to enable power and ahb clock. + */ + ret = dsi_phy_enable_resource(phy); + if (ret) + goto fail; + + phy->pll = msm_dsi_pll_init(pdev, phy->cfg->type, phy->id); + if (!phy->pll) + dev_info(&pdev->dev, + "%s: pll init failed, need separate pll clk driver\n", + __func__); + + dsi_phy_disable_resource(phy); + + platform_set_drvdata(pdev, phy); + + return 0; - return phy; +fail: + return ret; +} + +static int dsi_phy_driver_remove(struct platform_device *pdev) +{ + struct msm_dsi_phy *phy = platform_get_drvdata(pdev); + + if (phy && phy->pll) { + msm_dsi_pll_destroy(phy->pll); + phy->pll = NULL; + } + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver dsi_phy_platform_driver = { + .probe = dsi_phy_driver_probe, + .remove = dsi_phy_driver_remove, + .driver = { + .name = "msm_dsi_phy", + .of_match_table = dsi_phy_dt_match, + }, +}; + +void __init msm_dsi_phy_driver_register(void) +{ + platform_driver_register(&dsi_phy_platform_driver); +} + +void __exit msm_dsi_phy_driver_unregister(void) +{ + platform_driver_unregister(&dsi_phy_platform_driver); } int msm_dsi_phy_enable(struct msm_dsi_phy *phy, bool is_dual_panel, const unsigned long bit_rate, const unsigned long esc_rate) { - if (!phy || !phy->enable) + int ret; + + if (!phy || !phy->cfg->ops.enable) return -EINVAL; - return phy->enable(phy, is_dual_panel, bit_rate, esc_rate); + + ret = dsi_phy_regulator_enable(phy); + if (ret) { + dev_err(&phy->pdev->dev, "%s: regulator enable failed, %d\n", + __func__, ret); + return ret; + } + + return phy->cfg->ops.enable(phy, is_dual_panel, bit_rate, esc_rate); } int msm_dsi_phy_disable(struct msm_dsi_phy *phy) { - if (!phy || !phy->disable) + if (!phy || !phy->cfg->ops.disable) return -EINVAL; - return phy->disable(phy); + + phy->cfg->ops.disable(phy); + dsi_phy_regulator_disable(phy); + + return 0; } void msm_dsi_phy_get_clk_pre_post(struct msm_dsi_phy *phy, @@ -350,3 +597,11 @@ void msm_dsi_phy_get_clk_pre_post(struct msm_dsi_phy *phy, *clk_post = phy->timing.clk_post; } +struct msm_dsi_pll *msm_dsi_phy_get_pll(struct msm_dsi_phy *phy) +{ + if (!phy) + return NULL; + + return phy->pll; +} + diff --git a/drivers/gpu/drm/msm/dsi/mmss_cc.xml.h b/drivers/gpu/drm/msm/dsi/mmss_cc.xml.h index 695f99d4bec2..728152f3ef48 100644 --- a/drivers/gpu/drm/msm/dsi/mmss_cc.xml.h +++ b/drivers/gpu/drm/msm/dsi/mmss_cc.xml.h @@ -10,15 +10,15 @@ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: - /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2014-12-05 15:34:49) - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20908 bytes, from 2014-12-08 16:13:00) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2357 bytes, from 2014-12-08 16:13:00) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 27208 bytes, from 2015-01-13 23:56:11) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2015-03-24 22:05:22) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2352 bytes, from 2015-04-12 15:02:42) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 35083 bytes, from 2015-04-12 15:04:03) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 22094 bytes, from 2015-05-12 12:45:23) - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32) - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2014-10-31 16:48:57) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12) -- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 26848 bytes, from 2015-01-13 23:55:57) -- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 8253 bytes, from 2014-12-08 16:13:00) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 29012 bytes, from 2015-05-12 12:45:23) +- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2015-05-12 12:45:23) Copyright (C) 2013-2014 by the following authors: - Rob Clark <robdclark@gmail.com> (robclark) diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c new file mode 100644 index 000000000000..509376fdd112 --- /dev/null +++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "dsi_pll.h" + +static int dsi_pll_enable(struct msm_dsi_pll *pll) +{ + int i, ret = 0; + + /* + * Certain PLLs do not allow VCO rate update when it is on. + * Keep track of their status to turn on/off after set rate success. + */ + if (unlikely(pll->pll_on)) + return 0; + + /* Try all enable sequences until one succeeds */ + for (i = 0; i < pll->en_seq_cnt; i++) { + ret = pll->enable_seqs[i](pll); + DBG("DSI PLL %s after sequence #%d", + ret ? "unlocked" : "locked", i + 1); + if (!ret) + break; + } + + if (ret) { + DRM_ERROR("DSI PLL failed to lock\n"); + return ret; + } + + pll->pll_on = true; + + return 0; +} + +static void dsi_pll_disable(struct msm_dsi_pll *pll) +{ + if (unlikely(!pll->pll_on)) + return; + + pll->disable_seq(pll); + + pll->pll_on = false; +} + +/* + * DSI PLL Helper functions + */ +long msm_dsi_pll_helper_clk_round_rate(struct clk_hw *hw, + unsigned long rate, unsigned long *parent_rate) +{ + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); + + if (rate < pll->min_rate) + return pll->min_rate; + else if (rate > pll->max_rate) + return pll->max_rate; + else + return rate; +} + +int msm_dsi_pll_helper_clk_prepare(struct clk_hw *hw) +{ + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); + int ret; + + /* + * Certain PLLs need to update the same VCO rate and registers + * after resume in suspend/resume scenario. + */ + if (pll->restore_state) { + ret = pll->restore_state(pll); + if (ret) + goto error; + } + + ret = dsi_pll_enable(pll); + +error: + return ret; +} + +void msm_dsi_pll_helper_clk_unprepare(struct clk_hw *hw) +{ + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); + + if (pll->save_state) + pll->save_state(pll); + + dsi_pll_disable(pll); +} + +void msm_dsi_pll_helper_unregister_clks(struct platform_device *pdev, + struct clk **clks, u32 num_clks) +{ + of_clk_del_provider(pdev->dev.of_node); + + if (!num_clks || !clks) + return; + + do { + clk_unregister(clks[--num_clks]); + clks[num_clks] = NULL; + } while (num_clks); +} + +/* + * DSI PLL API + */ +int msm_dsi_pll_get_clk_provider(struct msm_dsi_pll *pll, + struct clk **byte_clk_provider, struct clk **pixel_clk_provider) +{ + if (pll->get_provider) + return pll->get_provider(pll, + byte_clk_provider, + pixel_clk_provider); + + return -EINVAL; +} + +void msm_dsi_pll_destroy(struct msm_dsi_pll *pll) +{ + if (pll->destroy) + pll->destroy(pll); +} + +struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev, + enum msm_dsi_phy_type type, int id) +{ + struct device *dev = &pdev->dev; + struct msm_dsi_pll *pll; + + switch (type) { + case MSM_DSI_PHY_28NM_HPM: + case MSM_DSI_PHY_28NM_LP: + pll = msm_dsi_pll_28nm_init(pdev, type, id); + break; + default: + pll = ERR_PTR(-ENXIO); + break; + } + + if (IS_ERR(pll)) { + dev_err(dev, "%s: failed to init DSI PLL\n", __func__); + return NULL; + } + + pll->type = type; + + DBG("DSI:%d PLL registered", id); + + return pll; +} + diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h new file mode 100644 index 000000000000..5a3bb241c039 --- /dev/null +++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __DSI_PLL_H__ +#define __DSI_PLL_H__ + +#include <linux/clk.h> +#include <linux/clk-provider.h> + +#include "dsi.h" + +#define NUM_DSI_CLOCKS_MAX 6 +#define MAX_DSI_PLL_EN_SEQS 10 + +struct msm_dsi_pll { + enum msm_dsi_phy_type type; + + struct clk_hw clk_hw; + bool pll_on; + + unsigned long min_rate; + unsigned long max_rate; + u32 en_seq_cnt; + + int (*enable_seqs[MAX_DSI_PLL_EN_SEQS])(struct msm_dsi_pll *pll); + void (*disable_seq)(struct msm_dsi_pll *pll); + int (*get_provider)(struct msm_dsi_pll *pll, + struct clk **byte_clk_provider, + struct clk **pixel_clk_provider); + void (*destroy)(struct msm_dsi_pll *pll); + void (*save_state)(struct msm_dsi_pll *pll); + int (*restore_state)(struct msm_dsi_pll *pll); +}; + +#define hw_clk_to_pll(x) container_of(x, struct msm_dsi_pll, clk_hw) + +static inline void pll_write(void __iomem *reg, u32 data) +{ + msm_writel(data, reg); +} + +static inline u32 pll_read(const void __iomem *reg) +{ + return msm_readl(reg); +} + +static inline void pll_write_udelay(void __iomem *reg, u32 data, u32 delay_us) +{ + pll_write(reg, data); + udelay(delay_us); +} + +static inline void pll_write_ndelay(void __iomem *reg, u32 data, u32 delay_ns) +{ + pll_write((reg), data); + ndelay(delay_ns); +} + +/* + * DSI PLL Helper functions + */ + +/* clock callbacks */ +long msm_dsi_pll_helper_clk_round_rate(struct clk_hw *hw, + unsigned long rate, unsigned long *parent_rate); +int msm_dsi_pll_helper_clk_prepare(struct clk_hw *hw); +void msm_dsi_pll_helper_clk_unprepare(struct clk_hw *hw); +/* misc */ +void msm_dsi_pll_helper_unregister_clks(struct platform_device *pdev, + struct clk **clks, u32 num_clks); + +/* + * Initialization for Each PLL Type + */ +struct msm_dsi_pll *msm_dsi_pll_28nm_init(struct platform_device *pdev, + enum msm_dsi_phy_type type, int id); + +#endif /* __DSI_PLL_H__ */ + diff --git a/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm.c b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm.c new file mode 100644 index 000000000000..eb8ac3097ff5 --- /dev/null +++ b/drivers/gpu/drm/msm/dsi/pll/dsi_pll_28nm.c @@ -0,0 +1,652 @@ +/* + * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk.h> +#include <linux/clk-provider.h> + +#include "dsi_pll.h" +#include "dsi.xml.h" + +/* + * DSI PLL 28nm - clock diagram (eg: DSI0): + * + * dsi0analog_postdiv_clk + * | dsi0indirect_path_div2_clk + * | | + * +------+ | +----+ | |\ dsi0byte_mux + * dsi0vco_clk --o--| DIV1 |--o--| /2 |--o--| \ | + * | +------+ +----+ | m| | +----+ + * | | u|--o--| /4 |-- dsi0pllbyte + * | | x| +----+ + * o--------------------------| / + * | |/ + * | +------+ + * o----------| DIV3 |------------------------- dsi0pll + * +------+ + */ + +#define POLL_MAX_READS 10 +#define POLL_TIMEOUT_US 50 + +#define NUM_PROVIDED_CLKS 2 + +#define VCO_REF_CLK_RATE 19200000 +#define VCO_MIN_RATE 350000000 +#define VCO_MAX_RATE 750000000 + +#define DSI_BYTE_PLL_CLK 0 +#define DSI_PIXEL_PLL_CLK 1 + +#define LPFR_LUT_SIZE 10 +struct lpfr_cfg { + unsigned long vco_rate; + u32 resistance; +}; + +/* Loop filter resistance: */ +static const struct lpfr_cfg lpfr_lut[LPFR_LUT_SIZE] = { + { 479500000, 8 }, + { 480000000, 11 }, + { 575500000, 8 }, + { 576000000, 12 }, + { 610500000, 8 }, + { 659500000, 9 }, + { 671500000, 10 }, + { 672000000, 14 }, + { 708500000, 10 }, + { 750000000, 11 }, +}; + +struct pll_28nm_cached_state { + unsigned long vco_rate; + u8 postdiv3; + u8 postdiv1; + u8 byte_mux; +}; + +struct dsi_pll_28nm { + struct msm_dsi_pll base; + + int id; + struct platform_device *pdev; + void __iomem *mmio; + + int vco_delay; + + /* private clocks: */ + struct clk *clks[NUM_DSI_CLOCKS_MAX]; + u32 num_clks; + + /* clock-provider: */ + struct clk *provided_clks[NUM_PROVIDED_CLKS]; + struct clk_onecell_data clk_data; + + struct pll_28nm_cached_state cached_state; +}; + +#define to_pll_28nm(x) container_of(x, struct dsi_pll_28nm, base) + +static bool pll_28nm_poll_for_ready(struct dsi_pll_28nm *pll_28nm, + u32 nb_tries, u32 timeout_us) +{ + bool pll_locked = false; + u32 val; + + while (nb_tries--) { + val = pll_read(pll_28nm->mmio + REG_DSI_28nm_PHY_PLL_STATUS); + pll_locked = !!(val & DSI_28nm_PHY_PLL_STATUS_PLL_RDY); + + if (pll_locked) + break; + + udelay(timeout_us); + } + DBG("DSI PLL is %slocked", pll_locked ? "" : "*not* "); + + return pll_locked; +} + +static void pll_28nm_software_reset(struct dsi_pll_28nm *pll_28nm) +{ + void __iomem *base = pll_28nm->mmio; + + /* + * Add HW recommended delays after toggling the software + * reset bit off and back on. + */ + pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_TEST_CFG, + DSI_28nm_PHY_PLL_TEST_CFG_PLL_SW_RESET, 1); + pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_TEST_CFG, 0x00, 1); +} + +/* + * Clock Callbacks + */ +static int dsi_pll_28nm_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); + struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); + struct device *dev = &pll_28nm->pdev->dev; + void __iomem *base = pll_28nm->mmio; + unsigned long div_fbx1000, gen_vco_clk; + u32 refclk_cfg, frac_n_mode, frac_n_value; + u32 sdm_cfg0, sdm_cfg1, sdm_cfg2, sdm_cfg3; + u32 cal_cfg10, cal_cfg11; + u32 rem; + int i; + + VERB("rate=%lu, parent's=%lu", rate, parent_rate); + + /* Force postdiv2 to be div-4 */ + pll_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV2_CFG, 3); + + /* Configure the Loop filter resistance */ + for (i = 0; i < LPFR_LUT_SIZE; i++) + if (rate <= lpfr_lut[i].vco_rate) + break; + if (i == LPFR_LUT_SIZE) { + dev_err(dev, "unable to get loop filter resistance. vco=%lu\n", + rate); + return -EINVAL; + } + pll_write(base + REG_DSI_28nm_PHY_PLL_LPFR_CFG, lpfr_lut[i].resistance); + + /* Loop filter capacitance values : c1 and c2 */ + pll_write(base + REG_DSI_28nm_PHY_PLL_LPFC1_CFG, 0x70); + pll_write(base + REG_DSI_28nm_PHY_PLL_LPFC2_CFG, 0x15); + + rem = rate % VCO_REF_CLK_RATE; + if (rem) { + refclk_cfg = DSI_28nm_PHY_PLL_REFCLK_CFG_DBLR; + frac_n_mode = 1; + div_fbx1000 = rate / (VCO_REF_CLK_RATE / 500); + gen_vco_clk = div_fbx1000 * (VCO_REF_CLK_RATE / 500); + } else { + refclk_cfg = 0x0; + frac_n_mode = 0; + div_fbx1000 = rate / (VCO_REF_CLK_RATE / 1000); + gen_vco_clk = div_fbx1000 * (VCO_REF_CLK_RATE / 1000); + } + + DBG("refclk_cfg = %d", refclk_cfg); + + rem = div_fbx1000 % 1000; + frac_n_value = (rem << 16) / 1000; + + DBG("div_fb = %lu", div_fbx1000); + DBG("frac_n_value = %d", frac_n_value); + + DBG("Generated VCO Clock: %lu", gen_vco_clk); + rem = 0; + sdm_cfg1 = pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG1); + sdm_cfg1 &= ~DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET__MASK; + if (frac_n_mode) { + sdm_cfg0 = 0x0; + sdm_cfg0 |= DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV(0); + sdm_cfg1 |= DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET( + (u32)(((div_fbx1000 / 1000) & 0x3f) - 1)); + sdm_cfg3 = frac_n_value >> 8; + sdm_cfg2 = frac_n_value & 0xff; + } else { + sdm_cfg0 = DSI_28nm_PHY_PLL_SDM_CFG0_BYP; + sdm_cfg0 |= DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV( + (u32)(((div_fbx1000 / 1000) & 0x3f) - 1)); + sdm_cfg1 |= DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET(0); + sdm_cfg2 = 0; + sdm_cfg3 = 0; + } + + DBG("sdm_cfg0=%d", sdm_cfg0); + DBG("sdm_cfg1=%d", sdm_cfg1); + DBG("sdm_cfg2=%d", sdm_cfg2); + DBG("sdm_cfg3=%d", sdm_cfg3); + + cal_cfg11 = (u32)(gen_vco_clk / (256 * 1000000)); + cal_cfg10 = (u32)((gen_vco_clk % (256 * 1000000)) / 1000000); + DBG("cal_cfg10=%d, cal_cfg11=%d", cal_cfg10, cal_cfg11); + + pll_write(base + REG_DSI_28nm_PHY_PLL_CHGPUMP_CFG, 0x02); + pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG3, 0x2b); + pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG4, 0x06); + pll_write(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x0d); + + pll_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG1, sdm_cfg1); + pll_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG2, + DSI_28nm_PHY_PLL_SDM_CFG2_FREQ_SEED_7_0(sdm_cfg2)); + pll_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG3, + DSI_28nm_PHY_PLL_SDM_CFG3_FREQ_SEED_15_8(sdm_cfg3)); + pll_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG4, 0x00); + + /* Add hardware recommended delay for correct PLL configuration */ + if (pll_28nm->vco_delay) + udelay(pll_28nm->vco_delay); + + pll_write(base + REG_DSI_28nm_PHY_PLL_REFCLK_CFG, refclk_cfg); + pll_write(base + REG_DSI_28nm_PHY_PLL_PWRGEN_CFG, 0x00); + pll_write(base + REG_DSI_28nm_PHY_PLL_VCOLPF_CFG, 0x31); + pll_write(base + REG_DSI_28nm_PHY_PLL_SDM_CFG0, sdm_cfg0); + pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG0, 0x12); + pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG6, 0x30); + pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG7, 0x00); + pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG8, 0x60); + pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG9, 0x00); + pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG10, cal_cfg10 & 0xff); + pll_write(base + REG_DSI_28nm_PHY_PLL_CAL_CFG11, cal_cfg11 & 0xff); + pll_write(base + REG_DSI_28nm_PHY_PLL_EFUSE_CFG, 0x20); + + return 0; +} + +static int dsi_pll_28nm_clk_is_enabled(struct clk_hw *hw) +{ + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); + struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); + + return pll_28nm_poll_for_ready(pll_28nm, POLL_MAX_READS, + POLL_TIMEOUT_US); +} + +static unsigned long dsi_pll_28nm_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct msm_dsi_pll *pll = hw_clk_to_pll(hw); + struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); + void __iomem *base = pll_28nm->mmio; + u32 sdm0, doubler, sdm_byp_div; + u32 sdm_dc_off, sdm_freq_seed, sdm2, sdm3; + u32 ref_clk = VCO_REF_CLK_RATE; + unsigned long vco_rate; + + VERB("parent_rate=%lu", parent_rate); + + /* Check to see if the ref clk doubler is enabled */ + doubler = pll_read(base + REG_DSI_28nm_PHY_PLL_REFCLK_CFG) & + DSI_28nm_PHY_PLL_REFCLK_CFG_DBLR; + ref_clk += (doubler * VCO_REF_CLK_RATE); + + /* see if it is integer mode or sdm mode */ + sdm0 = pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG0); + if (sdm0 & DSI_28nm_PHY_PLL_SDM_CFG0_BYP) { + /* integer mode */ + sdm_byp_div = FIELD( + pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG0), + DSI_28nm_PHY_PLL_SDM_CFG0_BYP_DIV) + 1; + vco_rate = ref_clk * sdm_byp_div; + } else { + /* sdm mode */ + sdm_dc_off = FIELD( + pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG1), + DSI_28nm_PHY_PLL_SDM_CFG1_DC_OFFSET); + DBG("sdm_dc_off = %d", sdm_dc_off); + sdm2 = FIELD(pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG2), + DSI_28nm_PHY_PLL_SDM_CFG2_FREQ_SEED_7_0); + sdm3 = FIELD(pll_read(base + REG_DSI_28nm_PHY_PLL_SDM_CFG3), + DSI_28nm_PHY_PLL_SDM_CFG3_FREQ_SEED_15_8); + sdm_freq_seed = (sdm3 << 8) | sdm2; + DBG("sdm_freq_seed = %d", sdm_freq_seed); + + vco_rate = (ref_clk * (sdm_dc_off + 1)) + + mult_frac(ref_clk, sdm_freq_seed, BIT(16)); + DBG("vco rate = %lu", vco_rate); + } + + DBG("returning vco rate = %lu", vco_rate); + + return vco_rate; +} + +static const struct clk_ops clk_ops_dsi_pll_28nm_vco = { + .round_rate = msm_dsi_pll_helper_clk_round_rate, + .set_rate = dsi_pll_28nm_clk_set_rate, + .recalc_rate = dsi_pll_28nm_clk_recalc_rate, + .prepare = msm_dsi_pll_helper_clk_prepare, + .unprepare = msm_dsi_pll_helper_clk_unprepare, + .is_enabled = dsi_pll_28nm_clk_is_enabled, +}; + +/* + * PLL Callbacks + */ +static int dsi_pll_28nm_enable_seq_hpm(struct msm_dsi_pll *pll) +{ + struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); + struct device *dev = &pll_28nm->pdev->dev; + void __iomem *base = pll_28nm->mmio; + u32 max_reads = 5, timeout_us = 100; + bool locked; + u32 val; + int i; + + DBG("id=%d", pll_28nm->id); + + pll_28nm_software_reset(pll_28nm); + + /* + * PLL power up sequence. + * Add necessary delays recommended by hardware. + */ + val = DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B; + pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 1); + + val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B; + pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 200); + + val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B; + pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500); + + val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE; + pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 600); + + for (i = 0; i < 2; i++) { + /* DSI Uniphy lock detect setting */ + pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, + 0x0c, 100); + pll_write(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x0d); + + /* poll for PLL ready status */ + locked = pll_28nm_poll_for_ready(pll_28nm, + max_reads, timeout_us); + if (locked) + break; + + pll_28nm_software_reset(pll_28nm); + + /* + * PLL power up sequence. + * Add necessary delays recommended by hardware. + */ + val = DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B; + pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 1); + + val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B; + pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 200); + + val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B; + pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 250); + + val &= ~DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B; + pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 200); + + val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B; + pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500); + + val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE; + pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 600); + } + + if (unlikely(!locked)) + dev_err(dev, "DSI PLL lock failed\n"); + else + DBG("DSI PLL Lock success"); + + return locked ? 0 : -EINVAL; +} + +static int dsi_pll_28nm_enable_seq_lp(struct msm_dsi_pll *pll) +{ + struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); + struct device *dev = &pll_28nm->pdev->dev; + void __iomem *base = pll_28nm->mmio; + bool locked; + u32 max_reads = 10, timeout_us = 50; + u32 val; + + DBG("id=%d", pll_28nm->id); + + pll_28nm_software_reset(pll_28nm); + + /* + * PLL power up sequence. + * Add necessary delays recommended by hardware. + */ + pll_write_ndelay(base + REG_DSI_28nm_PHY_PLL_CAL_CFG1, 0x34, 500); + + val = DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B; + pll_write_ndelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500); + + val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B; + pll_write_ndelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500); + + val |= DSI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B | + DSI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE; + pll_write_ndelay(base + REG_DSI_28nm_PHY_PLL_GLB_CFG, val, 500); + + /* DSI PLL toggle lock detect setting */ + pll_write_ndelay(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x04, 500); + pll_write_udelay(base + REG_DSI_28nm_PHY_PLL_LKDET_CFG2, 0x05, 512); + + locked = pll_28nm_poll_for_ready(pll_28nm, max_reads, timeout_us); + + if (unlikely(!locked)) + dev_err(dev, "DSI PLL lock failed\n"); + else + DBG("DSI PLL lock success"); + + return locked ? 0 : -EINVAL; +} + +static void dsi_pll_28nm_disable_seq(struct msm_dsi_pll *pll) +{ + struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); + + DBG("id=%d", pll_28nm->id); + pll_write(pll_28nm->mmio + REG_DSI_28nm_PHY_PLL_GLB_CFG, 0x00); +} + +static void dsi_pll_28nm_save_state(struct msm_dsi_pll *pll) +{ + struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); + struct pll_28nm_cached_state *cached_state = &pll_28nm->cached_state; + void __iomem *base = pll_28nm->mmio; + + cached_state->postdiv3 = + pll_read(base + REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG); + cached_state->postdiv1 = + pll_read(base + REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG); + cached_state->byte_mux = pll_read(base + REG_DSI_28nm_PHY_PLL_VREG_CFG); + cached_state->vco_rate = __clk_get_rate(pll->clk_hw.clk); +} + +static int dsi_pll_28nm_restore_state(struct msm_dsi_pll *pll) +{ + struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); + struct pll_28nm_cached_state *cached_state = &pll_28nm->cached_state; + void __iomem *base = pll_28nm->mmio; + int ret; + + if ((cached_state->vco_rate != 0) && + (cached_state->vco_rate == __clk_get_rate(pll->clk_hw.clk))) { + ret = dsi_pll_28nm_clk_set_rate(&pll->clk_hw, + cached_state->vco_rate, 0); + if (ret) { + dev_err(&pll_28nm->pdev->dev, + "restore vco rate failed. ret=%d\n", ret); + return ret; + } + + pll_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG, + cached_state->postdiv3); + pll_write(base + REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG, + cached_state->postdiv1); + pll_write(base + REG_DSI_28nm_PHY_PLL_VREG_CFG, + cached_state->byte_mux); + + cached_state->vco_rate = 0; + } + + return 0; +} + +static int dsi_pll_28nm_get_provider(struct msm_dsi_pll *pll, + struct clk **byte_clk_provider, + struct clk **pixel_clk_provider) +{ + struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); + + if (byte_clk_provider) + *byte_clk_provider = pll_28nm->provided_clks[DSI_BYTE_PLL_CLK]; + if (pixel_clk_provider) + *pixel_clk_provider = + pll_28nm->provided_clks[DSI_PIXEL_PLL_CLK]; + + return 0; +} + +static void dsi_pll_28nm_destroy(struct msm_dsi_pll *pll) +{ + struct dsi_pll_28nm *pll_28nm = to_pll_28nm(pll); + int i; + + msm_dsi_pll_helper_unregister_clks(pll_28nm->pdev, + pll_28nm->clks, pll_28nm->num_clks); + + for (i = 0; i < NUM_PROVIDED_CLKS; i++) + pll_28nm->provided_clks[i] = NULL; + + pll_28nm->num_clks = 0; + pll_28nm->clk_data.clks = NULL; + pll_28nm->clk_data.clk_num = 0; +} + +static int pll_28nm_register(struct dsi_pll_28nm *pll_28nm) +{ + char clk_name[32], parent1[32], parent2[32], vco_name[32]; + struct clk_init_data vco_init = { + .parent_names = (const char *[]){ "xo" }, + .num_parents = 1, + .name = vco_name, + .ops = &clk_ops_dsi_pll_28nm_vco, + }; + struct device *dev = &pll_28nm->pdev->dev; + struct clk **clks = pll_28nm->clks; + struct clk **provided_clks = pll_28nm->provided_clks; + int num = 0; + int ret; + + DBG("%d", pll_28nm->id); + + snprintf(vco_name, 32, "dsi%dvco_clk", pll_28nm->id); + pll_28nm->base.clk_hw.init = &vco_init; + clks[num++] = clk_register(dev, &pll_28nm->base.clk_hw); + + snprintf(clk_name, 32, "dsi%danalog_postdiv_clk", pll_28nm->id); + snprintf(parent1, 32, "dsi%dvco_clk", pll_28nm->id); + clks[num++] = clk_register_divider(dev, clk_name, + parent1, CLK_SET_RATE_PARENT, + pll_28nm->mmio + + REG_DSI_28nm_PHY_PLL_POSTDIV1_CFG, + 0, 4, 0, NULL); + + snprintf(clk_name, 32, "dsi%dindirect_path_div2_clk", pll_28nm->id); + snprintf(parent1, 32, "dsi%danalog_postdiv_clk", pll_28nm->id); + clks[num++] = clk_register_fixed_factor(dev, clk_name, + parent1, CLK_SET_RATE_PARENT, + 1, 2); + + snprintf(clk_name, 32, "dsi%dpll", pll_28nm->id); + snprintf(parent1, 32, "dsi%dvco_clk", pll_28nm->id); + clks[num++] = provided_clks[DSI_PIXEL_PLL_CLK] = + clk_register_divider(dev, clk_name, + parent1, 0, pll_28nm->mmio + + REG_DSI_28nm_PHY_PLL_POSTDIV3_CFG, + 0, 8, 0, NULL); + + snprintf(clk_name, 32, "dsi%dbyte_mux", pll_28nm->id); + snprintf(parent1, 32, "dsi%dvco_clk", pll_28nm->id); + snprintf(parent2, 32, "dsi%dindirect_path_div2_clk", pll_28nm->id); + clks[num++] = clk_register_mux(dev, clk_name, + (const char *[]){ + parent1, parent2 + }, 2, CLK_SET_RATE_PARENT, pll_28nm->mmio + + REG_DSI_28nm_PHY_PLL_VREG_CFG, 1, 1, 0, NULL); + + snprintf(clk_name, 32, "dsi%dpllbyte", pll_28nm->id); + snprintf(parent1, 32, "dsi%dbyte_mux", pll_28nm->id); + clks[num++] = provided_clks[DSI_BYTE_PLL_CLK] = + clk_register_fixed_factor(dev, clk_name, + parent1, CLK_SET_RATE_PARENT, 1, 4); + + pll_28nm->num_clks = num; + + pll_28nm->clk_data.clk_num = NUM_PROVIDED_CLKS; + pll_28nm->clk_data.clks = provided_clks; + + ret = of_clk_add_provider(dev->of_node, + of_clk_src_onecell_get, &pll_28nm->clk_data); + if (ret) { + dev_err(dev, "failed to register clk provider: %d\n", ret); + return ret; + } + + return 0; +} + +struct msm_dsi_pll *msm_dsi_pll_28nm_init(struct platform_device *pdev, + enum msm_dsi_phy_type type, int id) +{ + struct dsi_pll_28nm *pll_28nm; + struct msm_dsi_pll *pll; + int ret; + + if (!pdev) + return ERR_PTR(-ENODEV); + + pll_28nm = devm_kzalloc(&pdev->dev, sizeof(*pll_28nm), GFP_KERNEL); + if (!pll_28nm) + return ERR_PTR(-ENOMEM); + + pll_28nm->pdev = pdev; + pll_28nm->id = id; + + pll_28nm->mmio = msm_ioremap(pdev, "dsi_pll", "DSI_PLL"); + if (IS_ERR_OR_NULL(pll_28nm->mmio)) { + dev_err(&pdev->dev, "%s: failed to map pll base\n", __func__); + return ERR_PTR(-ENOMEM); + } + + pll = &pll_28nm->base; + pll->min_rate = VCO_MIN_RATE; + pll->max_rate = VCO_MAX_RATE; + pll->get_provider = dsi_pll_28nm_get_provider; + pll->destroy = dsi_pll_28nm_destroy; + pll->disable_seq = dsi_pll_28nm_disable_seq; + pll->save_state = dsi_pll_28nm_save_state; + pll->restore_state = dsi_pll_28nm_restore_state; + + if (type == MSM_DSI_PHY_28NM_HPM) { + pll_28nm->vco_delay = 1; + + pll->en_seq_cnt = 3; + pll->enable_seqs[0] = dsi_pll_28nm_enable_seq_hpm; + pll->enable_seqs[1] = dsi_pll_28nm_enable_seq_hpm; + pll->enable_seqs[2] = dsi_pll_28nm_enable_seq_hpm; + } else if (type == MSM_DSI_PHY_28NM_LP) { + pll_28nm->vco_delay = 1000; + + pll->en_seq_cnt = 1; + pll->enable_seqs[0] = dsi_pll_28nm_enable_seq_lp; + } else { + dev_err(&pdev->dev, "phy type (%d) is not 28nm\n", type); + return ERR_PTR(-EINVAL); + } + + ret = pll_28nm_register(pll_28nm); + if (ret) { + dev_err(&pdev->dev, "failed to register PLL: %d\n", ret); + return ERR_PTR(ret); + } + + return pll; +} + diff --git a/drivers/gpu/drm/msm/dsi/sfpb.xml.h b/drivers/gpu/drm/msm/dsi/sfpb.xml.h index 50ff9851d73d..26f268e2dd3d 100644 --- a/drivers/gpu/drm/msm/dsi/sfpb.xml.h +++ b/drivers/gpu/drm/msm/dsi/sfpb.xml.h @@ -10,15 +10,15 @@ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: - /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2014-12-05 15:34:49) - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20908 bytes, from 2014-12-08 16:13:00) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2357 bytes, from 2014-12-08 16:13:00) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 27208 bytes, from 2015-01-13 23:56:11) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2015-03-24 22:05:22) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2352 bytes, from 2015-04-12 15:02:42) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 35083 bytes, from 2015-04-12 15:04:03) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 22094 bytes, from 2015-05-12 12:45:23) - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32) - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2014-10-31 16:48:57) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12) -- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 26848 bytes, from 2015-01-13 23:55:57) -- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 8253 bytes, from 2014-12-08 16:13:00) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 29012 bytes, from 2015-05-12 12:45:23) +- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2015-05-12 12:45:23) Copyright (C) 2013 by the following authors: - Rob Clark <robdclark@gmail.com> (robclark) diff --git a/drivers/gpu/drm/msm/edp/edp.xml.h b/drivers/gpu/drm/msm/edp/edp.xml.h index a29f1df15143..f9c71dceb5e2 100644 --- a/drivers/gpu/drm/msm/edp/edp.xml.h +++ b/drivers/gpu/drm/msm/edp/edp.xml.h @@ -10,17 +10,17 @@ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: - /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2014-12-05 15:34:49) - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20908 bytes, from 2014-12-08 16:13:00) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2357 bytes, from 2014-12-08 16:13:00) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 27208 bytes, from 2015-01-13 23:56:11) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2015-03-24 22:05:22) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2352 bytes, from 2015-04-12 15:02:42) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 35083 bytes, from 2015-04-12 15:04:03) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 22094 bytes, from 2015-05-12 12:45:23) - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32) - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2014-10-31 16:48:57) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12) -- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 26848 bytes, from 2015-01-13 23:55:57) -- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 8253 bytes, from 2014-12-08 16:13:00) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 29012 bytes, from 2015-05-12 12:45:23) +- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2015-05-12 12:45:23) -Copyright (C) 2013-2014 by the following authors: +Copyright (C) 2013-2015 by the following authors: - Rob Clark <robdclark@gmail.com> (robclark) Permission is hereby granted, free of charge, to any person obtaining @@ -288,5 +288,92 @@ static inline uint32_t REG_EDP_PHY_LN_PD_CTL(uint32_t i0) { return 0x00000404 + #define REG_EDP_PHY_GLB_PHY_STATUS 0x00000598 +#define REG_EDP_28nm_PHY_PLL_REFCLK_CFG 0x00000000 + +#define REG_EDP_28nm_PHY_PLL_POSTDIV1_CFG 0x00000004 + +#define REG_EDP_28nm_PHY_PLL_CHGPUMP_CFG 0x00000008 + +#define REG_EDP_28nm_PHY_PLL_VCOLPF_CFG 0x0000000c + +#define REG_EDP_28nm_PHY_PLL_VREG_CFG 0x00000010 + +#define REG_EDP_28nm_PHY_PLL_PWRGEN_CFG 0x00000014 + +#define REG_EDP_28nm_PHY_PLL_DMUX_CFG 0x00000018 + +#define REG_EDP_28nm_PHY_PLL_AMUX_CFG 0x0000001c + +#define REG_EDP_28nm_PHY_PLL_GLB_CFG 0x00000020 +#define EDP_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B 0x00000001 +#define EDP_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B 0x00000002 +#define EDP_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B 0x00000004 +#define EDP_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE 0x00000008 + +#define REG_EDP_28nm_PHY_PLL_POSTDIV2_CFG 0x00000024 + +#define REG_EDP_28nm_PHY_PLL_POSTDIV3_CFG 0x00000028 + +#define REG_EDP_28nm_PHY_PLL_LPFR_CFG 0x0000002c + +#define REG_EDP_28nm_PHY_PLL_LPFC1_CFG 0x00000030 + +#define REG_EDP_28nm_PHY_PLL_LPFC2_CFG 0x00000034 + +#define REG_EDP_28nm_PHY_PLL_SDM_CFG0 0x00000038 + +#define REG_EDP_28nm_PHY_PLL_SDM_CFG1 0x0000003c + +#define REG_EDP_28nm_PHY_PLL_SDM_CFG2 0x00000040 + +#define REG_EDP_28nm_PHY_PLL_SDM_CFG3 0x00000044 + +#define REG_EDP_28nm_PHY_PLL_SDM_CFG4 0x00000048 + +#define REG_EDP_28nm_PHY_PLL_SSC_CFG0 0x0000004c + +#define REG_EDP_28nm_PHY_PLL_SSC_CFG1 0x00000050 + +#define REG_EDP_28nm_PHY_PLL_SSC_CFG2 0x00000054 + +#define REG_EDP_28nm_PHY_PLL_SSC_CFG3 0x00000058 + +#define REG_EDP_28nm_PHY_PLL_LKDET_CFG0 0x0000005c + +#define REG_EDP_28nm_PHY_PLL_LKDET_CFG1 0x00000060 + +#define REG_EDP_28nm_PHY_PLL_LKDET_CFG2 0x00000064 + +#define REG_EDP_28nm_PHY_PLL_TEST_CFG 0x00000068 +#define EDP_28nm_PHY_PLL_TEST_CFG_PLL_SW_RESET 0x00000001 + +#define REG_EDP_28nm_PHY_PLL_CAL_CFG0 0x0000006c + +#define REG_EDP_28nm_PHY_PLL_CAL_CFG1 0x00000070 + +#define REG_EDP_28nm_PHY_PLL_CAL_CFG2 0x00000074 + +#define REG_EDP_28nm_PHY_PLL_CAL_CFG3 0x00000078 + +#define REG_EDP_28nm_PHY_PLL_CAL_CFG4 0x0000007c + +#define REG_EDP_28nm_PHY_PLL_CAL_CFG5 0x00000080 + +#define REG_EDP_28nm_PHY_PLL_CAL_CFG6 0x00000084 + +#define REG_EDP_28nm_PHY_PLL_CAL_CFG7 0x00000088 + +#define REG_EDP_28nm_PHY_PLL_CAL_CFG8 0x0000008c + +#define REG_EDP_28nm_PHY_PLL_CAL_CFG9 0x00000090 + +#define REG_EDP_28nm_PHY_PLL_CAL_CFG10 0x00000094 + +#define REG_EDP_28nm_PHY_PLL_CAL_CFG11 0x00000098 + +#define REG_EDP_28nm_PHY_PLL_EFUSE_CFG 0x0000009c + +#define REG_EDP_28nm_PHY_PLL_DEBUG_BUS_SEL 0x000000a0 + #endif /* EDP_XML */ diff --git a/drivers/gpu/drm/msm/edp/edp_aux.c b/drivers/gpu/drm/msm/edp/edp_aux.c index 208f9d47f82e..82789dd249ee 100644 --- a/drivers/gpu/drm/msm/edp/edp_aux.c +++ b/drivers/gpu/drm/msm/edp/edp_aux.c @@ -115,10 +115,12 @@ static int edp_msg_fifo_rx(struct edp_aux *aux, struct drm_dp_aux_msg *msg) * msm_edp_aux_ctrl() running concurrently in other threads, i.e. * start transaction only when AUX channel is fully enabled. */ -ssize_t edp_aux_transfer(struct drm_dp_aux *drm_aux, struct drm_dp_aux_msg *msg) +static ssize_t edp_aux_transfer(struct drm_dp_aux *drm_aux, + struct drm_dp_aux_msg *msg) { struct edp_aux *aux = to_edp_aux(drm_aux); ssize_t ret; + unsigned long time_left; bool native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ); bool read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ); @@ -147,15 +149,17 @@ ssize_t edp_aux_transfer(struct drm_dp_aux *drm_aux, struct drm_dp_aux_msg *msg) goto unlock_exit; DBG("wait_for_completion"); - ret = wait_for_completion_timeout(&aux->msg_comp, 300); - if (ret <= 0) { + time_left = wait_for_completion_timeout(&aux->msg_comp, + msecs_to_jiffies(300)); + if (!time_left) { /* * Clear GO and reset AUX channel * to cancel the current transaction. */ edp_write(aux->base + REG_EDP_AUX_TRANS_CTRL, 0); msm_edp_aux_ctrl(aux, 1); - pr_err("%s: aux timeout, %zd\n", __func__, ret); + pr_err("%s: aux timeout,\n", __func__); + ret = -ETIMEDOUT; goto unlock_exit; } DBG("completion"); diff --git a/drivers/gpu/drm/msm/edp/edp_ctrl.c b/drivers/gpu/drm/msm/edp/edp_ctrl.c index 29e52d7c61c0..7991069dd492 100644 --- a/drivers/gpu/drm/msm/edp/edp_ctrl.c +++ b/drivers/gpu/drm/msm/edp/edp_ctrl.c @@ -1018,7 +1018,7 @@ static void edp_ctrl_off_worker(struct work_struct *work) { struct edp_ctrl *ctrl = container_of( work, struct edp_ctrl, off_work); - int ret; + unsigned long time_left; mutex_lock(&ctrl->dev_mutex); @@ -1030,11 +1030,10 @@ static void edp_ctrl_off_worker(struct work_struct *work) reinit_completion(&ctrl->idle_comp); edp_state_ctrl(ctrl, EDP_STATE_CTRL_PUSH_IDLE); - ret = wait_for_completion_timeout(&ctrl->idle_comp, + time_left = wait_for_completion_timeout(&ctrl->idle_comp, msecs_to_jiffies(500)); - if (ret <= 0) - DBG("%s: idle pattern timedout, %d\n", - __func__, ret); + if (!time_left) + DBG("%s: idle pattern timedout\n", __func__); edp_state_ctrl(ctrl, 0); diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.xml.h b/drivers/gpu/drm/msm/hdmi/hdmi.xml.h index 350988740e9f..e6f034808371 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.xml.h +++ b/drivers/gpu/drm/msm/hdmi/hdmi.xml.h @@ -10,15 +10,15 @@ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: - /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2014-12-05 15:34:49) - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20908 bytes, from 2014-12-08 16:13:00) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2357 bytes, from 2014-12-08 16:13:00) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 27208 bytes, from 2015-01-13 23:56:11) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2015-03-24 22:05:22) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2352 bytes, from 2015-04-12 15:02:42) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 35083 bytes, from 2015-04-12 15:04:03) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 22094 bytes, from 2015-05-12 12:45:23) - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32) - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2014-10-31 16:48:57) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12) -- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 26848 bytes, from 2015-01-13 23:55:57) -- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 8253 bytes, from 2014-12-08 16:13:00) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 29012 bytes, from 2015-05-12 12:45:23) +- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2015-05-12 12:45:23) Copyright (C) 2013-2015 by the following authors: - Rob Clark <robdclark@gmail.com> (robclark) @@ -750,5 +750,92 @@ static inline uint32_t HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL(uint32_t val) #define REG_HDMI_8x74_BIST_PATN3 0x00000048 +#define REG_HDMI_28nm_PHY_PLL_REFCLK_CFG 0x00000000 + +#define REG_HDMI_28nm_PHY_PLL_POSTDIV1_CFG 0x00000004 + +#define REG_HDMI_28nm_PHY_PLL_CHGPUMP_CFG 0x00000008 + +#define REG_HDMI_28nm_PHY_PLL_VCOLPF_CFG 0x0000000c + +#define REG_HDMI_28nm_PHY_PLL_VREG_CFG 0x00000010 + +#define REG_HDMI_28nm_PHY_PLL_PWRGEN_CFG 0x00000014 + +#define REG_HDMI_28nm_PHY_PLL_DMUX_CFG 0x00000018 + +#define REG_HDMI_28nm_PHY_PLL_AMUX_CFG 0x0000001c + +#define REG_HDMI_28nm_PHY_PLL_GLB_CFG 0x00000020 +#define HDMI_28nm_PHY_PLL_GLB_CFG_PLL_PWRDN_B 0x00000001 +#define HDMI_28nm_PHY_PLL_GLB_CFG_PLL_LDO_PWRDN_B 0x00000002 +#define HDMI_28nm_PHY_PLL_GLB_CFG_PLL_PWRGEN_PWRDN_B 0x00000004 +#define HDMI_28nm_PHY_PLL_GLB_CFG_PLL_ENABLE 0x00000008 + +#define REG_HDMI_28nm_PHY_PLL_POSTDIV2_CFG 0x00000024 + +#define REG_HDMI_28nm_PHY_PLL_POSTDIV3_CFG 0x00000028 + +#define REG_HDMI_28nm_PHY_PLL_LPFR_CFG 0x0000002c + +#define REG_HDMI_28nm_PHY_PLL_LPFC1_CFG 0x00000030 + +#define REG_HDMI_28nm_PHY_PLL_LPFC2_CFG 0x00000034 + +#define REG_HDMI_28nm_PHY_PLL_SDM_CFG0 0x00000038 + +#define REG_HDMI_28nm_PHY_PLL_SDM_CFG1 0x0000003c + +#define REG_HDMI_28nm_PHY_PLL_SDM_CFG2 0x00000040 + +#define REG_HDMI_28nm_PHY_PLL_SDM_CFG3 0x00000044 + +#define REG_HDMI_28nm_PHY_PLL_SDM_CFG4 0x00000048 + +#define REG_HDMI_28nm_PHY_PLL_SSC_CFG0 0x0000004c + +#define REG_HDMI_28nm_PHY_PLL_SSC_CFG1 0x00000050 + +#define REG_HDMI_28nm_PHY_PLL_SSC_CFG2 0x00000054 + +#define REG_HDMI_28nm_PHY_PLL_SSC_CFG3 0x00000058 + +#define REG_HDMI_28nm_PHY_PLL_LKDET_CFG0 0x0000005c + +#define REG_HDMI_28nm_PHY_PLL_LKDET_CFG1 0x00000060 + +#define REG_HDMI_28nm_PHY_PLL_LKDET_CFG2 0x00000064 + +#define REG_HDMI_28nm_PHY_PLL_TEST_CFG 0x00000068 +#define HDMI_28nm_PHY_PLL_TEST_CFG_PLL_SW_RESET 0x00000001 + +#define REG_HDMI_28nm_PHY_PLL_CAL_CFG0 0x0000006c + +#define REG_HDMI_28nm_PHY_PLL_CAL_CFG1 0x00000070 + +#define REG_HDMI_28nm_PHY_PLL_CAL_CFG2 0x00000074 + +#define REG_HDMI_28nm_PHY_PLL_CAL_CFG3 0x00000078 + +#define REG_HDMI_28nm_PHY_PLL_CAL_CFG4 0x0000007c + +#define REG_HDMI_28nm_PHY_PLL_CAL_CFG5 0x00000080 + +#define REG_HDMI_28nm_PHY_PLL_CAL_CFG6 0x00000084 + +#define REG_HDMI_28nm_PHY_PLL_CAL_CFG7 0x00000088 + +#define REG_HDMI_28nm_PHY_PLL_CAL_CFG8 0x0000008c + +#define REG_HDMI_28nm_PHY_PLL_CAL_CFG9 0x00000090 + +#define REG_HDMI_28nm_PHY_PLL_CAL_CFG10 0x00000094 + +#define REG_HDMI_28nm_PHY_PLL_CAL_CFG11 0x00000098 + +#define REG_HDMI_28nm_PHY_PLL_EFUSE_CFG 0x0000009c + +#define REG_HDMI_28nm_PHY_PLL_DEBUG_BUS_SEL 0x000000a0 + #endif /* HDMI_XML */ diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c index b62cdb968614..54aa93ff5473 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c @@ -16,6 +16,7 @@ */ #include <linux/gpio.h> +#include <linux/pinctrl/consumer.h> #include "msm_kms.h" #include "hdmi.h" @@ -29,14 +30,14 @@ struct hdmi_connector { static int gpio_config(struct hdmi *hdmi, bool on) { - struct drm_device *dev = hdmi->dev; + struct device *dev = &hdmi->pdev->dev; const struct hdmi_platform_config *config = hdmi->config; int ret; if (on) { ret = gpio_request(config->ddc_clk_gpio, "HDMI_DDC_CLK"); if (ret) { - dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n", + dev_err(dev, "'%s'(%d) gpio_request failed: %d\n", "HDMI_DDC_CLK", config->ddc_clk_gpio, ret); goto error1; } @@ -44,7 +45,7 @@ static int gpio_config(struct hdmi *hdmi, bool on) ret = gpio_request(config->ddc_data_gpio, "HDMI_DDC_DATA"); if (ret) { - dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n", + dev_err(dev, "'%s'(%d) gpio_request failed: %d\n", "HDMI_DDC_DATA", config->ddc_data_gpio, ret); goto error2; } @@ -52,7 +53,7 @@ static int gpio_config(struct hdmi *hdmi, bool on) ret = gpio_request(config->hpd_gpio, "HDMI_HPD"); if (ret) { - dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n", + dev_err(dev, "'%s'(%d) gpio_request failed: %d\n", "HDMI_HPD", config->hpd_gpio, ret); goto error3; } @@ -62,7 +63,7 @@ static int gpio_config(struct hdmi *hdmi, bool on) if (config->mux_en_gpio != -1) { ret = gpio_request(config->mux_en_gpio, "HDMI_MUX_EN"); if (ret) { - dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n", + dev_err(dev, "'%s'(%d) gpio_request failed: %d\n", "HDMI_MUX_EN", config->mux_en_gpio, ret); goto error4; } @@ -72,7 +73,7 @@ static int gpio_config(struct hdmi *hdmi, bool on) if (config->mux_sel_gpio != -1) { ret = gpio_request(config->mux_sel_gpio, "HDMI_MUX_SEL"); if (ret) { - dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n", + dev_err(dev, "'%s'(%d) gpio_request failed: %d\n", "HDMI_MUX_SEL", config->mux_sel_gpio, ret); goto error5; } @@ -83,7 +84,7 @@ static int gpio_config(struct hdmi *hdmi, bool on) ret = gpio_request(config->mux_lpm_gpio, "HDMI_MUX_LPM"); if (ret) { - dev_err(dev->dev, + dev_err(dev, "'%s'(%d) gpio_request failed: %d\n", "HDMI_MUX_LPM", config->mux_lpm_gpio, ret); @@ -136,7 +137,7 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector) { struct hdmi *hdmi = hdmi_connector->hdmi; const struct hdmi_platform_config *config = hdmi->config; - struct drm_device *dev = hdmi_connector->base.dev; + struct device *dev = &hdmi->pdev->dev; struct hdmi_phy *phy = hdmi->phy; uint32_t hpd_ctrl; int i, ret; @@ -144,15 +145,21 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector) for (i = 0; i < config->hpd_reg_cnt; i++) { ret = regulator_enable(hdmi->hpd_regs[i]); if (ret) { - dev_err(dev->dev, "failed to enable hpd regulator: %s (%d)\n", + dev_err(dev, "failed to enable hpd regulator: %s (%d)\n", config->hpd_reg_names[i], ret); goto fail; } } + ret = pinctrl_pm_select_default_state(dev); + if (ret) { + dev_err(dev, "pinctrl state chg failed: %d\n", ret); + goto fail; + } + ret = gpio_config(hdmi, true); if (ret) { - dev_err(dev->dev, "failed to configure GPIOs: %d\n", ret); + dev_err(dev, "failed to configure GPIOs: %d\n", ret); goto fail; } @@ -161,13 +168,13 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector) ret = clk_set_rate(hdmi->hpd_clks[i], config->hpd_freq[i]); if (ret) - dev_warn(dev->dev, "failed to set clk %s (%d)\n", + dev_warn(dev, "failed to set clk %s (%d)\n", config->hpd_clk_names[i], ret); } ret = clk_prepare_enable(hdmi->hpd_clks[i]); if (ret) { - dev_err(dev->dev, "failed to enable hpd clk: %s (%d)\n", + dev_err(dev, "failed to enable hpd clk: %s (%d)\n", config->hpd_clk_names[i], ret); goto fail; } @@ -204,7 +211,7 @@ static void hdp_disable(struct hdmi_connector *hdmi_connector) { struct hdmi *hdmi = hdmi_connector->hdmi; const struct hdmi_platform_config *config = hdmi->config; - struct drm_device *dev = hdmi_connector->base.dev; + struct device *dev = &hdmi->pdev->dev; int i, ret = 0; /* Disable HPD interrupt */ @@ -217,12 +224,16 @@ static void hdp_disable(struct hdmi_connector *hdmi_connector) ret = gpio_config(hdmi, false); if (ret) - dev_warn(dev->dev, "failed to unconfigure GPIOs: %d\n", ret); + dev_warn(dev, "failed to unconfigure GPIOs: %d\n", ret); + + ret = pinctrl_pm_select_sleep_state(dev); + if (ret) + dev_warn(dev, "pinctrl state chg failed: %d\n", ret); for (i = 0; i < config->hpd_reg_cnt; i++) { ret = regulator_disable(hdmi->hpd_regs[i]); if (ret) - dev_warn(dev->dev, "failed to disable hpd regulator: %s (%d)\n", + dev_warn(dev, "failed to disable hpd regulator: %s (%d)\n", config->hpd_reg_names[i], ret); } } @@ -433,7 +444,7 @@ struct drm_connector *hdmi_connector_init(struct hdmi *hdmi) ret = hpd_enable(hdmi_connector); if (ret) { - dev_err(hdmi->dev->dev, "failed to enable HPD: %d\n", ret); + dev_err(&hdmi->pdev->dev, "failed to enable HPD: %d\n", ret); goto fail; } diff --git a/drivers/gpu/drm/msm/hdmi/qfprom.xml.h b/drivers/gpu/drm/msm/hdmi/qfprom.xml.h index 43bb54a9afbf..978c3f70872a 100644 --- a/drivers/gpu/drm/msm/hdmi/qfprom.xml.h +++ b/drivers/gpu/drm/msm/hdmi/qfprom.xml.h @@ -10,15 +10,15 @@ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: - /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2014-12-05 15:34:49) - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20908 bytes, from 2014-12-08 16:13:00) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2357 bytes, from 2014-12-08 16:13:00) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 27208 bytes, from 2015-01-13 23:56:11) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2015-03-24 22:05:22) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2352 bytes, from 2015-04-12 15:02:42) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 35083 bytes, from 2015-04-12 15:04:03) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 22094 bytes, from 2015-05-12 12:45:23) - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32) - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2014-10-31 16:48:57) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12) -- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 26848 bytes, from 2015-01-13 23:55:57) -- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 8253 bytes, from 2014-12-08 16:13:00) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 29012 bytes, from 2015-05-12 12:45:23) +- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2015-05-12 12:45:23) Copyright (C) 2013 by the following authors: - Rob Clark <robdclark@gmail.com> (robclark) diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h b/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h index 1d39174d91fb..153fc487d683 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h @@ -10,17 +10,17 @@ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: - /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2014-12-05 15:34:49) - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20908 bytes, from 2014-12-08 16:13:00) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2357 bytes, from 2014-12-08 16:13:00) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 27208 bytes, from 2015-01-13 23:56:11) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2015-03-24 22:05:22) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2352 bytes, from 2015-04-12 15:02:42) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 35083 bytes, from 2015-04-12 15:04:03) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 22094 bytes, from 2015-05-12 12:45:23) - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32) - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2014-10-31 16:48:57) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12) -- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 26848 bytes, from 2015-01-13 23:55:57) -- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 8253 bytes, from 2014-12-08 16:13:00) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 29012 bytes, from 2015-05-12 12:45:23) +- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2015-05-12 12:45:23) -Copyright (C) 2013-2014 by the following authors: +Copyright (C) 2013-2015 by the following authors: - Rob Clark <robdclark@gmail.com> (robclark) Permission is hereby granted, free of charge, to any person obtaining @@ -680,18 +680,18 @@ static inline uint32_t MDP4_PIPE_SRC_STRIDE_B_P3(uint32_t val) return ((val) << MDP4_PIPE_SRC_STRIDE_B_P3__SHIFT) & MDP4_PIPE_SRC_STRIDE_B_P3__MASK; } -static inline uint32_t REG_MDP4_PIPE_FRAME_SIZE(enum mdp4_pipe i0) { return 0x00020048 + 0x10000*i0; } -#define MDP4_PIPE_FRAME_SIZE_HEIGHT__MASK 0xffff0000 -#define MDP4_PIPE_FRAME_SIZE_HEIGHT__SHIFT 16 -static inline uint32_t MDP4_PIPE_FRAME_SIZE_HEIGHT(uint32_t val) +static inline uint32_t REG_MDP4_PIPE_SSTILE_FRAME_SIZE(enum mdp4_pipe i0) { return 0x00020048 + 0x10000*i0; } +#define MDP4_PIPE_SSTILE_FRAME_SIZE_HEIGHT__MASK 0xffff0000 +#define MDP4_PIPE_SSTILE_FRAME_SIZE_HEIGHT__SHIFT 16 +static inline uint32_t MDP4_PIPE_SSTILE_FRAME_SIZE_HEIGHT(uint32_t val) { - return ((val) << MDP4_PIPE_FRAME_SIZE_HEIGHT__SHIFT) & MDP4_PIPE_FRAME_SIZE_HEIGHT__MASK; + return ((val) << MDP4_PIPE_SSTILE_FRAME_SIZE_HEIGHT__SHIFT) & MDP4_PIPE_SSTILE_FRAME_SIZE_HEIGHT__MASK; } -#define MDP4_PIPE_FRAME_SIZE_WIDTH__MASK 0x0000ffff -#define MDP4_PIPE_FRAME_SIZE_WIDTH__SHIFT 0 -static inline uint32_t MDP4_PIPE_FRAME_SIZE_WIDTH(uint32_t val) +#define MDP4_PIPE_SSTILE_FRAME_SIZE_WIDTH__MASK 0x0000ffff +#define MDP4_PIPE_SSTILE_FRAME_SIZE_WIDTH__SHIFT 0 +static inline uint32_t MDP4_PIPE_SSTILE_FRAME_SIZE_WIDTH(uint32_t val) { - return ((val) << MDP4_PIPE_FRAME_SIZE_WIDTH__SHIFT) & MDP4_PIPE_FRAME_SIZE_WIDTH__MASK; + return ((val) << MDP4_PIPE_SSTILE_FRAME_SIZE_WIDTH__SHIFT) & MDP4_PIPE_SSTILE_FRAME_SIZE_WIDTH__MASK; } static inline uint32_t REG_MDP4_PIPE_SRC_FORMAT(enum mdp4_pipe i0) { return 0x00020050 + 0x10000*i0; } diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c index 73afa21822b4..c4bb9d9c7667 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c @@ -51,6 +51,11 @@ struct mdp4_crtc { /* if there is a pending flip, these will be non-null: */ struct drm_pending_vblank_event *event; + /* Bits have been flushed at the last commit, + * used to decide if a vsync has happened since last commit. + */ + u32 flushed_mask; + #define PENDING_CURSOR 0x1 #define PENDING_FLIP 0x2 atomic_t pending; @@ -93,6 +98,8 @@ static void crtc_flush(struct drm_crtc *crtc) DBG("%s: flush=%08x", mdp4_crtc->name, flush); + mdp4_crtc->flushed_mask = flush; + mdp4_write(mdp4_kms, REG_MDP4_OVERLAY_FLUSH, flush); } @@ -537,6 +544,29 @@ static void mdp4_crtc_err_irq(struct mdp_irq *irq, uint32_t irqstatus) crtc_flush(crtc); } +static void mdp4_crtc_wait_for_flush_done(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); + struct mdp4_kms *mdp4_kms = get_kms(crtc); + int ret; + + ret = drm_crtc_vblank_get(crtc); + if (ret) + return; + + ret = wait_event_timeout(dev->vblank[drm_crtc_index(crtc)].queue, + !(mdp4_read(mdp4_kms, REG_MDP4_OVERLAY_FLUSH) & + mdp4_crtc->flushed_mask), + msecs_to_jiffies(50)); + if (ret <= 0) + dev_warn(dev->dev, "vblank time out, crtc=%d\n", mdp4_crtc->id); + + mdp4_crtc->flushed_mask = 0; + + drm_crtc_vblank_put(crtc); +} + uint32_t mdp4_crtc_vblank(struct drm_crtc *crtc) { struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); @@ -600,6 +630,15 @@ void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf, int mixer) mdp4_write(mdp4_kms, REG_MDP4_DISP_INTF_SEL, intf_sel); } +void mdp4_crtc_wait_for_commit_done(struct drm_crtc *crtc) +{ + /* wait_for_flush_done is the only case for now. + * Later we will have command mode CRTC to wait for + * other event. + */ + mdp4_crtc_wait_for_flush_done(crtc); +} + static const char *dma_names[] = { "DMA_P", "DMA_S", "DMA_E", }; diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c index 7896323b2631..89614c6a6c1b 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c @@ -38,7 +38,7 @@ static struct mdp4_kms *get_kms(struct drm_encoder *encoder) return to_mdp4_kms(to_mdp_kms(priv->kms)); } -#ifdef CONFIG_MSM_BUS_SCALING +#ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING #include <mach/board.h> /* not ironically named at all.. no, really.. */ static void bs_init(struct mdp4_dtv_encoder *mdp4_dtv_encoder) diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c index d847b9436194..531e4acc2a87 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c @@ -119,6 +119,8 @@ static int mdp4_hw_init(struct msm_kms *kms) if (mdp4_kms->rev > 1) mdp4_write(mdp4_kms, REG_MDP4_RESET_STATUS, 1); + dev->mode_config.allow_fb_modifiers = true; + out: pm_runtime_put_sync(dev->dev); @@ -157,6 +159,12 @@ static void mdp4_complete_commit(struct msm_kms *kms, struct drm_atomic_state *s mdp4_disable(mdp4_kms); } +static void mdp4_wait_for_crtc_commit_done(struct msm_kms *kms, + struct drm_crtc *crtc) +{ + mdp4_crtc_wait_for_commit_done(crtc); +} + static long mdp4_round_pixclk(struct msm_kms *kms, unsigned long rate, struct drm_encoder *encoder) { @@ -195,6 +203,7 @@ static const struct mdp_kms_funcs kms_funcs = { .disable_vblank = mdp4_disable_vblank, .prepare_commit = mdp4_prepare_commit, .complete_commit = mdp4_complete_commit, + .wait_for_crtc_commit_done = mdp4_wait_for_crtc_commit_done, .get_format = mdp_get_format, .round_pixclk = mdp4_round_pixclk, .preclose = mdp4_preclose, diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h index 0a5c58bde7a9..c1ecb9d6bdef 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h @@ -206,6 +206,7 @@ uint32_t mdp4_crtc_vblank(struct drm_crtc *crtc); void mdp4_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file); void mdp4_crtc_set_config(struct drm_crtc *crtc, uint32_t config); void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf, int mixer); +void mdp4_crtc_wait_for_commit_done(struct drm_crtc *crtc); struct drm_crtc *mdp4_crtc_init(struct drm_device *dev, struct drm_plane *plane, int id, int ovlp_id, enum mdp4_dma dma_id); @@ -229,7 +230,7 @@ static inline struct clk *mpd4_lvds_pll_init(struct drm_device *dev) } #endif -#ifdef CONFIG_MSM_BUS_SCALING +#ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING static inline int match_dev_name(struct device *dev, void *data) { return !strcmp(dev_name(dev), data); diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c index 60ec8222c9f6..c04843376c54 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c @@ -38,7 +38,7 @@ static struct mdp4_kms *get_kms(struct drm_encoder *encoder) return to_mdp4_kms(to_mdp_kms(priv->kms)); } -#ifdef CONFIG_MSM_BUS_SCALING +#ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING #include <mach/board.h> static void bs_init(struct mdp4_lcdc_encoder *mdp4_lcdc_encoder) { diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c index dbc068988377..0d1dbb737933 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c @@ -33,6 +33,21 @@ struct mdp4_plane { }; #define to_mdp4_plane(x) container_of(x, struct mdp4_plane, base) +/* MDP format helper functions */ +static inline +enum mdp4_frame_format mdp4_get_frame_format(struct drm_framebuffer *fb) +{ + bool is_tile = false; + + if (fb->modifier[1] == DRM_FORMAT_MOD_SAMSUNG_64_32_TILE) + is_tile = true; + + if (fb->pixel_format == DRM_FORMAT_NV12 && is_tile) + return FRAME_TILE_YCBCR_420; + + return FRAME_LINEAR; +} + static void mdp4_plane_set_scanout(struct drm_plane *plane, struct drm_framebuffer *fb); static int mdp4_plane_mode_set(struct drm_plane *plane, @@ -205,6 +220,7 @@ static int mdp4_plane_mode_set(struct drm_plane *plane, uint32_t op_mode = 0; uint32_t phasex_step = MDP4_VG_PHASE_STEP_DEFAULT; uint32_t phasey_step = MDP4_VG_PHASE_STEP_DEFAULT; + enum mdp4_frame_format frame_type = mdp4_get_frame_format(fb); if (!(crtc && fb)) { DBG("%s: disabled!", mdp4_plane->name); @@ -304,6 +320,7 @@ static int mdp4_plane_mode_set(struct drm_plane *plane, MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) | MDP4_PIPE_SRC_FORMAT_FETCH_PLANES(format->fetch_type) | MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP(format->chroma_sample) | + MDP4_PIPE_SRC_FORMAT_FRAME_FORMAT(frame_type) | COND(format->unpack_tight, MDP4_PIPE_SRC_FORMAT_UNPACK_TIGHT)); mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_UNPACK(pipe), @@ -324,6 +341,11 @@ static int mdp4_plane_mode_set(struct drm_plane *plane, mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEX_STEP(pipe), phasex_step); mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEY_STEP(pipe), phasey_step); + if (frame_type != FRAME_LINEAR) + mdp4_write(mdp4_kms, REG_MDP4_PIPE_SSTILE_FRAME_SIZE(pipe), + MDP4_PIPE_SSTILE_FRAME_SIZE_WIDTH(src_w) | + MDP4_PIPE_SSTILE_FRAME_SIZE_HEIGHT(src_h)); + return 0; } diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h index b9a4ded6e400..50e17527e2e5 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h @@ -8,9 +8,17 @@ http://github.com/freedreno/envytools/ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: -- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp5.xml ( 29312 bytes, from 2015-03-23 21:18:48) -- /local/mnt2/workspace2/sviau/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2014-06-02 18:31:15) -- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp_common.xml ( 2357 bytes, from 2015-03-23 20:38:49) +- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2014-12-05 15:34:49) +- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2015-03-24 22:05:22) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2352 bytes, from 2015-04-12 15:02:42) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 35083 bytes, from 2015-04-12 15:04:03) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 22094 bytes, from 2015-05-12 12:45:23) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2014-10-31 16:48:57) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 29012 bytes, from 2015-05-12 12:45:23) +- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2015-05-12 12:45:23) Copyright (C) 2013-2015 by the following authors: - Rob Clark <robdclark@gmail.com> (robclark) @@ -120,6 +128,21 @@ enum mdp5_data_format { DATA_FORMAT_YUV = 1, }; +enum mdp5_block_size { + BLOCK_SIZE_64 = 0, + BLOCK_SIZE_128 = 1, +}; + +enum mdp5_rotate_mode { + ROTATE_0 = 0, + ROTATE_90 = 1, +}; + +enum mdp5_chroma_downsample_method { + DS_MTHD_NO_PIXEL_DROP = 0, + DS_MTHD_PIXEL_DROP = 1, +}; + #define MDP5_IRQ_WB_0_DONE 0x00000001 #define MDP5_IRQ_WB_1_DONE 0x00000002 #define MDP5_IRQ_WB_2_DONE 0x00000010 @@ -314,19 +337,19 @@ static inline uint32_t MDP5_MDP_IGC_LUT_REG_VAL(uint32_t val) #define MDP5_MDP_IGC_LUT_REG_DISABLE_PIPE_1 0x20000000 #define MDP5_MDP_IGC_LUT_REG_DISABLE_PIPE_2 0x40000000 -#define REG_MDP5_SPLIT_DPL_EN 0x000003f4 +static inline uint32_t REG_MDP5_MDP_SPLIT_DPL_EN(uint32_t i0) { return 0x000002f4 + __offset_MDP(i0); } -#define REG_MDP5_SPLIT_DPL_UPPER 0x000003f8 -#define MDP5_SPLIT_DPL_UPPER_SMART_PANEL 0x00000002 -#define MDP5_SPLIT_DPL_UPPER_SMART_PANEL_FREE_RUN 0x00000004 -#define MDP5_SPLIT_DPL_UPPER_INTF1_SW_TRG_MUX 0x00000010 -#define MDP5_SPLIT_DPL_UPPER_INTF2_SW_TRG_MUX 0x00000100 +static inline uint32_t REG_MDP5_MDP_SPLIT_DPL_UPPER(uint32_t i0) { return 0x000002f8 + __offset_MDP(i0); } +#define MDP5_MDP_SPLIT_DPL_UPPER_SMART_PANEL 0x00000002 +#define MDP5_MDP_SPLIT_DPL_UPPER_SMART_PANEL_FREE_RUN 0x00000004 +#define MDP5_MDP_SPLIT_DPL_UPPER_INTF1_SW_TRG_MUX 0x00000010 +#define MDP5_MDP_SPLIT_DPL_UPPER_INTF2_SW_TRG_MUX 0x00000100 -#define REG_MDP5_SPLIT_DPL_LOWER 0x000004f0 -#define MDP5_SPLIT_DPL_LOWER_SMART_PANEL 0x00000002 -#define MDP5_SPLIT_DPL_LOWER_SMART_PANEL_FREE_RUN 0x00000004 -#define MDP5_SPLIT_DPL_LOWER_INTF1_TG_SYNC 0x00000010 -#define MDP5_SPLIT_DPL_LOWER_INTF2_TG_SYNC 0x00000100 +static inline uint32_t REG_MDP5_MDP_SPLIT_DPL_LOWER(uint32_t i0) { return 0x000003f0 + __offset_MDP(i0); } +#define MDP5_MDP_SPLIT_DPL_LOWER_SMART_PANEL 0x00000002 +#define MDP5_MDP_SPLIT_DPL_LOWER_SMART_PANEL_FREE_RUN 0x00000004 +#define MDP5_MDP_SPLIT_DPL_LOWER_INTF1_TG_SYNC 0x00000010 +#define MDP5_MDP_SPLIT_DPL_LOWER_INTF2_TG_SYNC 0x00000100 static inline uint32_t __offset_CTL(uint32_t idx) { @@ -782,7 +805,7 @@ static inline uint32_t MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(uint32_t val) #define MDP5_PIPE_SRC_FORMAT_UNPACK_ALIGN_MSB 0x00040000 #define MDP5_PIPE_SRC_FORMAT_NUM_PLANES__MASK 0x00180000 #define MDP5_PIPE_SRC_FORMAT_NUM_PLANES__SHIFT 19 -static inline uint32_t MDP5_PIPE_SRC_FORMAT_NUM_PLANES(enum mdp_sspp_fetch_type val) +static inline uint32_t MDP5_PIPE_SRC_FORMAT_NUM_PLANES(enum mdp_fetch_type val) { return ((val) << MDP5_PIPE_SRC_FORMAT_NUM_PLANES__SHIFT) & MDP5_PIPE_SRC_FORMAT_NUM_PLANES__MASK; } @@ -1234,6 +1257,351 @@ static inline uint32_t REG_MDP5_PP_FBC_BUDGET_CTL(uint32_t i0) { return 0x000000 static inline uint32_t REG_MDP5_PP_FBC_LOSSY_MODE(uint32_t i0) { return 0x0000003c + __offset_PP(i0); } +static inline uint32_t __offset_WB(uint32_t idx) +{ + switch (idx) { + default: return INVALID_IDX(idx); + } +} +static inline uint32_t REG_MDP5_WB(uint32_t i0) { return 0x00000000 + __offset_WB(i0); } + +static inline uint32_t REG_MDP5_WB_DST_FORMAT(uint32_t i0) { return 0x00000000 + __offset_WB(i0); } +#define MDP5_WB_DST_FORMAT_DSTC0_OUT__MASK 0x00000003 +#define MDP5_WB_DST_FORMAT_DSTC0_OUT__SHIFT 0 +static inline uint32_t MDP5_WB_DST_FORMAT_DSTC0_OUT(uint32_t val) +{ + return ((val) << MDP5_WB_DST_FORMAT_DSTC0_OUT__SHIFT) & MDP5_WB_DST_FORMAT_DSTC0_OUT__MASK; +} +#define MDP5_WB_DST_FORMAT_DSTC1_OUT__MASK 0x0000000c +#define MDP5_WB_DST_FORMAT_DSTC1_OUT__SHIFT 2 +static inline uint32_t MDP5_WB_DST_FORMAT_DSTC1_OUT(uint32_t val) +{ + return ((val) << MDP5_WB_DST_FORMAT_DSTC1_OUT__SHIFT) & MDP5_WB_DST_FORMAT_DSTC1_OUT__MASK; +} +#define MDP5_WB_DST_FORMAT_DSTC2_OUT__MASK 0x00000030 +#define MDP5_WB_DST_FORMAT_DSTC2_OUT__SHIFT 4 +static inline uint32_t MDP5_WB_DST_FORMAT_DSTC2_OUT(uint32_t val) +{ + return ((val) << MDP5_WB_DST_FORMAT_DSTC2_OUT__SHIFT) & MDP5_WB_DST_FORMAT_DSTC2_OUT__MASK; +} +#define MDP5_WB_DST_FORMAT_DSTC3_OUT__MASK 0x000000c0 +#define MDP5_WB_DST_FORMAT_DSTC3_OUT__SHIFT 6 +static inline uint32_t MDP5_WB_DST_FORMAT_DSTC3_OUT(uint32_t val) +{ + return ((val) << MDP5_WB_DST_FORMAT_DSTC3_OUT__SHIFT) & MDP5_WB_DST_FORMAT_DSTC3_OUT__MASK; +} +#define MDP5_WB_DST_FORMAT_DSTC3_EN 0x00000100 +#define MDP5_WB_DST_FORMAT_DST_BPP__MASK 0x00000600 +#define MDP5_WB_DST_FORMAT_DST_BPP__SHIFT 9 +static inline uint32_t MDP5_WB_DST_FORMAT_DST_BPP(uint32_t val) +{ + return ((val) << MDP5_WB_DST_FORMAT_DST_BPP__SHIFT) & MDP5_WB_DST_FORMAT_DST_BPP__MASK; +} +#define MDP5_WB_DST_FORMAT_PACK_COUNT__MASK 0x00003000 +#define MDP5_WB_DST_FORMAT_PACK_COUNT__SHIFT 12 +static inline uint32_t MDP5_WB_DST_FORMAT_PACK_COUNT(uint32_t val) +{ + return ((val) << MDP5_WB_DST_FORMAT_PACK_COUNT__SHIFT) & MDP5_WB_DST_FORMAT_PACK_COUNT__MASK; +} +#define MDP5_WB_DST_FORMAT_DST_ALPHA_X 0x00004000 +#define MDP5_WB_DST_FORMAT_PACK_TIGHT 0x00020000 +#define MDP5_WB_DST_FORMAT_PACK_ALIGN_MSB 0x00040000 +#define MDP5_WB_DST_FORMAT_WRITE_PLANES__MASK 0x00180000 +#define MDP5_WB_DST_FORMAT_WRITE_PLANES__SHIFT 19 +static inline uint32_t MDP5_WB_DST_FORMAT_WRITE_PLANES(uint32_t val) +{ + return ((val) << MDP5_WB_DST_FORMAT_WRITE_PLANES__SHIFT) & MDP5_WB_DST_FORMAT_WRITE_PLANES__MASK; +} +#define MDP5_WB_DST_FORMAT_DST_DITHER_EN 0x00400000 +#define MDP5_WB_DST_FORMAT_DST_CHROMA_SAMP__MASK 0x03800000 +#define MDP5_WB_DST_FORMAT_DST_CHROMA_SAMP__SHIFT 23 +static inline uint32_t MDP5_WB_DST_FORMAT_DST_CHROMA_SAMP(uint32_t val) +{ + return ((val) << MDP5_WB_DST_FORMAT_DST_CHROMA_SAMP__SHIFT) & MDP5_WB_DST_FORMAT_DST_CHROMA_SAMP__MASK; +} +#define MDP5_WB_DST_FORMAT_DST_CHROMA_SITE__MASK 0x3c000000 +#define MDP5_WB_DST_FORMAT_DST_CHROMA_SITE__SHIFT 26 +static inline uint32_t MDP5_WB_DST_FORMAT_DST_CHROMA_SITE(uint32_t val) +{ + return ((val) << MDP5_WB_DST_FORMAT_DST_CHROMA_SITE__SHIFT) & MDP5_WB_DST_FORMAT_DST_CHROMA_SITE__MASK; +} +#define MDP5_WB_DST_FORMAT_FRAME_FORMAT__MASK 0xc0000000 +#define MDP5_WB_DST_FORMAT_FRAME_FORMAT__SHIFT 30 +static inline uint32_t MDP5_WB_DST_FORMAT_FRAME_FORMAT(uint32_t val) +{ + return ((val) << MDP5_WB_DST_FORMAT_FRAME_FORMAT__SHIFT) & MDP5_WB_DST_FORMAT_FRAME_FORMAT__MASK; +} + +static inline uint32_t REG_MDP5_WB_DST_OP_MODE(uint32_t i0) { return 0x00000004 + __offset_WB(i0); } +#define MDP5_WB_DST_OP_MODE_BWC_ENC_EN 0x00000001 +#define MDP5_WB_DST_OP_MODE_BWC_ENC_OP__MASK 0x00000006 +#define MDP5_WB_DST_OP_MODE_BWC_ENC_OP__SHIFT 1 +static inline uint32_t MDP5_WB_DST_OP_MODE_BWC_ENC_OP(uint32_t val) +{ + return ((val) << MDP5_WB_DST_OP_MODE_BWC_ENC_OP__SHIFT) & MDP5_WB_DST_OP_MODE_BWC_ENC_OP__MASK; +} +#define MDP5_WB_DST_OP_MODE_BLOCK_SIZE__MASK 0x00000010 +#define MDP5_WB_DST_OP_MODE_BLOCK_SIZE__SHIFT 4 +static inline uint32_t MDP5_WB_DST_OP_MODE_BLOCK_SIZE(uint32_t val) +{ + return ((val) << MDP5_WB_DST_OP_MODE_BLOCK_SIZE__SHIFT) & MDP5_WB_DST_OP_MODE_BLOCK_SIZE__MASK; +} +#define MDP5_WB_DST_OP_MODE_ROT_MODE__MASK 0x00000020 +#define MDP5_WB_DST_OP_MODE_ROT_MODE__SHIFT 5 +static inline uint32_t MDP5_WB_DST_OP_MODE_ROT_MODE(uint32_t val) +{ + return ((val) << MDP5_WB_DST_OP_MODE_ROT_MODE__SHIFT) & MDP5_WB_DST_OP_MODE_ROT_MODE__MASK; +} +#define MDP5_WB_DST_OP_MODE_ROT_EN 0x00000040 +#define MDP5_WB_DST_OP_MODE_CSC_EN 0x00000100 +#define MDP5_WB_DST_OP_MODE_CSC_SRC_DATA_FORMAT__MASK 0x00000200 +#define MDP5_WB_DST_OP_MODE_CSC_SRC_DATA_FORMAT__SHIFT 9 +static inline uint32_t MDP5_WB_DST_OP_MODE_CSC_SRC_DATA_FORMAT(uint32_t val) +{ + return ((val) << MDP5_WB_DST_OP_MODE_CSC_SRC_DATA_FORMAT__SHIFT) & MDP5_WB_DST_OP_MODE_CSC_SRC_DATA_FORMAT__MASK; +} +#define MDP5_WB_DST_OP_MODE_CSC_DST_DATA_FORMAT__MASK 0x00000400 +#define MDP5_WB_DST_OP_MODE_CSC_DST_DATA_FORMAT__SHIFT 10 +static inline uint32_t MDP5_WB_DST_OP_MODE_CSC_DST_DATA_FORMAT(uint32_t val) +{ + return ((val) << MDP5_WB_DST_OP_MODE_CSC_DST_DATA_FORMAT__SHIFT) & MDP5_WB_DST_OP_MODE_CSC_DST_DATA_FORMAT__MASK; +} +#define MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_EN 0x00000800 +#define MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_FORMAT__MASK 0x00001000 +#define MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_FORMAT__SHIFT 12 +static inline uint32_t MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_FORMAT(uint32_t val) +{ + return ((val) << MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_FORMAT__SHIFT) & MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_FORMAT__MASK; +} +#define MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_H_MTHD__MASK 0x00002000 +#define MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_H_MTHD__SHIFT 13 +static inline uint32_t MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_H_MTHD(uint32_t val) +{ + return ((val) << MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_H_MTHD__SHIFT) & MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_H_MTHD__MASK; +} +#define MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_V_MTHD__MASK 0x00004000 +#define MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_V_MTHD__SHIFT 14 +static inline uint32_t MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_V_MTHD(uint32_t val) +{ + return ((val) << MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_V_MTHD__SHIFT) & MDP5_WB_DST_OP_MODE_CHROMA_DWN_SAMPLE_V_MTHD__MASK; +} + +static inline uint32_t REG_MDP5_WB_DST_PACK_PATTERN(uint32_t i0) { return 0x00000008 + __offset_WB(i0); } +#define MDP5_WB_DST_PACK_PATTERN_ELEMENT0__MASK 0x00000003 +#define MDP5_WB_DST_PACK_PATTERN_ELEMENT0__SHIFT 0 +static inline uint32_t MDP5_WB_DST_PACK_PATTERN_ELEMENT0(uint32_t val) +{ + return ((val) << MDP5_WB_DST_PACK_PATTERN_ELEMENT0__SHIFT) & MDP5_WB_DST_PACK_PATTERN_ELEMENT0__MASK; +} +#define MDP5_WB_DST_PACK_PATTERN_ELEMENT1__MASK 0x00000300 +#define MDP5_WB_DST_PACK_PATTERN_ELEMENT1__SHIFT 8 +static inline uint32_t MDP5_WB_DST_PACK_PATTERN_ELEMENT1(uint32_t val) +{ + return ((val) << MDP5_WB_DST_PACK_PATTERN_ELEMENT1__SHIFT) & MDP5_WB_DST_PACK_PATTERN_ELEMENT1__MASK; +} +#define MDP5_WB_DST_PACK_PATTERN_ELEMENT2__MASK 0x00030000 +#define MDP5_WB_DST_PACK_PATTERN_ELEMENT2__SHIFT 16 +static inline uint32_t MDP5_WB_DST_PACK_PATTERN_ELEMENT2(uint32_t val) +{ + return ((val) << MDP5_WB_DST_PACK_PATTERN_ELEMENT2__SHIFT) & MDP5_WB_DST_PACK_PATTERN_ELEMENT2__MASK; +} +#define MDP5_WB_DST_PACK_PATTERN_ELEMENT3__MASK 0x03000000 +#define MDP5_WB_DST_PACK_PATTERN_ELEMENT3__SHIFT 24 +static inline uint32_t MDP5_WB_DST_PACK_PATTERN_ELEMENT3(uint32_t val) +{ + return ((val) << MDP5_WB_DST_PACK_PATTERN_ELEMENT3__SHIFT) & MDP5_WB_DST_PACK_PATTERN_ELEMENT3__MASK; +} + +static inline uint32_t REG_MDP5_WB_DST0_ADDR(uint32_t i0) { return 0x0000000c + __offset_WB(i0); } + +static inline uint32_t REG_MDP5_WB_DST1_ADDR(uint32_t i0) { return 0x00000010 + __offset_WB(i0); } + +static inline uint32_t REG_MDP5_WB_DST2_ADDR(uint32_t i0) { return 0x00000014 + __offset_WB(i0); } + +static inline uint32_t REG_MDP5_WB_DST3_ADDR(uint32_t i0) { return 0x00000018 + __offset_WB(i0); } + +static inline uint32_t REG_MDP5_WB_DST_YSTRIDE0(uint32_t i0) { return 0x0000001c + __offset_WB(i0); } +#define MDP5_WB_DST_YSTRIDE0_DST0_YSTRIDE__MASK 0x0000ffff +#define MDP5_WB_DST_YSTRIDE0_DST0_YSTRIDE__SHIFT 0 +static inline uint32_t MDP5_WB_DST_YSTRIDE0_DST0_YSTRIDE(uint32_t val) +{ + return ((val) << MDP5_WB_DST_YSTRIDE0_DST0_YSTRIDE__SHIFT) & MDP5_WB_DST_YSTRIDE0_DST0_YSTRIDE__MASK; +} +#define MDP5_WB_DST_YSTRIDE0_DST1_YSTRIDE__MASK 0xffff0000 +#define MDP5_WB_DST_YSTRIDE0_DST1_YSTRIDE__SHIFT 16 +static inline uint32_t MDP5_WB_DST_YSTRIDE0_DST1_YSTRIDE(uint32_t val) +{ + return ((val) << MDP5_WB_DST_YSTRIDE0_DST1_YSTRIDE__SHIFT) & MDP5_WB_DST_YSTRIDE0_DST1_YSTRIDE__MASK; +} + +static inline uint32_t REG_MDP5_WB_DST_YSTRIDE1(uint32_t i0) { return 0x00000020 + __offset_WB(i0); } +#define MDP5_WB_DST_YSTRIDE1_DST2_YSTRIDE__MASK 0x0000ffff +#define MDP5_WB_DST_YSTRIDE1_DST2_YSTRIDE__SHIFT 0 +static inline uint32_t MDP5_WB_DST_YSTRIDE1_DST2_YSTRIDE(uint32_t val) +{ + return ((val) << MDP5_WB_DST_YSTRIDE1_DST2_YSTRIDE__SHIFT) & MDP5_WB_DST_YSTRIDE1_DST2_YSTRIDE__MASK; +} +#define MDP5_WB_DST_YSTRIDE1_DST3_YSTRIDE__MASK 0xffff0000 +#define MDP5_WB_DST_YSTRIDE1_DST3_YSTRIDE__SHIFT 16 +static inline uint32_t MDP5_WB_DST_YSTRIDE1_DST3_YSTRIDE(uint32_t val) +{ + return ((val) << MDP5_WB_DST_YSTRIDE1_DST3_YSTRIDE__SHIFT) & MDP5_WB_DST_YSTRIDE1_DST3_YSTRIDE__MASK; +} + +static inline uint32_t REG_MDP5_WB_DST_DITHER_BITDEPTH(uint32_t i0) { return 0x00000024 + __offset_WB(i0); } + +static inline uint32_t REG_MDP5_WB_DITHER_MATRIX_ROW0(uint32_t i0) { return 0x00000030 + __offset_WB(i0); } + +static inline uint32_t REG_MDP5_WB_DITHER_MATRIX_ROW1(uint32_t i0) { return 0x00000034 + __offset_WB(i0); } + +static inline uint32_t REG_MDP5_WB_DITHER_MATRIX_ROW2(uint32_t i0) { return 0x00000038 + __offset_WB(i0); } + +static inline uint32_t REG_MDP5_WB_DITHER_MATRIX_ROW3(uint32_t i0) { return 0x0000003c + __offset_WB(i0); } + +static inline uint32_t REG_MDP5_WB_DST_WRITE_CONFIG(uint32_t i0) { return 0x00000048 + __offset_WB(i0); } + +static inline uint32_t REG_MDP5_WB_ROTATION_DNSCALER(uint32_t i0) { return 0x00000050 + __offset_WB(i0); } + +static inline uint32_t REG_MDP5_WB_N16_INIT_PHASE_X_0_3(uint32_t i0) { return 0x00000060 + __offset_WB(i0); } + +static inline uint32_t REG_MDP5_WB_N16_INIT_PHASE_X_1_2(uint32_t i0) { return 0x00000064 + __offset_WB(i0); } + +static inline uint32_t REG_MDP5_WB_N16_INIT_PHASE_Y_0_3(uint32_t i0) { return 0x00000068 + __offset_WB(i0); } + +static inline uint32_t REG_MDP5_WB_N16_INIT_PHASE_Y_1_2(uint32_t i0) { return 0x0000006c + __offset_WB(i0); } + +static inline uint32_t REG_MDP5_WB_OUT_SIZE(uint32_t i0) { return 0x00000074 + __offset_WB(i0); } +#define MDP5_WB_OUT_SIZE_DST_W__MASK 0x0000ffff +#define MDP5_WB_OUT_SIZE_DST_W__SHIFT 0 +static inline uint32_t MDP5_WB_OUT_SIZE_DST_W(uint32_t val) +{ + return ((val) << MDP5_WB_OUT_SIZE_DST_W__SHIFT) & MDP5_WB_OUT_SIZE_DST_W__MASK; +} +#define MDP5_WB_OUT_SIZE_DST_H__MASK 0xffff0000 +#define MDP5_WB_OUT_SIZE_DST_H__SHIFT 16 +static inline uint32_t MDP5_WB_OUT_SIZE_DST_H(uint32_t val) +{ + return ((val) << MDP5_WB_OUT_SIZE_DST_H__SHIFT) & MDP5_WB_OUT_SIZE_DST_H__MASK; +} + +static inline uint32_t REG_MDP5_WB_ALPHA_X_VALUE(uint32_t i0) { return 0x00000078 + __offset_WB(i0); } + +static inline uint32_t REG_MDP5_WB_CSC_MATRIX_COEFF_0(uint32_t i0) { return 0x00000260 + __offset_WB(i0); } +#define MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_11__MASK 0x00001fff +#define MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_11__SHIFT 0 +static inline uint32_t MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_11(uint32_t val) +{ + return ((val) << MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_11__SHIFT) & MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_11__MASK; +} +#define MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_12__MASK 0x1fff0000 +#define MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_12__SHIFT 16 +static inline uint32_t MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_12(uint32_t val) +{ + return ((val) << MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_12__SHIFT) & MDP5_WB_CSC_MATRIX_COEFF_0_COEFF_12__MASK; +} + +static inline uint32_t REG_MDP5_WB_CSC_MATRIX_COEFF_1(uint32_t i0) { return 0x00000264 + __offset_WB(i0); } +#define MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_13__MASK 0x00001fff +#define MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_13__SHIFT 0 +static inline uint32_t MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_13(uint32_t val) +{ + return ((val) << MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_13__SHIFT) & MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_13__MASK; +} +#define MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_21__MASK 0x1fff0000 +#define MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_21__SHIFT 16 +static inline uint32_t MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_21(uint32_t val) +{ + return ((val) << MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_21__SHIFT) & MDP5_WB_CSC_MATRIX_COEFF_1_COEFF_21__MASK; +} + +static inline uint32_t REG_MDP5_WB_CSC_MATRIX_COEFF_2(uint32_t i0) { return 0x00000268 + __offset_WB(i0); } +#define MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_22__MASK 0x00001fff +#define MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_22__SHIFT 0 +static inline uint32_t MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_22(uint32_t val) +{ + return ((val) << MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_22__SHIFT) & MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_22__MASK; +} +#define MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_23__MASK 0x1fff0000 +#define MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_23__SHIFT 16 +static inline uint32_t MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_23(uint32_t val) +{ + return ((val) << MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_23__SHIFT) & MDP5_WB_CSC_MATRIX_COEFF_2_COEFF_23__MASK; +} + +static inline uint32_t REG_MDP5_WB_CSC_MATRIX_COEFF_3(uint32_t i0) { return 0x0000026c + __offset_WB(i0); } +#define MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_31__MASK 0x00001fff +#define MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_31__SHIFT 0 +static inline uint32_t MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_31(uint32_t val) +{ + return ((val) << MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_31__SHIFT) & MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_31__MASK; +} +#define MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_32__MASK 0x1fff0000 +#define MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_32__SHIFT 16 +static inline uint32_t MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_32(uint32_t val) +{ + return ((val) << MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_32__SHIFT) & MDP5_WB_CSC_MATRIX_COEFF_3_COEFF_32__MASK; +} + +static inline uint32_t REG_MDP5_WB_CSC_MATRIX_COEFF_4(uint32_t i0) { return 0x00000270 + __offset_WB(i0); } +#define MDP5_WB_CSC_MATRIX_COEFF_4_COEFF_33__MASK 0x00001fff +#define MDP5_WB_CSC_MATRIX_COEFF_4_COEFF_33__SHIFT 0 +static inline uint32_t MDP5_WB_CSC_MATRIX_COEFF_4_COEFF_33(uint32_t val) +{ + return ((val) << MDP5_WB_CSC_MATRIX_COEFF_4_COEFF_33__SHIFT) & MDP5_WB_CSC_MATRIX_COEFF_4_COEFF_33__MASK; +} + +static inline uint32_t REG_MDP5_WB_CSC_COMP_PRECLAMP(uint32_t i0, uint32_t i1) { return 0x00000274 + __offset_WB(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP5_WB_CSC_COMP_PRECLAMP_REG(uint32_t i0, uint32_t i1) { return 0x00000274 + __offset_WB(i0) + 0x4*i1; } +#define MDP5_WB_CSC_COMP_PRECLAMP_REG_HIGH__MASK 0x000000ff +#define MDP5_WB_CSC_COMP_PRECLAMP_REG_HIGH__SHIFT 0 +static inline uint32_t MDP5_WB_CSC_COMP_PRECLAMP_REG_HIGH(uint32_t val) +{ + return ((val) << MDP5_WB_CSC_COMP_PRECLAMP_REG_HIGH__SHIFT) & MDP5_WB_CSC_COMP_PRECLAMP_REG_HIGH__MASK; +} +#define MDP5_WB_CSC_COMP_PRECLAMP_REG_LOW__MASK 0x0000ff00 +#define MDP5_WB_CSC_COMP_PRECLAMP_REG_LOW__SHIFT 8 +static inline uint32_t MDP5_WB_CSC_COMP_PRECLAMP_REG_LOW(uint32_t val) +{ + return ((val) << MDP5_WB_CSC_COMP_PRECLAMP_REG_LOW__SHIFT) & MDP5_WB_CSC_COMP_PRECLAMP_REG_LOW__MASK; +} + +static inline uint32_t REG_MDP5_WB_CSC_COMP_POSTCLAMP(uint32_t i0, uint32_t i1) { return 0x00000280 + __offset_WB(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP5_WB_CSC_COMP_POSTCLAMP_REG(uint32_t i0, uint32_t i1) { return 0x00000280 + __offset_WB(i0) + 0x4*i1; } +#define MDP5_WB_CSC_COMP_POSTCLAMP_REG_HIGH__MASK 0x000000ff +#define MDP5_WB_CSC_COMP_POSTCLAMP_REG_HIGH__SHIFT 0 +static inline uint32_t MDP5_WB_CSC_COMP_POSTCLAMP_REG_HIGH(uint32_t val) +{ + return ((val) << MDP5_WB_CSC_COMP_POSTCLAMP_REG_HIGH__SHIFT) & MDP5_WB_CSC_COMP_POSTCLAMP_REG_HIGH__MASK; +} +#define MDP5_WB_CSC_COMP_POSTCLAMP_REG_LOW__MASK 0x0000ff00 +#define MDP5_WB_CSC_COMP_POSTCLAMP_REG_LOW__SHIFT 8 +static inline uint32_t MDP5_WB_CSC_COMP_POSTCLAMP_REG_LOW(uint32_t val) +{ + return ((val) << MDP5_WB_CSC_COMP_POSTCLAMP_REG_LOW__SHIFT) & MDP5_WB_CSC_COMP_POSTCLAMP_REG_LOW__MASK; +} + +static inline uint32_t REG_MDP5_WB_CSC_COMP_PREBIAS(uint32_t i0, uint32_t i1) { return 0x0000028c + __offset_WB(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP5_WB_CSC_COMP_PREBIAS_REG(uint32_t i0, uint32_t i1) { return 0x0000028c + __offset_WB(i0) + 0x4*i1; } +#define MDP5_WB_CSC_COMP_PREBIAS_REG_VALUE__MASK 0x000001ff +#define MDP5_WB_CSC_COMP_PREBIAS_REG_VALUE__SHIFT 0 +static inline uint32_t MDP5_WB_CSC_COMP_PREBIAS_REG_VALUE(uint32_t val) +{ + return ((val) << MDP5_WB_CSC_COMP_PREBIAS_REG_VALUE__SHIFT) & MDP5_WB_CSC_COMP_PREBIAS_REG_VALUE__MASK; +} + +static inline uint32_t REG_MDP5_WB_CSC_COMP_POSTBIAS(uint32_t i0, uint32_t i1) { return 0x00000298 + __offset_WB(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP5_WB_CSC_COMP_POSTBIAS_REG(uint32_t i0, uint32_t i1) { return 0x00000298 + __offset_WB(i0) + 0x4*i1; } +#define MDP5_WB_CSC_COMP_POSTBIAS_REG_VALUE__MASK 0x000001ff +#define MDP5_WB_CSC_COMP_POSTBIAS_REG_VALUE__SHIFT 0 +static inline uint32_t MDP5_WB_CSC_COMP_POSTBIAS_REG_VALUE(uint32_t val) +{ + return ((val) << MDP5_WB_CSC_COMP_POSTBIAS_REG_VALUE__SHIFT) & MDP5_WB_CSC_COMP_POSTBIAS_REG_VALUE__MASK; +} + static inline uint32_t __offset_INTF(uint32_t idx) { switch (idx) { diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c index e4e89567f51d..ee31b16fe7ea 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c @@ -30,7 +30,7 @@ static struct mdp5_kms *get_kms(struct drm_encoder *encoder) return to_mdp5_kms(to_mdp_kms(priv->kms)); } -#ifdef CONFIG_MSM_BUS_SCALING +#ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING #include <mach/board.h> #include <linux/msm-bus.h> #include <linux/msm-bus-board.h> @@ -216,16 +216,12 @@ static void mdp5_cmd_encoder_mode_set(struct drm_encoder *encoder, static void mdp5_cmd_encoder_disable(struct drm_encoder *encoder) { struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder); - struct mdp5_kms *mdp5_kms = get_kms(encoder); struct mdp5_ctl *ctl = mdp5_crtc_get_ctl(encoder->crtc); struct mdp5_interface *intf = &mdp5_cmd_enc->intf; - int lm = mdp5_crtc_get_lm(encoder->crtc); if (WARN_ON(!mdp5_cmd_enc->enabled)) return; - /* Wait for the last frame done */ - mdp_irq_wait(&mdp5_kms->base, lm2ppdone(lm)); pingpong_tearcheck_disable(encoder); mdp5_ctl_set_encoder_state(ctl, false); @@ -281,22 +277,22 @@ int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder, * start signal for the slave encoder */ if (intf_num == 1) - data |= MDP5_SPLIT_DPL_UPPER_INTF2_SW_TRG_MUX; + data |= MDP5_MDP_SPLIT_DPL_UPPER_INTF2_SW_TRG_MUX; else if (intf_num == 2) - data |= MDP5_SPLIT_DPL_UPPER_INTF1_SW_TRG_MUX; + data |= MDP5_MDP_SPLIT_DPL_UPPER_INTF1_SW_TRG_MUX; else return -EINVAL; /* Smart Panel, Sync mode */ - data |= MDP5_SPLIT_DPL_UPPER_SMART_PANEL; + data |= MDP5_MDP_SPLIT_DPL_UPPER_SMART_PANEL; /* Make sure clocks are on when connectors calling this function. */ mdp5_enable(mdp5_kms); - mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_UPPER, data); + mdp5_write(mdp5_kms, REG_MDP5_MDP_SPLIT_DPL_UPPER(0), data); - mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_LOWER, - MDP5_SPLIT_DPL_LOWER_SMART_PANEL); - mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_EN, 1); + mdp5_write(mdp5_kms, REG_MDP5_MDP_SPLIT_DPL_LOWER(0), + MDP5_MDP_SPLIT_DPL_LOWER_SMART_PANEL); + mdp5_write(mdp5_kms, REG_MDP5_MDP_SPLIT_DPL_EN(0), 1); mdp5_disable(mdp5_kms); return 0; diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c index c1530772187d..dea3d2e559b1 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> * @@ -46,6 +46,11 @@ struct mdp5_crtc { /* if there is a pending flip, these will be non-null: */ struct drm_pending_vblank_event *event; + /* Bits have been flushed at the last commit, + * used to decide if a vsync has happened since last commit. + */ + u32 flushed_mask; + #define PENDING_CURSOR 0x1 #define PENDING_FLIP 0x2 atomic_t pending; @@ -55,6 +60,11 @@ struct mdp5_crtc { struct mdp_irq vblank; struct mdp_irq err; + struct mdp_irq pp_done; + + struct completion pp_completion; + + bool cmd_mode; struct { /* protect REG_MDP5_LM_CURSOR* registers and cursor scanout_bo*/ @@ -82,12 +92,18 @@ static void request_pending(struct drm_crtc *crtc, uint32_t pending) mdp_irq_register(&get_kms(crtc)->base, &mdp5_crtc->vblank); } -static void crtc_flush(struct drm_crtc *crtc, u32 flush_mask) +static void request_pp_done_pending(struct drm_crtc *crtc) +{ + struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); + reinit_completion(&mdp5_crtc->pp_completion); +} + +static u32 crtc_flush(struct drm_crtc *crtc, u32 flush_mask) { struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); DBG("%s: flush=%08x", mdp5_crtc->name, flush_mask); - mdp5_ctl_commit(mdp5_crtc->ctl, flush_mask); + return mdp5_ctl_commit(mdp5_crtc->ctl, flush_mask); } /* @@ -95,7 +111,7 @@ static void crtc_flush(struct drm_crtc *crtc, u32 flush_mask) * so that we can safely queue unref to current fb (ie. next * vblank we know hw is done w/ previous scanout_fb). */ -static void crtc_flush_all(struct drm_crtc *crtc) +static u32 crtc_flush_all(struct drm_crtc *crtc) { struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); struct drm_plane *plane; @@ -103,7 +119,7 @@ static void crtc_flush_all(struct drm_crtc *crtc) /* this should not happen: */ if (WARN_ON(!mdp5_crtc->ctl)) - return; + return 0; drm_atomic_crtc_for_each_plane(plane, crtc) { flush_mask |= mdp5_plane_get_flush(plane); @@ -111,7 +127,7 @@ static void crtc_flush_all(struct drm_crtc *crtc) flush_mask |= mdp_ctl_flush_mask_lm(mdp5_crtc->lm); - crtc_flush(crtc, flush_mask); + return crtc_flush(crtc, flush_mask); } /* if file!=NULL, this is preclose potential cancel-flip path */ @@ -143,6 +159,8 @@ static void complete_flip(struct drm_crtc *crtc, struct drm_file *file) } if (mdp5_crtc->ctl && !crtc->state->enable) { + /* set STAGE_UNUSED for all layers */ + mdp5_ctl_blend(mdp5_crtc->ctl, mdp5_crtc->lm, 0x00000000); mdp5_ctl_release(mdp5_crtc->ctl); mdp5_crtc->ctl = NULL; } @@ -274,8 +292,8 @@ static void mdp5_crtc_disable(struct drm_crtc *crtc) if (WARN_ON(!mdp5_crtc->enabled)) return; - /* set STAGE_UNUSED for all layers */ - mdp5_ctl_blend(mdp5_crtc->ctl, mdp5_crtc->lm, 0x00000000); + if (mdp5_crtc->cmd_mode) + mdp_irq_unregister(&mdp5_kms->base, &mdp5_crtc->pp_done); mdp_irq_unregister(&mdp5_kms->base, &mdp5_crtc->err); mdp5_disable(mdp5_kms); @@ -296,6 +314,9 @@ static void mdp5_crtc_enable(struct drm_crtc *crtc) mdp5_enable(mdp5_kms); mdp_irq_register(&mdp5_kms->base, &mdp5_crtc->err); + if (mdp5_crtc->cmd_mode) + mdp_irq_register(&mdp5_kms->base, &mdp5_crtc->pp_done); + mdp5_crtc->enabled = true; } @@ -396,7 +417,18 @@ static void mdp5_crtc_atomic_flush(struct drm_crtc *crtc) return; blend_setup(crtc); - crtc_flush_all(crtc); + + /* PP_DONE irq is only used by command mode for now. + * It is better to request pending before FLUSH and START trigger + * to make sure no pp_done irq missed. + * This is safe because no pp_done will happen before SW trigger + * in command mode. + */ + if (mdp5_crtc->cmd_mode) + request_pp_done_pending(crtc); + + mdp5_crtc->flushed_mask = crtc_flush_all(crtc); + request_pending(crtc, PENDING_FLIP); } @@ -601,6 +633,52 @@ static void mdp5_crtc_err_irq(struct mdp_irq *irq, uint32_t irqstatus) DBG("%s: error: %08x", mdp5_crtc->name, irqstatus); } +static void mdp5_crtc_pp_done_irq(struct mdp_irq *irq, uint32_t irqstatus) +{ + struct mdp5_crtc *mdp5_crtc = container_of(irq, struct mdp5_crtc, + pp_done); + + complete(&mdp5_crtc->pp_completion); +} + +static void mdp5_crtc_wait_for_pp_done(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); + int ret; + + ret = wait_for_completion_timeout(&mdp5_crtc->pp_completion, + msecs_to_jiffies(50)); + if (ret == 0) + dev_warn(dev->dev, "pp done time out, lm=%d\n", mdp5_crtc->lm); +} + +static void mdp5_crtc_wait_for_flush_done(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); + int ret; + + /* Should not call this function if crtc is disabled. */ + if (!mdp5_crtc->ctl) + return; + + ret = drm_crtc_vblank_get(crtc); + if (ret) + return; + + ret = wait_event_timeout(dev->vblank[drm_crtc_index(crtc)].queue, + ((mdp5_ctl_get_commit_status(mdp5_crtc->ctl) & + mdp5_crtc->flushed_mask) == 0), + msecs_to_jiffies(50)); + if (ret <= 0) + dev_warn(dev->dev, "vblank time out, crtc=%d\n", mdp5_crtc->id); + + mdp5_crtc->flushed_mask = 0; + + drm_crtc_vblank_put(crtc); +} + uint32_t mdp5_crtc_vblank(struct drm_crtc *crtc) { struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); @@ -622,16 +700,19 @@ void mdp5_crtc_set_intf(struct drm_crtc *crtc, struct mdp5_interface *intf) /* now that we know what irq's we want: */ mdp5_crtc->err.irqmask = intf2err(intf->num); + mdp5_crtc->vblank.irqmask = intf2vblank(lm, intf); + + if ((intf->type == INTF_DSI) && + (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)) { + mdp5_crtc->pp_done.irqmask = lm2ppdone(lm); + mdp5_crtc->pp_done.irq = mdp5_crtc_pp_done_irq; + mdp5_crtc->cmd_mode = true; + } else { + mdp5_crtc->pp_done.irqmask = 0; + mdp5_crtc->pp_done.irq = NULL; + mdp5_crtc->cmd_mode = false; + } - /* Register command mode Pingpong done as vblank for now, - * so that atomic commit should wait for it to finish. - * Ideally, in the future, we should take rd_ptr done as vblank, - * and let atomic commit wait for pingpong done for commond mode. - */ - if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND) - mdp5_crtc->vblank.irqmask = lm2ppdone(lm); - else - mdp5_crtc->vblank.irqmask = intf2vblank(lm, intf); mdp_irq_update(&mdp5_kms->base); mdp5_ctl_set_intf(mdp5_crtc->ctl, intf); @@ -649,6 +730,16 @@ struct mdp5_ctl *mdp5_crtc_get_ctl(struct drm_crtc *crtc) return WARN_ON(!crtc) ? NULL : mdp5_crtc->ctl; } +void mdp5_crtc_wait_for_commit_done(struct drm_crtc *crtc) +{ + struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); + + if (mdp5_crtc->cmd_mode) + mdp5_crtc_wait_for_pp_done(crtc); + else + mdp5_crtc_wait_for_flush_done(crtc); +} + /* initialize crtc */ struct drm_crtc *mdp5_crtc_init(struct drm_device *dev, struct drm_plane *plane, int id) @@ -667,6 +758,7 @@ struct drm_crtc *mdp5_crtc_init(struct drm_device *dev, spin_lock_init(&mdp5_crtc->lm_lock); spin_lock_init(&mdp5_crtc->cursor.lock); + init_completion(&mdp5_crtc->pp_completion); mdp5_crtc->vblank.irq = mdp5_crtc_vblank_irq; mdp5_crtc->err.irq = mdp5_crtc_err_irq; diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c index 5488b687c8d1..f2530f224a76 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c @@ -392,8 +392,10 @@ static u32 fix_sw_flush(struct mdp5_ctl *ctl, u32 flush_mask) * CTL registers need to be flushed in some circumstances; if that is the * case, some trigger bits will be present in both flush mask and * ctl->pending_ctl_trigger. + * + * Return H/W flushed bit mask. */ -int mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask) +u32 mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask) { struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm; struct op_mode *pipeline = &ctl->pipeline; @@ -424,7 +426,12 @@ int mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask) refill_start_mask(ctl); } - return 0; + return flush_mask; +} + +u32 mdp5_ctl_get_commit_status(struct mdp5_ctl *ctl) +{ + return ctl_read(ctl, REG_MDP5_CTL_FLUSH(ctl->id)); } void mdp5_ctl_release(struct mdp5_ctl *ctl) diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h index 7a62000994a1..4678228c4f14 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h @@ -88,7 +88,8 @@ u32 mdp_ctl_flush_mask_cursor(int cursor_id); u32 mdp_ctl_flush_mask_encoder(struct mdp5_interface *intf); /* @flush_mask: see CTL flush masks definitions below */ -int mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask); +u32 mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask); +u32 mdp5_ctl_get_commit_status(struct mdp5_ctl *ctl); void mdp5_ctl_release(struct mdp5_ctl *ctl); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c index 1188f4bf1e60..de97c08f3f1f 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c @@ -36,7 +36,7 @@ static struct mdp5_kms *get_kms(struct drm_encoder *encoder) return to_mdp5_kms(to_mdp_kms(priv->kms)); } -#ifdef CONFIG_MSM_BUS_SCALING +#ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING #include <mach/board.h> #include <mach/msm_bus.h> #include <mach/msm_bus_board.h> @@ -144,10 +144,14 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder, mode->type, mode->flags); ctrl_pol = 0; - if (mode->flags & DRM_MODE_FLAG_NHSYNC) - ctrl_pol |= MDP5_INTF_POLARITY_CTL_HSYNC_LOW; - if (mode->flags & DRM_MODE_FLAG_NVSYNC) - ctrl_pol |= MDP5_INTF_POLARITY_CTL_VSYNC_LOW; + + /* DSI controller cannot handle active-low sync signals. */ + if (mdp5_encoder->intf.type != INTF_DSI) { + if (mode->flags & DRM_MODE_FLAG_NHSYNC) + ctrl_pol |= MDP5_INTF_POLARITY_CTL_HSYNC_LOW; + if (mode->flags & DRM_MODE_FLAG_NVSYNC) + ctrl_pol |= MDP5_INTF_POLARITY_CTL_VSYNC_LOW; + } /* probably need to get DATA_EN polarity from panel.. */ dtv_hsync_skew = 0; /* get this from panel? */ @@ -304,9 +308,9 @@ int mdp5_encoder_set_split_display(struct drm_encoder *encoder, * to use the master's enable signal for the slave encoder. */ if (intf_num == 1) - data |= MDP5_SPLIT_DPL_LOWER_INTF2_TG_SYNC; + data |= MDP5_MDP_SPLIT_DPL_LOWER_INTF2_TG_SYNC; else if (intf_num == 2) - data |= MDP5_SPLIT_DPL_LOWER_INTF1_TG_SYNC; + data |= MDP5_MDP_SPLIT_DPL_LOWER_INTF1_TG_SYNC; else return -EINVAL; @@ -315,9 +319,9 @@ int mdp5_encoder_set_split_display(struct drm_encoder *encoder, mdp5_write(mdp5_kms, REG_MDP5_MDP_SPARE_0(0), MDP5_MDP_SPARE_0_SPLIT_DPL_SINGLE_FLUSH_EN); /* Dumb Panel, Sync mode */ - mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_UPPER, 0); - mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_LOWER, data); - mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_EN, 1); + mdp5_write(mdp5_kms, REG_MDP5_MDP_SPLIT_DPL_UPPER(0), 0); + mdp5_write(mdp5_kms, REG_MDP5_MDP_SPLIT_DPL_LOWER(0), data); + mdp5_write(mdp5_kms, REG_MDP5_MDP_SPLIT_DPL_EN(0), 1); mdp5_disable(mdp5_kms); return 0; diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index bbacf9d2b738..206f758f7d64 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -80,6 +80,12 @@ static void mdp5_complete_commit(struct msm_kms *kms, struct drm_atomic_state *s mdp5_disable(mdp5_kms); } +static void mdp5_wait_for_crtc_commit_done(struct msm_kms *kms, + struct drm_crtc *crtc) +{ + mdp5_crtc_wait_for_commit_done(crtc); +} + static long mdp5_round_pixclk(struct msm_kms *kms, unsigned long rate, struct drm_encoder *encoder) { @@ -141,6 +147,7 @@ static const struct mdp_kms_funcs kms_funcs = { .disable_vblank = mdp5_disable_vblank, .prepare_commit = mdp5_prepare_commit, .complete_commit = mdp5_complete_commit, + .wait_for_crtc_commit_done = mdp5_wait_for_crtc_commit_done, .get_format = mdp_get_format, .round_pixclk = mdp5_round_pixclk, .set_split_display = mdp5_set_split_display, diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h index 2c0de174cc09..e0eb24587c84 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h @@ -237,6 +237,7 @@ int mdp5_crtc_get_lm(struct drm_crtc *crtc); struct mdp5_ctl *mdp5_crtc_get_ctl(struct drm_crtc *crtc); void mdp5_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file); void mdp5_crtc_set_intf(struct drm_crtc *crtc, struct mdp5_interface *intf); +void mdp5_crtc_wait_for_commit_done(struct drm_crtc *crtc); struct drm_crtc *mdp5_crtc_init(struct drm_device *dev, struct drm_plane *plane, int id); diff --git a/drivers/gpu/drm/msm/mdp/mdp_common.xml.h b/drivers/gpu/drm/msm/mdp/mdp_common.xml.h index a1d35f162c7f..641d036c5bcb 100644 --- a/drivers/gpu/drm/msm/mdp/mdp_common.xml.h +++ b/drivers/gpu/drm/msm/mdp/mdp_common.xml.h @@ -10,17 +10,17 @@ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: - /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2014-12-05 15:34:49) - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20908 bytes, from 2014-12-08 16:13:00) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2357 bytes, from 2014-12-08 16:13:00) -- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 27208 bytes, from 2015-01-13 23:56:11) -- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20915 bytes, from 2015-03-24 22:05:22) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2352 bytes, from 2015-04-12 15:02:42) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 35083 bytes, from 2015-04-12 15:04:03) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 22094 bytes, from 2015-05-12 12:45:23) - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32) - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2014-10-31 16:48:57) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12) -- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 26848 bytes, from 2015-01-13 23:55:57) -- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 8253 bytes, from 2014-12-08 16:13:00) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 29012 bytes, from 2015-05-12 12:45:23) +- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 10416 bytes, from 2015-05-12 12:45:23) -Copyright (C) 2013-2014 by the following authors: +Copyright (C) 2013-2015 by the following authors: - Rob Clark <robdclark@gmail.com> (robclark) Permission is hereby granted, free of charge, to any person obtaining @@ -52,7 +52,7 @@ enum mdp_chroma_samp_type { CHROMA_420 = 3, }; -enum mdp_sspp_fetch_type { +enum mdp_fetch_type { MDP_PLANE_INTERLEAVED = 0, MDP_PLANE_PLANAR = 1, MDP_PLANE_PSEUDO_PLANAR = 2, diff --git a/drivers/gpu/drm/msm/mdp/mdp_format.c b/drivers/gpu/drm/msm/mdp/mdp_format.c index f683433b6727..7b0524dc1872 100644 --- a/drivers/gpu/drm/msm/mdp/mdp_format.c +++ b/drivers/gpu/drm/msm/mdp/mdp_format.c @@ -96,6 +96,12 @@ static const struct mdp_format formats[] = { /* name a r g b e0 e1 e2 e3 alpha tight cpp cnt ... */ FMT(ARGB8888, 8, 8, 8, 8, 1, 0, 2, 3, true, true, 4, 4, MDP_PLANE_INTERLEAVED, CHROMA_RGB), + FMT(ABGR8888, 8, 8, 8, 8, 2, 0, 1, 3, true, true, 4, 4, + MDP_PLANE_INTERLEAVED, CHROMA_RGB), + FMT(RGBA8888, 8, 8, 8, 8, 3, 1, 0, 2, true, true, 4, 4, + MDP_PLANE_INTERLEAVED, CHROMA_RGB), + FMT(BGRA8888, 8, 8, 8, 8, 3, 2, 0, 1, true, true, 4, 4, + MDP_PLANE_INTERLEAVED, CHROMA_RGB), FMT(XRGB8888, 8, 8, 8, 8, 1, 0, 2, 3, false, true, 4, 4, MDP_PLANE_INTERLEAVED, CHROMA_RGB), FMT(RGB888, 0, 8, 8, 8, 1, 0, 2, 0, false, true, 3, 3, diff --git a/drivers/gpu/drm/msm/mdp/mdp_kms.h b/drivers/gpu/drm/msm/mdp/mdp_kms.h index 5ae4039d68e4..2d3428cb74d0 100644 --- a/drivers/gpu/drm/msm/mdp/mdp_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp_kms.h @@ -88,7 +88,7 @@ struct mdp_format { uint8_t unpack[4]; bool alpha_enable, unpack_tight; uint8_t cpp, unpack_count; - enum mdp_sspp_fetch_type fetch_type; + enum mdp_fetch_type fetch_type; enum mdp_chroma_samp_type chroma_sample; }; #define to_mdp_format(x) container_of(x, struct mdp_format, base) diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index 5b192128cda2..1b22d8bfe142 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -84,6 +84,33 @@ static void commit_destroy(struct msm_commit *c) kfree(c); } +static void msm_atomic_wait_for_commit_done(struct drm_device *dev, + struct drm_atomic_state *old_state) +{ + struct drm_crtc *crtc; + struct msm_drm_private *priv = old_state->dev->dev_private; + struct msm_kms *kms = priv->kms; + int ncrtcs = old_state->dev->mode_config.num_crtc; + int i; + + for (i = 0; i < ncrtcs; i++) { + crtc = old_state->crtcs[i]; + + if (!crtc) + continue; + + if (!crtc->state->enable) + continue; + + /* Legacy cursor ioctls are completely unsynced, and userspace + * relies on that (by doing tons of cursor updates). */ + if (old_state->legacy_cursor_update) + continue; + + kms->funcs->wait_for_crtc_commit_done(kms, crtc); + } +} + /* The (potentially) asynchronous part of the commit. At this point * nothing can fail short of armageddon. */ @@ -115,7 +142,7 @@ static void complete_commit(struct msm_commit *c) * not be critical path) */ - drm_atomic_helper_wait_for_vblanks(dev, state); + msm_atomic_wait_for_commit_done(dev, state); drm_atomic_helper_cleanup_planes(dev, state); @@ -139,7 +166,6 @@ static void add_fb(struct msm_commit *c, struct drm_framebuffer *fb) c->fence = max(c->fence, msm_gem_fence(to_msm_bo(obj), MSM_PREP_READ)); } - int msm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) { @@ -178,7 +204,7 @@ int msm_atomic_commit(struct drm_device *dev, { int nplanes = dev->mode_config.num_total_plane; int ncrtcs = dev->mode_config.num_crtc; - struct timespec timeout; + ktime_t timeout; struct msm_commit *c; int i, ret; @@ -187,8 +213,10 @@ int msm_atomic_commit(struct drm_device *dev, return ret; c = commit_init(state); - if (!c) - return -ENOMEM; + if (!c) { + ret = -ENOMEM; + goto error; + } /* * Figure out what crtcs we have: @@ -221,7 +249,7 @@ int msm_atomic_commit(struct drm_device *dev, ret = start_atomic(dev->dev_private, c->crtc_mask); if (ret) { kfree(c); - return ret; + goto error; } /* @@ -253,7 +281,7 @@ int msm_atomic_commit(struct drm_device *dev, return 0; } - jiffies_to_timespec(jiffies + msecs_to_jiffies(1000), &timeout); + timeout = ktime_add_ms(ktime_get(), 1000); ret = msm_wait_fence_interruptable(dev, c->fence, &timeout); if (ret) { @@ -265,4 +293,8 @@ int msm_atomic_commit(struct drm_device *dev, complete_commit(c); return 0; + +error: + drm_atomic_helper_cleanup_planes(dev, state); + return ret; } diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index c80a6bee2b18..b7ef56ed8d1c 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -638,7 +638,7 @@ static void msm_debugfs_cleanup(struct drm_minor *minor) */ int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence, - struct timespec *timeout) + ktime_t *timeout) { struct msm_drm_private *priv = dev->dev_private; int ret; @@ -656,14 +656,16 @@ int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence, /* no-wait: */ ret = fence_completed(dev, fence) ? 0 : -EBUSY; } else { - unsigned long timeout_jiffies = timespec_to_jiffies(timeout); - unsigned long start_jiffies = jiffies; + ktime_t now = ktime_get(); unsigned long remaining_jiffies; - if (time_after(start_jiffies, timeout_jiffies)) + if (ktime_compare(*timeout, now) < 0) { remaining_jiffies = 0; - else - remaining_jiffies = timeout_jiffies - start_jiffies; + } else { + ktime_t rem = ktime_sub(*timeout, now); + struct timespec ts = ktime_to_timespec(rem); + remaining_jiffies = timespec_to_jiffies(&ts); + } ret = wait_event_interruptible_timeout(priv->fence_event, fence_completed(dev, fence), @@ -772,13 +774,17 @@ static int msm_ioctl_gem_new(struct drm_device *dev, void *data, args->flags, &args->handle); } -#define TS(t) ((struct timespec){ .tv_sec = (t).tv_sec, .tv_nsec = (t).tv_nsec }) +static inline ktime_t to_ktime(struct drm_msm_timespec timeout) +{ + return ktime_set(timeout.tv_sec, timeout.tv_nsec); +} static int msm_ioctl_gem_cpu_prep(struct drm_device *dev, void *data, struct drm_file *file) { struct drm_msm_gem_cpu_prep *args = data; struct drm_gem_object *obj; + ktime_t timeout = to_ktime(args->timeout); int ret; if (args->op & ~MSM_PREP_FLAGS) { @@ -790,7 +796,7 @@ static int msm_ioctl_gem_cpu_prep(struct drm_device *dev, void *data, if (!obj) return -ENOENT; - ret = msm_gem_cpu_prep(obj, args->op, &TS(args->timeout)); + ret = msm_gem_cpu_prep(obj, args->op, &timeout); drm_gem_object_unreference_unlocked(obj); @@ -840,14 +846,14 @@ static int msm_ioctl_wait_fence(struct drm_device *dev, void *data, struct drm_file *file) { struct drm_msm_wait_fence *args = data; + ktime_t timeout = to_ktime(args->timeout); if (args->pad) { DRM_ERROR("invalid pad: %08x\n", args->pad); return -EINVAL; } - return msm_wait_fence_interruptable(dev, args->fence, - &TS(args->timeout)); + return msm_wait_fence_interruptable(dev, args->fence, &timeout); } static const struct drm_ioctl_desc msm_ioctls[] = { @@ -885,6 +891,7 @@ static struct drm_driver msm_driver = { DRIVER_GEM | DRIVER_PRIME | DRIVER_RENDER | + DRIVER_ATOMIC | DRIVER_MODESET, .load = msm_load, .unload = msm_unload, diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 04db4bd1b5b6..e7c5ea125d45 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -165,7 +165,7 @@ int msm_atomic_commit(struct drm_device *dev, int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu); int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence, - struct timespec *timeout); + ktime_t *timeout); int msm_queue_fence_cb(struct drm_device *dev, struct msm_fence_cb *cb, uint32_t fence); void msm_update_fence(struct drm_device *dev, uint32_t fence); @@ -205,7 +205,7 @@ void msm_gem_move_to_active(struct drm_gem_object *obj, struct msm_gpu *gpu, bool write, uint32_t fence); void msm_gem_move_to_inactive(struct drm_gem_object *obj); int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, - struct timespec *timeout); + ktime_t *timeout); int msm_gem_cpu_fini(struct drm_gem_object *obj); void msm_gem_free_object(struct drm_gem_object *obj); int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file, diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 52839769eb6c..f211b80e3a1e 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -448,8 +448,7 @@ void msm_gem_move_to_inactive(struct drm_gem_object *obj) list_add_tail(&msm_obj->mm_list, &priv->inactive_list); } -int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, - struct timespec *timeout) +int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout) { struct drm_device *dev = obj->dev; struct msm_gem_object *msm_obj = to_msm_bo(obj); @@ -540,6 +539,7 @@ void msm_gem_free_object(struct drm_gem_object *obj) if (msm_obj->pages) drm_free_large(msm_obj->pages); + drm_prime_gem_destroy(obj, msm_obj->sgt); } else { vunmap(msm_obj->vaddr); put_pages(obj); diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index 85d481e29276..6fc59bfeedeb 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -96,6 +96,7 @@ static inline uint32_t msm_gem_fence(struct msm_gem_object *msm_obj, struct msm_gem_submit { struct drm_device *dev; struct msm_gpu *gpu; + struct list_head node; /* node in gpu submit_list */ struct list_head bo_list; struct ww_acquire_ctx ticket; uint32_t fence; diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index cd0554f68316..6d7cd3fe21e7 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -314,7 +314,6 @@ static void submit_cleanup(struct msm_gem_submit *submit, bool fail) } ww_acquire_fini(&submit->ticket); - kfree(submit); } int msm_ioctl_gem_submit(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 4a0dce587745..8f70d9248ac5 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -24,7 +24,7 @@ * Power Management: */ -#ifdef CONFIG_MSM_BUS_SCALING +#ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING #include <mach/board.h> static void bs_init(struct msm_gpu *gpu) { @@ -265,6 +265,8 @@ static void inactive_start(struct msm_gpu *gpu) * Hangcheck detection for locked gpu: */ +static void retire_submits(struct msm_gpu *gpu, uint32_t fence); + static void recover_worker(struct work_struct *work) { struct msm_gpu *gpu = container_of(work, struct msm_gpu, recover_work); @@ -274,8 +276,19 @@ static void recover_worker(struct work_struct *work) mutex_lock(&dev->struct_mutex); if (msm_gpu_active(gpu)) { + struct msm_gem_submit *submit; + uint32_t fence = gpu->funcs->last_fence(gpu); + + /* retire completed submits, plus the one that hung: */ + retire_submits(gpu, fence + 1); + inactive_cancel(gpu); gpu->funcs->recover(gpu); + + /* replay the remaining submits after the one that hung: */ + list_for_each_entry(submit, &gpu->submit_list, node) { + gpu->funcs->submit(gpu, submit, NULL); + } } mutex_unlock(&dev->struct_mutex); @@ -418,6 +431,27 @@ out: * Cmdstream submission/retirement: */ +static void retire_submits(struct msm_gpu *gpu, uint32_t fence) +{ + struct drm_device *dev = gpu->dev; + + WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + + while (!list_empty(&gpu->submit_list)) { + struct msm_gem_submit *submit; + + submit = list_first_entry(&gpu->submit_list, + struct msm_gem_submit, node); + + if (submit->fence <= fence) { + list_del(&submit->node); + kfree(submit); + } else { + break; + } + } +} + static void retire_worker(struct work_struct *work) { struct msm_gpu *gpu = container_of(work, struct msm_gpu, retire_work); @@ -428,6 +462,8 @@ static void retire_worker(struct work_struct *work) mutex_lock(&dev->struct_mutex); + retire_submits(gpu, fence); + while (!list_empty(&gpu->active_list)) { struct msm_gem_object *obj; @@ -467,21 +503,22 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, struct msm_drm_private *priv = dev->dev_private; int i, ret; + WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + submit->fence = ++priv->next_fence; gpu->submitted_fence = submit->fence; inactive_cancel(gpu); + list_add_tail(&submit->node, &gpu->submit_list); + msm_rd_dump_submit(submit); gpu->submitted_fence = submit->fence; update_sw_cntrs(gpu); - ret = gpu->funcs->submit(gpu, submit, ctx); - priv->lastctx = ctx; - for (i = 0; i < submit->nr_bos; i++) { struct msm_gem_object *msm_obj = submit->bos[i].obj; @@ -505,6 +542,10 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, if (submit->bos[i].flags & MSM_SUBMIT_BO_WRITE) msm_gem_move_to_active(&msm_obj->base, gpu, true, submit->fence); } + + ret = gpu->funcs->submit(gpu, submit, ctx); + priv->lastctx = ctx; + hangcheck_timer_reset(gpu); return ret; @@ -522,6 +563,7 @@ static irqreturn_t irq_handler(int irq, void *data) static const char *clk_names[] = { "src_clk", "core_clk", "iface_clk", "mem_clk", "mem_iface_clk", + "alt_mem_iface_clk", }; int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, @@ -544,6 +586,8 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, INIT_WORK(&gpu->inactive_work, inactive_worker); INIT_WORK(&gpu->recover_work, recover_worker); + INIT_LIST_HEAD(&gpu->submit_list); + setup_timer(&gpu->inactive_timer, inactive_handler, (unsigned long)gpu); setup_timer(&gpu->hangcheck_timer, hangcheck_handler, diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index fd1e4b4a6d40..2bbe85a3d6f6 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -100,10 +100,10 @@ struct msm_gpu { /* Power Control: */ struct regulator *gpu_reg, *gpu_cx; - struct clk *ebi1_clk, *grp_clks[5]; + struct clk *ebi1_clk, *grp_clks[6]; uint32_t fast_rate, slow_rate, bus_freq; -#ifdef CONFIG_MSM_BUS_SCALING +#ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING struct msm_bus_scale_pdata *bus_scale_table; uint32_t bsc; #endif @@ -119,6 +119,8 @@ struct msm_gpu { struct timer_list hangcheck_timer; uint32_t hangcheck_fence; struct work_struct recover_work; + + struct list_head submit_list; }; static inline bool msm_gpu_active(struct msm_gpu *gpu) diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h index a9f17bdb4530..9bcabaada179 100644 --- a/drivers/gpu/drm/msm/msm_kms.h +++ b/drivers/gpu/drm/msm/msm_kms.h @@ -43,6 +43,9 @@ struct msm_kms_funcs { /* modeset, bracketing atomic_commit(): */ void (*prepare_commit)(struct msm_kms *kms, struct drm_atomic_state *state); void (*complete_commit)(struct msm_kms *kms, struct drm_atomic_state *state); + /* functions to wait for atomic commit completed on each CRTC */ + void (*wait_for_crtc_commit_done)(struct msm_kms *kms, + struct drm_crtc *crtc); /* misc: */ const struct msm_format *(*get_format)(struct msm_kms *kms, uint32_t format); long (*round_pixclk)(struct msm_kms *kms, unsigned long rate, diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 89049335b738..649024d4daf1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -23,6 +23,7 @@ */ #include <linux/console.h> +#include <linux/delay.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/pm_runtime.h> @@ -666,6 +667,7 @@ nouveau_pmops_suspend(struct device *dev) pci_save_state(pdev); pci_disable_device(pdev); pci_set_power_state(pdev, PCI_D3hot); + udelay(200); return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 0e690bf19fc9..af1ee517f372 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -555,10 +555,7 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan, static inline void u_free(void *addr) { - if (!is_vmalloc_addr(addr)) - kfree(addr); - else - vfree(addr); + kvfree(addr); } static inline void * diff --git a/drivers/gpu/drm/panel/panel-ld9040.c b/drivers/gpu/drm/panel/panel-ld9040.c index 08cf2c588c3d..9c27bded4c09 100644 --- a/drivers/gpu/drm/panel/panel-ld9040.c +++ b/drivers/gpu/drm/panel/panel-ld9040.c @@ -367,18 +367,18 @@ static int ld9040_remove(struct spi_device *spi) return 0; } -static struct of_device_id ld9040_of_match[] = { +static const struct of_device_id ld9040_of_match[] = { { .compatible = "samsung,ld9040" }, { } }; MODULE_DEVICE_TABLE(of, ld9040_of_match); static struct spi_driver ld9040_driver = { - .probe = ld9040_probe, - .remove = ld9040_remove, + .probe = ld9040_probe, + .remove = ld9040_remove, .driver = { - .name = "ld9040", - .owner = THIS_MODULE, + .name = "ld9040", + .owner = THIS_MODULE, .of_match_table = ld9040_of_match, }, }; diff --git a/drivers/gpu/drm/panel/panel-s6e8aa0.c b/drivers/gpu/drm/panel/panel-s6e8aa0.c index 144b2733e3d7..30051108eec4 100644 --- a/drivers/gpu/drm/panel/panel-s6e8aa0.c +++ b/drivers/gpu/drm/panel/panel-s6e8aa0.c @@ -1041,7 +1041,7 @@ static int s6e8aa0_remove(struct mipi_dsi_device *dsi) return 0; } -static struct of_device_id s6e8aa0_of_match[] = { +static const struct of_device_id s6e8aa0_of_match[] = { { .compatible = "samsung,s6e8aa0" }, { } }; diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 30904a9b2a4c..f94201b6e882 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -731,6 +731,30 @@ static const struct panel_desc hannstar_hsd070pww1 = { }, }; +static const struct display_timing hannstar_hsd100pxn1_timing = { + .pixelclock = { 55000000, 65000000, 75000000 }, + .hactive = { 1024, 1024, 1024 }, + .hfront_porch = { 40, 40, 40 }, + .hback_porch = { 220, 220, 220 }, + .hsync_len = { 20, 60, 100 }, + .vactive = { 768, 768, 768 }, + .vfront_porch = { 7, 7, 7 }, + .vback_porch = { 21, 21, 21 }, + .vsync_len = { 10, 10, 10 }, + .flags = DISPLAY_FLAGS_DE_HIGH, +}; + +static const struct panel_desc hannstar_hsd100pxn1 = { + .timings = &hannstar_hsd100pxn1_timing, + .num_timings = 1, + .bpc = 6, + .size = { + .width = 203, + .height = 152, + }, + .bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, +}; + static const struct drm_display_mode hitachi_tx23d38vm0caa_mode = { .clock = 33333, .hdisplay = 800, @@ -872,6 +896,30 @@ static const struct panel_desc innolux_zj070na_01p = { }, }; +static const struct drm_display_mode lg_lb070wv8_mode = { + .clock = 33246, + .hdisplay = 800, + .hsync_start = 800 + 88, + .hsync_end = 800 + 88 + 80, + .htotal = 800 + 88 + 80 + 88, + .vdisplay = 480, + .vsync_start = 480 + 10, + .vsync_end = 480 + 10 + 25, + .vtotal = 480 + 10 + 25 + 10, + .vrefresh = 60, +}; + +static const struct panel_desc lg_lb070wv8 = { + .modes = &lg_lb070wv8_mode, + .num_modes = 1, + .bpc = 16, + .size = { + .width = 151, + .height = 91, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, +}; + static const struct drm_display_mode lg_lp129qe_mode = { .clock = 285250, .hdisplay = 2560, @@ -1038,6 +1086,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "hannstar,hsd070pww1", .data = &hannstar_hsd070pww1, }, { + .compatible = "hannstar,hsd100pxn1", + .data = &hannstar_hsd100pxn1, + }, { .compatible = "hit,tx23d38vm0caa", .data = &hitachi_tx23d38vm0caa }, { @@ -1056,6 +1107,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "innolux,zj070na-01p", .data = &innolux_zj070na_01p, }, { + .compatible = "lg,lb070wv8", + .data = &lg_lb070wv8, + }, { .compatible = "lg,lp129qe", .data = &lg_lp129qe, }, { diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h index 92be50c39ffd..ab89eed9ddd9 100644 --- a/drivers/gpu/drm/radeon/atombios.h +++ b/drivers/gpu/drm/radeon/atombios.h @@ -7944,8 +7944,8 @@ typedef struct { typedef struct { AMD_ACPI_DESCRIPTION_HEADER SHeader; UCHAR TableUUID[16]; //0x24 - ULONG VBIOSImageOffset; //0x34. Offset to the first GOP_VBIOS_CONTENT block from the beginning of the stucture. - ULONG Lib1ImageOffset; //0x38. Offset to the first GOP_LIB1_CONTENT block from the beginning of the stucture. + ULONG VBIOSImageOffset; //0x34. Offset to the first GOP_VBIOS_CONTENT block from the beginning of the structure. + ULONG Lib1ImageOffset; //0x38. Offset to the first GOP_LIB1_CONTENT block from the beginning of the structure. ULONG Reserved[4]; //0x3C }UEFI_ACPI_VFCT; diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index e597ffc26563..dac78ad24b31 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -580,9 +580,6 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, else radeon_crtc->pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV; - /* if there is no audio, set MINM_OVER_MAXP */ - if (!drm_detect_monitor_audio(radeon_connector_edid(connector))) - radeon_crtc->pll_flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP; if (rdev->family < CHIP_RV770) radeon_crtc->pll_flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP; /* use frac fb div on APUs */ @@ -1798,9 +1795,7 @@ static int radeon_get_shared_nondp_ppll(struct drm_crtc *crtc) if ((crtc->mode.clock == test_crtc->mode.clock) && (adjusted_clock == test_adjusted_clock) && (radeon_crtc->ss_enabled == test_radeon_crtc->ss_enabled) && - (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID) && - (drm_detect_monitor_audio(radeon_connector_edid(test_radeon_crtc->connector)) == - drm_detect_monitor_audio(radeon_connector_edid(radeon_crtc->connector)))) + (test_radeon_crtc->pll_id != ATOM_PPLL_INVALID)) return test_radeon_crtc->pll_id; } } diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index b0688b0c8908..248953d2fdb7 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -4604,6 +4604,31 @@ void cik_compute_set_wptr(struct radeon_device *rdev, WDOORBELL32(ring->doorbell_index, ring->wptr); } +static void cik_compute_stop(struct radeon_device *rdev, + struct radeon_ring *ring) +{ + u32 j, tmp; + + cik_srbm_select(rdev, ring->me, ring->pipe, ring->queue, 0); + /* Disable wptr polling. */ + tmp = RREG32(CP_PQ_WPTR_POLL_CNTL); + tmp &= ~WPTR_POLL_EN; + WREG32(CP_PQ_WPTR_POLL_CNTL, tmp); + /* Disable HQD. */ + if (RREG32(CP_HQD_ACTIVE) & 1) { + WREG32(CP_HQD_DEQUEUE_REQUEST, 1); + for (j = 0; j < rdev->usec_timeout; j++) { + if (!(RREG32(CP_HQD_ACTIVE) & 1)) + break; + udelay(1); + } + WREG32(CP_HQD_DEQUEUE_REQUEST, 0); + WREG32(CP_HQD_PQ_RPTR, 0); + WREG32(CP_HQD_PQ_WPTR, 0); + } + cik_srbm_select(rdev, 0, 0, 0, 0); +} + /** * cik_cp_compute_enable - enable/disable the compute CP MEs * @@ -4617,6 +4642,15 @@ static void cik_cp_compute_enable(struct radeon_device *rdev, bool enable) if (enable) WREG32(CP_MEC_CNTL, 0); else { + /* + * To make hibernation reliable we need to clear compute ring + * configuration before halting the compute ring. + */ + mutex_lock(&rdev->srbm_mutex); + cik_compute_stop(rdev,&rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX]); + cik_compute_stop(rdev,&rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX]); + mutex_unlock(&rdev->srbm_mutex); + WREG32(CP_MEC_CNTL, (MEC_ME1_HALT | MEC_ME2_HALT)); rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX].ready = false; rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX].ready = false; @@ -7930,23 +7964,27 @@ restart_ih: case 1: /* D1 vblank/vline */ switch (src_data) { case 0: /* D1 vblank */ - if (rdev->irq.stat_regs.cik.disp_int & LB_D1_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[0]) { - drm_handle_vblank(rdev->ddev, 0); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[0])) - radeon_crtc_handle_vblank(rdev, 0); - rdev->irq.stat_regs.cik.disp_int &= ~LB_D1_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D1 vblank\n"); + if (!(rdev->irq.stat_regs.cik.disp_int & LB_D1_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[0]) { + drm_handle_vblank(rdev->ddev, 0); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[0])) + radeon_crtc_handle_vblank(rdev, 0); + rdev->irq.stat_regs.cik.disp_int &= ~LB_D1_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D1 vblank\n"); + break; case 1: /* D1 vline */ - if (rdev->irq.stat_regs.cik.disp_int & LB_D1_VLINE_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int &= ~LB_D1_VLINE_INTERRUPT; - DRM_DEBUG("IH: D1 vline\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int & LB_D1_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int &= ~LB_D1_VLINE_INTERRUPT; + DRM_DEBUG("IH: D1 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -7956,23 +7994,27 @@ restart_ih: case 2: /* D2 vblank/vline */ switch (src_data) { case 0: /* D2 vblank */ - if (rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[1]) { - drm_handle_vblank(rdev->ddev, 1); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[1])) - radeon_crtc_handle_vblank(rdev, 1); - rdev->irq.stat_regs.cik.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D2 vblank\n"); + if (!(rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[1]) { + drm_handle_vblank(rdev->ddev, 1); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[1])) + radeon_crtc_handle_vblank(rdev, 1); + rdev->irq.stat_regs.cik.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D2 vblank\n"); + break; case 1: /* D2 vline */ - if (rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VLINE_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT; - DRM_DEBUG("IH: D2 vline\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT; + DRM_DEBUG("IH: D2 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -7982,23 +8024,27 @@ restart_ih: case 3: /* D3 vblank/vline */ switch (src_data) { case 0: /* D3 vblank */ - if (rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[2]) { - drm_handle_vblank(rdev->ddev, 2); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[2])) - radeon_crtc_handle_vblank(rdev, 2); - rdev->irq.stat_regs.cik.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D3 vblank\n"); + if (!(rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[2]) { + drm_handle_vblank(rdev->ddev, 2); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[2])) + radeon_crtc_handle_vblank(rdev, 2); + rdev->irq.stat_regs.cik.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D3 vblank\n"); + break; case 1: /* D3 vline */ - if (rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VLINE_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT; - DRM_DEBUG("IH: D3 vline\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT; + DRM_DEBUG("IH: D3 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -8008,23 +8054,27 @@ restart_ih: case 4: /* D4 vblank/vline */ switch (src_data) { case 0: /* D4 vblank */ - if (rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[3]) { - drm_handle_vblank(rdev->ddev, 3); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[3])) - radeon_crtc_handle_vblank(rdev, 3); - rdev->irq.stat_regs.cik.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D4 vblank\n"); + if (!(rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[3]) { + drm_handle_vblank(rdev->ddev, 3); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[3])) + radeon_crtc_handle_vblank(rdev, 3); + rdev->irq.stat_regs.cik.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D4 vblank\n"); + break; case 1: /* D4 vline */ - if (rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VLINE_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT; - DRM_DEBUG("IH: D4 vline\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT; + DRM_DEBUG("IH: D4 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -8034,23 +8084,27 @@ restart_ih: case 5: /* D5 vblank/vline */ switch (src_data) { case 0: /* D5 vblank */ - if (rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[4]) { - drm_handle_vblank(rdev->ddev, 4); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[4])) - radeon_crtc_handle_vblank(rdev, 4); - rdev->irq.stat_regs.cik.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D5 vblank\n"); + if (!(rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[4]) { + drm_handle_vblank(rdev->ddev, 4); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[4])) + radeon_crtc_handle_vblank(rdev, 4); + rdev->irq.stat_regs.cik.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D5 vblank\n"); + break; case 1: /* D5 vline */ - if (rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VLINE_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT; - DRM_DEBUG("IH: D5 vline\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT; + DRM_DEBUG("IH: D5 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -8060,23 +8114,27 @@ restart_ih: case 6: /* D6 vblank/vline */ switch (src_data) { case 0: /* D6 vblank */ - if (rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[5]) { - drm_handle_vblank(rdev->ddev, 5); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[5])) - radeon_crtc_handle_vblank(rdev, 5); - rdev->irq.stat_regs.cik.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D6 vblank\n"); + if (!(rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[5]) { + drm_handle_vblank(rdev->ddev, 5); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[5])) + radeon_crtc_handle_vblank(rdev, 5); + rdev->irq.stat_regs.cik.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D6 vblank\n"); + break; case 1: /* D6 vline */ - if (rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VLINE_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT; - DRM_DEBUG("IH: D6 vline\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT; + DRM_DEBUG("IH: D6 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -8096,88 +8154,112 @@ restart_ih: case 42: /* HPD hotplug */ switch (src_data) { case 0: - if (rdev->irq.stat_regs.cik.disp_int & DC_HPD1_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int &= ~DC_HPD1_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD1\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int & DC_HPD1_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int &= ~DC_HPD1_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD1\n"); + break; case 1: - if (rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont &= ~DC_HPD2_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD2\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont &= ~DC_HPD2_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD2\n"); + break; case 2: - if (rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont2 &= ~DC_HPD3_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD3\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont2 &= ~DC_HPD3_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD3\n"); + break; case 3: - if (rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont3 &= ~DC_HPD4_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD4\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont3 &= ~DC_HPD4_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD4\n"); + break; case 4: - if (rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont4 &= ~DC_HPD5_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD5\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont4 &= ~DC_HPD5_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD5\n"); + break; case 5: - if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont5 &= ~DC_HPD6_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD6\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont5 &= ~DC_HPD6_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD6\n"); + break; case 6: - if (rdev->irq.stat_regs.cik.disp_int & DC_HPD1_RX_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int &= ~DC_HPD1_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 1\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int & DC_HPD1_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int &= ~DC_HPD1_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 1\n"); + break; case 7: - if (rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_RX_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 2\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 2\n"); + break; case 8: - if (rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 3\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 3\n"); + break; case 9: - if (rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 4\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 4\n"); + break; case 10: - if (rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 5\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 5\n"); + break; case 11: - if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) { - rdev->irq.stat_regs.cik.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 6\n"); - } + if (!(rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.cik.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 6\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); diff --git a/drivers/gpu/drm/radeon/cik_sdma.c b/drivers/gpu/drm/radeon/cik_sdma.c index f86eb54e7763..d16f2eebd95e 100644 --- a/drivers/gpu/drm/radeon/cik_sdma.c +++ b/drivers/gpu/drm/radeon/cik_sdma.c @@ -268,6 +268,17 @@ static void cik_sdma_gfx_stop(struct radeon_device *rdev) } rdev->ring[R600_RING_TYPE_DMA_INDEX].ready = false; rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX].ready = false; + + /* FIXME use something else than big hammer but after few days can not + * seem to find good combination so reset SDMA blocks as it seems we + * do not shut them down properly. This fix hibernation and does not + * affect suspend to ram. + */ + WREG32(SRBM_SOFT_RESET, SOFT_RESET_SDMA | SOFT_RESET_SDMA1); + (void)RREG32(SRBM_SOFT_RESET); + udelay(50); + WREG32(SRBM_SOFT_RESET, 0); + (void)RREG32(SRBM_SOFT_RESET); } /** diff --git a/drivers/gpu/drm/radeon/dce3_1_afmt.c b/drivers/gpu/drm/radeon/dce3_1_afmt.c index f04205170b8a..cfa3a84a2af0 100644 --- a/drivers/gpu/drm/radeon/dce3_1_afmt.c +++ b/drivers/gpu/drm/radeon/dce3_1_afmt.c @@ -173,7 +173,7 @@ void dce3_2_hdmi_update_acr(struct drm_encoder *encoder, long offset, struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; - WREG32(HDMI0_ACR_PACKET_CONTROL + offset, + WREG32(DCE3_HDMI0_ACR_PACKET_CONTROL + offset, HDMI0_ACR_SOURCE | /* select SW CTS value */ HDMI0_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */ diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 3a6d483a2c36..0acde1949c18 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -4924,7 +4924,7 @@ restart_ih: return IRQ_NONE; rptr = rdev->ih.rptr; - DRM_DEBUG("r600_irq_process start: rptr %d, wptr %d\n", rptr, wptr); + DRM_DEBUG("evergreen_irq_process start: rptr %d, wptr %d\n", rptr, wptr); /* Order reading of wptr vs. reading of IH ring data */ rmb(); @@ -4942,23 +4942,27 @@ restart_ih: case 1: /* D1 vblank/vline */ switch (src_data) { case 0: /* D1 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[0]) { - drm_handle_vblank(rdev->ddev, 0); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[0])) - radeon_crtc_handle_vblank(rdev, 0); - rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D1 vblank\n"); + if (!(rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: D1 vblank - IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[0]) { + drm_handle_vblank(rdev->ddev, 0); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[0])) + radeon_crtc_handle_vblank(rdev, 0); + rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D1 vblank\n"); + break; case 1: /* D1 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VLINE_INTERRUPT; - DRM_DEBUG("IH: D1 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT)) + DRM_DEBUG("IH: D1 vline - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VLINE_INTERRUPT; + DRM_DEBUG("IH: D1 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -4968,23 +4972,27 @@ restart_ih: case 2: /* D2 vblank/vline */ switch (src_data) { case 0: /* D2 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[1]) { - drm_handle_vblank(rdev->ddev, 1); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[1])) - radeon_crtc_handle_vblank(rdev, 1); - rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D2 vblank\n"); + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: D2 vblank - IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[1]) { + drm_handle_vblank(rdev->ddev, 1); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[1])) + radeon_crtc_handle_vblank(rdev, 1); + rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D2 vblank\n"); + break; case 1: /* D2 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT; - DRM_DEBUG("IH: D2 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT)) + DRM_DEBUG("IH: D2 vline - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT; + DRM_DEBUG("IH: D2 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -4994,23 +5002,27 @@ restart_ih: case 3: /* D3 vblank/vline */ switch (src_data) { case 0: /* D3 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[2]) { - drm_handle_vblank(rdev->ddev, 2); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[2])) - radeon_crtc_handle_vblank(rdev, 2); - rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D3 vblank\n"); + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: D3 vblank - IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[2]) { + drm_handle_vblank(rdev->ddev, 2); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[2])) + radeon_crtc_handle_vblank(rdev, 2); + rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D3 vblank\n"); + break; case 1: /* D3 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT; - DRM_DEBUG("IH: D3 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT)) + DRM_DEBUG("IH: D3 vline - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT; + DRM_DEBUG("IH: D3 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -5020,23 +5032,27 @@ restart_ih: case 4: /* D4 vblank/vline */ switch (src_data) { case 0: /* D4 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[3]) { - drm_handle_vblank(rdev->ddev, 3); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[3])) - radeon_crtc_handle_vblank(rdev, 3); - rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D4 vblank\n"); + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: D4 vblank - IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[3]) { + drm_handle_vblank(rdev->ddev, 3); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[3])) + radeon_crtc_handle_vblank(rdev, 3); + rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D4 vblank\n"); + break; case 1: /* D4 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT; - DRM_DEBUG("IH: D4 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT)) + DRM_DEBUG("IH: D4 vline - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT; + DRM_DEBUG("IH: D4 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -5046,23 +5062,27 @@ restart_ih: case 5: /* D5 vblank/vline */ switch (src_data) { case 0: /* D5 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[4]) { - drm_handle_vblank(rdev->ddev, 4); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[4])) - radeon_crtc_handle_vblank(rdev, 4); - rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D5 vblank\n"); + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: D5 vblank - IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[4]) { + drm_handle_vblank(rdev->ddev, 4); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[4])) + radeon_crtc_handle_vblank(rdev, 4); + rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D5 vblank\n"); + break; case 1: /* D5 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT; - DRM_DEBUG("IH: D5 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT)) + DRM_DEBUG("IH: D5 vline - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT; + DRM_DEBUG("IH: D5 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -5072,23 +5092,27 @@ restart_ih: case 6: /* D6 vblank/vline */ switch (src_data) { case 0: /* D6 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[5]) { - drm_handle_vblank(rdev->ddev, 5); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[5])) - radeon_crtc_handle_vblank(rdev, 5); - rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D6 vblank\n"); + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: D6 vblank - IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[5]) { + drm_handle_vblank(rdev->ddev, 5); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[5])) + radeon_crtc_handle_vblank(rdev, 5); + rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D6 vblank\n"); + break; case 1: /* D6 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT; - DRM_DEBUG("IH: D6 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT)) + DRM_DEBUG("IH: D6 vline - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT; + DRM_DEBUG("IH: D6 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -5108,88 +5132,100 @@ restart_ih: case 42: /* HPD hotplug */ switch (src_data) { case 0: - if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD1\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD1\n"); break; case 1: - if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD2\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD2\n"); break; case 2: - if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD3\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD3\n"); break; case 3: - if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD4\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD4\n"); break; case 4: - if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD5\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD5\n"); break; case 5: - if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD6\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD6\n"); break; case 6: - if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 1\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 1\n"); break; case 7: - if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 2\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 2\n"); break; case 8: - if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 3\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 3\n"); break; case 9: - if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 4\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 4\n"); break; case 10: - if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 5\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 5\n"); break; case 11: - if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 6\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 6\n"); break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -5199,46 +5235,52 @@ restart_ih: case 44: /* hdmi */ switch (src_data) { case 0: - if (rdev->irq.stat_regs.evergreen.afmt_status1 & AFMT_AZ_FORMAT_WTRIG) { - rdev->irq.stat_regs.evergreen.afmt_status1 &= ~AFMT_AZ_FORMAT_WTRIG; - queue_hdmi = true; - DRM_DEBUG("IH: HDMI0\n"); - } + if (!(rdev->irq.stat_regs.evergreen.afmt_status1 & AFMT_AZ_FORMAT_WTRIG)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.afmt_status1 &= ~AFMT_AZ_FORMAT_WTRIG; + queue_hdmi = true; + DRM_DEBUG("IH: HDMI0\n"); break; case 1: - if (rdev->irq.stat_regs.evergreen.afmt_status2 & AFMT_AZ_FORMAT_WTRIG) { - rdev->irq.stat_regs.evergreen.afmt_status2 &= ~AFMT_AZ_FORMAT_WTRIG; - queue_hdmi = true; - DRM_DEBUG("IH: HDMI1\n"); - } + if (!(rdev->irq.stat_regs.evergreen.afmt_status2 & AFMT_AZ_FORMAT_WTRIG)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.afmt_status2 &= ~AFMT_AZ_FORMAT_WTRIG; + queue_hdmi = true; + DRM_DEBUG("IH: HDMI1\n"); break; case 2: - if (rdev->irq.stat_regs.evergreen.afmt_status3 & AFMT_AZ_FORMAT_WTRIG) { - rdev->irq.stat_regs.evergreen.afmt_status3 &= ~AFMT_AZ_FORMAT_WTRIG; - queue_hdmi = true; - DRM_DEBUG("IH: HDMI2\n"); - } + if (!(rdev->irq.stat_regs.evergreen.afmt_status3 & AFMT_AZ_FORMAT_WTRIG)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.afmt_status3 &= ~AFMT_AZ_FORMAT_WTRIG; + queue_hdmi = true; + DRM_DEBUG("IH: HDMI2\n"); break; case 3: - if (rdev->irq.stat_regs.evergreen.afmt_status4 & AFMT_AZ_FORMAT_WTRIG) { - rdev->irq.stat_regs.evergreen.afmt_status4 &= ~AFMT_AZ_FORMAT_WTRIG; - queue_hdmi = true; - DRM_DEBUG("IH: HDMI3\n"); - } + if (!(rdev->irq.stat_regs.evergreen.afmt_status4 & AFMT_AZ_FORMAT_WTRIG)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.afmt_status4 &= ~AFMT_AZ_FORMAT_WTRIG; + queue_hdmi = true; + DRM_DEBUG("IH: HDMI3\n"); break; case 4: - if (rdev->irq.stat_regs.evergreen.afmt_status5 & AFMT_AZ_FORMAT_WTRIG) { - rdev->irq.stat_regs.evergreen.afmt_status5 &= ~AFMT_AZ_FORMAT_WTRIG; - queue_hdmi = true; - DRM_DEBUG("IH: HDMI4\n"); - } + if (!(rdev->irq.stat_regs.evergreen.afmt_status5 & AFMT_AZ_FORMAT_WTRIG)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.afmt_status5 &= ~AFMT_AZ_FORMAT_WTRIG; + queue_hdmi = true; + DRM_DEBUG("IH: HDMI4\n"); break; case 5: - if (rdev->irq.stat_regs.evergreen.afmt_status6 & AFMT_AZ_FORMAT_WTRIG) { - rdev->irq.stat_regs.evergreen.afmt_status6 &= ~AFMT_AZ_FORMAT_WTRIG; - queue_hdmi = true; - DRM_DEBUG("IH: HDMI5\n"); - } + if (!(rdev->irq.stat_regs.evergreen.afmt_status6 & AFMT_AZ_FORMAT_WTRIG)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.afmt_status6 &= ~AFMT_AZ_FORMAT_WTRIG; + queue_hdmi = true; + DRM_DEBUG("IH: HDMI5\n"); break; default: DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data); diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 8e5aeeb058a5..158872eb78e4 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -2162,18 +2162,20 @@ static int cayman_startup(struct radeon_device *rdev) DRM_ERROR("radeon: failed initializing UVD (%d).\n", r); } - ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX]; - if (ring->ring_size) - r = radeon_ring_init(rdev, ring, ring->ring_size, 0, 0x0); + if (rdev->family == CHIP_ARUBA) { + ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX]; + if (ring->ring_size) + r = radeon_ring_init(rdev, ring, ring->ring_size, 0, 0x0); - ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX]; - if (ring->ring_size) - r = radeon_ring_init(rdev, ring, ring->ring_size, 0, 0x0); + ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX]; + if (ring->ring_size) + r = radeon_ring_init(rdev, ring, ring->ring_size, 0, 0x0); - if (!r) - r = vce_v1_0_init(rdev); - else if (r != -ENOENT) - DRM_ERROR("radeon: failed initializing VCE (%d).\n", r); + if (!r) + r = vce_v1_0_init(rdev); + if (r) + DRM_ERROR("radeon: failed initializing VCE (%d).\n", r); + } r = radeon_ib_pool_init(rdev); if (r) { @@ -2396,7 +2398,8 @@ void cayman_fini(struct radeon_device *rdev) radeon_irq_kms_fini(rdev); uvd_v1_0_fini(rdev); radeon_uvd_fini(rdev); - radeon_vce_fini(rdev); + if (rdev->family == CHIP_ARUBA) + radeon_vce_fini(rdev); cayman_pcie_gart_fini(rdev); r600_vram_scratch_fini(rdev); radeon_gem_fini(rdev); diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 35dafd77a639..4ea5b10ff5f4 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -4086,23 +4086,27 @@ restart_ih: case 1: /* D1 vblank/vline */ switch (src_data) { case 0: /* D1 vblank */ - if (rdev->irq.stat_regs.r600.disp_int & LB_D1_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[0]) { - drm_handle_vblank(rdev->ddev, 0); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[0])) - radeon_crtc_handle_vblank(rdev, 0); - rdev->irq.stat_regs.r600.disp_int &= ~LB_D1_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D1 vblank\n"); + if (!(rdev->irq.stat_regs.r600.disp_int & LB_D1_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: D1 vblank - IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[0]) { + drm_handle_vblank(rdev->ddev, 0); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[0])) + radeon_crtc_handle_vblank(rdev, 0); + rdev->irq.stat_regs.r600.disp_int &= ~LB_D1_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D1 vblank\n"); + break; case 1: /* D1 vline */ - if (rdev->irq.stat_regs.r600.disp_int & LB_D1_VLINE_INTERRUPT) { - rdev->irq.stat_regs.r600.disp_int &= ~LB_D1_VLINE_INTERRUPT; - DRM_DEBUG("IH: D1 vline\n"); - } + if (!(rdev->irq.stat_regs.r600.disp_int & LB_D1_VLINE_INTERRUPT)) + DRM_DEBUG("IH: D1 vline - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.disp_int &= ~LB_D1_VLINE_INTERRUPT; + DRM_DEBUG("IH: D1 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -4112,23 +4116,27 @@ restart_ih: case 5: /* D2 vblank/vline */ switch (src_data) { case 0: /* D2 vblank */ - if (rdev->irq.stat_regs.r600.disp_int & LB_D2_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[1]) { - drm_handle_vblank(rdev->ddev, 1); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[1])) - radeon_crtc_handle_vblank(rdev, 1); - rdev->irq.stat_regs.r600.disp_int &= ~LB_D2_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D2 vblank\n"); + if (!(rdev->irq.stat_regs.r600.disp_int & LB_D2_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: D2 vblank - IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[1]) { + drm_handle_vblank(rdev->ddev, 1); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[1])) + radeon_crtc_handle_vblank(rdev, 1); + rdev->irq.stat_regs.r600.disp_int &= ~LB_D2_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D2 vblank\n"); + break; case 1: /* D1 vline */ - if (rdev->irq.stat_regs.r600.disp_int & LB_D2_VLINE_INTERRUPT) { - rdev->irq.stat_regs.r600.disp_int &= ~LB_D2_VLINE_INTERRUPT; - DRM_DEBUG("IH: D2 vline\n"); - } + if (!(rdev->irq.stat_regs.r600.disp_int & LB_D2_VLINE_INTERRUPT)) + DRM_DEBUG("IH: D2 vline - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.disp_int &= ~LB_D2_VLINE_INTERRUPT; + DRM_DEBUG("IH: D2 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -4148,46 +4156,53 @@ restart_ih: case 19: /* HPD/DAC hotplug */ switch (src_data) { case 0: - if (rdev->irq.stat_regs.r600.disp_int & DC_HPD1_INTERRUPT) { - rdev->irq.stat_regs.r600.disp_int &= ~DC_HPD1_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD1\n"); - } + if (!(rdev->irq.stat_regs.r600.disp_int & DC_HPD1_INTERRUPT)) + DRM_DEBUG("IH: HPD1 - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.disp_int &= ~DC_HPD1_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD1\n"); break; case 1: - if (rdev->irq.stat_regs.r600.disp_int & DC_HPD2_INTERRUPT) { - rdev->irq.stat_regs.r600.disp_int &= ~DC_HPD2_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD2\n"); - } + if (!(rdev->irq.stat_regs.r600.disp_int & DC_HPD2_INTERRUPT)) + DRM_DEBUG("IH: HPD2 - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.disp_int &= ~DC_HPD2_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD2\n"); break; case 4: - if (rdev->irq.stat_regs.r600.disp_int_cont & DC_HPD3_INTERRUPT) { - rdev->irq.stat_regs.r600.disp_int_cont &= ~DC_HPD3_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD3\n"); - } + if (!(rdev->irq.stat_regs.r600.disp_int_cont & DC_HPD3_INTERRUPT)) + DRM_DEBUG("IH: HPD3 - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.disp_int_cont &= ~DC_HPD3_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD3\n"); break; case 5: - if (rdev->irq.stat_regs.r600.disp_int_cont & DC_HPD4_INTERRUPT) { - rdev->irq.stat_regs.r600.disp_int_cont &= ~DC_HPD4_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD4\n"); - } + if (!(rdev->irq.stat_regs.r600.disp_int_cont & DC_HPD4_INTERRUPT)) + DRM_DEBUG("IH: HPD4 - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.disp_int_cont &= ~DC_HPD4_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD4\n"); break; case 10: - if (rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD5_INTERRUPT) { - rdev->irq.stat_regs.r600.disp_int_cont2 &= ~DC_HPD5_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD5\n"); - } + if (!(rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD5_INTERRUPT)) + DRM_DEBUG("IH: HPD5 - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.disp_int_cont2 &= ~DC_HPD5_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD5\n"); break; case 12: - if (rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD6_INTERRUPT) { - rdev->irq.stat_regs.r600.disp_int_cont2 &= ~DC_HPD6_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD6\n"); - } + if (!(rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD6_INTERRUPT)) + DRM_DEBUG("IH: HPD6 - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.disp_int_cont2 &= ~DC_HPD6_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD6\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -4197,18 +4212,22 @@ restart_ih: case 21: /* hdmi */ switch (src_data) { case 4: - if (rdev->irq.stat_regs.r600.hdmi0_status & HDMI0_AZ_FORMAT_WTRIG) { - rdev->irq.stat_regs.r600.hdmi0_status &= ~HDMI0_AZ_FORMAT_WTRIG; - queue_hdmi = true; - DRM_DEBUG("IH: HDMI0\n"); - } + if (!(rdev->irq.stat_regs.r600.hdmi0_status & HDMI0_AZ_FORMAT_WTRIG)) + DRM_DEBUG("IH: HDMI0 - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.hdmi0_status &= ~HDMI0_AZ_FORMAT_WTRIG; + queue_hdmi = true; + DRM_DEBUG("IH: HDMI0\n"); + break; case 5: - if (rdev->irq.stat_regs.r600.hdmi1_status & HDMI0_AZ_FORMAT_WTRIG) { - rdev->irq.stat_regs.r600.hdmi1_status &= ~HDMI0_AZ_FORMAT_WTRIG; - queue_hdmi = true; - DRM_DEBUG("IH: HDMI1\n"); - } + if (!(rdev->irq.stat_regs.r600.hdmi1_status & HDMI0_AZ_FORMAT_WTRIG)) + DRM_DEBUG("IH: HDMI1 - IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.r600.hdmi1_status &= ~HDMI0_AZ_FORMAT_WTRIG; + queue_hdmi = true; + DRM_DEBUG("IH: HDMI1\n"); + break; default: DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data); diff --git a/drivers/gpu/drm/radeon/r600_cp.c b/drivers/gpu/drm/radeon/r600_cp.c index 09e3f39925fa..98f9adaccc3d 100644 --- a/drivers/gpu/drm/radeon/r600_cp.c +++ b/drivers/gpu/drm/radeon/r600_cp.c @@ -2483,7 +2483,7 @@ int r600_cp_dispatch_texture(struct drm_device *dev, struct drm_buf *buf; u32 *buffer; const u8 __user *data; - int size, pass_size; + unsigned int size, pass_size; u64 src_offset, dst_offset; if (!radeon_check_offset(dev_priv, tex->offset)) { diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 4d2d0579fd49..f03b7eb15233 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -2458,7 +2458,6 @@ struct radeon_device { /* amdkfd interface */ struct kfd_dev *kfd; - struct radeon_sa_manager kfd_bo; struct mutex mn_lock; DECLARE_HASHTABLE(mn_hash, 7); diff --git a/drivers/gpu/drm/radeon/radeon_audio.c b/drivers/gpu/drm/radeon/radeon_audio.c index c89215275053..fa719c53449b 100644 --- a/drivers/gpu/drm/radeon/radeon_audio.c +++ b/drivers/gpu/drm/radeon/radeon_audio.c @@ -469,22 +469,22 @@ void radeon_audio_detect(struct drm_connector *connector, dig = radeon_encoder->enc_priv; if (status == connector_status_connected) { - struct radeon_connector *radeon_connector; - int sink_type; - if (!drm_detect_monitor_audio(radeon_connector_edid(connector))) { radeon_encoder->audio = NULL; return; } - radeon_connector = to_radeon_connector(connector); - sink_type = radeon_dp_getsinktype(radeon_connector); + if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); - if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort && - sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) - radeon_encoder->audio = rdev->audio.dp_funcs; - else + if (radeon_dp_getsinktype(radeon_connector) == + CONNECTOR_OBJECT_ID_DISPLAYPORT) + radeon_encoder->audio = rdev->audio.dp_funcs; + else + radeon_encoder->audio = rdev->audio.hdmi_funcs; + } else { radeon_encoder->audio = rdev->audio.hdmi_funcs; + } dig->afmt->pin = radeon_audio_get_pin(connector->encoder); radeon_audio_enable(rdev, dig->afmt->pin, 0xf); diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c index 45e54060ee97..afaf346bd50e 100644 --- a/drivers/gpu/drm/radeon/radeon_cursor.c +++ b/drivers/gpu/drm/radeon/radeon_cursor.c @@ -91,15 +91,34 @@ static void radeon_show_cursor(struct drm_crtc *crtc) struct radeon_device *rdev = crtc->dev->dev_private; if (ASIC_IS_DCE4(rdev)) { + WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, + upper_32_bits(radeon_crtc->cursor_addr)); + WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, + lower_32_bits(radeon_crtc->cursor_addr)); WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset); WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_EN | EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) | EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2)); } else if (ASIC_IS_AVIVO(rdev)) { + if (rdev->family >= CHIP_RV770) { + if (radeon_crtc->crtc_id) + WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH, + upper_32_bits(radeon_crtc->cursor_addr)); + else + WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH, + upper_32_bits(radeon_crtc->cursor_addr)); + } + + WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, + lower_32_bits(radeon_crtc->cursor_addr)); WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset); WREG32(RADEON_MM_DATA, AVIVO_D1CURSOR_EN | (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT)); } else { + /* offset is from DISP(2)_BASE_ADDRESS */ + WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, + radeon_crtc->cursor_addr - radeon_crtc->legacy_display_base_addr); + switch (radeon_crtc->crtc_id) { case 0: WREG32(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL); @@ -205,8 +224,9 @@ static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y) | (x << 16) | y)); /* offset is from DISP(2)_BASE_ADDRESS */ - WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, (radeon_crtc->legacy_cursor_offset + - (yorigin * 256))); + WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, + radeon_crtc->cursor_addr - radeon_crtc->legacy_display_base_addr + + yorigin * 256); } radeon_crtc->cursor_x = x; @@ -227,53 +247,6 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc, return ret; } -static int radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj) -{ - struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); - struct radeon_device *rdev = crtc->dev->dev_private; - struct radeon_bo *robj = gem_to_radeon_bo(obj); - uint64_t gpu_addr; - int ret; - - ret = radeon_bo_reserve(robj, false); - if (unlikely(ret != 0)) - goto fail; - /* Only 27 bit offset for legacy cursor */ - ret = radeon_bo_pin_restricted(robj, RADEON_GEM_DOMAIN_VRAM, - ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27, - &gpu_addr); - radeon_bo_unreserve(robj); - if (ret) - goto fail; - - if (ASIC_IS_DCE4(rdev)) { - WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, - upper_32_bits(gpu_addr)); - WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, - gpu_addr & 0xffffffff); - } else if (ASIC_IS_AVIVO(rdev)) { - if (rdev->family >= CHIP_RV770) { - if (radeon_crtc->crtc_id) - WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr)); - else - WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr)); - } - WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, - gpu_addr & 0xffffffff); - } else { - radeon_crtc->legacy_cursor_offset = gpu_addr - radeon_crtc->legacy_display_base_addr; - /* offset is from DISP(2)_BASE_ADDRESS */ - WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, radeon_crtc->legacy_cursor_offset); - } - - return 0; - -fail: - drm_gem_object_unreference_unlocked(obj); - - return ret; -} - int radeon_crtc_cursor_set2(struct drm_crtc *crtc, struct drm_file *file_priv, uint32_t handle, @@ -283,7 +256,9 @@ int radeon_crtc_cursor_set2(struct drm_crtc *crtc, int32_t hot_y) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct radeon_device *rdev = crtc->dev->dev_private; struct drm_gem_object *obj; + struct radeon_bo *robj; int ret; if (!handle) { @@ -305,6 +280,23 @@ int radeon_crtc_cursor_set2(struct drm_crtc *crtc, return -ENOENT; } + robj = gem_to_radeon_bo(obj); + ret = radeon_bo_reserve(robj, false); + if (ret != 0) { + drm_gem_object_unreference_unlocked(obj); + return ret; + } + /* Only 27 bit offset for legacy cursor */ + ret = radeon_bo_pin_restricted(robj, RADEON_GEM_DOMAIN_VRAM, + ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27, + &radeon_crtc->cursor_addr); + radeon_bo_unreserve(robj); + if (ret) { + DRM_ERROR("Failed to pin new cursor BO (%d)\n", ret); + drm_gem_object_unreference_unlocked(obj); + return ret; + } + radeon_crtc->cursor_width = width; radeon_crtc->cursor_height = height; @@ -323,13 +315,7 @@ int radeon_crtc_cursor_set2(struct drm_crtc *crtc, radeon_crtc->cursor_hot_y = hot_y; } - ret = radeon_set_cursor(crtc, obj); - - if (ret) - DRM_ERROR("radeon_set_cursor returned %d, not changing cursor\n", - ret); - else - radeon_show_cursor(crtc); + radeon_show_cursor(crtc); radeon_lock_cursor(crtc, false); @@ -341,8 +327,7 @@ unpin: radeon_bo_unpin(robj); radeon_bo_unreserve(robj); } - if (radeon_crtc->cursor_bo != obj) - drm_gem_object_unreference_unlocked(radeon_crtc->cursor_bo); + drm_gem_object_unreference_unlocked(radeon_crtc->cursor_bo); } radeon_crtc->cursor_bo = obj; @@ -360,7 +345,6 @@ unpin: void radeon_cursor_reset(struct drm_crtc *crtc) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); - int ret; if (radeon_crtc->cursor_bo) { radeon_lock_cursor(crtc, true); @@ -368,12 +352,7 @@ void radeon_cursor_reset(struct drm_crtc *crtc) radeon_cursor_move_locked(crtc, radeon_crtc->cursor_x, radeon_crtc->cursor_y); - ret = radeon_set_cursor(crtc, radeon_crtc->cursor_bo); - if (ret) - DRM_ERROR("radeon_set_cursor returned %d, not showing " - "cursor\n", ret); - else - radeon_show_cursor(crtc); + radeon_show_cursor(crtc); radeon_lock_cursor(crtc, false); } diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 13e207e0dff0..d8319dae8358 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1080,6 +1080,22 @@ static bool radeon_check_pot_argument(int arg) } /** + * Determine a sensible default GART size according to ASIC family. + * + * @family ASIC family name + */ +static int radeon_gart_size_auto(enum radeon_family family) +{ + /* default to a larger gart size on newer asics */ + if (family >= CHIP_TAHITI) + return 2048; + else if (family >= CHIP_RV770) + return 1024; + else + return 512; +} + +/** * radeon_check_arguments - validate module params * * @rdev: radeon_device pointer @@ -1097,27 +1113,17 @@ static void radeon_check_arguments(struct radeon_device *rdev) } if (radeon_gart_size == -1) { - /* default to a larger gart size on newer asics */ - if (rdev->family >= CHIP_RV770) - radeon_gart_size = 1024; - else - radeon_gart_size = 512; + radeon_gart_size = radeon_gart_size_auto(rdev->family); } /* gtt size must be power of two and greater or equal to 32M */ if (radeon_gart_size < 32) { dev_warn(rdev->dev, "gart size (%d) too small\n", radeon_gart_size); - if (rdev->family >= CHIP_RV770) - radeon_gart_size = 1024; - else - radeon_gart_size = 512; + radeon_gart_size = radeon_gart_size_auto(rdev->family); } else if (!radeon_check_pot_argument(radeon_gart_size)) { dev_warn(rdev->dev, "gart size (%d) must be a power of 2\n", radeon_gart_size); - if (rdev->family >= CHIP_RV770) - radeon_gart_size = 1024; - else - radeon_gart_size = 512; + radeon_gart_size = radeon_gart_size_auto(rdev->family); } rdev->mc.gtt_size = (uint64_t)radeon_gart_size << 20; @@ -1463,6 +1469,21 @@ int radeon_device_init(struct radeon_device *rdev, if (r) DRM_ERROR("ib ring test failed (%d).\n", r); + /* + * Turks/Thames GPU will freeze whole laptop if DPM is not restarted + * after the CP ring have chew one packet at least. Hence here we stop + * and restart DPM after the radeon_ib_ring_tests(). + */ + if (rdev->pm.dpm_enabled && + (rdev->pm.pm_method == PM_METHOD_DPM) && + (rdev->family == CHIP_TURKS) && + (rdev->flags & RADEON_IS_MOBILITY)) { + mutex_lock(&rdev->pm.mutex); + radeon_dpm_disable(rdev); + radeon_dpm_enable(rdev); + mutex_unlock(&rdev->pm.mutex); + } + if ((radeon_testing & 1)) { if (rdev->accel_working) radeon_test_moves(rdev); @@ -1557,11 +1578,21 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon) drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); } - /* unpin the front buffers */ + /* unpin the front buffers and cursors */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->primary->fb); struct radeon_bo *robj; + if (radeon_crtc->cursor_bo) { + struct radeon_bo *robj = gem_to_radeon_bo(radeon_crtc->cursor_bo); + r = radeon_bo_reserve(robj, false); + if (r == 0) { + radeon_bo_unpin(robj); + radeon_bo_unreserve(robj); + } + } + if (rfb == NULL || rfb->obj == NULL) { continue; } @@ -1624,6 +1655,7 @@ int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon) { struct drm_connector *connector; struct radeon_device *rdev = dev->dev_private; + struct drm_crtc *crtc; int r; if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) @@ -1663,6 +1695,27 @@ int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon) radeon_restore_bios_scratch_regs(rdev); + /* pin cursors */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + + if (radeon_crtc->cursor_bo) { + struct radeon_bo *robj = gem_to_radeon_bo(radeon_crtc->cursor_bo); + r = radeon_bo_reserve(robj, false); + if (r == 0) { + /* Only 27 bit offset for legacy cursor */ + r = radeon_bo_pin_restricted(robj, + RADEON_GEM_DOMAIN_VRAM, + ASIC_IS_AVIVO(rdev) ? + 0 : 1 << 27, + &radeon_crtc->cursor_addr); + if (r != 0) + DRM_ERROR("Failed to pin cursor BO (%d)\n", r); + radeon_bo_unreserve(robj); + } + } + } + /* init dig PHYs, disp eng pll */ if (rdev->is_atom_bios) { radeon_atom_encoder_init(rdev); diff --git a/drivers/gpu/drm/radeon/radeon_dp_mst.c b/drivers/gpu/drm/radeon/radeon_dp_mst.c index 2b98ed3e684d..257b10be5cda 100644 --- a/drivers/gpu/drm/radeon/radeon_dp_mst.c +++ b/drivers/gpu/drm/radeon/radeon_dp_mst.c @@ -663,12 +663,17 @@ int radeon_dp_mst_probe(struct radeon_connector *radeon_connector) { struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; + struct drm_device *dev = radeon_connector->base.dev; + struct radeon_device *rdev = dev->dev_private; int ret; u8 msg[1]; if (!radeon_mst) return 0; + if (!ASIC_IS_DCE5(rdev)) + return 0; + if (dig_connector->dpcd[DP_DPCD_REV] < 0x12) return 0; diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index ac3c1310b953..013ec7106e55 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -428,7 +428,6 @@ int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data, int radeon_gem_busy_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { - struct radeon_device *rdev = dev->dev_private; struct drm_radeon_gem_busy *args = data; struct drm_gem_object *gobj; struct radeon_bo *robj; @@ -440,10 +439,16 @@ int radeon_gem_busy_ioctl(struct drm_device *dev, void *data, return -ENOENT; } robj = gem_to_radeon_bo(gobj); - r = radeon_bo_wait(robj, &cur_placement, true); + + r = reservation_object_test_signaled_rcu(robj->tbo.resv, true); + if (r == 0) + r = -EBUSY; + else + r = 0; + + cur_placement = ACCESS_ONCE(robj->tbo.mem.mem_type); args->domain = radeon_mem_type_to_domain(cur_placement); drm_gem_object_unreference_unlocked(gobj); - r = radeon_gem_handle_lockup(rdev, r); return r; } @@ -471,6 +476,7 @@ int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data, r = ret; /* Flush HDP cache via MMIO if necessary */ + cur_placement = ACCESS_ONCE(robj->tbo.mem.mem_type); if (rdev->asic->mmio_hdp_flush && radeon_mem_type_to_domain(cur_placement) == RADEON_GEM_DOMAIN_VRAM) robj->rdev->asic->mmio_hdp_flush(rdev); diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 9632e886ddc3..4a119c255ba9 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -576,6 +576,9 @@ static int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file if (radeon_get_allowed_info_register(rdev, *value, value)) return -EINVAL; break; + case RADEON_INFO_VA_UNMAP_WORKING: + *value = true; + break; case RADEON_INFO_GPU_RESET_COUNTER: *value = atomic_read(&rdev->gpu_reset_counter); break; diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 6de5459316b5..07909d817381 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -343,7 +343,6 @@ struct radeon_crtc { int max_cursor_width; int max_cursor_height; uint32_t legacy_display_base_addr; - uint32_t legacy_cursor_offset; enum radeon_rmx_type rmx_type; u8 h_border; u8 v_border; diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index edafd3c2b170..06ac59fe332a 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -719,7 +719,7 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm) return 0; if (gtt && gtt->userptr) { - ttm->sg = kcalloc(1, sizeof(struct sg_table), GFP_KERNEL); + ttm->sg = kzalloc(sizeof(struct sg_table), GFP_KERNEL); if (!ttm->sg) return -ENOMEM; diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c index 9739ded91b7a..48d97c040f49 100644 --- a/drivers/gpu/drm/radeon/radeon_vm.c +++ b/drivers/gpu/drm/radeon/radeon_vm.c @@ -457,14 +457,16 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev, /* make sure object fit at this offset */ eoffset = soffset + size; if (soffset >= eoffset) { - return -EINVAL; + r = -EINVAL; + goto error_unreserve; } last_pfn = eoffset / RADEON_GPU_PAGE_SIZE; if (last_pfn > rdev->vm_manager.max_pfn) { dev_err(rdev->dev, "va above limit (0x%08X > 0x%08X)\n", last_pfn, rdev->vm_manager.max_pfn); - return -EINVAL; + r = -EINVAL; + goto error_unreserve; } } else { @@ -485,42 +487,41 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev, "(bo %p 0x%010lx 0x%010lx)\n", bo_va->bo, soffset, tmp->bo, tmp->it.start, tmp->it.last); mutex_unlock(&vm->mutex); - return -EINVAL; + r = -EINVAL; + goto error_unreserve; } } if (bo_va->it.start || bo_va->it.last) { - spin_lock(&vm->status_lock); - if (list_empty(&bo_va->vm_status)) { - /* add a clone of the bo_va to clear the old address */ - struct radeon_bo_va *tmp; - spin_unlock(&vm->status_lock); - tmp = kzalloc(sizeof(struct radeon_bo_va), GFP_KERNEL); - if (!tmp) { - mutex_unlock(&vm->mutex); - return -ENOMEM; - } - tmp->it.start = bo_va->it.start; - tmp->it.last = bo_va->it.last; - tmp->vm = vm; - tmp->bo = radeon_bo_ref(bo_va->bo); - spin_lock(&vm->status_lock); - list_add(&tmp->vm_status, &vm->freed); + /* add a clone of the bo_va to clear the old address */ + struct radeon_bo_va *tmp; + tmp = kzalloc(sizeof(struct radeon_bo_va), GFP_KERNEL); + if (!tmp) { + mutex_unlock(&vm->mutex); + r = -ENOMEM; + goto error_unreserve; } - spin_unlock(&vm->status_lock); + tmp->it.start = bo_va->it.start; + tmp->it.last = bo_va->it.last; + tmp->vm = vm; + tmp->bo = radeon_bo_ref(bo_va->bo); interval_tree_remove(&bo_va->it, &vm->va); + spin_lock(&vm->status_lock); bo_va->it.start = 0; bo_va->it.last = 0; + list_del_init(&bo_va->vm_status); + list_add(&tmp->vm_status, &vm->freed); + spin_unlock(&vm->status_lock); } if (soffset || eoffset) { + spin_lock(&vm->status_lock); bo_va->it.start = soffset; bo_va->it.last = eoffset - 1; - interval_tree_insert(&bo_va->it, &vm->va); - spin_lock(&vm->status_lock); list_add(&bo_va->vm_status, &vm->cleared); spin_unlock(&vm->status_lock); + interval_tree_insert(&bo_va->it, &vm->va); } bo_va->flags = flags; @@ -555,7 +556,6 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev, r = radeon_vm_clear_bo(rdev, pt); if (r) { radeon_bo_unref(&pt); - radeon_bo_reserve(bo_va->bo, false); return r; } @@ -575,6 +575,10 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev, mutex_unlock(&vm->mutex); return 0; + +error_unreserve: + radeon_bo_unreserve(bo_va->bo); + return r; } /** @@ -1122,12 +1126,12 @@ void radeon_vm_bo_rmv(struct radeon_device *rdev, interval_tree_remove(&bo_va->it, &vm->va); spin_lock(&vm->status_lock); - if (list_empty(&bo_va->vm_status)) { + list_del(&bo_va->vm_status); + if (bo_va->it.start || bo_va->it.last) { bo_va->bo = radeon_bo_ref(bo_va->bo); list_add(&bo_va->vm_status, &vm->freed); } else { radeon_fence_unref(&bo_va->last_pt_update); - list_del(&bo_va->vm_status); kfree(bo_va); } spin_unlock(&vm->status_lock); @@ -1151,7 +1155,8 @@ void radeon_vm_bo_invalidate(struct radeon_device *rdev, list_for_each_entry(bo_va, &bo->va, bo_list) { spin_lock(&bo_va->vm->status_lock); - if (list_empty(&bo_va->vm_status)) + if (list_empty(&bo_va->vm_status) && + (bo_va->it.start || bo_va->it.last)) list_add(&bo_va->vm_status, &bo_va->vm->invalidated); spin_unlock(&bo_va->vm->status_lock); } diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 26388b5dd6ed..07037e32dea3 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -6466,23 +6466,27 @@ restart_ih: case 1: /* D1 vblank/vline */ switch (src_data) { case 0: /* D1 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[0]) { - drm_handle_vblank(rdev->ddev, 0); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[0])) - radeon_crtc_handle_vblank(rdev, 0); - rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D1 vblank\n"); + if (!(rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[0]) { + drm_handle_vblank(rdev->ddev, 0); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[0])) + radeon_crtc_handle_vblank(rdev, 0); + rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D1 vblank\n"); + break; case 1: /* D1 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VLINE_INTERRUPT; - DRM_DEBUG("IH: D1 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VLINE_INTERRUPT; + DRM_DEBUG("IH: D1 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -6492,23 +6496,27 @@ restart_ih: case 2: /* D2 vblank/vline */ switch (src_data) { case 0: /* D2 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[1]) { - drm_handle_vblank(rdev->ddev, 1); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[1])) - radeon_crtc_handle_vblank(rdev, 1); - rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D2 vblank\n"); + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[1]) { + drm_handle_vblank(rdev->ddev, 1); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[1])) + radeon_crtc_handle_vblank(rdev, 1); + rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D2 vblank\n"); + break; case 1: /* D2 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT; - DRM_DEBUG("IH: D2 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT; + DRM_DEBUG("IH: D2 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -6518,23 +6526,27 @@ restart_ih: case 3: /* D3 vblank/vline */ switch (src_data) { case 0: /* D3 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[2]) { - drm_handle_vblank(rdev->ddev, 2); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[2])) - radeon_crtc_handle_vblank(rdev, 2); - rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D3 vblank\n"); + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[2]) { + drm_handle_vblank(rdev->ddev, 2); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[2])) + radeon_crtc_handle_vblank(rdev, 2); + rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D3 vblank\n"); + break; case 1: /* D3 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT; - DRM_DEBUG("IH: D3 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT; + DRM_DEBUG("IH: D3 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -6544,23 +6556,27 @@ restart_ih: case 4: /* D4 vblank/vline */ switch (src_data) { case 0: /* D4 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[3]) { - drm_handle_vblank(rdev->ddev, 3); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[3])) - radeon_crtc_handle_vblank(rdev, 3); - rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D4 vblank\n"); + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[3]) { + drm_handle_vblank(rdev->ddev, 3); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[3])) + radeon_crtc_handle_vblank(rdev, 3); + rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D4 vblank\n"); + break; case 1: /* D4 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT; - DRM_DEBUG("IH: D4 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT; + DRM_DEBUG("IH: D4 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -6570,23 +6586,27 @@ restart_ih: case 5: /* D5 vblank/vline */ switch (src_data) { case 0: /* D5 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[4]) { - drm_handle_vblank(rdev->ddev, 4); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[4])) - radeon_crtc_handle_vblank(rdev, 4); - rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D5 vblank\n"); + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[4]) { + drm_handle_vblank(rdev->ddev, 4); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[4])) + radeon_crtc_handle_vblank(rdev, 4); + rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D5 vblank\n"); + break; case 1: /* D5 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT; - DRM_DEBUG("IH: D5 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT; + DRM_DEBUG("IH: D5 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -6596,23 +6616,27 @@ restart_ih: case 6: /* D6 vblank/vline */ switch (src_data) { case 0: /* D6 vblank */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) { - if (rdev->irq.crtc_vblank_int[5]) { - drm_handle_vblank(rdev->ddev, 5); - rdev->pm.vblank_sync = true; - wake_up(&rdev->irq.vblank_queue); - } - if (atomic_read(&rdev->irq.pflip[5])) - radeon_crtc_handle_vblank(rdev, 5); - rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D6 vblank\n"); + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + if (rdev->irq.crtc_vblank_int[5]) { + drm_handle_vblank(rdev->ddev, 5); + rdev->pm.vblank_sync = true; + wake_up(&rdev->irq.vblank_queue); } + if (atomic_read(&rdev->irq.pflip[5])) + radeon_crtc_handle_vblank(rdev, 5); + rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT; + DRM_DEBUG("IH: D6 vblank\n"); + break; case 1: /* D6 vline */ - if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT; - DRM_DEBUG("IH: D6 vline\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT; + DRM_DEBUG("IH: D6 vline\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); @@ -6632,88 +6656,112 @@ restart_ih: case 42: /* HPD hotplug */ switch (src_data) { case 0: - if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD1\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD1\n"); + break; case 1: - if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD2\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD2\n"); + break; case 2: - if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD3\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD3\n"); + break; case 3: - if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD4\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD4\n"); + break; case 4: - if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD5\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD5\n"); + break; case 5: - if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD6\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_INTERRUPT; + queue_hotplug = true; + DRM_DEBUG("IH: HPD6\n"); + break; case 6: - if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 1\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 1\n"); + break; case 7: - if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 2\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 2\n"); + break; case 8: - if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 3\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 3\n"); + break; case 9: - if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 4\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 4\n"); + break; case 10: - if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 5\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 5\n"); + break; case 11: - if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT) { - rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT; - queue_dp = true; - DRM_DEBUG("IH: HPD_RX 6\n"); - } + if (!(rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_RX_INTERRUPT)) + DRM_DEBUG("IH: IH event w/o asserted irq bit?\n"); + + rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_RX_INTERRUPT; + queue_dp = true; + DRM_DEBUG("IH: HPD_RX 6\n"); + break; default: DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data); diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index e6a32c4e4040..65d6ba6621ac 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -214,7 +214,7 @@ static void rcar_du_crtc_update_planes(struct rcar_du_crtc *rcrtc) unsigned int i; u32 dspr = 0; - for (i = 0; i < ARRAY_SIZE(rcrtc->group->planes); ++i) { + for (i = 0; i < rcrtc->group->num_planes; ++i) { struct rcar_du_plane *plane = &rcrtc->group->planes[i]; unsigned int j; @@ -398,6 +398,19 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc) if (!rcrtc->started) return; + /* Disable all planes and wait for the change to take effect. This is + * required as the DSnPR registers are updated on vblank, and no vblank + * will occur once the CRTC is stopped. Disabling planes when starting + * the CRTC thus wouldn't be enough as it would start scanning out + * immediately from old frame buffers until the next vblank. + * + * This increases the CRTC stop delay, especially when multiple CRTCs + * are stopped in one operation as we now wait for one vblank per CRTC. + * Whether this can be improved needs to be researched. + */ + rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0); + drm_crtc_wait_one_vblank(crtc); + /* Disable vertical blanking interrupt reporting. We first need to wait * for page flip completion before stopping the CRTC as userspace * expects page flips to eventually complete. @@ -432,7 +445,7 @@ void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc) rcar_du_crtc_start(rcrtc); /* Commit the planes state. */ - for (i = 0; i < ARRAY_SIZE(rcrtc->group->planes); ++i) { + for (i = 0; i < rcrtc->group->num_planes; ++i) { struct rcar_du_plane *plane = &rcrtc->group->planes[i]; if (plane->plane.state->crtc != &rcrtc->crtc) diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index da1216a73969..780ca11512ba 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -190,7 +190,7 @@ static int rcar_du_load(struct drm_device *dev, unsigned long flags) /* DRM/KMS objects */ ret = rcar_du_modeset_init(rcdu); if (ret < 0) { - dev_err(&pdev->dev, "failed to initialize DRM/KMS\n"); + dev_err(&pdev->dev, "failed to initialize DRM/KMS (%d)\n", ret); goto done; } diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.h b/drivers/gpu/drm/rcar-du/rcar_du_group.h index 7b414b31c3be..d7318e1a6b00 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_group.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_group.h @@ -30,6 +30,7 @@ struct rcar_du_device; * @used_crtcs: number of CRTCs currently in use * @lock: protects the dptsr_planes field and the DPTSR register * @dptsr_planes: bitmask of planes driven by dot-clock and timing generator 1 + * @num_planes: number of planes in the group * @planes: planes handled by the group */ struct rcar_du_group { @@ -44,6 +45,7 @@ struct rcar_du_group { struct mutex lock; unsigned int dptsr_planes; + unsigned int num_planes; struct rcar_du_plane planes[RCAR_DU_NUM_KMS_PLANES]; }; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index 20859aae882e..56518eb1269a 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -336,7 +336,7 @@ static int rcar_du_atomic_check(struct drm_device *dev, dev_dbg(rcdu->dev, "%s: finding free planes for group %u\n", __func__, index); - for (i = 0; i < RCAR_DU_NUM_KMS_PLANES; ++i) { + for (i = 0; i < group->num_planes; ++i) { struct rcar_du_plane *plane = &group->planes[i]; struct rcar_du_plane_state *plane_state; struct drm_plane_state *s; @@ -495,8 +495,10 @@ static int rcar_du_atomic_commit(struct drm_device *dev, /* Allocate the commit object. */ commit = kzalloc(sizeof(*commit), GFP_KERNEL); - if (commit == NULL) - return -ENOMEM; + if (commit == NULL) { + ret = -ENOMEM; + goto error; + } INIT_WORK(&commit->work, rcar_du_atomic_work); commit->dev = dev; @@ -519,7 +521,7 @@ static int rcar_du_atomic_commit(struct drm_device *dev, if (ret) { kfree(commit); - return ret; + goto error; } /* Swap the state, this is the point of no return. */ @@ -531,6 +533,10 @@ static int rcar_du_atomic_commit(struct drm_device *dev, rcar_du_atomic_complete(commit); return 0; + +error: + drm_atomic_helper_cleanup_planes(dev, state); + return ret; } /* ----------------------------------------------------------------------------- @@ -573,7 +579,7 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu, if (!entity) { dev_dbg(rcdu->dev, "unconnected endpoint %s, skipping\n", ep->local_node->full_name); - return 0; + return -ENODEV; } entity_ep_node = of_parse_phandle(ep->local_node, "remote-endpoint", 0); @@ -596,7 +602,7 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu, encoder->full_name); of_node_put(entity_ep_node); of_node_put(encoder); - return 0; + return -ENODEV; } break; @@ -625,7 +631,7 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu, encoder->full_name); of_node_put(encoder); of_node_put(connector); - return 0; + return -EINVAL; } } else { /* @@ -639,7 +645,12 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu, of_node_put(encoder); of_node_put(connector); - return ret < 0 ? ret : 1; + if (ret && ret != -EPROBE_DEFER) + dev_warn(rcdu->dev, + "failed to initialize encoder %s (%d), skipping\n", + encoder->full_name, ret); + + return ret; } static int rcar_du_encoders_init(struct rcar_du_device *rcdu) @@ -688,12 +699,10 @@ static int rcar_du_encoders_init(struct rcar_du_device *rcdu) return ret; } - dev_info(rcdu->dev, - "encoder initialization failed, skipping\n"); continue; } - num_encoders += ret; + num_encoders++; } return num_encoders; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c index 3e30d84b798f..c66986414bb4 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c @@ -302,13 +302,15 @@ rcar_du_plane_atomic_duplicate_state(struct drm_plane *plane) struct rcar_du_plane_state *state; struct rcar_du_plane_state *copy; + if (WARN_ON(!plane->state)) + return NULL; + state = to_rcar_plane_state(plane->state); copy = kmemdup(state, sizeof(*state), GFP_KERNEL); if (copy == NULL) return NULL; - if (copy->state.fb) - drm_framebuffer_reference(copy->state.fb); + __drm_atomic_helper_plane_duplicate_state(plane, ©->state); return ©->state; } @@ -316,9 +318,7 @@ rcar_du_plane_atomic_duplicate_state(struct drm_plane *plane) static void rcar_du_plane_atomic_destroy_state(struct drm_plane *plane, struct drm_plane_state *state) { - if (state->fb) - drm_framebuffer_unreference(state->fb); - + __drm_atomic_helper_plane_destroy_state(plane, state); kfree(to_rcar_plane_state(state)); } @@ -390,7 +390,6 @@ static const uint32_t formats[] = { int rcar_du_planes_init(struct rcar_du_group *rgrp) { struct rcar_du_device *rcdu = rgrp->dev; - unsigned int num_planes; unsigned int crtcs; unsigned int i; int ret; @@ -398,11 +397,11 @@ int rcar_du_planes_init(struct rcar_du_group *rgrp) /* Create one primary plane per CRTC in this group and seven overlay * planes. */ - num_planes = rgrp->num_crtcs + 7; + rgrp->num_planes = rgrp->num_crtcs + 7; crtcs = ((1 << rcdu->num_crtcs) - 1) & (3 << (2 * rgrp->index)); - for (i = 0; i < num_planes; ++i) { + for (i = 0; i < rgrp->num_planes; ++i) { enum drm_plane_type type = i < rgrp->num_crtcs ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 3962176ee713..01b558fe3695 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -21,6 +21,7 @@ #include <drm/drm_fb_helper.h> #include <linux/dma-mapping.h> #include <linux/pm_runtime.h> +#include <linux/module.h> #include <linux/of_graph.h> #include <linux/component.h> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 4557f335a8a5..dc65161d7cad 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -19,6 +19,7 @@ #include <drm/drm_plane_helper.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/of.h> diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c index d6b55e3e3716..07b26972f487 100644 --- a/drivers/gpu/drm/tegra/dpaux.c +++ b/drivers/gpu/drm/tegra/dpaux.c @@ -56,15 +56,14 @@ static inline struct tegra_dpaux *work_to_dpaux(struct work_struct *work) return container_of(work, struct tegra_dpaux, work); } -static inline unsigned long tegra_dpaux_readl(struct tegra_dpaux *dpaux, - unsigned long offset) +static inline u32 tegra_dpaux_readl(struct tegra_dpaux *dpaux, + unsigned long offset) { return readl(dpaux->regs + (offset << 2)); } static inline void tegra_dpaux_writel(struct tegra_dpaux *dpaux, - unsigned long value, - unsigned long offset) + u32 value, unsigned long offset) { writel(value, dpaux->regs + (offset << 2)); } @@ -72,34 +71,32 @@ static inline void tegra_dpaux_writel(struct tegra_dpaux *dpaux, static void tegra_dpaux_write_fifo(struct tegra_dpaux *dpaux, const u8 *buffer, size_t size) { - unsigned long offset = DPAUX_DP_AUXDATA_WRITE(0); size_t i, j; - for (i = 0; i < size; i += 4) { - size_t num = min_t(size_t, size - i, 4); - unsigned long value = 0; + for (i = 0; i < DIV_ROUND_UP(size, 4); i++) { + size_t num = min_t(size_t, size - i * 4, 4); + u32 value = 0; for (j = 0; j < num; j++) - value |= buffer[i + j] << (j * 8); + value |= buffer[i * 4 + j] << (j * 8); - tegra_dpaux_writel(dpaux, value, offset++); + tegra_dpaux_writel(dpaux, value, DPAUX_DP_AUXDATA_WRITE(i)); } } static void tegra_dpaux_read_fifo(struct tegra_dpaux *dpaux, u8 *buffer, size_t size) { - unsigned long offset = DPAUX_DP_AUXDATA_READ(0); size_t i, j; - for (i = 0; i < size; i += 4) { - size_t num = min_t(size_t, size - i, 4); - unsigned long value; + for (i = 0; i < DIV_ROUND_UP(size, 4); i++) { + size_t num = min_t(size_t, size - i * 4, 4); + u32 value; - value = tegra_dpaux_readl(dpaux, offset++); + value = tegra_dpaux_readl(dpaux, DPAUX_DP_AUXDATA_READ(i)); for (j = 0; j < num; j++) - buffer[i + j] = value >> (j * 8); + buffer[i * 4 + j] = value >> (j * 8); } } @@ -250,7 +247,7 @@ static irqreturn_t tegra_dpaux_irq(int irq, void *data) { struct tegra_dpaux *dpaux = data; irqreturn_t ret = IRQ_HANDLED; - unsigned long value; + u32 value; /* clear interrupts */ value = tegra_dpaux_readl(dpaux, DPAUX_INTR_AUX); @@ -273,7 +270,7 @@ static int tegra_dpaux_probe(struct platform_device *pdev) { struct tegra_dpaux *dpaux; struct resource *regs; - unsigned long value; + u32 value; int err; dpaux = devm_kzalloc(&pdev->dev, sizeof(*dpaux), GFP_KERNEL); @@ -465,7 +462,7 @@ int tegra_dpaux_detach(struct tegra_dpaux *dpaux) enum drm_connector_status tegra_dpaux_detect(struct tegra_dpaux *dpaux) { - unsigned long value; + u32 value; value = tegra_dpaux_readl(dpaux, DPAUX_DP_AUXSTAT); @@ -477,7 +474,7 @@ enum drm_connector_status tegra_dpaux_detect(struct tegra_dpaux *dpaux) int tegra_dpaux_enable(struct tegra_dpaux *dpaux) { - unsigned long value; + u32 value; value = DPAUX_HYBRID_PADCTL_AUX_CMH(2) | DPAUX_HYBRID_PADCTL_AUX_DRVZ(4) | @@ -495,7 +492,7 @@ int tegra_dpaux_enable(struct tegra_dpaux *dpaux) int tegra_dpaux_disable(struct tegra_dpaux *dpaux) { - unsigned long value; + u32 value; value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE); value |= DPAUX_HYBRID_SPARE_PAD_POWER_DOWN; diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index bfad15a913a0..427f50c6803c 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -124,14 +124,22 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags) return -ENOMEM; if (iommu_present(&platform_bus_type)) { + struct iommu_domain_geometry *geometry; + u64 start, end; + tegra->domain = iommu_domain_alloc(&platform_bus_type); if (!tegra->domain) { err = -ENOMEM; goto free; } - DRM_DEBUG("IOMMU context initialized\n"); - drm_mm_init(&tegra->mm, 0, SZ_2G); + geometry = &tegra->domain->geometry; + start = geometry->aperture_start; + end = geometry->aperture_end; + + DRM_DEBUG("IOMMU context initialized (aperture: %#llx-%#llx)\n", + start, end); + drm_mm_init(&tegra->mm, start, end - start + 1); } mutex_init(&tegra->clients_lock); diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index 1217272a51f2..01e16e146bfe 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -189,7 +189,6 @@ static void tegra_bo_free(struct drm_device *drm, struct tegra_bo *bo) static int tegra_bo_get_pages(struct drm_device *drm, struct tegra_bo *bo) { struct scatterlist *s; - struct sg_table *sgt; unsigned int i; bo->pages = drm_gem_get_pages(&bo->gem); @@ -198,36 +197,28 @@ static int tegra_bo_get_pages(struct drm_device *drm, struct tegra_bo *bo) bo->num_pages = bo->gem.size >> PAGE_SHIFT; - sgt = drm_prime_pages_to_sg(bo->pages, bo->num_pages); - if (IS_ERR(sgt)) + bo->sgt = drm_prime_pages_to_sg(bo->pages, bo->num_pages); + if (IS_ERR(bo->sgt)) goto put_pages; /* - * Fake up the SG table so that dma_map_sg() can be used to flush the - * pages associated with it. Note that this relies on the fact that - * the DMA API doesn't hook into IOMMU on Tegra, therefore mapping is - * only cache maintenance. + * Fake up the SG table so that dma_sync_sg_for_device() can be used + * to flush the pages associated with it. * * TODO: Replace this by drm_clflash_sg() once it can be implemented * without relying on symbols that are not exported. */ - for_each_sg(sgt->sgl, s, sgt->nents, i) + for_each_sg(bo->sgt->sgl, s, bo->sgt->nents, i) sg_dma_address(s) = sg_phys(s); - if (dma_map_sg(drm->dev, sgt->sgl, sgt->nents, DMA_TO_DEVICE) == 0) - goto release_sgt; - - bo->sgt = sgt; + dma_sync_sg_for_device(drm->dev, bo->sgt->sgl, bo->sgt->nents, + DMA_TO_DEVICE); return 0; -release_sgt: - sg_free_table(sgt); - kfree(sgt); - sgt = ERR_PTR(-ENOMEM); put_pages: drm_gem_put_pages(&bo->gem, bo->pages, false, false); - return PTR_ERR(sgt); + return PTR_ERR(bo->sgt); } static int tegra_bo_alloc(struct drm_device *drm, struct tegra_bo *bo) diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c index 7a207ca547be..6394547cf67a 100644 --- a/drivers/gpu/drm/vgem/vgem_drv.c +++ b/drivers/gpu/drm/vgem/vgem_drv.c @@ -328,6 +328,8 @@ static int __init vgem_init(void) goto out; } + drm_dev_set_unique(vgem_device, "vgem"); + ret = drm_dev_register(vgem_device, 0); if (ret) diff --git a/drivers/gpu/drm/virtio/virtgpu_drm_bus.c b/drivers/gpu/drm/virtio/virtgpu_drm_bus.c index f4ec816e9468..88a39165edd5 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drm_bus.c +++ b/drivers/gpu/drm/virtio/virtgpu_drm_bus.c @@ -37,6 +37,26 @@ int drm_virtio_set_busid(struct drm_device *dev, struct drm_master *master) return 0; } +static void virtio_pci_kick_out_firmware_fb(struct pci_dev *pci_dev) +{ + struct apertures_struct *ap; + bool primary; + + ap = alloc_apertures(1); + if (!ap) + return; + + ap->ranges[0].base = pci_resource_start(pci_dev, 0); + ap->ranges[0].size = pci_resource_len(pci_dev, 0); + + primary = pci_dev->resource[PCI_ROM_RESOURCE].flags + & IORESOURCE_ROM_SHADOW; + + remove_conflicting_framebuffers(ap, "virtiodrmfb", primary); + + kfree(ap); +} + int drm_virtio_init(struct drm_driver *driver, struct virtio_device *vdev) { struct drm_device *dev; @@ -52,27 +72,11 @@ int drm_virtio_init(struct drm_driver *driver, struct virtio_device *vdev) struct pci_dev *pdev = to_pci_dev(vdev->dev.parent); bool vga = (pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA; - if (vga) { - /* - * Need to make sure we don't have two drivers - * for the same hardware here. Some day we - * will simply kick out the firmware - * (vesa/efi) framebuffer. - * - * Virtual hardware specs for virtio-vga are - * not finalized yet, therefore we can't add - * code for that yet. - * - * So ignore the device for the time being, - * and suggest to the user use the device - * variant without vga compatibility mode. - */ - DRM_ERROR("virtio-vga not (yet) supported\n"); - DRM_ERROR("please use virtio-gpu-pci instead\n"); - ret = -ENODEV; - goto err_free; - } + DRM_INFO("pci: %s detected\n", + vga ? "virtio-vga" : "virtio-gpu-pci"); dev->pdev = pdev; + if (vga) + virtio_pci_kick_out_firmware_fb(pdev); } ret = drm_dev_register(dev, 0); diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index e5a2c092460b..6d4db2dba90b 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -162,6 +162,7 @@ struct virtio_gpu_device { struct virtio_gpu_queue ctrlq; struct virtio_gpu_queue cursorq; struct list_head free_vbufs; + spinlock_t free_vbufs_lock; void *vbufs; bool vqs_ready; @@ -171,6 +172,7 @@ struct virtio_gpu_device { wait_queue_head_t resp_wq; /* current display info */ spinlock_t display_info_lock; + bool display_info_pending; struct virtio_gpu_fence_driver fence_drv; diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c index 132405f15389..782766c00d70 100644 --- a/drivers/gpu/drm/virtio/virtgpu_kms.c +++ b/drivers/gpu/drm/virtio/virtgpu_kms.c @@ -137,9 +137,11 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) virtio_device_ready(vgdev->vdev); vgdev->vqs_ready = true; + virtio_gpu_cmd_get_display_info(vgdev); + wait_event_timeout(vgdev->resp_wq, !vgdev->display_info_pending, + 5 * HZ); if (virtio_gpu_fbdev) virtio_gpu_fbdev_init(vgdev); - virtio_gpu_cmd_get_display_info(vgdev); return 0; diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index 8fa6513eb3bc..1698669f4185 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c @@ -79,6 +79,7 @@ int virtio_gpu_alloc_vbufs(struct virtio_gpu_device *vgdev) void *ptr; INIT_LIST_HEAD(&vgdev->free_vbufs); + spin_lock_init(&vgdev->free_vbufs_lock); count += virtqueue_get_vring_size(vgdev->ctrlq.vq); count += virtqueue_get_vring_size(vgdev->cursorq.vq); size = count * VBUFFER_SIZE; @@ -106,6 +107,7 @@ void virtio_gpu_free_vbufs(struct virtio_gpu_device *vgdev) count += virtqueue_get_vring_size(vgdev->ctrlq.vq); count += virtqueue_get_vring_size(vgdev->cursorq.vq); + spin_lock(&vgdev->free_vbufs_lock); for (i = 0; i < count; i++) { if (WARN_ON(list_empty(&vgdev->free_vbufs))) return; @@ -113,6 +115,7 @@ void virtio_gpu_free_vbufs(struct virtio_gpu_device *vgdev) struct virtio_gpu_vbuffer, list); list_del(&vbuf->list); } + spin_unlock(&vgdev->free_vbufs_lock); kfree(vgdev->vbufs); } @@ -123,10 +126,12 @@ virtio_gpu_get_vbuf(struct virtio_gpu_device *vgdev, { struct virtio_gpu_vbuffer *vbuf; + spin_lock(&vgdev->free_vbufs_lock); BUG_ON(list_empty(&vgdev->free_vbufs)); vbuf = list_first_entry(&vgdev->free_vbufs, struct virtio_gpu_vbuffer, list); list_del(&vbuf->list); + spin_unlock(&vgdev->free_vbufs_lock); memset(vbuf, 0, VBUFFER_SIZE); BUG_ON(size > MAX_INLINE_CMD_SIZE); @@ -201,7 +206,9 @@ static void free_vbuf(struct virtio_gpu_device *vgdev, if (vbuf->resp_size > MAX_INLINE_RESP_SIZE) kfree(vbuf->resp_buf); kfree(vbuf->data_buf); + spin_lock(&vgdev->free_vbufs_lock); list_add(&vbuf->list, &vgdev->free_vbufs); + spin_unlock(&vgdev->free_vbufs_lock); } static void reclaim_vbufs(struct virtqueue *vq, struct list_head *reclaim_list) @@ -534,6 +541,7 @@ static void virtio_gpu_cmd_get_display_info_cb(struct virtio_gpu_device *vgdev, } } + vgdev->display_info_pending = false; spin_unlock(&vgdev->display_info_lock); wake_up(&vgdev->resp_wq); @@ -558,6 +566,7 @@ int virtio_gpu_cmd_get_display_info(struct virtio_gpu_device *vgdev) resp_buf); memset(cmd_p, 0, sizeof(*cmd_p)); + vgdev->display_info_pending = true; cmd_p->type = cpu_to_le32(VIRTIO_GPU_CMD_GET_DISPLAY_INFO); virtio_gpu_queue_ctrl_buffer(vgdev, vbuf); return 0; |