diff options
Diffstat (limited to 'drivers/gpu/drm')
31 files changed, 1674 insertions, 750 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 92af057dbf6d..492aebc44e51 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -39,6 +39,7 @@ #include "amdgpu.h" #include "amdgpu_trace.h" #include "amdgpu_amdkfd.h" +#include "amdgpu_vram_mgr.h" /** * DOC: amdgpu_object @@ -601,8 +602,7 @@ int amdgpu_bo_create(struct amdgpu_device *adev, if (!amdgpu_bo_support_uswc(bo->flags)) bo->flags &= ~AMDGPU_GEM_CREATE_CPU_GTT_USWC; - if (adev->ras_enabled) - bo->flags |= AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE; + bo->flags |= AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE; bo->tbo.bdev = &adev->mman.bdev; if (bp->domain & (AMDGPU_GEM_DOMAIN_GWS | AMDGPU_GEM_DOMAIN_OA | @@ -633,7 +633,7 @@ int amdgpu_bo_create(struct amdgpu_device *adev, bo->tbo.resource->mem_type == TTM_PL_VRAM) { struct dma_fence *fence; - r = amdgpu_fill_buffer(bo, 0, bo->tbo.base.resv, &fence, true); + r = amdgpu_ttm_clear_buffer(bo, bo->tbo.base.resv, &fence); if (unlikely(r)) goto fail_unreserve; @@ -1366,8 +1366,9 @@ void amdgpu_bo_release_notify(struct ttm_buffer_object *bo) if (WARN_ON_ONCE(!dma_resv_trylock(bo->base.resv))) return; - r = amdgpu_fill_buffer(abo, AMDGPU_POISON, bo->base.resv, &fence, true); + r = amdgpu_fill_buffer(abo, 0, bo->base.resv, &fence, true); if (!WARN_ON(r)) { + amdgpu_vram_mgr_set_cleared(bo->resource); amdgpu_bo_fence(abo, fence, false); dma_fence_put(fence); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h index 381101d2bf05..50fcd86e1033 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h @@ -164,4 +164,29 @@ static inline void amdgpu_res_next(struct amdgpu_res_cursor *cur, uint64_t size) } } +/** + * amdgpu_res_cleared - check if blocks are cleared + * + * @cur: the cursor to extract the block + * + * Check if the @cur block is cleared + */ +static inline bool amdgpu_res_cleared(struct amdgpu_res_cursor *cur) +{ + struct drm_buddy_block *block; + + switch (cur->mem_type) { + case TTM_PL_VRAM: + block = cur->node; + + if (!amdgpu_vram_mgr_is_cleared(block)) + return false; + break; + default: + return false; + } + + return true; +} + #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 1d71729e3f6b..6b48bcf53ce9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -378,11 +378,12 @@ static int amdgpu_move_blit(struct ttm_buffer_object *bo, (abo->flags & AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE)) { struct dma_fence *wipe_fence = NULL; - r = amdgpu_fill_buffer(abo, AMDGPU_POISON, NULL, &wipe_fence, - false); + r = amdgpu_fill_buffer(abo, 0, NULL, &wipe_fence, + false); if (r) { goto error; } else if (wipe_fence) { + amdgpu_vram_mgr_set_cleared(bo->resource); dma_fence_put(fence); fence = wipe_fence; } @@ -2226,6 +2227,71 @@ static int amdgpu_ttm_fill_mem(struct amdgpu_ring *ring, uint32_t src_data, return 0; } +/** + * amdgpu_ttm_clear_buffer - clear memory buffers + * @bo: amdgpu buffer object + * @resv: reservation object + * @fence: dma_fence associated with the operation + * + * Clear the memory buffer resource. + * + * Returns: + * 0 for success or a negative error code on failure. + */ +int amdgpu_ttm_clear_buffer(struct amdgpu_bo *bo, + struct dma_resv *resv, + struct dma_fence **fence) +{ + struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); + struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring; + struct amdgpu_res_cursor cursor; + u64 addr; + int r; + + if (!adev->mman.buffer_funcs_enabled) + return -EINVAL; + + if (!fence) + return -EINVAL; + + *fence = dma_fence_get_stub(); + + amdgpu_res_first(bo->tbo.resource, 0, amdgpu_bo_size(bo), &cursor); + + mutex_lock(&adev->mman.gtt_window_lock); + while (cursor.remaining) { + struct dma_fence *next = NULL; + u64 size; + + if (amdgpu_res_cleared(&cursor)) { + amdgpu_res_next(&cursor, cursor.size); + continue; + } + + /* Never clear more than 256MiB at once to avoid timeouts */ + size = min(cursor.size, 256ULL << 20); + + r = amdgpu_ttm_map_buffer(&bo->tbo, bo->tbo.resource, &cursor, + 1, ring, false, &size, &addr); + if (r) + goto err; + + r = amdgpu_ttm_fill_mem(ring, 0, addr, size, resv, + &next, true, true); + if (r) + goto err; + + dma_fence_put(*fence); + *fence = next; + + amdgpu_res_next(&cursor, size); + } +err: + mutex_unlock(&adev->mman.gtt_window_lock); + + return r; +} + int amdgpu_fill_buffer(struct amdgpu_bo *bo, uint32_t src_data, struct dma_resv *resv, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h index 32cf6b6f6efd..4f5e70ee9ad0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h @@ -38,8 +38,6 @@ #define AMDGPU_GTT_MAX_TRANSFER_SIZE 512 #define AMDGPU_GTT_NUM_TRANSFER_WINDOWS 2 -#define AMDGPU_POISON 0xd0bed0be - extern const struct attribute_group amdgpu_vram_mgr_attr_group; extern const struct attribute_group amdgpu_gtt_mgr_attr_group; @@ -158,6 +156,9 @@ int amdgpu_ttm_copy_mem_to_mem(struct amdgpu_device *adev, uint64_t size, bool tmz, struct dma_resv *resv, struct dma_fence **f); +int amdgpu_ttm_clear_buffer(struct amdgpu_bo *bo, + struct dma_resv *resv, + struct dma_fence **fence); int amdgpu_fill_buffer(struct amdgpu_bo *bo, uint32_t src_data, struct dma_resv *resv, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c index 8db880244324..e494f5bf136a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c @@ -450,6 +450,7 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, { struct amdgpu_vram_mgr *mgr = to_vram_mgr(man); struct amdgpu_device *adev = to_amdgpu_device(mgr); + struct amdgpu_bo *bo = ttm_to_amdgpu_bo(tbo); u64 vis_usage = 0, max_bytes, min_block_size; struct amdgpu_vram_mgr_resource *vres; u64 size, remaining_size, lpfn, fpfn; @@ -501,6 +502,9 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, if (place->flags & TTM_PL_FLAG_CONTIGUOUS) vres->flags |= DRM_BUDDY_CONTIGUOUS_ALLOCATION; + if (bo->flags & AMDGPU_GEM_CREATE_VRAM_CLEARED) + vres->flags |= DRM_BUDDY_CLEAR_ALLOCATION; + if (fpfn || lpfn != mgr->mm.size) /* Allocate blocks in desired range */ vres->flags |= DRM_BUDDY_RANGE_ALLOCATION; @@ -571,7 +575,7 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, return 0; error_free_blocks: - drm_buddy_free_list(mm, &vres->blocks); + drm_buddy_free_list(mm, &vres->blocks, 0); mutex_unlock(&mgr->lock); error_fini: ttm_resource_fini(man, &vres->base); @@ -604,7 +608,7 @@ static void amdgpu_vram_mgr_del(struct ttm_resource_manager *man, amdgpu_vram_mgr_do_reserve(man); - drm_buddy_free_list(mm, &vres->blocks); + drm_buddy_free_list(mm, &vres->blocks, vres->flags); mutex_unlock(&mgr->lock); atomic64_sub(vis_usage, &mgr->vis_usage); @@ -912,7 +916,7 @@ void amdgpu_vram_mgr_fini(struct amdgpu_device *adev) kfree(rsv); list_for_each_entry_safe(rsv, temp, &mgr->reserved_pages, blocks) { - drm_buddy_free_list(&mgr->mm, &rsv->allocated); + drm_buddy_free_list(&mgr->mm, &rsv->allocated, 0); kfree(rsv); } if (!adev->gmc.is_app_apu) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h index 0e04e42cf809..b256cbc2bc27 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h @@ -53,10 +53,20 @@ static inline u64 amdgpu_vram_mgr_block_size(struct drm_buddy_block *block) return (u64)PAGE_SIZE << drm_buddy_block_order(block); } +static inline bool amdgpu_vram_mgr_is_cleared(struct drm_buddy_block *block) +{ + return drm_buddy_block_is_clear(block); +} + static inline struct amdgpu_vram_mgr_resource * to_amdgpu_vram_mgr_resource(struct ttm_resource *res) { return container_of(res, struct amdgpu_vram_mgr_resource, base); } +static inline void amdgpu_vram_mgr_set_cleared(struct ttm_resource *res) +{ + to_amdgpu_vram_mgr_resource(res)->flags |= DRM_BUDDY_CLEARED; +} + #endif diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c index 5ebdd6f8f36e..284ebae71cc4 100644 --- a/drivers/gpu/drm/drm_buddy.c +++ b/drivers/gpu/drm/drm_buddy.c @@ -57,6 +57,16 @@ static void list_insert_sorted(struct drm_buddy *mm, __list_add(&block->link, node->link.prev, &node->link); } +static void clear_reset(struct drm_buddy_block *block) +{ + block->header &= ~DRM_BUDDY_HEADER_CLEAR; +} + +static void mark_cleared(struct drm_buddy_block *block) +{ + block->header |= DRM_BUDDY_HEADER_CLEAR; +} + static void mark_allocated(struct drm_buddy_block *block) { block->header &= ~DRM_BUDDY_HEADER_STATE; @@ -82,6 +92,133 @@ static void mark_split(struct drm_buddy_block *block) list_del(&block->link); } +static inline bool overlaps(u64 s1, u64 e1, u64 s2, u64 e2) +{ + return s1 <= e2 && e1 >= s2; +} + +static inline bool contains(u64 s1, u64 e1, u64 s2, u64 e2) +{ + return s1 <= s2 && e1 >= e2; +} + +static struct drm_buddy_block * +__get_buddy(struct drm_buddy_block *block) +{ + struct drm_buddy_block *parent; + + parent = block->parent; + if (!parent) + return NULL; + + if (parent->left == block) + return parent->right; + + return parent->left; +} + +static unsigned int __drm_buddy_free(struct drm_buddy *mm, + struct drm_buddy_block *block, + bool force_merge) +{ + struct drm_buddy_block *parent; + unsigned int order; + + while ((parent = block->parent)) { + struct drm_buddy_block *buddy; + + buddy = __get_buddy(block); + + if (!drm_buddy_block_is_free(buddy)) + break; + + if (!force_merge) { + /* + * Check the block and its buddy clear state and exit + * the loop if they both have the dissimilar state. + */ + if (drm_buddy_block_is_clear(block) != + drm_buddy_block_is_clear(buddy)) + break; + + if (drm_buddy_block_is_clear(block)) + mark_cleared(parent); + } + + list_del(&buddy->link); + if (force_merge && drm_buddy_block_is_clear(buddy)) + mm->clear_avail -= drm_buddy_block_size(mm, buddy); + + drm_block_free(mm, block); + drm_block_free(mm, buddy); + + block = parent; + } + + order = drm_buddy_block_order(block); + mark_free(mm, block); + + return order; +} + +static int __force_merge(struct drm_buddy *mm, + u64 start, + u64 end, + unsigned int min_order) +{ + unsigned int order; + int i; + + if (!min_order) + return -ENOMEM; + + if (min_order > mm->max_order) + return -EINVAL; + + for (i = min_order - 1; i >= 0; i--) { + struct drm_buddy_block *block, *prev; + + list_for_each_entry_safe_reverse(block, prev, &mm->free_list[i], link) { + struct drm_buddy_block *buddy; + u64 block_start, block_end; + + if (!block->parent) + continue; + + block_start = drm_buddy_block_offset(block); + block_end = block_start + drm_buddy_block_size(mm, block) - 1; + + if (!contains(start, end, block_start, block_end)) + continue; + + buddy = __get_buddy(block); + if (!drm_buddy_block_is_free(buddy)) + continue; + + WARN_ON(drm_buddy_block_is_clear(block) == + drm_buddy_block_is_clear(buddy)); + + /* + * If the prev block is same as buddy, don't access the + * block in the next iteration as we would free the + * buddy block as part of the free function. + */ + if (prev == buddy) + prev = list_prev_entry(prev, link); + + list_del(&block->link); + if (drm_buddy_block_is_clear(block)) + mm->clear_avail -= drm_buddy_block_size(mm, block); + + order = __drm_buddy_free(mm, block, true); + if (order >= min_order) + return 0; + } + } + + return -ENOMEM; +} + /** * drm_buddy_init - init memory manager * @@ -186,11 +323,21 @@ EXPORT_SYMBOL(drm_buddy_init); */ void drm_buddy_fini(struct drm_buddy *mm) { + u64 root_size, size; + unsigned int order; int i; + size = mm->size; + for (i = 0; i < mm->n_roots; ++i) { + order = ilog2(size) - ilog2(mm->chunk_size); + __force_merge(mm, 0, size, order); + WARN_ON(!drm_buddy_block_is_free(mm->roots[i])); drm_block_free(mm, mm->roots[i]); + + root_size = mm->chunk_size << order; + size -= root_size; } WARN_ON(mm->avail != mm->size); @@ -223,26 +370,17 @@ static int split_block(struct drm_buddy *mm, mark_free(mm, block->left); mark_free(mm, block->right); + if (drm_buddy_block_is_clear(block)) { + mark_cleared(block->left); + mark_cleared(block->right); + clear_reset(block); + } + mark_split(block); return 0; } -static struct drm_buddy_block * -__get_buddy(struct drm_buddy_block *block) -{ - struct drm_buddy_block *parent; - - parent = block->parent; - if (!parent) - return NULL; - - if (parent->left == block) - return parent->right; - - return parent->left; -} - /** * drm_get_buddy - get buddy address * @@ -260,30 +398,6 @@ drm_get_buddy(struct drm_buddy_block *block) } EXPORT_SYMBOL(drm_get_buddy); -static void __drm_buddy_free(struct drm_buddy *mm, - struct drm_buddy_block *block) -{ - struct drm_buddy_block *parent; - - while ((parent = block->parent)) { - struct drm_buddy_block *buddy; - - buddy = __get_buddy(block); - - if (!drm_buddy_block_is_free(buddy)) - break; - - list_del(&buddy->link); - - drm_block_free(mm, block); - drm_block_free(mm, buddy); - - block = parent; - } - - mark_free(mm, block); -} - /** * drm_buddy_free_block - free a block * @@ -295,42 +409,74 @@ void drm_buddy_free_block(struct drm_buddy *mm, { BUG_ON(!drm_buddy_block_is_allocated(block)); mm->avail += drm_buddy_block_size(mm, block); - __drm_buddy_free(mm, block); + if (drm_buddy_block_is_clear(block)) + mm->clear_avail += drm_buddy_block_size(mm, block); + + __drm_buddy_free(mm, block, false); } EXPORT_SYMBOL(drm_buddy_free_block); -/** - * drm_buddy_free_list - free blocks - * - * @mm: DRM buddy manager - * @objects: input list head to free blocks - */ -void drm_buddy_free_list(struct drm_buddy *mm, struct list_head *objects) +static void __drm_buddy_free_list(struct drm_buddy *mm, + struct list_head *objects, + bool mark_clear, + bool mark_dirty) { struct drm_buddy_block *block, *on; + WARN_ON(mark_dirty && mark_clear); + list_for_each_entry_safe(block, on, objects, link) { + if (mark_clear) + mark_cleared(block); + else if (mark_dirty) + clear_reset(block); drm_buddy_free_block(mm, block); cond_resched(); } INIT_LIST_HEAD(objects); } -EXPORT_SYMBOL(drm_buddy_free_list); -static inline bool overlaps(u64 s1, u64 e1, u64 s2, u64 e2) +static void drm_buddy_free_list_internal(struct drm_buddy *mm, + struct list_head *objects) { - return s1 <= e2 && e1 >= s2; + /* + * Don't touch the clear/dirty bit, since allocation is still internal + * at this point. For example we might have just failed part of the + * allocation. + */ + __drm_buddy_free_list(mm, objects, false, false); } -static inline bool contains(u64 s1, u64 e1, u64 s2, u64 e2) +/** + * drm_buddy_free_list - free blocks + * + * @mm: DRM buddy manager + * @objects: input list head to free blocks + * @flags: optional flags like DRM_BUDDY_CLEARED + */ +void drm_buddy_free_list(struct drm_buddy *mm, + struct list_head *objects, + unsigned int flags) { - return s1 <= s2 && e1 >= e2; + bool mark_clear = flags & DRM_BUDDY_CLEARED; + + __drm_buddy_free_list(mm, objects, mark_clear, !mark_clear); +} +EXPORT_SYMBOL(drm_buddy_free_list); + +static bool block_incompatible(struct drm_buddy_block *block, unsigned int flags) +{ + bool needs_clear = flags & DRM_BUDDY_CLEAR_ALLOCATION; + + return needs_clear != drm_buddy_block_is_clear(block); } static struct drm_buddy_block * -alloc_range_bias(struct drm_buddy *mm, - u64 start, u64 end, - unsigned int order) +__alloc_range_bias(struct drm_buddy *mm, + u64 start, u64 end, + unsigned int order, + unsigned long flags, + bool fallback) { u64 req_size = mm->chunk_size << order; struct drm_buddy_block *block; @@ -379,6 +525,9 @@ alloc_range_bias(struct drm_buddy *mm, if (contains(start, end, block_start, block_end) && order == drm_buddy_block_order(block)) { + if (!fallback && block_incompatible(block, flags)) + continue; + /* * Find the free block within the range. */ @@ -410,30 +559,57 @@ err_undo: if (buddy && (drm_buddy_block_is_free(block) && drm_buddy_block_is_free(buddy))) - __drm_buddy_free(mm, block); + __drm_buddy_free(mm, block, false); return ERR_PTR(err); } static struct drm_buddy_block * -get_maxblock(struct drm_buddy *mm, unsigned int order) +__drm_buddy_alloc_range_bias(struct drm_buddy *mm, + u64 start, u64 end, + unsigned int order, + unsigned long flags) +{ + struct drm_buddy_block *block; + bool fallback = false; + + block = __alloc_range_bias(mm, start, end, order, + flags, fallback); + if (IS_ERR(block) && mm->clear_avail) + return __alloc_range_bias(mm, start, end, order, + flags, !fallback); + + return block; +} + +static struct drm_buddy_block * +get_maxblock(struct drm_buddy *mm, unsigned int order, + unsigned long flags) { - struct drm_buddy_block *max_block = NULL, *node; + struct drm_buddy_block *max_block = NULL, *block = NULL; unsigned int i; for (i = order; i <= mm->max_order; ++i) { - if (!list_empty(&mm->free_list[i])) { - node = list_last_entry(&mm->free_list[i], - struct drm_buddy_block, - link); - if (!max_block) { - max_block = node; + struct drm_buddy_block *tmp_block; + + list_for_each_entry_reverse(tmp_block, &mm->free_list[i], link) { + if (block_incompatible(tmp_block, flags)) continue; - } - if (drm_buddy_block_offset(node) > - drm_buddy_block_offset(max_block)) { - max_block = node; - } + block = tmp_block; + break; + } + + if (!block) + continue; + + if (!max_block) { + max_block = block; + continue; + } + + if (drm_buddy_block_offset(block) > + drm_buddy_block_offset(max_block)) { + max_block = block; } } @@ -450,12 +626,30 @@ alloc_from_freelist(struct drm_buddy *mm, int err; if (flags & DRM_BUDDY_TOPDOWN_ALLOCATION) { - block = get_maxblock(mm, order); + block = get_maxblock(mm, order, flags); if (block) /* Store the obtained block order */ tmp = drm_buddy_block_order(block); } else { for (tmp = order; tmp <= mm->max_order; ++tmp) { + struct drm_buddy_block *tmp_block; + + list_for_each_entry_reverse(tmp_block, &mm->free_list[tmp], link) { + if (block_incompatible(tmp_block, flags)) + continue; + + block = tmp_block; + break; + } + + if (block) + break; + } + } + + if (!block) { + /* Fallback method */ + for (tmp = order; tmp <= mm->max_order; ++tmp) { if (!list_empty(&mm->free_list[tmp])) { block = list_last_entry(&mm->free_list[tmp], struct drm_buddy_block, @@ -464,10 +658,10 @@ alloc_from_freelist(struct drm_buddy *mm, break; } } - } - if (!block) - return ERR_PTR(-ENOSPC); + if (!block) + return ERR_PTR(-ENOSPC); + } BUG_ON(!drm_buddy_block_is_free(block)); @@ -483,7 +677,7 @@ alloc_from_freelist(struct drm_buddy *mm, err_undo: if (tmp != order) - __drm_buddy_free(mm, block); + __drm_buddy_free(mm, block, false); return ERR_PTR(err); } @@ -526,16 +720,18 @@ static int __alloc_range(struct drm_buddy *mm, } if (contains(start, end, block_start, block_end)) { - if (!drm_buddy_block_is_free(block)) { + if (drm_buddy_block_is_free(block)) { + mark_allocated(block); + total_allocated += drm_buddy_block_size(mm, block); + mm->avail -= drm_buddy_block_size(mm, block); + if (drm_buddy_block_is_clear(block)) + mm->clear_avail -= drm_buddy_block_size(mm, block); + list_add_tail(&block->link, &allocated); + continue; + } else if (!mm->clear_avail) { err = -ENOSPC; goto err_free; } - - mark_allocated(block); - total_allocated += drm_buddy_block_size(mm, block); - mm->avail -= drm_buddy_block_size(mm, block); - list_add_tail(&block->link, &allocated); - continue; } if (!drm_buddy_block_is_split(block)) { @@ -567,14 +763,14 @@ err_undo: if (buddy && (drm_buddy_block_is_free(block) && drm_buddy_block_is_free(buddy))) - __drm_buddy_free(mm, block); + __drm_buddy_free(mm, block, false); err_free: if (err == -ENOSPC && total_allocated_on_err) { list_splice_tail(&allocated, blocks); *total_allocated_on_err = total_allocated; } else { - drm_buddy_free_list(mm, &allocated); + drm_buddy_free_list_internal(mm, &allocated); } return err; @@ -640,11 +836,11 @@ static int __alloc_contig_try_harder(struct drm_buddy *mm, list_splice(&blocks_lhs, blocks); return 0; } else if (err != -ENOSPC) { - drm_buddy_free_list(mm, blocks); + drm_buddy_free_list_internal(mm, blocks); return err; } /* Free blocks for the next iteration */ - drm_buddy_free_list(mm, blocks); + drm_buddy_free_list_internal(mm, blocks); } return -ENOSPC; @@ -700,6 +896,8 @@ int drm_buddy_block_trim(struct drm_buddy *mm, list_del(&block->link); mark_free(mm, block); mm->avail += drm_buddy_block_size(mm, block); + if (drm_buddy_block_is_clear(block)) + mm->clear_avail += drm_buddy_block_size(mm, block); /* Prevent recursively freeing this node */ parent = block->parent; @@ -711,6 +909,8 @@ int drm_buddy_block_trim(struct drm_buddy *mm, if (err) { mark_allocated(block); mm->avail -= drm_buddy_block_size(mm, block); + if (drm_buddy_block_is_clear(block)) + mm->clear_avail -= drm_buddy_block_size(mm, block); list_add(&block->link, blocks); } @@ -719,13 +919,28 @@ int drm_buddy_block_trim(struct drm_buddy *mm, } EXPORT_SYMBOL(drm_buddy_block_trim); +static struct drm_buddy_block * +__drm_buddy_alloc_blocks(struct drm_buddy *mm, + u64 start, u64 end, + unsigned int order, + unsigned long flags) +{ + if (flags & DRM_BUDDY_RANGE_ALLOCATION) + /* Allocate traversing within the range */ + return __drm_buddy_alloc_range_bias(mm, start, end, + order, flags); + else + /* Allocate from freelist */ + return alloc_from_freelist(mm, order, flags); +} + /** * drm_buddy_alloc_blocks - allocate power-of-two blocks * * @mm: DRM buddy manager to allocate from * @start: start of the allowed range for this block * @end: end of the allowed range for this block - * @size: size of the allocation + * @size: size of the allocation in bytes * @min_block_size: alignment of the allocation * @blocks: output list head to add allocated blocks * @flags: DRM_BUDDY_*_ALLOCATION flags @@ -800,23 +1015,33 @@ int drm_buddy_alloc_blocks(struct drm_buddy *mm, BUG_ON(order < min_order); do { - if (flags & DRM_BUDDY_RANGE_ALLOCATION) - /* Allocate traversing within the range */ - block = alloc_range_bias(mm, start, end, order); - else - /* Allocate from freelist */ - block = alloc_from_freelist(mm, order, flags); - + block = __drm_buddy_alloc_blocks(mm, start, + end, + order, + flags); if (!IS_ERR(block)) break; if (order-- == min_order) { + /* Try allocation through force merge method */ + if (mm->clear_avail && + !__force_merge(mm, start, end, min_order)) { + block = __drm_buddy_alloc_blocks(mm, start, + end, + min_order, + flags); + if (!IS_ERR(block)) { + order = min_order; + break; + } + } + + /* + * Try contiguous block allocation through + * try harder method. + */ if (flags & DRM_BUDDY_CONTIGUOUS_ALLOCATION && !(flags & DRM_BUDDY_RANGE_ALLOCATION)) - /* - * Try contiguous block allocation through - * try harder method - */ return __alloc_contig_try_harder(mm, original_size, original_min_size, @@ -828,6 +1053,8 @@ int drm_buddy_alloc_blocks(struct drm_buddy *mm, mark_allocated(block); mm->avail -= drm_buddy_block_size(mm, block); + if (drm_buddy_block_is_clear(block)) + mm->clear_avail -= drm_buddy_block_size(mm, block); kmemleak_update_trace(block); list_add_tail(&block->link, &allocated); @@ -866,7 +1093,7 @@ int drm_buddy_alloc_blocks(struct drm_buddy *mm, return 0; err_free: - drm_buddy_free_list(mm, &allocated); + drm_buddy_free_list_internal(mm, &allocated); return err; } EXPORT_SYMBOL(drm_buddy_alloc_blocks); @@ -899,8 +1126,8 @@ void drm_buddy_print(struct drm_buddy *mm, struct drm_printer *p) { int order; - drm_printf(p, "chunk_size: %lluKiB, total: %lluMiB, free: %lluMiB\n", - mm->chunk_size >> 10, mm->size >> 20, mm->avail >> 20); + drm_printf(p, "chunk_size: %lluKiB, total: %lluMiB, free: %lluMiB, clear_free: %lluMiB\n", + mm->chunk_size >> 10, mm->size >> 20, mm->avail >> 20, mm->clear_avail >> 20); for (order = mm->max_order; order >= 0; order--) { struct drm_buddy_block *block; diff --git a/drivers/gpu/drm/drm_displayid_internal.h b/drivers/gpu/drm/drm_displayid_internal.h index 56fd3bb0a779..aee1b86a73c1 100644 --- a/drivers/gpu/drm/drm_displayid_internal.h +++ b/drivers/gpu/drm/drm_displayid_internal.h @@ -31,7 +31,6 @@ struct drm_edid; #define VESA_IEEE_OUI 0x3a0292 /* DisplayID Structure versions */ -#define DISPLAY_ID_STRUCTURE_VER_12 0x12 #define DISPLAY_ID_STRUCTURE_VER_20 0x20 /* DisplayID Structure v1r2 Data Blocks */ diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 513590931cc5..4f54c91b31b2 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -7462,7 +7462,7 @@ static void drm_parse_tiled_block(struct drm_connector *connector, static bool displayid_is_tiled_block(const struct displayid_iter *iter, const struct displayid_block *block) { - return (displayid_version(iter) == DISPLAY_ID_STRUCTURE_VER_12 && + return (displayid_version(iter) < DISPLAY_ID_STRUCTURE_VER_20 && block->tag == DATA_BLOCK_TILED_DISPLAY) || (displayid_version(iter) == DISPLAY_ID_STRUCTURE_VER_20 && block->tag == DATA_BLOCK_2_TILED_DISPLAY_TOPOLOGY); diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index eecc24c54efd..57662a1fd345 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -1750,7 +1750,7 @@ int drm_plane_create_scaling_filter_property(struct drm_plane *plane, EXPORT_SYMBOL(drm_plane_create_scaling_filter_property); /** - * drm_plane_add_size_hint_property - create a size hint property + * drm_plane_add_size_hints_property - create a size hints property * * @plane: drm plane * @hints: size hints diff --git a/drivers/gpu/drm/gud/gud_connector.c b/drivers/gpu/drm/gud/gud_connector.c index 034e78360d4f..0f07d77c5d52 100644 --- a/drivers/gpu/drm/gud/gud_connector.c +++ b/drivers/gpu/drm/gud/gud_connector.c @@ -221,7 +221,7 @@ static int gud_connector_get_modes(struct drm_connector *connector) struct gud_display_mode_req *reqmodes = NULL; struct gud_connector_get_edid_ctx edid_ctx; unsigned int i, num_modes = 0; - struct edid *edid = NULL; + const struct drm_edid *drm_edid = NULL; int idx, ret; if (!drm_dev_enter(connector->dev, &idx)) @@ -238,13 +238,13 @@ static int gud_connector_get_modes(struct drm_connector *connector) gud_conn_err(connector, "Invalid EDID size", ret); } else if (ret > 0) { edid_ctx.len = ret; - edid = drm_do_get_edid(connector, gud_connector_get_edid_block, &edid_ctx); + drm_edid = drm_edid_read_custom(connector, gud_connector_get_edid_block, &edid_ctx); } kfree(edid_ctx.buf); - drm_connector_update_edid_property(connector, edid); + drm_edid_connector_update(connector, drm_edid); - if (edid && edid_ctx.edid_override) + if (drm_edid && edid_ctx.edid_override) goto out; reqmodes = kmalloc_array(GUD_CONNECTOR_MAX_NUM_MODES, sizeof(*reqmodes), GFP_KERNEL); @@ -276,10 +276,10 @@ static int gud_connector_get_modes(struct drm_connector *connector) } out: if (!num_modes) - num_modes = drm_add_edid_modes(connector, edid); + num_modes = drm_edid_connector_add_modes(connector); kfree(reqmodes); - kfree(edid); + drm_edid_free(drm_edid); drm_dev_exit(idx); return num_modes; diff --git a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c index 0d735d5c2b35..942345548bc3 100644 --- a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c +++ b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c @@ -126,7 +126,7 @@ static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man, return 0; err_free_blocks: - drm_buddy_free_list(mm, &bman_res->blocks); + drm_buddy_free_list(mm, &bman_res->blocks, 0); mutex_unlock(&bman->lock); err_free_res: ttm_resource_fini(man, &bman_res->base); @@ -141,7 +141,7 @@ static void i915_ttm_buddy_man_free(struct ttm_resource_manager *man, struct i915_ttm_buddy_manager *bman = to_buddy_manager(man); mutex_lock(&bman->lock); - drm_buddy_free_list(&bman->mm, &bman_res->blocks); + drm_buddy_free_list(&bman->mm, &bman_res->blocks, 0); bman->visible_avail += bman_res->used_visible_size; mutex_unlock(&bman->lock); @@ -345,7 +345,7 @@ int i915_ttm_buddy_man_fini(struct ttm_device *bdev, unsigned int type) ttm_set_driver_manager(bdev, type, NULL); mutex_lock(&bman->lock); - drm_buddy_free_list(mm, &bman->reserved); + drm_buddy_free_list(mm, &bman->reserved, 0); drm_buddy_fini(mm); bman->visible_avail += bman->visible_reserved; WARN_ON_ONCE(bman->visible_avail != bman->visible_size); diff --git a/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c b/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c index a6bc1bdb3d0d..a10cff3ca1fe 100644 --- a/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c +++ b/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c @@ -95,6 +95,7 @@ static int dw_mipi_dsi_phy_init(void *priv_data) return ret; } + clk_disable_unprepare(mipi_dsi->px_clk); ret = clk_set_rate(mipi_dsi->px_clk, mipi_dsi->mode->clock * 1000); if (ret) { @@ -103,6 +104,12 @@ static int dw_mipi_dsi_phy_init(void *priv_data) return ret; } + ret = clk_prepare_enable(mipi_dsi->px_clk); + if (ret) { + dev_err(mipi_dsi->dev, "Failed to enable DSI Pixel clock (ret %d)\n", ret); + return ret; + } + switch (mipi_dsi->dsi_device->format) { case MIPI_DSI_FMT_RGB888: dpi_data_format = DPI_COLOR_24BIT; diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index ab67789e59a2..e54f6f5604ed 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -553,6 +553,18 @@ config DRM_PANEL_RAYDIUM_RM692E5 Say Y here if you want to enable support for Raydium RM692E5-based display panels, such as the one found in the Fairphone 5 smartphone. +config DRM_PANEL_RAYDIUM_RM69380 + tristate "Raydium RM69380-based DSI panel" + depends on OF && GPIOLIB + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for Raydium RM69380-based + display panels. + + This panel controller can be found in the Lenovo Xiaoxin Pad Pro 2021 + in combination with an EDO OLED panel. + config DRM_PANEL_RONBO_RB070D30 tristate "Ronbo Electronics RB070D30 panel" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 0b40b010e8e7..f0203f6e02f4 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -56,6 +56,7 @@ obj-$(CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN) += panel-raspberrypi-touchscreen obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM67191) += panel-raydium-rm67191.o obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM68200) += panel-raydium-rm68200.o obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM692E5) += panel-raydium-rm692e5.o +obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM69380) += panel-raydium-rm69380.o obj-$(CONFIG_DRM_PANEL_RONBO_RB070D30) += panel-ronbo-rb070d30.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_ATNA33XC20) += panel-samsung-atna33xc20.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_DB7430) += panel-samsung-db7430.o diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index d29bacf25c12..ece1e3553c1f 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -242,7 +242,7 @@ struct panel_edp { const struct edp_panel_entry *detected_panel; - struct edid *edid; + const struct drm_edid *drm_edid; struct drm_display_mode override_mode; @@ -617,13 +617,16 @@ static int panel_edp_get_modes(struct drm_panel *panel, if (p->ddc) { pm_runtime_get_sync(panel->dev); - if (!p->edid) - p->edid = drm_get_edid(connector, p->ddc); + if (!p->drm_edid) + p->drm_edid = drm_edid_read_ddc(connector, p->ddc); + + drm_edid_connector_update(connector, p->drm_edid); + /* * If both edid and hard-coded modes exists, skip edid modes to * avoid multiple preferred modes. */ - if (p->edid && !has_hard_coded_modes) { + if (p->drm_edid && !has_hard_coded_modes) { if (has_override_edid_mode) { /* * override_edid_mode is specified. Use @@ -632,7 +635,7 @@ static int panel_edp_get_modes(struct drm_panel *panel, num += panel_edp_override_edid_mode(p, connector, p->detected_panel->override_edid_mode); } else { - num += drm_add_edid_modes(connector, p->edid); + num += drm_edid_connector_add_modes(connector); } } @@ -981,8 +984,8 @@ static void panel_edp_remove(struct device *dev) if (panel->ddc && (!panel->aux || panel->ddc != &panel->aux->ddc)) put_device(&panel->ddc->dev); - kfree(panel->edid); - panel->edid = NULL; + drm_edid_free(panel->drm_edid); + panel->drm_edid = NULL; } static void panel_edp_shutdown(struct device *dev) diff --git a/drivers/gpu/drm/panel/panel-khadas-ts050.c b/drivers/gpu/drm/panel/panel-khadas-ts050.c index b942a0162274..c54be0cc3f08 100644 --- a/drivers/gpu/drm/panel/panel-khadas-ts050.c +++ b/drivers/gpu/drm/panel/panel-khadas-ts050.c @@ -25,6 +25,7 @@ struct khadas_ts050_panel { struct regulator *supply; struct gpio_desc *reset_gpio; struct gpio_desc *enable_gpio; + struct khadas_ts050_panel_data *panel_data; bool prepared; bool enabled; @@ -32,544 +33,601 @@ struct khadas_ts050_panel { struct khadas_ts050_panel_cmd { u8 cmd; - u8 data; + u8 data[55]; + u8 size; +}; + +struct khadas_ts050_panel_data { + struct khadas_ts050_panel_cmd *init_code; + int len; +}; + +static const struct khadas_ts050_panel_cmd ts050v2_init_code[] = { + {0xB9, {0xFF, 0x83, 0x99}, 0x03}, + {0xBA, {0x63, 0x23, 0x68, 0xCF}, 0x04}, + {0xD2, {0x55}, 0x01}, + {0xB1, {0x02, 0x04, 0x70, 0x90, 0x01, 0x32, 0x33, + 0x11, 0x11, 0x4D, 0x57, 0x56, 0x73, 0x02, 0x02}, 0x0f}, + {0xB2, {0x00, 0x80, 0x80, 0xAE, 0x0A, 0x0E, 0x75, 0x11, 0x00, 0x00, 0x00}, 0x0b}, + {0xB4, {0x00, 0xFF, 0x04, 0xA4, 0x02, 0xA0, 0x00, 0x00, 0x10, 0x00, 0x00, 0x02, + 0x00, 0x24, 0x02, 0x04, 0x0A, 0x21, 0x03, 0x00, 0x00, 0x08, 0xA6, 0x88, + 0x04, 0xA4, 0x02, 0xA0, 0x00, 0x00, 0x10, 0x00, 0x00, 0x02, 0x00, 0x24, + 0x02, 0x04, 0x0A, 0x00, 0x00, 0x08, 0xA6, 0x00, 0x08, 0x11}, 0x2e}, + {0xD3, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x18, 0x32, 0x10, 0x09, 0x00, 0x09, 0x32, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x11, 0x00, 0x02, 0x02, 0x03, 0x00, 0x00, 0x00, 0x0A, + 0x40}, 0x21}, + {0xD5, {0x18, 0x18, 0x18, 0x18, 0x21, 0x20, 0x18, 0x18, 0x19, 0x19, 0x19, + 0x19, 0x18, 0x18, 0x18, 0x18, 0x03, 0x02, 0x01, 0x00, 0x2F, 0x2F, + 0x30, 0x30, 0x31, 0x31, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, 0x20}, + {0xD6, {0x18, 0x18, 0x18, 0x18, 0x20, 0x21, 0x19, 0x19, 0x18, 0x18, 0x19, + 0x19, 0x18, 0x18, 0x18, 0x18, 0x00, 0x01, 0x02, 0x03, 0x2F, 0x2F, + 0x30, 0x30, 0x31, 0x31, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, 0x20}, + {0xD8, {0x0A, 0xBE, 0xFA, 0xA0, 0x0A, 0xBE, 0xFA, 0xA0}, 0x08}, + {0xBD, {0x01}, 0x01}, + {0xD8, {0x0F, 0xFF, 0xFF, 0xE0, 0x0F, 0xFF, 0xFF, 0xE0}, 0x08}, + {0xBD, {0x02}, 0x01}, + {0xD8, {0x0F, 0xFF, 0xFF, 0xE0, 0x0F, 0xFF, 0xFF, 0xE0}, 0x08}, + {0xBD, {0x00}, 0x01}, + {0xE0, {0x01, 0x35, 0x41, 0x3B, 0x79, 0x81, 0x8C, 0x85, 0x8E, + 0x95, 0x9B, 0xA0, 0xA4, 0xAB, 0xB1, 0xB3, 0xB7, 0xC5, 0xBD, 0xC5, + 0xB6, 0xC2, 0xC2, 0x62, 0x5D, 0x66, 0x73, 0x01, 0x35, 0x41, 0x3B, + 0x79, 0x81, 0x8C, 0x85, 0x8E, 0x95, 0x9B, 0xA0, 0xA4, 0xAB, 0xB1, + 0xB3, 0xB7, 0xB5, 0xBD, 0xC5, 0xB6, 0xC2, 0xC2, 0x62, 0x5D, 0x66, + 0x73}, 0x36}, + {0xB6, {0x97, 0x97}, 0x02}, + {0xCC, {0xC8}, 0x02}, + {0xBF, {0x40, 0x41, 0x50, 0x19}, 0x04}, + {0xC6, {0xFF, 0xF9}, 0x02}, + {0xC0, {0x25, 0x5A}, 0x02}, }; /* Only the CMD1 User Command set is documented */ -static const struct khadas_ts050_panel_cmd init_code[] = { +static const struct khadas_ts050_panel_cmd ts050_init_code[] = { /* Select Unknown CMD Page (Undocumented) */ - {0xff, 0xee}, + {0xff, {0xee}, 0x01}, /* Reload CMD1: Don't reload default value to register */ - {0xfb, 0x01}, - {0x1f, 0x45}, - {0x24, 0x4f}, - {0x38, 0xc8}, - {0x39, 0x27}, - {0x1e, 0x77}, - {0x1d, 0x0f}, - {0x7e, 0x71}, - {0x7c, 0x03}, - {0xff, 0x00}, - {0xfb, 0x01}, - {0x35, 0x01}, + {0xfb, {0x01}, 0x01}, + {0x1f, {0x45}, 0x01}, + {0x24, {0x4f}, 0x01}, + {0x38, {0xc8}, 0x01}, + {0x39, {0x27}, 0x01}, + {0x1e, {0x77}, 0x01}, + {0x1d, {0x0f}, 0x01}, + {0x7e, {0x71}, 0x01}, + {0x7c, {0x03}, 0x01}, + {0xff, {0x00}, 0x01}, + {0xfb, {0x01}, 0x01}, + {0x35, {0x01}, 0x01}, /* Select CMD2 Page0 (Undocumented) */ - {0xff, 0x01}, + {0xff, {0x01}, 0x01}, /* Reload CMD1: Don't reload default value to register */ - {0xfb, 0x01}, - {0x00, 0x01}, - {0x01, 0x55}, - {0x02, 0x40}, - {0x05, 0x40}, - {0x06, 0x4a}, - {0x07, 0x24}, - {0x08, 0x0c}, - {0x0b, 0x7d}, - {0x0c, 0x7d}, - {0x0e, 0xb0}, - {0x0f, 0xae}, - {0x11, 0x10}, - {0x12, 0x10}, - {0x13, 0x03}, - {0x14, 0x4a}, - {0x15, 0x12}, - {0x16, 0x12}, - {0x18, 0x00}, - {0x19, 0x77}, - {0x1a, 0x55}, - {0x1b, 0x13}, - {0x1c, 0x00}, - {0x1d, 0x00}, - {0x1e, 0x13}, - {0x1f, 0x00}, - {0x23, 0x00}, - {0x24, 0x00}, - {0x25, 0x00}, - {0x26, 0x00}, - {0x27, 0x00}, - {0x28, 0x00}, - {0x35, 0x00}, - {0x66, 0x00}, - {0x58, 0x82}, - {0x59, 0x02}, - {0x5a, 0x02}, - {0x5b, 0x02}, - {0x5c, 0x82}, - {0x5d, 0x82}, - {0x5e, 0x02}, - {0x5f, 0x02}, - {0x72, 0x31}, + {0xfb, {0x01}, 0x01}, + {0x00, {0x01}, 0x01}, + {0x01, {0x55}, 0x01}, + {0x02, {0x40}, 0x01}, + {0x05, {0x40}, 0x01}, + {0x06, {0x4a}, 0x01}, + {0x07, {0x24}, 0x01}, + {0x08, {0x0c}, 0x01}, + {0x0b, {0x7d}, 0x01}, + {0x0c, {0x7d}, 0x01}, + {0x0e, {0xb0}, 0x01}, + {0x0f, {0xae}, 0x01}, + {0x11, {0x10}, 0x01}, + {0x12, {0x10}, 0x01}, + {0x13, {0x03}, 0x01}, + {0x14, {0x4a}, 0x01}, + {0x15, {0x12}, 0x01}, + {0x16, {0x12}, 0x01}, + {0x18, {0x00}, 0x01}, + {0x19, {0x77}, 0x01}, + {0x1a, {0x55}, 0x01}, + {0x1b, {0x13}, 0x01}, + {0x1c, {0x00}, 0x01}, + {0x1d, {0x00}, 0x01}, + {0x1e, {0x13}, 0x01}, + {0x1f, {0x00}, 0x01}, + {0x23, {0x00}, 0x01}, + {0x24, {0x00}, 0x01}, + {0x25, {0x00}, 0x01}, + {0x26, {0x00}, 0x01}, + {0x27, {0x00}, 0x01}, + {0x28, {0x00}, 0x01}, + {0x35, {0x00}, 0x01}, + {0x66, {0x00}, 0x01}, + {0x58, {0x82}, 0x01}, + {0x59, {0x02}, 0x01}, + {0x5a, {0x02}, 0x01}, + {0x5b, {0x02}, 0x01}, + {0x5c, {0x82}, 0x01}, + {0x5d, {0x82}, 0x01}, + {0x5e, {0x02}, 0x01}, + {0x5f, {0x02}, 0x01}, + {0x72, {0x31}, 0x01}, /* Select CMD2 Page4 (Undocumented) */ - {0xff, 0x05}, + {0xff, {0x05}, 0x01}, /* Reload CMD1: Don't reload default value to register */ - {0xfb, 0x01}, - {0x00, 0x01}, - {0x01, 0x0b}, - {0x02, 0x0c}, - {0x03, 0x09}, - {0x04, 0x0a}, - {0x05, 0x00}, - {0x06, 0x0f}, - {0x07, 0x10}, - {0x08, 0x00}, - {0x09, 0x00}, - {0x0a, 0x00}, - {0x0b, 0x00}, - {0x0c, 0x00}, - {0x0d, 0x13}, - {0x0e, 0x15}, - {0x0f, 0x17}, - {0x10, 0x01}, - {0x11, 0x0b}, - {0x12, 0x0c}, - {0x13, 0x09}, - {0x14, 0x0a}, - {0x15, 0x00}, - {0x16, 0x0f}, - {0x17, 0x10}, - {0x18, 0x00}, - {0x19, 0x00}, - {0x1a, 0x00}, - {0x1b, 0x00}, - {0x1c, 0x00}, - {0x1d, 0x13}, - {0x1e, 0x15}, - {0x1f, 0x17}, - {0x20, 0x00}, - {0x21, 0x03}, - {0x22, 0x01}, - {0x23, 0x40}, - {0x24, 0x40}, - {0x25, 0xed}, - {0x29, 0x58}, - {0x2a, 0x12}, - {0x2b, 0x01}, - {0x4b, 0x06}, - {0x4c, 0x11}, - {0x4d, 0x20}, - {0x4e, 0x02}, - {0x4f, 0x02}, - {0x50, 0x20}, - {0x51, 0x61}, - {0x52, 0x01}, - {0x53, 0x63}, - {0x54, 0x77}, - {0x55, 0xed}, - {0x5b, 0x00}, - {0x5c, 0x00}, - {0x5d, 0x00}, - {0x5e, 0x00}, - {0x5f, 0x15}, - {0x60, 0x75}, - {0x61, 0x00}, - {0x62, 0x00}, - {0x63, 0x00}, - {0x64, 0x00}, - {0x65, 0x00}, - {0x66, 0x00}, - {0x67, 0x00}, - {0x68, 0x04}, - {0x69, 0x00}, - {0x6a, 0x00}, - {0x6c, 0x40}, - {0x75, 0x01}, - {0x76, 0x01}, - {0x7a, 0x80}, - {0x7b, 0xa3}, - {0x7c, 0xd8}, - {0x7d, 0x60}, - {0x7f, 0x15}, - {0x80, 0x81}, - {0x83, 0x05}, - {0x93, 0x08}, - {0x94, 0x10}, - {0x8a, 0x00}, - {0x9b, 0x0f}, - {0xea, 0xff}, - {0xec, 0x00}, + {0xfb, {0x01}, 0x01}, + {0x00, {0x01}, 0x01}, + {0x01, {0x0b}, 0x01}, + {0x02, {0x0c}, 0x01}, + {0x03, {0x09}, 0x01}, + {0x04, {0x0a}, 0x01}, + {0x05, {0x00}, 0x01}, + {0x06, {0x0f}, 0x01}, + {0x07, {0x10}, 0x01}, + {0x08, {0x00}, 0x01}, + {0x09, {0x00}, 0x01}, + {0x0a, {0x00}, 0x01}, + {0x0b, {0x00}, 0x01}, + {0x0c, {0x00}, 0x01}, + {0x0d, {0x13}, 0x01}, + {0x0e, {0x15}, 0x01}, + {0x0f, {0x17}, 0x01}, + {0x10, {0x01}, 0x01}, + {0x11, {0x0b}, 0x01}, + {0x12, {0x0c}, 0x01}, + {0x13, {0x09}, 0x01}, + {0x14, {0x0a}, 0x01}, + {0x15, {0x00}, 0x01}, + {0x16, {0x0f}, 0x01}, + {0x17, {0x10}, 0x01}, + {0x18, {0x00}, 0x01}, + {0x19, {0x00}, 0x01}, + {0x1a, {0x00}, 0x01}, + {0x1b, {0x00}, 0x01}, + {0x1c, {0x00}, 0x01}, + {0x1d, {0x13}, 0x01}, + {0x1e, {0x15}, 0x01}, + {0x1f, {0x17}, 0x01}, + {0x20, {0x00}, 0x01}, + {0x21, {0x03}, 0x01}, + {0x22, {0x01}, 0x01}, + {0x23, {0x40}, 0x01}, + {0x24, {0x40}, 0x01}, + {0x25, {0xed}, 0x01}, + {0x29, {0x58}, 0x01}, + {0x2a, {0x12}, 0x01}, + {0x2b, {0x01}, 0x01}, + {0x4b, {0x06}, 0x01}, + {0x4c, {0x11}, 0x01}, + {0x4d, {0x20}, 0x01}, + {0x4e, {0x02}, 0x01}, + {0x4f, {0x02}, 0x01}, + {0x50, {0x20}, 0x01}, + {0x51, {0x61}, 0x01}, + {0x52, {0x01}, 0x01}, + {0x53, {0x63}, 0x01}, + {0x54, {0x77}, 0x01}, + {0x55, {0xed}, 0x01}, + {0x5b, {0x00}, 0x01}, + {0x5c, {0x00}, 0x01}, + {0x5d, {0x00}, 0x01}, + {0x5e, {0x00}, 0x01}, + {0x5f, {0x15}, 0x01}, + {0x60, {0x75}, 0x01}, + {0x61, {0x00}, 0x01}, + {0x62, {0x00}, 0x01}, + {0x63, {0x00}, 0x01}, + {0x64, {0x00}, 0x01}, + {0x65, {0x00}, 0x01}, + {0x66, {0x00}, 0x01}, + {0x67, {0x00}, 0x01}, + {0x68, {0x04}, 0x01}, + {0x69, {0x00}, 0x01}, + {0x6a, {0x00}, 0x01}, + {0x6c, {0x40}, 0x01}, + {0x75, {0x01}, 0x01}, + {0x76, {0x01}, 0x01}, + {0x7a, {0x80}, 0x01}, + {0x7b, {0xa3}, 0x01}, + {0x7c, {0xd8}, 0x01}, + {0x7d, {0x60}, 0x01}, + {0x7f, {0x15}, 0x01}, + {0x80, {0x81}, 0x01}, + {0x83, {0x05}, 0x01}, + {0x93, {0x08}, 0x01}, + {0x94, {0x10}, 0x01}, + {0x8a, {0x00}, 0x01}, + {0x9b, {0x0f}, 0x01}, + {0xea, {0xff}, 0x01}, + {0xec, {0x00}, 0x01}, /* Select CMD2 Page0 (Undocumented) */ - {0xff, 0x01}, + {0xff, {0x01}, 0x01}, /* Reload CMD1: Don't reload default value to register */ - {0xfb, 0x01}, - {0x75, 0x00}, - {0x76, 0xdf}, - {0x77, 0x00}, - {0x78, 0xe4}, - {0x79, 0x00}, - {0x7a, 0xed}, - {0x7b, 0x00}, - {0x7c, 0xf6}, - {0x7d, 0x00}, - {0x7e, 0xff}, - {0x7f, 0x01}, - {0x80, 0x07}, - {0x81, 0x01}, - {0x82, 0x10}, - {0x83, 0x01}, - {0x84, 0x18}, - {0x85, 0x01}, - {0x86, 0x20}, - {0x87, 0x01}, - {0x88, 0x3d}, - {0x89, 0x01}, - {0x8a, 0x56}, - {0x8b, 0x01}, - {0x8c, 0x84}, - {0x8d, 0x01}, - {0x8e, 0xab}, - {0x8f, 0x01}, - {0x90, 0xec}, - {0x91, 0x02}, - {0x92, 0x22}, - {0x93, 0x02}, - {0x94, 0x23}, - {0x95, 0x02}, - {0x96, 0x55}, - {0x97, 0x02}, - {0x98, 0x8b}, - {0x99, 0x02}, - {0x9a, 0xaf}, - {0x9b, 0x02}, - {0x9c, 0xdf}, - {0x9d, 0x03}, - {0x9e, 0x01}, - {0x9f, 0x03}, - {0xa0, 0x2c}, - {0xa2, 0x03}, - {0xa3, 0x39}, - {0xa4, 0x03}, - {0xa5, 0x47}, - {0xa6, 0x03}, - {0xa7, 0x56}, - {0xa9, 0x03}, - {0xaa, 0x66}, - {0xab, 0x03}, - {0xac, 0x76}, - {0xad, 0x03}, - {0xae, 0x85}, - {0xaf, 0x03}, - {0xb0, 0x90}, - {0xb1, 0x03}, - {0xb2, 0xcb}, - {0xb3, 0x00}, - {0xb4, 0xdf}, - {0xb5, 0x00}, - {0xb6, 0xe4}, - {0xb7, 0x00}, - {0xb8, 0xed}, - {0xb9, 0x00}, - {0xba, 0xf6}, - {0xbb, 0x00}, - {0xbc, 0xff}, - {0xbd, 0x01}, - {0xbe, 0x07}, - {0xbf, 0x01}, - {0xc0, 0x10}, - {0xc1, 0x01}, - {0xc2, 0x18}, - {0xc3, 0x01}, - {0xc4, 0x20}, - {0xc5, 0x01}, - {0xc6, 0x3d}, - {0xc7, 0x01}, - {0xc8, 0x56}, - {0xc9, 0x01}, - {0xca, 0x84}, - {0xcb, 0x01}, - {0xcc, 0xab}, - {0xcd, 0x01}, - {0xce, 0xec}, - {0xcf, 0x02}, - {0xd0, 0x22}, - {0xd1, 0x02}, - {0xd2, 0x23}, - {0xd3, 0x02}, - {0xd4, 0x55}, - {0xd5, 0x02}, - {0xd6, 0x8b}, - {0xd7, 0x02}, - {0xd8, 0xaf}, - {0xd9, 0x02}, - {0xda, 0xdf}, - {0xdb, 0x03}, - {0xdc, 0x01}, - {0xdd, 0x03}, - {0xde, 0x2c}, - {0xdf, 0x03}, - {0xe0, 0x39}, - {0xe1, 0x03}, - {0xe2, 0x47}, - {0xe3, 0x03}, - {0xe4, 0x56}, - {0xe5, 0x03}, - {0xe6, 0x66}, - {0xe7, 0x03}, - {0xe8, 0x76}, - {0xe9, 0x03}, - {0xea, 0x85}, - {0xeb, 0x03}, - {0xec, 0x90}, - {0xed, 0x03}, - {0xee, 0xcb}, - {0xef, 0x00}, - {0xf0, 0xbb}, - {0xf1, 0x00}, - {0xf2, 0xc0}, - {0xf3, 0x00}, - {0xf4, 0xcc}, - {0xf5, 0x00}, - {0xf6, 0xd6}, - {0xf7, 0x00}, - {0xf8, 0xe1}, - {0xf9, 0x00}, - {0xfa, 0xea}, + {0xfb, {0x01}, 0x01}, + {0x75, {0x00}, 0x01}, + {0x76, {0xdf}, 0x01}, + {0x77, {0x00}, 0x01}, + {0x78, {0xe4}, 0x01}, + {0x79, {0x00}, 0x01}, + {0x7a, {0xed}, 0x01}, + {0x7b, {0x00}, 0x01}, + {0x7c, {0xf6}, 0x01}, + {0x7d, {0x00}, 0x01}, + {0x7e, {0xff}, 0x01}, + {0x7f, {0x01}, 0x01}, + {0x80, {0x07}, 0x01}, + {0x81, {0x01}, 0x01}, + {0x82, {0x10}, 0x01}, + {0x83, {0x01}, 0x01}, + {0x84, {0x18}, 0x01}, + {0x85, {0x01}, 0x01}, + {0x86, {0x20}, 0x01}, + {0x87, {0x01}, 0x01}, + {0x88, {0x3d}, 0x01}, + {0x89, {0x01}, 0x01}, + {0x8a, {0x56}, 0x01}, + {0x8b, {0x01}, 0x01}, + {0x8c, {0x84}, 0x01}, + {0x8d, {0x01}, 0x01}, + {0x8e, {0xab}, 0x01}, + {0x8f, {0x01}, 0x01}, + {0x90, {0xec}, 0x01}, + {0x91, {0x02}, 0x01}, + {0x92, {0x22}, 0x01}, + {0x93, {0x02}, 0x01}, + {0x94, {0x23}, 0x01}, + {0x95, {0x02}, 0x01}, + {0x96, {0x55}, 0x01}, + {0x97, {0x02}, 0x01}, + {0x98, {0x8b}, 0x01}, + {0x99, {0x02}, 0x01}, + {0x9a, {0xaf}, 0x01}, + {0x9b, {0x02}, 0x01}, + {0x9c, {0xdf}, 0x01}, + {0x9d, {0x03}, 0x01}, + {0x9e, {0x01}, 0x01}, + {0x9f, {0x03}, 0x01}, + {0xa0, {0x2c}, 0x01}, + {0xa2, {0x03}, 0x01}, + {0xa3, {0x39}, 0x01}, + {0xa4, {0x03}, 0x01}, + {0xa5, {0x47}, 0x01}, + {0xa6, {0x03}, 0x01}, + {0xa7, {0x56}, 0x01}, + {0xa9, {0x03}, 0x01}, + {0xaa, {0x66}, 0x01}, + {0xab, {0x03}, 0x01}, + {0xac, {0x76}, 0x01}, + {0xad, {0x03}, 0x01}, + {0xae, {0x85}, 0x01}, + {0xaf, {0x03}, 0x01}, + {0xb0, {0x90}, 0x01}, + {0xb1, {0x03}, 0x01}, + {0xb2, {0xcb}, 0x01}, + {0xb3, {0x00}, 0x01}, + {0xb4, {0xdf}, 0x01}, + {0xb5, {0x00}, 0x01}, + {0xb6, {0xe4}, 0x01}, + {0xb7, {0x00}, 0x01}, + {0xb8, {0xed}, 0x01}, + {0xb9, {0x00}, 0x01}, + {0xba, {0xf6}, 0x01}, + {0xbb, {0x00}, 0x01}, + {0xbc, {0xff}, 0x01}, + {0xbd, {0x01}, 0x01}, + {0xbe, {0x07}, 0x01}, + {0xbf, {0x01}, 0x01}, + {0xc0, {0x10}, 0x01}, + {0xc1, {0x01}, 0x01}, + {0xc2, {0x18}, 0x01}, + {0xc3, {0x01}, 0x01}, + {0xc4, {0x20}, 0x01}, + {0xc5, {0x01}, 0x01}, + {0xc6, {0x3d}, 0x01}, + {0xc7, {0x01}, 0x01}, + {0xc8, {0x56}, 0x01}, + {0xc9, {0x01}, 0x01}, + {0xca, {0x84}, 0x01}, + {0xcb, {0x01}, 0x01}, + {0xcc, {0xab}, 0x01}, + {0xcd, {0x01}, 0x01}, + {0xce, {0xec}, 0x01}, + {0xcf, {0x02}, 0x01}, + {0xd0, {0x22}, 0x01}, + {0xd1, {0x02}, 0x01}, + {0xd2, {0x23}, 0x01}, + {0xd3, {0x02}, 0x01}, + {0xd4, {0x55}, 0x01}, + {0xd5, {0x02}, 0x01}, + {0xd6, {0x8b}, 0x01}, + {0xd7, {0x02}, 0x01}, + {0xd8, {0xaf}, 0x01}, + {0xd9, {0x02}, 0x01}, + {0xda, {0xdf}, 0x01}, + {0xdb, {0x03}, 0x01}, + {0xdc, {0x01}, 0x01}, + {0xdd, {0x03}, 0x01}, + {0xde, {0x2c}, 0x01}, + {0xdf, {0x03}, 0x01}, + {0xe0, {0x39}, 0x01}, + {0xe1, {0x03}, 0x01}, + {0xe2, {0x47}, 0x01}, + {0xe3, {0x03}, 0x01}, + {0xe4, {0x56}, 0x01}, + {0xe5, {0x03}, 0x01}, + {0xe6, {0x66}, 0x01}, + {0xe7, {0x03}, 0x01}, + {0xe8, {0x76}, 0x01}, + {0xe9, {0x03}, 0x01}, + {0xea, {0x85}, 0x01}, + {0xeb, {0x03}, 0x01}, + {0xec, {0x90}, 0x01}, + {0xed, {0x03}, 0x01}, + {0xee, {0xcb}, 0x01}, + {0xef, {0x00}, 0x01}, + {0xf0, {0xbb}, 0x01}, + {0xf1, {0x00}, 0x01}, + {0xf2, {0xc0}, 0x01}, + {0xf3, {0x00}, 0x01}, + {0xf4, {0xcc}, 0x01}, + {0xf5, {0x00}, 0x01}, + {0xf6, {0xd6}, 0x01}, + {0xf7, {0x00}, 0x01}, + {0xf8, {0xe1}, 0x01}, + {0xf9, {0x00}, 0x01}, + {0xfa, {0xea}, 0x01}, /* Select CMD2 Page2 (Undocumented) */ - {0xff, 0x02}, + {0xff, {0x02}, 0x01}, /* Reload CMD1: Don't reload default value to register */ - {0xfb, 0x01}, - {0x00, 0x00}, - {0x01, 0xf4}, - {0x02, 0x00}, - {0x03, 0xef}, - {0x04, 0x01}, - {0x05, 0x07}, - {0x06, 0x01}, - {0x07, 0x28}, - {0x08, 0x01}, - {0x09, 0x44}, - {0x0a, 0x01}, - {0x0b, 0x76}, - {0x0c, 0x01}, - {0x0d, 0xa0}, - {0x0e, 0x01}, - {0x0f, 0xe7}, - {0x10, 0x02}, - {0x11, 0x1f}, - {0x12, 0x02}, - {0x13, 0x22}, - {0x14, 0x02}, - {0x15, 0x54}, - {0x16, 0x02}, - {0x17, 0x8b}, - {0x18, 0x02}, - {0x19, 0xaf}, - {0x1a, 0x02}, - {0x1b, 0xe0}, - {0x1c, 0x03}, - {0x1d, 0x01}, - {0x1e, 0x03}, - {0x1f, 0x2d}, - {0x20, 0x03}, - {0x21, 0x39}, - {0x22, 0x03}, - {0x23, 0x47}, - {0x24, 0x03}, - {0x25, 0x57}, - {0x26, 0x03}, - {0x27, 0x65}, - {0x28, 0x03}, - {0x29, 0x77}, - {0x2a, 0x03}, - {0x2b, 0x85}, - {0x2d, 0x03}, - {0x2f, 0x8f}, - {0x30, 0x03}, - {0x31, 0xcb}, - {0x32, 0x00}, - {0x33, 0xbb}, - {0x34, 0x00}, - {0x35, 0xc0}, - {0x36, 0x00}, - {0x37, 0xcc}, - {0x38, 0x00}, - {0x39, 0xd6}, - {0x3a, 0x00}, - {0x3b, 0xe1}, - {0x3d, 0x00}, - {0x3f, 0xea}, - {0x40, 0x00}, - {0x41, 0xf4}, - {0x42, 0x00}, - {0x43, 0xfe}, - {0x44, 0x01}, - {0x45, 0x07}, - {0x46, 0x01}, - {0x47, 0x28}, - {0x48, 0x01}, - {0x49, 0x44}, - {0x4a, 0x01}, - {0x4b, 0x76}, - {0x4c, 0x01}, - {0x4d, 0xa0}, - {0x4e, 0x01}, - {0x4f, 0xe7}, - {0x50, 0x02}, - {0x51, 0x1f}, - {0x52, 0x02}, - {0x53, 0x22}, - {0x54, 0x02}, - {0x55, 0x54}, - {0x56, 0x02}, - {0x58, 0x8b}, - {0x59, 0x02}, - {0x5a, 0xaf}, - {0x5b, 0x02}, - {0x5c, 0xe0}, - {0x5d, 0x03}, - {0x5e, 0x01}, - {0x5f, 0x03}, - {0x60, 0x2d}, - {0x61, 0x03}, - {0x62, 0x39}, - {0x63, 0x03}, - {0x64, 0x47}, - {0x65, 0x03}, - {0x66, 0x57}, - {0x67, 0x03}, - {0x68, 0x65}, - {0x69, 0x03}, - {0x6a, 0x77}, - {0x6b, 0x03}, - {0x6c, 0x85}, - {0x6d, 0x03}, - {0x6e, 0x8f}, - {0x6f, 0x03}, - {0x70, 0xcb}, - {0x71, 0x00}, - {0x72, 0x00}, - {0x73, 0x00}, - {0x74, 0x21}, - {0x75, 0x00}, - {0x76, 0x4c}, - {0x77, 0x00}, - {0x78, 0x6b}, - {0x79, 0x00}, - {0x7a, 0x85}, - {0x7b, 0x00}, - {0x7c, 0x9a}, - {0x7d, 0x00}, - {0x7e, 0xad}, - {0x7f, 0x00}, - {0x80, 0xbe}, - {0x81, 0x00}, - {0x82, 0xcd}, - {0x83, 0x01}, - {0x84, 0x01}, - {0x85, 0x01}, - {0x86, 0x29}, - {0x87, 0x01}, - {0x88, 0x68}, - {0x89, 0x01}, - {0x8a, 0x98}, - {0x8b, 0x01}, - {0x8c, 0xe5}, - {0x8d, 0x02}, - {0x8e, 0x1e}, - {0x8f, 0x02}, - {0x90, 0x30}, - {0x91, 0x02}, - {0x92, 0x52}, - {0x93, 0x02}, - {0x94, 0x88}, - {0x95, 0x02}, - {0x96, 0xaa}, - {0x97, 0x02}, - {0x98, 0xd7}, - {0x99, 0x02}, - {0x9a, 0xf7}, - {0x9b, 0x03}, - {0x9c, 0x21}, - {0x9d, 0x03}, - {0x9e, 0x2e}, - {0x9f, 0x03}, - {0xa0, 0x3d}, - {0xa2, 0x03}, - {0xa3, 0x4c}, - {0xa4, 0x03}, - {0xa5, 0x5e}, - {0xa6, 0x03}, - {0xa7, 0x71}, - {0xa9, 0x03}, - {0xaa, 0x86}, - {0xab, 0x03}, - {0xac, 0x94}, - {0xad, 0x03}, - {0xae, 0xfa}, - {0xaf, 0x00}, - {0xb0, 0x00}, - {0xb1, 0x00}, - {0xb2, 0x21}, - {0xb3, 0x00}, - {0xb4, 0x4c}, - {0xb5, 0x00}, - {0xb6, 0x6b}, - {0xb7, 0x00}, - {0xb8, 0x85}, - {0xb9, 0x00}, - {0xba, 0x9a}, - {0xbb, 0x00}, - {0xbc, 0xad}, - {0xbd, 0x00}, - {0xbe, 0xbe}, - {0xbf, 0x00}, - {0xc0, 0xcd}, - {0xc1, 0x01}, - {0xc2, 0x01}, - {0xc3, 0x01}, - {0xc4, 0x29}, - {0xc5, 0x01}, - {0xc6, 0x68}, - {0xc7, 0x01}, - {0xc8, 0x98}, - {0xc9, 0x01}, - {0xca, 0xe5}, - {0xcb, 0x02}, - {0xcc, 0x1e}, - {0xcd, 0x02}, - {0xce, 0x20}, - {0xcf, 0x02}, - {0xd0, 0x52}, - {0xd1, 0x02}, - {0xd2, 0x88}, - {0xd3, 0x02}, - {0xd4, 0xaa}, - {0xd5, 0x02}, - {0xd6, 0xd7}, - {0xd7, 0x02}, - {0xd8, 0xf7}, - {0xd9, 0x03}, - {0xda, 0x21}, - {0xdb, 0x03}, - {0xdc, 0x2e}, - {0xdd, 0x03}, - {0xde, 0x3d}, - {0xdf, 0x03}, - {0xe0, 0x4c}, - {0xe1, 0x03}, - {0xe2, 0x5e}, - {0xe3, 0x03}, - {0xe4, 0x71}, - {0xe5, 0x03}, - {0xe6, 0x86}, - {0xe7, 0x03}, - {0xe8, 0x94}, - {0xe9, 0x03}, - {0xea, 0xfa}, + {0xfb, {0x01}, 0x01}, + {0x00, {0x00}, 0x01}, + {0x01, {0xf4}, 0x01}, + {0x02, {0x00}, 0x01}, + {0x03, {0xef}, 0x01}, + {0x04, {0x01}, 0x01}, + {0x05, {0x07}, 0x01}, + {0x06, {0x01}, 0x01}, + {0x07, {0x28}, 0x01}, + {0x08, {0x01}, 0x01}, + {0x09, {0x44}, 0x01}, + {0x0a, {0x01}, 0x01}, + {0x0b, {0x76}, 0x01}, + {0x0c, {0x01}, 0x01}, + {0x0d, {0xa0}, 0x01}, + {0x0e, {0x01}, 0x01}, + {0x0f, {0xe7}, 0x01}, + {0x10, {0x02}, 0x01}, + {0x11, {0x1f}, 0x01}, + {0x12, {0x02}, 0x01}, + {0x13, {0x22}, 0x01}, + {0x14, {0x02}, 0x01}, + {0x15, {0x54}, 0x01}, + {0x16, {0x02}, 0x01}, + {0x17, {0x8b}, 0x01}, + {0x18, {0x02}, 0x01}, + {0x19, {0xaf}, 0x01}, + {0x1a, {0x02}, 0x01}, + {0x1b, {0xe0}, 0x01}, + {0x1c, {0x03}, 0x01}, + {0x1d, {0x01}, 0x01}, + {0x1e, {0x03}, 0x01}, + {0x1f, {0x2d}, 0x01}, + {0x20, {0x03}, 0x01}, + {0x21, {0x39}, 0x01}, + {0x22, {0x03}, 0x01}, + {0x23, {0x47}, 0x01}, + {0x24, {0x03}, 0x01}, + {0x25, {0x57}, 0x01}, + {0x26, {0x03}, 0x01}, + {0x27, {0x65}, 0x01}, + {0x28, {0x03}, 0x01}, + {0x29, {0x77}, 0x01}, + {0x2a, {0x03}, 0x01}, + {0x2b, {0x85}, 0x01}, + {0x2d, {0x03}, 0x01}, + {0x2f, {0x8f}, 0x01}, + {0x30, {0x03}, 0x01}, + {0x31, {0xcb}, 0x01}, + {0x32, {0x00}, 0x01}, + {0x33, {0xbb}, 0x01}, + {0x34, {0x00}, 0x01}, + {0x35, {0xc0}, 0x01}, + {0x36, {0x00}, 0x01}, + {0x37, {0xcc}, 0x01}, + {0x38, {0x00}, 0x01}, + {0x39, {0xd6}, 0x01}, + {0x3a, {0x00}, 0x01}, + {0x3b, {0xe1}, 0x01}, + {0x3d, {0x00}, 0x01}, + {0x3f, {0xea}, 0x01}, + {0x40, {0x00}, 0x01}, + {0x41, {0xf4}, 0x01}, + {0x42, {0x00}, 0x01}, + {0x43, {0xfe}, 0x01}, + {0x44, {0x01}, 0x01}, + {0x45, {0x07}, 0x01}, + {0x46, {0x01}, 0x01}, + {0x47, {0x28}, 0x01}, + {0x48, {0x01}, 0x01}, + {0x49, {0x44}, 0x01}, + {0x4a, {0x01}, 0x01}, + {0x4b, {0x76}, 0x01}, + {0x4c, {0x01}, 0x01}, + {0x4d, {0xa0}, 0x01}, + {0x4e, {0x01}, 0x01}, + {0x4f, {0xe7}, 0x01}, + {0x50, {0x02}, 0x01}, + {0x51, {0x1f}, 0x01}, + {0x52, {0x02}, 0x01}, + {0x53, {0x22}, 0x01}, + {0x54, {0x02}, 0x01}, + {0x55, {0x54}, 0x01}, + {0x56, {0x02}, 0x01}, + {0x58, {0x8b}, 0x01}, + {0x59, {0x02}, 0x01}, + {0x5a, {0xaf}, 0x01}, + {0x5b, {0x02}, 0x01}, + {0x5c, {0xe0}, 0x01}, + {0x5d, {0x03}, 0x01}, + {0x5e, {0x01}, 0x01}, + {0x5f, {0x03}, 0x01}, + {0x60, {0x2d}, 0x01}, + {0x61, {0x03}, 0x01}, + {0x62, {0x39}, 0x01}, + {0x63, {0x03}, 0x01}, + {0x64, {0x47}, 0x01}, + {0x65, {0x03}, 0x01}, + {0x66, {0x57}, 0x01}, + {0x67, {0x03}, 0x01}, + {0x68, {0x65}, 0x01}, + {0x69, {0x03}, 0x01}, + {0x6a, {0x77}, 0x01}, + {0x6b, {0x03}, 0x01}, + {0x6c, {0x85}, 0x01}, + {0x6d, {0x03}, 0x01}, + {0x6e, {0x8f}, 0x01}, + {0x6f, {0x03}, 0x01}, + {0x70, {0xcb}, 0x01}, + {0x71, {0x00}, 0x01}, + {0x72, {0x00}, 0x01}, + {0x73, {0x00}, 0x01}, + {0x74, {0x21}, 0x01}, + {0x75, {0x00}, 0x01}, + {0x76, {0x4c}, 0x01}, + {0x77, {0x00}, 0x01}, + {0x78, {0x6b}, 0x01}, + {0x79, {0x00}, 0x01}, + {0x7a, {0x85}, 0x01}, + {0x7b, {0x00}, 0x01}, + {0x7c, {0x9a}, 0x01}, + {0x7d, {0x00}, 0x01}, + {0x7e, {0xad}, 0x01}, + {0x7f, {0x00}, 0x01}, + {0x80, {0xbe}, 0x01}, + {0x81, {0x00}, 0x01}, + {0x82, {0xcd}, 0x01}, + {0x83, {0x01}, 0x01}, + {0x84, {0x01}, 0x01}, + {0x85, {0x01}, 0x01}, + {0x86, {0x29}, 0x01}, + {0x87, {0x01}, 0x01}, + {0x88, {0x68}, 0x01}, + {0x89, {0x01}, 0x01}, + {0x8a, {0x98}, 0x01}, + {0x8b, {0x01}, 0x01}, + {0x8c, {0xe5}, 0x01}, + {0x8d, {0x02}, 0x01}, + {0x8e, {0x1e}, 0x01}, + {0x8f, {0x02}, 0x01}, + {0x90, {0x30}, 0x01}, + {0x91, {0x02}, 0x01}, + {0x92, {0x52}, 0x01}, + {0x93, {0x02}, 0x01}, + {0x94, {0x88}, 0x01}, + {0x95, {0x02}, 0x01}, + {0x96, {0xaa}, 0x01}, + {0x97, {0x02}, 0x01}, + {0x98, {0xd7}, 0x01}, + {0x99, {0x02}, 0x01}, + {0x9a, {0xf7}, 0x01}, + {0x9b, {0x03}, 0x01}, + {0x9c, {0x21}, 0x01}, + {0x9d, {0x03}, 0x01}, + {0x9e, {0x2e}, 0x01}, + {0x9f, {0x03}, 0x01}, + {0xa0, {0x3d}, 0x01}, + {0xa2, {0x03}, 0x01}, + {0xa3, {0x4c}, 0x01}, + {0xa4, {0x03}, 0x01}, + {0xa5, {0x5e}, 0x01}, + {0xa6, {0x03}, 0x01}, + {0xa7, {0x71}, 0x01}, + {0xa9, {0x03}, 0x01}, + {0xaa, {0x86}, 0x01}, + {0xab, {0x03}, 0x01}, + {0xac, {0x94}, 0x01}, + {0xad, {0x03}, 0x01}, + {0xae, {0xfa}, 0x01}, + {0xaf, {0x00}, 0x01}, + {0xb0, {0x00}, 0x01}, + {0xb1, {0x00}, 0x01}, + {0xb2, {0x21}, 0x01}, + {0xb3, {0x00}, 0x01}, + {0xb4, {0x4c}, 0x01}, + {0xb5, {0x00}, 0x01}, + {0xb6, {0x6b}, 0x01}, + {0xb7, {0x00}, 0x01}, + {0xb8, {0x85}, 0x01}, + {0xb9, {0x00}, 0x01}, + {0xba, {0x9a}, 0x01}, + {0xbb, {0x00}, 0x01}, + {0xbc, {0xad}, 0x01}, + {0xbd, {0x00}, 0x01}, + {0xbe, {0xbe}, 0x01}, + {0xbf, {0x00}, 0x01}, + {0xc0, {0xcd}, 0x01}, + {0xc1, {0x01}, 0x01}, + {0xc2, {0x01}, 0x01}, + {0xc3, {0x01}, 0x01}, + {0xc4, {0x29}, 0x01}, + {0xc5, {0x01}, 0x01}, + {0xc6, {0x68}, 0x01}, + {0xc7, {0x01}, 0x01}, + {0xc8, {0x98}, 0x01}, + {0xc9, {0x01}, 0x01}, + {0xca, {0xe5}, 0x01}, + {0xcb, {0x02}, 0x01}, + {0xcc, {0x1e}, 0x01}, + {0xcd, {0x02}, 0x01}, + {0xce, {0x20}, 0x01}, + {0xcf, {0x02}, 0x01}, + {0xd0, {0x52}, 0x01}, + {0xd1, {0x02}, 0x01}, + {0xd2, {0x88}, 0x01}, + {0xd3, {0x02}, 0x01}, + {0xd4, {0xaa}, 0x01}, + {0xd5, {0x02}, 0x01}, + {0xd6, {0xd7}, 0x01}, + {0xd7, {0x02}, 0x01}, + {0xd8, {0xf7}, 0x01}, + {0xd9, {0x03}, 0x01}, + {0xda, {0x21}, 0x01}, + {0xdb, {0x03}, 0x01}, + {0xdc, {0x2e}, 0x01}, + {0xdd, {0x03}, 0x01}, + {0xde, {0x3d}, 0x01}, + {0xdf, {0x03}, 0x01}, + {0xe0, {0x4c}, 0x01}, + {0xe1, {0x03}, 0x01}, + {0xe2, {0x5e}, 0x01}, + {0xe3, {0x03}, 0x01}, + {0xe4, {0x71}, 0x01}, + {0xe5, {0x03}, 0x01}, + {0xe6, {0x86}, 0x01}, + {0xe7, {0x03}, 0x01}, + {0xe8, {0x94}, 0x01}, + {0xe9, {0x03}, 0x01}, + {0xea, {0xfa}, 0x01}, /* Select CMD2 Page0 (Undocumented) */ - {0xff, 0x01}, + {0xff, {0x01}, 0x01}, /* Reload CMD1: Don't reload default value to register */ - {0xfb, 0x01}, + {0xfb, {0x01}, 0x01}, /* Select CMD2 Page1 (Undocumented) */ - {0xff, 0x02}, + {0xff, {0x02}, 0x01}, /* Reload CMD1: Don't reload default value to register */ - {0xfb, 0x01}, + {0xfb, {0x01}, 0x01}, /* Select CMD2 Page3 (Undocumented) */ - {0xff, 0x04}, + {0xff, {0x04}, 0x01}, /* Reload CMD1: Don't reload default value to register */ - {0xfb, 0x01}, + {0xfb, {0x01}, 0x01}, /* Select CMD1 */ - {0xff, 0x00}, - {0xd3, 0x22}, /* RGBMIPICTRL: VSYNC back porch = 34 */ - {0xd4, 0x04}, /* RGBMIPICTRL: VSYNC front porch = 4 */ + {0xff, {0x00}, 0x01}, + {0xd3, {0x22}, 0x01}, /* RGBMIPICTRL: VSYNC back porch = 34 */ + {0xd4, {0x04}, 0x01}, /* RGBMIPICTRL: VSYNC front porch = 4 */ +}; + +struct khadas_ts050_panel_data ts050_panel_data = { + .init_code = (struct khadas_ts050_panel_cmd *)ts050_init_code, + .len = ARRAY_SIZE(ts050_init_code) +}; + +struct khadas_ts050_panel_data ts050v2_panel_data = { + .init_code = (struct khadas_ts050_panel_cmd *)ts050v2_init_code, + .len = ARRAY_SIZE(ts050v2_init_code) }; static inline @@ -613,10 +671,11 @@ static int khadas_ts050_panel_prepare(struct drm_panel *panel) msleep(100); - for (i = 0; i < ARRAY_SIZE(init_code); i++) { + for (i = 0; i < khadas_ts050->panel_data->len; i++) { err = mipi_dsi_dcs_write(khadas_ts050->link, - init_code[i].cmd, - &init_code[i].data, 1); + khadas_ts050->panel_data->init_code[i].cmd, + &khadas_ts050->panel_data->init_code[i].data, + khadas_ts050->panel_data->init_code[i].size); if (err < 0) { dev_err(panel->dev, "failed write cmds: %d\n", err); goto poweroff; @@ -762,7 +821,8 @@ static const struct drm_panel_funcs khadas_ts050_panel_funcs = { }; static const struct of_device_id khadas_ts050_of_match[] = { - { .compatible = "khadas,ts050", }, + { .compatible = "khadas,ts050", .data = &ts050_panel_data, }, + { .compatible = "khadas,ts050v2", .data = &ts050v2_panel_data, }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, khadas_ts050_of_match); @@ -806,6 +866,13 @@ static int khadas_ts050_panel_probe(struct mipi_dsi_device *dsi) struct khadas_ts050_panel *khadas_ts050; int err; + const void *data = of_device_get_match_data(&dsi->dev); + + if (!data) { + dev_err(&dsi->dev, "No matching data\n"); + return -ENODEV; + } + dsi->lanes = 4; dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | @@ -816,6 +883,7 @@ static int khadas_ts050_panel_probe(struct mipi_dsi_device *dsi) if (!khadas_ts050) return -ENOMEM; + khadas_ts050->panel_data = (struct khadas_ts050_panel_data *)data; mipi_dsi_set_drvdata(dsi, khadas_ts050); khadas_ts050->link = dsi; diff --git a/drivers/gpu/drm/panel/panel-raydium-rm69380.c b/drivers/gpu/drm/panel/panel-raydium-rm69380.c new file mode 100644 index 000000000000..4dca6802faef --- /dev/null +++ b/drivers/gpu/drm/panel/panel-raydium-rm69380.c @@ -0,0 +1,344 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree. + * Copyright (c) 2024 David Wronek <david@mainlining.org> + */ + +#include <linux/backlight.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_graph.h> +#include <linux/regulator/consumer.h> + +#include <video/mipi_display.h> + +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> +#include <drm/drm_probe_helper.h> + +struct rm69380_panel { + struct drm_panel panel; + struct mipi_dsi_device *dsi[2]; + struct regulator_bulk_data supplies[2]; + struct gpio_desc *reset_gpio; +}; + +static inline +struct rm69380_panel *to_rm69380_panel(struct drm_panel *panel) +{ + return container_of(panel, struct rm69380_panel, panel); +} + +static void rm69380_reset(struct rm69380_panel *ctx) +{ + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + usleep_range(15000, 16000); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + usleep_range(10000, 11000); + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + msleep(30); +} + +static int rm69380_on(struct rm69380_panel *ctx) +{ + struct mipi_dsi_device *dsi = ctx->dsi[0]; + struct device *dev = &dsi->dev; + int ret; + + dsi->mode_flags |= MIPI_DSI_MODE_LPM; + if (ctx->dsi[1]) + ctx->dsi[1]->mode_flags |= MIPI_DSI_MODE_LPM; + + mipi_dsi_dcs_write_seq(dsi, 0xfe, 0xd4); + mipi_dsi_dcs_write_seq(dsi, 0x00, 0x80); + mipi_dsi_dcs_write_seq(dsi, 0xfe, 0xd0); + mipi_dsi_dcs_write_seq(dsi, 0x48, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xfe, 0x26); + mipi_dsi_dcs_write_seq(dsi, 0x75, 0x3f); + mipi_dsi_dcs_write_seq(dsi, 0x1d, 0x1a); + mipi_dsi_dcs_write_seq(dsi, 0xfe, 0x00); + mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x28); + mipi_dsi_dcs_write_seq(dsi, 0xc2, 0x08); + + ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK); + if (ret < 0) { + dev_err(dev, "Failed to set tear on: %d\n", ret); + return ret; + } + + ret = mipi_dsi_dcs_exit_sleep_mode(dsi); + if (ret < 0) { + dev_err(dev, "Failed to exit sleep mode: %d\n", ret); + return ret; + } + msleep(20); + + ret = mipi_dsi_dcs_set_display_on(dsi); + if (ret < 0) { + dev_err(dev, "Failed to set display on: %d\n", ret); + return ret; + } + msleep(36); + + return 0; +} + +static int rm69380_off(struct rm69380_panel *ctx) +{ + struct mipi_dsi_device *dsi = ctx->dsi[0]; + struct device *dev = &dsi->dev; + int ret; + + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + if (ctx->dsi[1]) + ctx->dsi[1]->mode_flags &= ~MIPI_DSI_MODE_LPM; + + ret = mipi_dsi_dcs_set_display_off(dsi); + if (ret < 0) { + dev_err(dev, "Failed to set display off: %d\n", ret); + return ret; + } + msleep(35); + + ret = mipi_dsi_dcs_enter_sleep_mode(dsi); + if (ret < 0) { + dev_err(dev, "Failed to enter sleep mode: %d\n", ret); + return ret; + } + msleep(20); + + return 0; +} + +static int rm69380_prepare(struct drm_panel *panel) +{ + struct rm69380_panel *ctx = to_rm69380_panel(panel); + struct device *dev = &ctx->dsi[0]->dev; + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + if (ret < 0) { + dev_err(dev, "Failed to enable regulators: %d\n", ret); + return ret; + } + + rm69380_reset(ctx); + + ret = rm69380_on(ctx); + if (ret < 0) { + dev_err(dev, "Failed to initialize panel: %d\n", ret); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + return ret; + } + + return 0; +} + +static int rm69380_unprepare(struct drm_panel *panel) +{ + struct rm69380_panel *ctx = to_rm69380_panel(panel); + struct device *dev = &ctx->dsi[0]->dev; + int ret; + + ret = rm69380_off(ctx); + if (ret < 0) + dev_err(dev, "Failed to un-initialize panel: %d\n", ret); + + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + + return 0; +} + +static const struct drm_display_mode rm69380_mode = { + .clock = (2560 + 32 + 12 + 38) * (1600 + 20 + 4 + 8) * 90 / 1000, + .hdisplay = 2560, + .hsync_start = 2560 + 32, + .hsync_end = 2560 + 32 + 12, + .htotal = 2560 + 32 + 12 + 38, + .vdisplay = 1600, + .vsync_start = 1600 + 20, + .vsync_end = 1600 + 20 + 4, + .vtotal = 1600 + 20 + 4 + 8, + .width_mm = 248, + .height_mm = 155, + .type = DRM_MODE_TYPE_DRIVER, +}; + +static int rm69380_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + return drm_connector_helper_get_modes_fixed(connector, &rm69380_mode); +} + +static const struct drm_panel_funcs rm69380_panel_funcs = { + .prepare = rm69380_prepare, + .unprepare = rm69380_unprepare, + .get_modes = rm69380_get_modes, +}; + +static int rm69380_bl_update_status(struct backlight_device *bl) +{ + struct mipi_dsi_device *dsi = bl_get_data(bl); + u16 brightness = backlight_get_brightness(bl); + int ret; + + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + + ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness); + if (ret < 0) + return ret; + + dsi->mode_flags |= MIPI_DSI_MODE_LPM; + + return 0; +} + +static int rm69380_bl_get_brightness(struct backlight_device *bl) +{ + struct mipi_dsi_device *dsi = bl_get_data(bl); + u16 brightness; + int ret; + + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + + ret = mipi_dsi_dcs_get_display_brightness_large(dsi, &brightness); + if (ret < 0) + return ret; + + dsi->mode_flags |= MIPI_DSI_MODE_LPM; + + return brightness; +} + +static const struct backlight_ops rm69380_bl_ops = { + .update_status = rm69380_bl_update_status, + .get_brightness = rm69380_bl_get_brightness, +}; + +static struct backlight_device * +rm69380_create_backlight(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + const struct backlight_properties props = { + .type = BACKLIGHT_RAW, + .brightness = 511, + .max_brightness = 2047, + }; + + return devm_backlight_device_register(dev, dev_name(dev), dev, dsi, + &rm69380_bl_ops, &props); +} + +static int rm69380_probe(struct mipi_dsi_device *dsi) +{ + struct mipi_dsi_host *dsi_sec_host; + struct rm69380_panel *ctx; + struct device *dev = &dsi->dev; + struct device_node *dsi_sec; + int ret, i; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->supplies[0].supply = "vddio"; + ctx->supplies[1].supply = "avdd"; + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), + ctx->supplies); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to get regulators\n"); + + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(ctx->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), + "Failed to get reset-gpios\n"); + + dsi_sec = of_graph_get_remote_node(dsi->dev.of_node, 1, -1); + + if (dsi_sec) { + const struct mipi_dsi_device_info info = { "RM69380 DSI1", 0, + dsi_sec }; + + dsi_sec_host = of_find_mipi_dsi_host_by_node(dsi_sec); + of_node_put(dsi_sec); + if (!dsi_sec_host) + return dev_err_probe(dev, -EPROBE_DEFER, + "Cannot get secondary DSI host\n"); + + ctx->dsi[1] = + devm_mipi_dsi_device_register_full(dev, dsi_sec_host, &info); + if (IS_ERR(ctx->dsi[1])) + return dev_err_probe(dev, PTR_ERR(ctx->dsi[1]), + "Cannot get secondary DSI node\n"); + + mipi_dsi_set_drvdata(ctx->dsi[1], ctx); + } + + ctx->dsi[0] = dsi; + mipi_dsi_set_drvdata(dsi, ctx); + + drm_panel_init(&ctx->panel, dev, &rm69380_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + ctx->panel.prepare_prev_first = true; + + ctx->panel.backlight = rm69380_create_backlight(dsi); + if (IS_ERR(ctx->panel.backlight)) + return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight), + "Failed to create backlight\n"); + + drm_panel_add(&ctx->panel); + + for (i = 0; i < ARRAY_SIZE(ctx->dsi); i++) { + if (!ctx->dsi[i]) + continue; + + dev_dbg(&ctx->dsi[i]->dev, "Binding DSI %d\n", i); + + ctx->dsi[i]->lanes = 4; + ctx->dsi[i]->format = MIPI_DSI_FMT_RGB888; + ctx->dsi[i]->mode_flags = MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_CLOCK_NON_CONTINUOUS; + + ret = devm_mipi_dsi_attach(dev, ctx->dsi[i]); + if (ret < 0) { + drm_panel_remove(&ctx->panel); + return dev_err_probe(dev, ret, + "Failed to attach to DSI%d\n", i); + } + } + + return 0; +} + +static void rm69380_remove(struct mipi_dsi_device *dsi) +{ + struct rm69380_panel *ctx = mipi_dsi_get_drvdata(dsi); + + drm_panel_remove(&ctx->panel); +} + +static const struct of_device_id rm69380_of_match[] = { + { .compatible = "lenovo,j716f-edo-rm69380" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rm69380_of_match); + +static struct mipi_dsi_driver rm69380_panel_driver = { + .probe = rm69380_probe, + .remove = rm69380_remove, + .driver = { + .name = "panel-raydium-rm69380", + .of_match_table = rm69380_of_match, + }, +}; +module_mipi_dsi_driver(rm69380_panel_driver); + +MODULE_AUTHOR("David Wronek <david@mainlining.org"); +MODULE_DESCRIPTION("DRM driver for Raydium RM69380-equipped DSI panels"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-samsung-atna33xc20.c b/drivers/gpu/drm/panel/panel-samsung-atna33xc20.c index 6828a4f24d14..a9f0d214a900 100644 --- a/drivers/gpu/drm/panel/panel-samsung-atna33xc20.c +++ b/drivers/gpu/drm/panel/panel-samsung-atna33xc20.c @@ -36,7 +36,7 @@ struct atana33xc20_panel { struct gpio_desc *el_on3_gpio; struct drm_dp_aux *aux; - struct edid *edid; + const struct drm_edid *drm_edid; ktime_t powered_off_time; ktime_t powered_on_time; @@ -253,9 +253,12 @@ static int atana33xc20_get_modes(struct drm_panel *panel, pm_runtime_get_sync(panel->dev); - if (!p->edid) - p->edid = drm_get_edid(connector, &aux_ep->aux->ddc); - num = drm_add_edid_modes(connector, p->edid); + if (!p->drm_edid) + p->drm_edid = drm_edid_read_ddc(connector, &aux_ep->aux->ddc); + + drm_edid_connector_update(connector, p->drm_edid); + + num = drm_edid_connector_add_modes(connector); pm_runtime_mark_last_busy(panel->dev); pm_runtime_put_autosuspend(panel->dev); @@ -351,7 +354,7 @@ static void atana33xc20_remove(struct dp_aux_ep_device *aux_ep) drm_panel_disable(&panel->base); drm_panel_unprepare(&panel->base); - kfree(panel->edid); + drm_edid_free(panel->drm_edid); } static void atana33xc20_shutdown(struct dp_aux_ep_device *aux_ep) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 50c855476d78..dcb6d0b6ced0 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -151,7 +151,7 @@ struct panel_simple { struct gpio_desc *enable_gpio; - struct edid *edid; + const struct drm_edid *drm_edid; struct drm_display_mode override_mode; @@ -309,8 +309,8 @@ static int panel_simple_suspend(struct device *dev) regulator_disable(p->supply); p->unprepared_time = ktime_get_boottime(); - kfree(p->edid); - p->edid = NULL; + drm_edid_free(p->drm_edid); + p->drm_edid = NULL; return 0; } @@ -399,11 +399,12 @@ static int panel_simple_get_modes(struct drm_panel *panel, if (p->ddc) { pm_runtime_get_sync(panel->dev); - if (!p->edid) - p->edid = drm_get_edid(connector, p->ddc); + if (!p->drm_edid) + p->drm_edid = drm_edid_read_ddc(connector, p->ddc); - if (p->edid) - num += drm_add_edid_modes(connector, p->edid); + drm_edid_connector_update(connector, p->drm_edid); + + num += drm_edid_connector_add_modes(connector); pm_runtime_mark_last_busy(panel->dev); pm_runtime_put_autosuspend(panel->dev); diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c index d4bc652b34d5..b3a51a6de523 100644 --- a/drivers/gpu/drm/panthor/panthor_sched.c +++ b/drivers/gpu/drm/panthor/panthor_sched.c @@ -2546,7 +2546,7 @@ void panthor_sched_suspend(struct panthor_device *ptdev) { struct panthor_scheduler *sched = ptdev->scheduler; struct panthor_csg_slots_upd_ctx upd_ctx; - u64 suspended_slots, faulty_slots; + u32 suspended_slots, faulty_slots; struct panthor_group *group; u32 i; diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index a855c45ae7f3..bd7aa891b839 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -262,20 +262,21 @@ static const struct drm_connector_funcs cdn_dp_atomic_connector_funcs = { static int cdn_dp_connector_get_modes(struct drm_connector *connector) { struct cdn_dp_device *dp = connector_to_dp(connector); - struct edid *edid; int ret = 0; mutex_lock(&dp->lock); - edid = dp->edid; - if (edid) { + + if (dp->drm_edid) { + /* FIXME: get rid of drm_edid_raw() */ + const struct edid *edid = drm_edid_raw(dp->drm_edid); + DRM_DEV_DEBUG_KMS(dp->dev, "got edid: width[%d] x height[%d]\n", edid->width_cm, edid->height_cm); - dp->sink_has_audio = drm_detect_monitor_audio(edid); - - drm_connector_update_edid_property(connector, edid); - ret = drm_add_edid_modes(connector, edid); } + + ret = drm_edid_connector_add_modes(connector); + mutex_unlock(&dp->lock); return ret; @@ -380,9 +381,13 @@ static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp) return ret; } - kfree(dp->edid); - dp->edid = drm_do_get_edid(&dp->connector, - cdn_dp_get_edid_block, dp); + drm_edid_free(dp->drm_edid); + dp->drm_edid = drm_edid_read_custom(&dp->connector, + cdn_dp_get_edid_block, dp); + drm_edid_connector_update(&dp->connector, dp->drm_edid); + + dp->sink_has_audio = dp->connector.display_info.has_audio; + return 0; } @@ -488,8 +493,8 @@ static int cdn_dp_disable(struct cdn_dp_device *dp) dp->max_lanes = 0; dp->max_rate = 0; if (!dp->connected) { - kfree(dp->edid); - dp->edid = NULL; + drm_edid_free(dp->drm_edid); + dp->drm_edid = NULL; } return 0; @@ -1131,8 +1136,8 @@ static void cdn_dp_unbind(struct device *dev, struct device *master, void *data) pm_runtime_disable(dev); if (dp->fw_loaded) release_firmware(dp->fw); - kfree(dp->edid); - dp->edid = NULL; + drm_edid_free(dp->drm_edid); + dp->drm_edid = NULL; } static const struct component_ops cdn_dp_component_ops = { @@ -1259,7 +1264,6 @@ struct platform_driver cdn_dp_driver = { .shutdown = cdn_dp_shutdown, .driver = { .name = "cdn-dp", - .owner = THIS_MODULE, .of_match_table = cdn_dp_dt_ids, .pm = &cdn_dp_pm_ops, }, diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index 5b2fed1f5f55..8e6e95d269da 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -70,7 +70,7 @@ struct cdn_dp_device { struct drm_display_mode mode; struct platform_device *audio_pdev; struct work_struct event_work; - struct edid *edid; + const struct drm_edid *drm_edid; struct mutex lock; bool connected; diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 1d2261643743..3df2cfcf9998 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -606,18 +606,16 @@ inno_hdmi_connector_detect(struct drm_connector *connector, bool force) static int inno_hdmi_connector_get_modes(struct drm_connector *connector) { struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector); - struct edid *edid; + const struct drm_edid *drm_edid; int ret = 0; if (!hdmi->ddc) return 0; - edid = drm_get_edid(connector, hdmi->ddc); - if (edid) { - drm_connector_update_edid_property(connector, edid); - ret = drm_add_edid_modes(connector, edid); - kfree(edid); - } + drm_edid = drm_edid_read_ddc(connector, hdmi->ddc); + drm_edid_connector_update(connector, drm_edid); + ret = drm_edid_connector_add_modes(connector); + drm_edid_free(drm_edid); return ret; } diff --git a/drivers/gpu/drm/rockchip/rk3066_hdmi.c b/drivers/gpu/drm/rockchip/rk3066_hdmi.c index 95cd1b49eda8..784de990da1b 100644 --- a/drivers/gpu/drm/rockchip/rk3066_hdmi.c +++ b/drivers/gpu/drm/rockchip/rk3066_hdmi.c @@ -466,18 +466,16 @@ rk3066_hdmi_connector_detect(struct drm_connector *connector, bool force) static int rk3066_hdmi_connector_get_modes(struct drm_connector *connector) { struct rk3066_hdmi *hdmi = connector_to_rk3066_hdmi(connector); - struct edid *edid; + const struct drm_edid *drm_edid; int ret = 0; if (!hdmi->ddc) return 0; - edid = drm_get_edid(connector, hdmi->ddc); - if (edid) { - drm_connector_update_edid_property(connector, edid); - ret = drm_add_edid_modes(connector, edid); - kfree(edid); - } + drm_edid = drm_edid_read_ddc(connector, hdmi->ddc); + drm_edid_connector_update(connector, drm_edid); + ret = drm_edid_connector_add_modes(connector); + drm_edid_free(drm_edid); return ret; } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index fdd768bbd487..62ebbdb16253 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -706,6 +706,8 @@ static void vop2_setup_scale(struct vop2 *vop2, const struct vop2_win *win, const struct drm_format_info *info; u16 hor_scl_mode, ver_scl_mode; u16 hscl_filter_mode, vscl_filter_mode; + uint16_t cbcr_src_w = src_w; + uint16_t cbcr_src_h = src_h; u8 gt2 = 0; u8 gt4 = 0; u32 val; @@ -763,27 +765,27 @@ static void vop2_setup_scale(struct vop2 *vop2, const struct vop2_win *win, vop2_win_write(win, VOP2_WIN_YRGB_VSCL_FILTER_MODE, vscl_filter_mode); if (info->is_yuv) { - src_w /= info->hsub; - src_h /= info->vsub; + cbcr_src_w /= info->hsub; + cbcr_src_h /= info->vsub; gt4 = 0; gt2 = 0; - if (src_h >= (4 * dst_h)) { + if (cbcr_src_h >= (4 * dst_h)) { gt4 = 1; - src_h >>= 2; - } else if (src_h >= (2 * dst_h)) { + cbcr_src_h >>= 2; + } else if (cbcr_src_h >= (2 * dst_h)) { gt2 = 1; - src_h >>= 1; + cbcr_src_h >>= 1; } - hor_scl_mode = scl_get_scl_mode(src_w, dst_w); - ver_scl_mode = scl_get_scl_mode(src_h, dst_h); + hor_scl_mode = scl_get_scl_mode(cbcr_src_w, dst_w); + ver_scl_mode = scl_get_scl_mode(cbcr_src_h, dst_h); - val = vop2_scale_factor(src_w, dst_w); + val = vop2_scale_factor(cbcr_src_w, dst_w); vop2_win_write(win, VOP2_WIN_SCALE_CBCR_X, val); - val = vop2_scale_factor(src_h, dst_h); + val = vop2_scale_factor(cbcr_src_h, dst_h); vop2_win_write(win, VOP2_WIN_SCALE_CBCR_Y, val); vop2_win_write(win, VOP2_WIN_VSD_CBCR_GT4, gt4); diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c index 77b76cff1adb..9a01aa450741 100644 --- a/drivers/gpu/drm/rockchip/rockchip_lvds.c +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c @@ -17,7 +17,6 @@ #include <linux/regmap.h> #include <linux/reset.h> -#include <drm/display/drm_dp_helper.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_bridge_connector.h> diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c index 2d1880c61b50..245b34adca5a 100644 --- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c +++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c @@ -214,20 +214,24 @@ sun4i_hdmi_connector_mode_valid(struct drm_connector *connector, static int sun4i_hdmi_get_modes(struct drm_connector *connector) { struct sun4i_hdmi *hdmi = drm_connector_to_sun4i_hdmi(connector); - struct edid *edid; + const struct drm_edid *drm_edid; int ret; - edid = drm_get_edid(connector, hdmi->ddc_i2c ?: hdmi->i2c); - if (!edid) + drm_edid = drm_edid_read_ddc(connector, hdmi->ddc_i2c ?: hdmi->i2c); + + drm_edid_connector_update(connector, drm_edid); + cec_s_phys_addr(hdmi->cec_adap, + connector->display_info.source_physical_address, false); + + if (!drm_edid) return 0; DRM_DEBUG_DRIVER("Monitor is %s monitor\n", connector->display_info.is_hdmi ? "an HDMI" : "a DVI"); - drm_connector_update_edid_property(connector, edid); - cec_s_phys_addr_from_edid(hdmi->cec_adap, edid); - ret = drm_add_edid_modes(connector, edid); - kfree(edid); + + ret = drm_edid_connector_add_modes(connector); + drm_edid_free(drm_edid); return ret; } diff --git a/drivers/gpu/drm/tests/drm_buddy_test.c b/drivers/gpu/drm/tests/drm_buddy_test.c index e48863a44556..e3b50e240d36 100644 --- a/drivers/gpu/drm/tests/drm_buddy_test.c +++ b/drivers/gpu/drm/tests/drm_buddy_test.c @@ -103,7 +103,7 @@ static void drm_test_buddy_alloc_range_bias(struct kunit *test) DRM_BUDDY_RANGE_ALLOCATION), "buddy_alloc i failed with bias(%x-%x), size=%u, ps=%u\n", bias_start, bias_end, bias_size, bias_size); - drm_buddy_free_list(&mm, &tmp); + drm_buddy_free_list(&mm, &tmp, 0); /* single page with internal round_up */ KUNIT_ASSERT_FALSE_MSG(test, @@ -113,7 +113,7 @@ static void drm_test_buddy_alloc_range_bias(struct kunit *test) DRM_BUDDY_RANGE_ALLOCATION), "buddy_alloc failed with bias(%x-%x), size=%u, ps=%u\n", bias_start, bias_end, ps, bias_size); - drm_buddy_free_list(&mm, &tmp); + drm_buddy_free_list(&mm, &tmp, 0); /* random size within */ size = max(round_up(prandom_u32_state(&prng) % bias_rem, ps), ps); @@ -153,14 +153,14 @@ static void drm_test_buddy_alloc_range_bias(struct kunit *test) * unallocated, and ideally not always on the bias * boundaries. */ - drm_buddy_free_list(&mm, &tmp); + drm_buddy_free_list(&mm, &tmp, 0); } else { list_splice_tail(&tmp, &allocated); } } kfree(order); - drm_buddy_free_list(&mm, &allocated); + drm_buddy_free_list(&mm, &allocated, 0); drm_buddy_fini(&mm); /* @@ -220,7 +220,149 @@ static void drm_test_buddy_alloc_range_bias(struct kunit *test) "buddy_alloc passed with bias(%x-%x), size=%u\n", bias_start, bias_end, ps); - drm_buddy_free_list(&mm, &allocated); + drm_buddy_free_list(&mm, &allocated, 0); + drm_buddy_fini(&mm); +} + +static void drm_test_buddy_alloc_clear(struct kunit *test) +{ + unsigned long n_pages, total, i = 0; + DRM_RND_STATE(prng, random_seed); + const unsigned long ps = SZ_4K; + struct drm_buddy_block *block; + const int max_order = 12; + LIST_HEAD(allocated); + struct drm_buddy mm; + unsigned int order; + u32 mm_size, size; + LIST_HEAD(dirty); + LIST_HEAD(clean); + + mm_size = SZ_4K << max_order; + KUNIT_EXPECT_FALSE(test, drm_buddy_init(&mm, mm_size, ps)); + + KUNIT_EXPECT_EQ(test, mm.max_order, max_order); + + /* + * Idea is to allocate and free some random portion of the address space, + * returning those pages as non-dirty and randomly alternate between + * requesting dirty and non-dirty pages (not going over the limit + * we freed as non-dirty), putting that into two separate lists. + * Loop over both lists at the end checking that the dirty list + * is indeed all dirty pages and vice versa. Free it all again, + * keeping the dirty/clear status. + */ + KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, + 5 * ps, ps, &allocated, + DRM_BUDDY_TOPDOWN_ALLOCATION), + "buddy_alloc hit an error size=%lu\n", 5 * ps); + drm_buddy_free_list(&mm, &allocated, DRM_BUDDY_CLEARED); + + n_pages = 10; + do { + unsigned long flags; + struct list_head *list; + int slot = i % 2; + + if (slot == 0) { + list = &dirty; + flags = 0; + } else { + list = &clean; + flags = DRM_BUDDY_CLEAR_ALLOCATION; + } + + KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, + ps, ps, list, + flags), + "buddy_alloc hit an error size=%lu\n", ps); + } while (++i < n_pages); + + list_for_each_entry(block, &clean, link) + KUNIT_EXPECT_EQ(test, drm_buddy_block_is_clear(block), true); + + list_for_each_entry(block, &dirty, link) + KUNIT_EXPECT_EQ(test, drm_buddy_block_is_clear(block), false); + + drm_buddy_free_list(&mm, &clean, DRM_BUDDY_CLEARED); + + /* + * Trying to go over the clear limit for some allocation. + * The allocation should never fail with reasonable page-size. + */ + KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, + 10 * ps, ps, &clean, + DRM_BUDDY_CLEAR_ALLOCATION), + "buddy_alloc hit an error size=%lu\n", 10 * ps); + + drm_buddy_free_list(&mm, &clean, DRM_BUDDY_CLEARED); + drm_buddy_free_list(&mm, &dirty, 0); + drm_buddy_fini(&mm); + + KUNIT_EXPECT_FALSE(test, drm_buddy_init(&mm, mm_size, ps)); + + /* + * Create a new mm. Intentionally fragment the address space by creating + * two alternating lists. Free both lists, one as dirty the other as clean. + * Try to allocate double the previous size with matching min_page_size. The + * allocation should never fail as it calls the force_merge. Also check that + * the page is always dirty after force_merge. Free the page as dirty, then + * repeat the whole thing, increment the order until we hit the max_order. + */ + + i = 0; + n_pages = mm_size / ps; + do { + struct list_head *list; + int slot = i % 2; + + if (slot == 0) + list = &dirty; + else + list = &clean; + + KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, + ps, ps, list, 0), + "buddy_alloc hit an error size=%lu\n", ps); + } while (++i < n_pages); + + drm_buddy_free_list(&mm, &clean, DRM_BUDDY_CLEARED); + drm_buddy_free_list(&mm, &dirty, 0); + + order = 1; + do { + size = SZ_4K << order; + + KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, + size, size, &allocated, + DRM_BUDDY_CLEAR_ALLOCATION), + "buddy_alloc hit an error size=%u\n", size); + total = 0; + list_for_each_entry(block, &allocated, link) { + if (size != mm_size) + KUNIT_EXPECT_EQ(test, drm_buddy_block_is_clear(block), false); + total += drm_buddy_block_size(&mm, block); + } + KUNIT_EXPECT_EQ(test, total, size); + + drm_buddy_free_list(&mm, &allocated, 0); + } while (++order <= max_order); + + drm_buddy_fini(&mm); + + /* + * Create a new mm with a non power-of-two size. Allocate a random size, free as + * cleared and then call fini. This will ensure the multi-root force merge during + * fini. + */ + mm_size = 12 * SZ_4K; + size = max(round_up(prandom_u32_state(&prng) % mm_size, ps), ps); + KUNIT_EXPECT_FALSE(test, drm_buddy_init(&mm, mm_size, ps)); + KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, + size, ps, &allocated, + DRM_BUDDY_TOPDOWN_ALLOCATION), + "buddy_alloc hit an error size=%u\n", size); + drm_buddy_free_list(&mm, &allocated, DRM_BUDDY_CLEARED); drm_buddy_fini(&mm); } @@ -269,7 +411,7 @@ static void drm_test_buddy_alloc_contiguous(struct kunit *test) DRM_BUDDY_CONTIGUOUS_ALLOCATION), "buddy_alloc didn't error size=%lu\n", 3 * ps); - drm_buddy_free_list(&mm, &middle); + drm_buddy_free_list(&mm, &middle, 0); KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, 3 * ps, ps, &allocated, DRM_BUDDY_CONTIGUOUS_ALLOCATION), @@ -279,7 +421,7 @@ static void drm_test_buddy_alloc_contiguous(struct kunit *test) DRM_BUDDY_CONTIGUOUS_ALLOCATION), "buddy_alloc didn't error size=%lu\n", 2 * ps); - drm_buddy_free_list(&mm, &right); + drm_buddy_free_list(&mm, &right, 0); KUNIT_ASSERT_TRUE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, 3 * ps, ps, &allocated, DRM_BUDDY_CONTIGUOUS_ALLOCATION), @@ -294,7 +436,7 @@ static void drm_test_buddy_alloc_contiguous(struct kunit *test) DRM_BUDDY_CONTIGUOUS_ALLOCATION), "buddy_alloc hit an error size=%lu\n", 2 * ps); - drm_buddy_free_list(&mm, &left); + drm_buddy_free_list(&mm, &left, 0); KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size, 3 * ps, ps, &allocated, DRM_BUDDY_CONTIGUOUS_ALLOCATION), @@ -306,7 +448,7 @@ static void drm_test_buddy_alloc_contiguous(struct kunit *test) KUNIT_ASSERT_EQ(test, total, ps * 2 + ps * 3); - drm_buddy_free_list(&mm, &allocated); + drm_buddy_free_list(&mm, &allocated, 0); drm_buddy_fini(&mm); } @@ -375,7 +517,7 @@ static void drm_test_buddy_alloc_pathological(struct kunit *test) top, max_order); } - drm_buddy_free_list(&mm, &holes); + drm_buddy_free_list(&mm, &holes, 0); /* Nothing larger than blocks of chunk_size now available */ for (order = 1; order <= max_order; order++) { @@ -387,7 +529,7 @@ static void drm_test_buddy_alloc_pathological(struct kunit *test) } list_splice_tail(&holes, &blocks); - drm_buddy_free_list(&mm, &blocks); + drm_buddy_free_list(&mm, &blocks, 0); drm_buddy_fini(&mm); } @@ -482,7 +624,7 @@ static void drm_test_buddy_alloc_pessimistic(struct kunit *test) list_del(&block->link); drm_buddy_free_block(&mm, block); - drm_buddy_free_list(&mm, &blocks); + drm_buddy_free_list(&mm, &blocks, 0); drm_buddy_fini(&mm); } @@ -528,7 +670,7 @@ static void drm_test_buddy_alloc_optimistic(struct kunit *test) size, size, &tmp, flags), "buddy_alloc unexpectedly succeeded, it should be full!"); - drm_buddy_free_list(&mm, &blocks); + drm_buddy_free_list(&mm, &blocks, 0); drm_buddy_fini(&mm); } @@ -563,7 +705,7 @@ static void drm_test_buddy_alloc_limit(struct kunit *test) drm_buddy_block_size(&mm, block), BIT_ULL(mm.max_order) * PAGE_SIZE); - drm_buddy_free_list(&mm, &allocated); + drm_buddy_free_list(&mm, &allocated, 0); drm_buddy_fini(&mm); } @@ -584,6 +726,7 @@ static struct kunit_case drm_buddy_tests[] = { KUNIT_CASE(drm_test_buddy_alloc_pessimistic), KUNIT_CASE(drm_test_buddy_alloc_pathological), KUNIT_CASE(drm_test_buddy_alloc_contiguous), + KUNIT_CASE(drm_test_buddy_alloc_clear), KUNIT_CASE(drm_test_buddy_alloc_range_bias), {} }; diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 5f8d51b29370..d30f8e8e8967 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -412,15 +412,14 @@ static void vc4_hdmi_handle_hotplug(struct vc4_hdmi *vc4_hdmi, enum drm_connector_status status) { struct drm_connector *connector = &vc4_hdmi->connector; - struct edid *edid; + const struct drm_edid *drm_edid; int ret; /* - * NOTE: This function should really be called with - * vc4_hdmi->mutex held, but doing so results in reentrancy - * issues since cec_s_phys_addr_from_edid might call - * .adap_enable, which leads to that funtion being called with - * our mutex held. + * NOTE: This function should really be called with vc4_hdmi->mutex + * held, but doing so results in reentrancy issues since + * cec_s_phys_addr() might call .adap_enable, which leads to that + * funtion being called with our mutex held. * * A similar situation occurs with vc4_hdmi_reset_link() that * will call into our KMS hooks if the scrambling was enabled. @@ -435,12 +434,16 @@ static void vc4_hdmi_handle_hotplug(struct vc4_hdmi *vc4_hdmi, return; } - edid = drm_get_edid(connector, vc4_hdmi->ddc); - if (!edid) + drm_edid = drm_edid_read_ddc(connector, vc4_hdmi->ddc); + + drm_edid_connector_update(connector, drm_edid); + cec_s_phys_addr(vc4_hdmi->cec_adap, + connector->display_info.source_physical_address, false); + + if (!drm_edid) return; - cec_s_phys_addr_from_edid(vc4_hdmi->cec_adap, edid); - kfree(edid); + drm_edid_free(drm_edid); for (;;) { ret = vc4_hdmi_reset_link(connector, ctx); @@ -492,28 +495,29 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) { struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector); struct vc4_dev *vc4 = to_vc4_dev(connector->dev); + const struct drm_edid *drm_edid; int ret = 0; - struct edid *edid; /* - * NOTE: This function should really take vc4_hdmi->mutex, but - * doing so results in reentrancy issues since - * cec_s_phys_addr_from_edid might call .adap_enable, which - * leads to that funtion being called with our mutex held. + * NOTE: This function should really take vc4_hdmi->mutex, but doing so + * results in reentrancy issues since cec_s_phys_addr() might call + * .adap_enable, which leads to that funtion being called with our mutex + * held. * * Concurrency isn't an issue at the moment since we don't share * any state with any of the other frameworks so we can ignore * the lock for now. */ - edid = drm_get_edid(connector, vc4_hdmi->ddc); - cec_s_phys_addr_from_edid(vc4_hdmi->cec_adap, edid); - if (!edid) + drm_edid = drm_edid_read_ddc(connector, vc4_hdmi->ddc); + drm_edid_connector_update(connector, drm_edid); + cec_s_phys_addr(vc4_hdmi->cec_adap, + connector->display_info.source_physical_address, false); + if (!drm_edid) return 0; - drm_connector_update_edid_property(connector, edid); - ret = drm_add_edid_modes(connector, edid); - kfree(edid); + ret = drm_edid_connector_add_modes(connector); + drm_edid_free(drm_edid); if (!vc4->hvs->vc5_hdmi_enable_hdmi_20) { struct drm_device *drm = connector->dev; diff --git a/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c b/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c index 115ec745e502..1ad678b62c4a 100644 --- a/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c +++ b/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c @@ -196,7 +196,7 @@ static int xe_ttm_vram_mgr_new(struct ttm_resource_manager *man, return 0; error_free_blocks: - drm_buddy_free_list(mm, &vres->blocks); + drm_buddy_free_list(mm, &vres->blocks, 0); mutex_unlock(&mgr->lock); error_fini: ttm_resource_fini(man, &vres->base); @@ -214,7 +214,7 @@ static void xe_ttm_vram_mgr_del(struct ttm_resource_manager *man, struct drm_buddy *mm = &mgr->mm; mutex_lock(&mgr->lock); - drm_buddy_free_list(mm, &vres->blocks); + drm_buddy_free_list(mm, &vres->blocks, 0); mgr->visible_avail += vres->used_visible_size; mutex_unlock(&mgr->lock); |