162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2023 Loongson Technology Corporation Limited 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/delay.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <drm/drm_atomic.h> 962306a36Sopenharmony_ci#include <drm/drm_atomic_helper.h> 1062306a36Sopenharmony_ci#include <drm/drm_framebuffer.h> 1162306a36Sopenharmony_ci#include <drm/drm_gem_atomic_helper.h> 1262306a36Sopenharmony_ci#include <drm/drm_plane_helper.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "lsdc_drv.h" 1562306a36Sopenharmony_ci#include "lsdc_regs.h" 1662306a36Sopenharmony_ci#include "lsdc_ttm.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic const u32 lsdc_primary_formats[] = { 1962306a36Sopenharmony_ci DRM_FORMAT_XRGB8888, 2062306a36Sopenharmony_ci}; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic const u32 lsdc_cursor_formats[] = { 2362306a36Sopenharmony_ci DRM_FORMAT_ARGB8888, 2462306a36Sopenharmony_ci}; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic const u64 lsdc_fb_format_modifiers[] = { 2762306a36Sopenharmony_ci DRM_FORMAT_MOD_LINEAR, 2862306a36Sopenharmony_ci DRM_FORMAT_MOD_INVALID 2962306a36Sopenharmony_ci}; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic unsigned int lsdc_get_fb_offset(struct drm_framebuffer *fb, 3262306a36Sopenharmony_ci struct drm_plane_state *state) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci unsigned int offset = fb->offsets[0]; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci offset += fb->format->cpp[0] * (state->src_x >> 16); 3762306a36Sopenharmony_ci offset += fb->pitches[0] * (state->src_y >> 16); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci return offset; 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic u64 lsdc_fb_base_addr(struct drm_framebuffer *fb) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci struct lsdc_device *ldev = to_lsdc(fb->dev); 4562306a36Sopenharmony_ci struct lsdc_bo *lbo = gem_to_lsdc_bo(fb->obj[0]); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci return lsdc_bo_gpu_offset(lbo) + ldev->vram_base; 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic int lsdc_primary_atomic_check(struct drm_plane *plane, 5162306a36Sopenharmony_ci struct drm_atomic_state *state) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); 5462306a36Sopenharmony_ci struct drm_crtc *crtc = new_plane_state->crtc; 5562306a36Sopenharmony_ci struct drm_crtc_state *new_crtc_state; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci if (!crtc) 5862306a36Sopenharmony_ci return 0; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci return drm_atomic_helper_check_plane_state(new_plane_state, 6362306a36Sopenharmony_ci new_crtc_state, 6462306a36Sopenharmony_ci DRM_PLANE_NO_SCALING, 6562306a36Sopenharmony_ci DRM_PLANE_NO_SCALING, 6662306a36Sopenharmony_ci false, true); 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic void lsdc_primary_atomic_update(struct drm_plane *plane, 7062306a36Sopenharmony_ci struct drm_atomic_state *state) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci struct lsdc_primary *primary = to_lsdc_primary(plane); 7362306a36Sopenharmony_ci const struct lsdc_primary_plane_ops *ops = primary->ops; 7462306a36Sopenharmony_ci struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); 7562306a36Sopenharmony_ci struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); 7662306a36Sopenharmony_ci struct drm_framebuffer *new_fb = new_plane_state->fb; 7762306a36Sopenharmony_ci struct drm_framebuffer *old_fb = old_plane_state->fb; 7862306a36Sopenharmony_ci u64 fb_addr = lsdc_fb_base_addr(new_fb); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci fb_addr += lsdc_get_fb_offset(new_fb, new_plane_state); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci ops->update_fb_addr(primary, fb_addr); 8362306a36Sopenharmony_ci ops->update_fb_stride(primary, new_fb->pitches[0]); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci if (!old_fb || old_fb->format != new_fb->format) 8662306a36Sopenharmony_ci ops->update_fb_format(primary, new_fb->format); 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic void lsdc_primary_atomic_disable(struct drm_plane *plane, 9062306a36Sopenharmony_ci struct drm_atomic_state *state) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci /* 9362306a36Sopenharmony_ci * Do nothing, just prevent call into atomic_update(). 9462306a36Sopenharmony_ci * Writing the format as LSDC_PF_NONE can disable the primary, 9562306a36Sopenharmony_ci * But it seems not necessary... 9662306a36Sopenharmony_ci */ 9762306a36Sopenharmony_ci drm_dbg(plane->dev, "%s disabled\n", plane->name); 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic int lsdc_plane_prepare_fb(struct drm_plane *plane, 10162306a36Sopenharmony_ci struct drm_plane_state *new_state) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci struct drm_framebuffer *fb = new_state->fb; 10462306a36Sopenharmony_ci struct lsdc_bo *lbo; 10562306a36Sopenharmony_ci u64 gpu_vaddr; 10662306a36Sopenharmony_ci int ret; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if (!fb) 10962306a36Sopenharmony_ci return 0; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci lbo = gem_to_lsdc_bo(fb->obj[0]); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci ret = lsdc_bo_reserve(lbo); 11462306a36Sopenharmony_ci if (unlikely(ret)) { 11562306a36Sopenharmony_ci drm_err(plane->dev, "bo %p reserve failed\n", lbo); 11662306a36Sopenharmony_ci return ret; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci ret = lsdc_bo_pin(lbo, LSDC_GEM_DOMAIN_VRAM, &gpu_vaddr); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci lsdc_bo_unreserve(lbo); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (unlikely(ret)) { 12462306a36Sopenharmony_ci drm_err(plane->dev, "bo %p pin failed\n", lbo); 12562306a36Sopenharmony_ci return ret; 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci lsdc_bo_ref(lbo); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (plane->type != DRM_PLANE_TYPE_CURSOR) 13162306a36Sopenharmony_ci drm_dbg(plane->dev, 13262306a36Sopenharmony_ci "%s[%p] pin at 0x%llx, bo size: %zu\n", 13362306a36Sopenharmony_ci plane->name, lbo, gpu_vaddr, lsdc_bo_size(lbo)); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci return drm_gem_plane_helper_prepare_fb(plane, new_state); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic void lsdc_plane_cleanup_fb(struct drm_plane *plane, 13962306a36Sopenharmony_ci struct drm_plane_state *old_state) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci struct drm_framebuffer *fb = old_state->fb; 14262306a36Sopenharmony_ci struct lsdc_bo *lbo; 14362306a36Sopenharmony_ci int ret; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (!fb) 14662306a36Sopenharmony_ci return; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci lbo = gem_to_lsdc_bo(fb->obj[0]); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci ret = lsdc_bo_reserve(lbo); 15162306a36Sopenharmony_ci if (unlikely(ret)) { 15262306a36Sopenharmony_ci drm_err(plane->dev, "%p reserve failed\n", lbo); 15362306a36Sopenharmony_ci return; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci lsdc_bo_unpin(lbo); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci lsdc_bo_unreserve(lbo); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci lsdc_bo_unref(lbo); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (plane->type != DRM_PLANE_TYPE_CURSOR) 16362306a36Sopenharmony_ci drm_dbg(plane->dev, "%s unpin\n", plane->name); 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic const struct drm_plane_helper_funcs lsdc_primary_helper_funcs = { 16762306a36Sopenharmony_ci .prepare_fb = lsdc_plane_prepare_fb, 16862306a36Sopenharmony_ci .cleanup_fb = lsdc_plane_cleanup_fb, 16962306a36Sopenharmony_ci .atomic_check = lsdc_primary_atomic_check, 17062306a36Sopenharmony_ci .atomic_update = lsdc_primary_atomic_update, 17162306a36Sopenharmony_ci .atomic_disable = lsdc_primary_atomic_disable, 17262306a36Sopenharmony_ci}; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic int lsdc_cursor_plane_atomic_async_check(struct drm_plane *plane, 17562306a36Sopenharmony_ci struct drm_atomic_state *state) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci struct drm_plane_state *new_state; 17862306a36Sopenharmony_ci struct drm_crtc_state *crtc_state; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci new_state = drm_atomic_get_new_plane_state(state, plane); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (!plane->state || !plane->state->fb) { 18362306a36Sopenharmony_ci drm_dbg(plane->dev, "%s: state is NULL\n", plane->name); 18462306a36Sopenharmony_ci return -EINVAL; 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (new_state->crtc_w != new_state->crtc_h) { 18862306a36Sopenharmony_ci drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n", 18962306a36Sopenharmony_ci new_state->crtc_w, new_state->crtc_h); 19062306a36Sopenharmony_ci return -EINVAL; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (new_state->crtc_w != 64 && new_state->crtc_w != 32) { 19462306a36Sopenharmony_ci drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n", 19562306a36Sopenharmony_ci new_state->crtc_w, new_state->crtc_h); 19662306a36Sopenharmony_ci return -EINVAL; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci crtc_state = drm_atomic_get_existing_crtc_state(state, new_state->crtc); 20062306a36Sopenharmony_ci if (!crtc_state->active) 20162306a36Sopenharmony_ci return -EINVAL; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (plane->state->crtc != new_state->crtc || 20462306a36Sopenharmony_ci plane->state->src_w != new_state->src_w || 20562306a36Sopenharmony_ci plane->state->src_h != new_state->src_h || 20662306a36Sopenharmony_ci plane->state->crtc_w != new_state->crtc_w || 20762306a36Sopenharmony_ci plane->state->crtc_h != new_state->crtc_h) 20862306a36Sopenharmony_ci return -EINVAL; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci if (new_state->visible != plane->state->visible) 21162306a36Sopenharmony_ci return -EINVAL; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci return drm_atomic_helper_check_plane_state(plane->state, 21462306a36Sopenharmony_ci crtc_state, 21562306a36Sopenharmony_ci DRM_PLANE_NO_SCALING, 21662306a36Sopenharmony_ci DRM_PLANE_NO_SCALING, 21762306a36Sopenharmony_ci true, true); 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic void lsdc_cursor_plane_atomic_async_update(struct drm_plane *plane, 22162306a36Sopenharmony_ci struct drm_atomic_state *state) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci struct lsdc_cursor *cursor = to_lsdc_cursor(plane); 22462306a36Sopenharmony_ci const struct lsdc_cursor_plane_ops *ops = cursor->ops; 22562306a36Sopenharmony_ci struct drm_framebuffer *old_fb = plane->state->fb; 22662306a36Sopenharmony_ci struct drm_framebuffer *new_fb; 22762306a36Sopenharmony_ci struct drm_plane_state *new_state; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci new_state = drm_atomic_get_new_plane_state(state, plane); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci new_fb = plane->state->fb; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci plane->state->crtc_x = new_state->crtc_x; 23462306a36Sopenharmony_ci plane->state->crtc_y = new_state->crtc_y; 23562306a36Sopenharmony_ci plane->state->crtc_h = new_state->crtc_h; 23662306a36Sopenharmony_ci plane->state->crtc_w = new_state->crtc_w; 23762306a36Sopenharmony_ci plane->state->src_x = new_state->src_x; 23862306a36Sopenharmony_ci plane->state->src_y = new_state->src_y; 23962306a36Sopenharmony_ci plane->state->src_h = new_state->src_h; 24062306a36Sopenharmony_ci plane->state->src_w = new_state->src_w; 24162306a36Sopenharmony_ci swap(plane->state->fb, new_state->fb); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci if (new_state->visible) { 24462306a36Sopenharmony_ci enum lsdc_cursor_size cursor_size; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci switch (new_state->crtc_w) { 24762306a36Sopenharmony_ci case 64: 24862306a36Sopenharmony_ci cursor_size = CURSOR_SIZE_64X64; 24962306a36Sopenharmony_ci break; 25062306a36Sopenharmony_ci case 32: 25162306a36Sopenharmony_ci cursor_size = CURSOR_SIZE_32X32; 25262306a36Sopenharmony_ci break; 25362306a36Sopenharmony_ci default: 25462306a36Sopenharmony_ci cursor_size = CURSOR_SIZE_32X32; 25562306a36Sopenharmony_ci break; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci ops->update_position(cursor, new_state->crtc_x, new_state->crtc_y); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci ops->update_cfg(cursor, cursor_size, CURSOR_FORMAT_ARGB8888); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if (!old_fb || old_fb != new_fb) 26362306a36Sopenharmony_ci ops->update_bo_addr(cursor, lsdc_fb_base_addr(new_fb)); 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci/* ls7a1000 cursor plane helpers */ 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic int ls7a1000_cursor_plane_atomic_check(struct drm_plane *plane, 27062306a36Sopenharmony_ci struct drm_atomic_state *state) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci struct drm_plane_state *new_plane_state; 27362306a36Sopenharmony_ci struct drm_crtc_state *new_crtc_state; 27462306a36Sopenharmony_ci struct drm_crtc *crtc; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci new_plane_state = drm_atomic_get_new_plane_state(state, plane); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci crtc = new_plane_state->crtc; 27962306a36Sopenharmony_ci if (!crtc) { 28062306a36Sopenharmony_ci drm_dbg(plane->dev, "%s is not bind to a crtc\n", plane->name); 28162306a36Sopenharmony_ci return 0; 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (new_plane_state->crtc_w != 32 || new_plane_state->crtc_h != 32) { 28562306a36Sopenharmony_ci drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n", 28662306a36Sopenharmony_ci new_plane_state->crtc_w, new_plane_state->crtc_h); 28762306a36Sopenharmony_ci return -EINVAL; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci return drm_atomic_helper_check_plane_state(new_plane_state, 29362306a36Sopenharmony_ci new_crtc_state, 29462306a36Sopenharmony_ci DRM_PLANE_NO_SCALING, 29562306a36Sopenharmony_ci DRM_PLANE_NO_SCALING, 29662306a36Sopenharmony_ci true, true); 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic void ls7a1000_cursor_plane_atomic_update(struct drm_plane *plane, 30062306a36Sopenharmony_ci struct drm_atomic_state *state) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci struct lsdc_cursor *cursor = to_lsdc_cursor(plane); 30362306a36Sopenharmony_ci struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); 30462306a36Sopenharmony_ci struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); 30562306a36Sopenharmony_ci struct drm_framebuffer *new_fb = new_plane_state->fb; 30662306a36Sopenharmony_ci struct drm_framebuffer *old_fb = old_plane_state->fb; 30762306a36Sopenharmony_ci const struct lsdc_cursor_plane_ops *ops = cursor->ops; 30862306a36Sopenharmony_ci u64 addr = lsdc_fb_base_addr(new_fb); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci if (!new_plane_state->visible) 31162306a36Sopenharmony_ci return; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci ops->update_position(cursor, new_plane_state->crtc_x, new_plane_state->crtc_y); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (!old_fb || old_fb != new_fb) 31662306a36Sopenharmony_ci ops->update_bo_addr(cursor, addr); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci ops->update_cfg(cursor, CURSOR_SIZE_32X32, CURSOR_FORMAT_ARGB8888); 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic void ls7a1000_cursor_plane_atomic_disable(struct drm_plane *plane, 32262306a36Sopenharmony_ci struct drm_atomic_state *state) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci struct lsdc_cursor *cursor = to_lsdc_cursor(plane); 32562306a36Sopenharmony_ci const struct lsdc_cursor_plane_ops *ops = cursor->ops; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci ops->update_cfg(cursor, CURSOR_SIZE_32X32, CURSOR_FORMAT_DISABLE); 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_cistatic const struct drm_plane_helper_funcs ls7a1000_cursor_plane_helper_funcs = { 33162306a36Sopenharmony_ci .prepare_fb = lsdc_plane_prepare_fb, 33262306a36Sopenharmony_ci .cleanup_fb = lsdc_plane_cleanup_fb, 33362306a36Sopenharmony_ci .atomic_check = ls7a1000_cursor_plane_atomic_check, 33462306a36Sopenharmony_ci .atomic_update = ls7a1000_cursor_plane_atomic_update, 33562306a36Sopenharmony_ci .atomic_disable = ls7a1000_cursor_plane_atomic_disable, 33662306a36Sopenharmony_ci .atomic_async_check = lsdc_cursor_plane_atomic_async_check, 33762306a36Sopenharmony_ci .atomic_async_update = lsdc_cursor_plane_atomic_async_update, 33862306a36Sopenharmony_ci}; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci/* ls7a2000 cursor plane helpers */ 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic int ls7a2000_cursor_plane_atomic_check(struct drm_plane *plane, 34362306a36Sopenharmony_ci struct drm_atomic_state *state) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci struct drm_plane_state *new_plane_state; 34662306a36Sopenharmony_ci struct drm_crtc_state *new_crtc_state; 34762306a36Sopenharmony_ci struct drm_crtc *crtc; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci new_plane_state = drm_atomic_get_new_plane_state(state, plane); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci crtc = new_plane_state->crtc; 35262306a36Sopenharmony_ci if (!crtc) { 35362306a36Sopenharmony_ci drm_dbg(plane->dev, "%s is not bind to a crtc\n", plane->name); 35462306a36Sopenharmony_ci return 0; 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci if (new_plane_state->crtc_w != new_plane_state->crtc_h) { 35862306a36Sopenharmony_ci drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n", 35962306a36Sopenharmony_ci new_plane_state->crtc_w, new_plane_state->crtc_h); 36062306a36Sopenharmony_ci return -EINVAL; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci if (new_plane_state->crtc_w != 64 && new_plane_state->crtc_w != 32) { 36462306a36Sopenharmony_ci drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n", 36562306a36Sopenharmony_ci new_plane_state->crtc_w, new_plane_state->crtc_h); 36662306a36Sopenharmony_ci return -EINVAL; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci return drm_atomic_helper_check_plane_state(new_plane_state, 37262306a36Sopenharmony_ci new_crtc_state, 37362306a36Sopenharmony_ci DRM_PLANE_NO_SCALING, 37462306a36Sopenharmony_ci DRM_PLANE_NO_SCALING, 37562306a36Sopenharmony_ci true, true); 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci/* Update the format, size and location of the cursor */ 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic void ls7a2000_cursor_plane_atomic_update(struct drm_plane *plane, 38162306a36Sopenharmony_ci struct drm_atomic_state *state) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci struct lsdc_cursor *cursor = to_lsdc_cursor(plane); 38462306a36Sopenharmony_ci struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); 38562306a36Sopenharmony_ci struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); 38662306a36Sopenharmony_ci struct drm_framebuffer *new_fb = new_plane_state->fb; 38762306a36Sopenharmony_ci struct drm_framebuffer *old_fb = old_plane_state->fb; 38862306a36Sopenharmony_ci const struct lsdc_cursor_plane_ops *ops = cursor->ops; 38962306a36Sopenharmony_ci enum lsdc_cursor_size cursor_size; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci if (!new_plane_state->visible) 39262306a36Sopenharmony_ci return; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci ops->update_position(cursor, new_plane_state->crtc_x, new_plane_state->crtc_y); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (!old_fb || new_fb != old_fb) { 39762306a36Sopenharmony_ci u64 addr = lsdc_fb_base_addr(new_fb); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci ops->update_bo_addr(cursor, addr); 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci switch (new_plane_state->crtc_w) { 40362306a36Sopenharmony_ci case 64: 40462306a36Sopenharmony_ci cursor_size = CURSOR_SIZE_64X64; 40562306a36Sopenharmony_ci break; 40662306a36Sopenharmony_ci case 32: 40762306a36Sopenharmony_ci cursor_size = CURSOR_SIZE_32X32; 40862306a36Sopenharmony_ci break; 40962306a36Sopenharmony_ci default: 41062306a36Sopenharmony_ci cursor_size = CURSOR_SIZE_64X64; 41162306a36Sopenharmony_ci break; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci ops->update_cfg(cursor, cursor_size, CURSOR_FORMAT_ARGB8888); 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_cistatic void ls7a2000_cursor_plane_atomic_disable(struct drm_plane *plane, 41862306a36Sopenharmony_ci struct drm_atomic_state *state) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci struct lsdc_cursor *cursor = to_lsdc_cursor(plane); 42162306a36Sopenharmony_ci const struct lsdc_cursor_plane_ops *hw_ops = cursor->ops; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci hw_ops->update_cfg(cursor, CURSOR_SIZE_64X64, CURSOR_FORMAT_DISABLE); 42462306a36Sopenharmony_ci} 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_cistatic const struct drm_plane_helper_funcs ls7a2000_cursor_plane_helper_funcs = { 42762306a36Sopenharmony_ci .prepare_fb = lsdc_plane_prepare_fb, 42862306a36Sopenharmony_ci .cleanup_fb = lsdc_plane_cleanup_fb, 42962306a36Sopenharmony_ci .atomic_check = ls7a2000_cursor_plane_atomic_check, 43062306a36Sopenharmony_ci .atomic_update = ls7a2000_cursor_plane_atomic_update, 43162306a36Sopenharmony_ci .atomic_disable = ls7a2000_cursor_plane_atomic_disable, 43262306a36Sopenharmony_ci .atomic_async_check = lsdc_cursor_plane_atomic_async_check, 43362306a36Sopenharmony_ci .atomic_async_update = lsdc_cursor_plane_atomic_async_update, 43462306a36Sopenharmony_ci}; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_cistatic void lsdc_plane_atomic_print_state(struct drm_printer *p, 43762306a36Sopenharmony_ci const struct drm_plane_state *state) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci struct drm_framebuffer *fb = state->fb; 44062306a36Sopenharmony_ci u64 addr; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (!fb) 44362306a36Sopenharmony_ci return; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci addr = lsdc_fb_base_addr(fb); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci drm_printf(p, "\tdma addr=%llx\n", addr); 44862306a36Sopenharmony_ci} 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cistatic const struct drm_plane_funcs lsdc_plane_funcs = { 45162306a36Sopenharmony_ci .update_plane = drm_atomic_helper_update_plane, 45262306a36Sopenharmony_ci .disable_plane = drm_atomic_helper_disable_plane, 45362306a36Sopenharmony_ci .destroy = drm_plane_cleanup, 45462306a36Sopenharmony_ci .reset = drm_atomic_helper_plane_reset, 45562306a36Sopenharmony_ci .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 45662306a36Sopenharmony_ci .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 45762306a36Sopenharmony_ci .atomic_print_state = lsdc_plane_atomic_print_state, 45862306a36Sopenharmony_ci}; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci/* Primary plane 0 hardware related ops */ 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic void lsdc_primary0_update_fb_addr(struct lsdc_primary *primary, u64 addr) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci struct lsdc_device *ldev = primary->ldev; 46562306a36Sopenharmony_ci u32 status; 46662306a36Sopenharmony_ci u32 lo, hi; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci /* 40-bit width physical address bus */ 46962306a36Sopenharmony_ci lo = addr & 0xFFFFFFFF; 47062306a36Sopenharmony_ci hi = (addr >> 32) & 0xFF; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci status = lsdc_rreg32(ldev, LSDC_CRTC0_CFG_REG); 47362306a36Sopenharmony_ci if (status & FB_REG_IN_USING) { 47462306a36Sopenharmony_ci lsdc_wreg32(ldev, LSDC_CRTC0_FB1_ADDR_LO_REG, lo); 47562306a36Sopenharmony_ci lsdc_wreg32(ldev, LSDC_CRTC0_FB1_ADDR_HI_REG, hi); 47662306a36Sopenharmony_ci } else { 47762306a36Sopenharmony_ci lsdc_wreg32(ldev, LSDC_CRTC0_FB0_ADDR_LO_REG, lo); 47862306a36Sopenharmony_ci lsdc_wreg32(ldev, LSDC_CRTC0_FB0_ADDR_HI_REG, hi); 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci} 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_cistatic void lsdc_primary0_update_fb_stride(struct lsdc_primary *primary, u32 stride) 48362306a36Sopenharmony_ci{ 48462306a36Sopenharmony_ci struct lsdc_device *ldev = primary->ldev; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci lsdc_wreg32(ldev, LSDC_CRTC0_STRIDE_REG, stride); 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cistatic void lsdc_primary0_update_fb_format(struct lsdc_primary *primary, 49062306a36Sopenharmony_ci const struct drm_format_info *format) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci struct lsdc_device *ldev = primary->ldev; 49362306a36Sopenharmony_ci u32 status; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci status = lsdc_rreg32(ldev, LSDC_CRTC0_CFG_REG); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci /* 49862306a36Sopenharmony_ci * TODO: add RGB565 support, only support XRBG8888 at present 49962306a36Sopenharmony_ci */ 50062306a36Sopenharmony_ci status &= ~CFG_PIX_FMT_MASK; 50162306a36Sopenharmony_ci status |= LSDC_PF_XRGB8888; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci lsdc_wreg32(ldev, LSDC_CRTC0_CFG_REG, status); 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci/* Primary plane 1 hardware related ops */ 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_cistatic void lsdc_primary1_update_fb_addr(struct lsdc_primary *primary, u64 addr) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci struct lsdc_device *ldev = primary->ldev; 51162306a36Sopenharmony_ci u32 status; 51262306a36Sopenharmony_ci u32 lo, hi; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci /* 40-bit width physical address bus */ 51562306a36Sopenharmony_ci lo = addr & 0xFFFFFFFF; 51662306a36Sopenharmony_ci hi = (addr >> 32) & 0xFF; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci status = lsdc_rreg32(ldev, LSDC_CRTC1_CFG_REG); 51962306a36Sopenharmony_ci if (status & FB_REG_IN_USING) { 52062306a36Sopenharmony_ci lsdc_wreg32(ldev, LSDC_CRTC1_FB1_ADDR_LO_REG, lo); 52162306a36Sopenharmony_ci lsdc_wreg32(ldev, LSDC_CRTC1_FB1_ADDR_HI_REG, hi); 52262306a36Sopenharmony_ci } else { 52362306a36Sopenharmony_ci lsdc_wreg32(ldev, LSDC_CRTC1_FB0_ADDR_LO_REG, lo); 52462306a36Sopenharmony_ci lsdc_wreg32(ldev, LSDC_CRTC1_FB0_ADDR_HI_REG, hi); 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_cistatic void lsdc_primary1_update_fb_stride(struct lsdc_primary *primary, u32 stride) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci struct lsdc_device *ldev = primary->ldev; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci lsdc_wreg32(ldev, LSDC_CRTC1_STRIDE_REG, stride); 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_cistatic void lsdc_primary1_update_fb_format(struct lsdc_primary *primary, 53662306a36Sopenharmony_ci const struct drm_format_info *format) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci struct lsdc_device *ldev = primary->ldev; 53962306a36Sopenharmony_ci u32 status; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci status = lsdc_rreg32(ldev, LSDC_CRTC1_CFG_REG); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci /* 54462306a36Sopenharmony_ci * TODO: add RGB565 support, only support XRBG8888 at present 54562306a36Sopenharmony_ci */ 54662306a36Sopenharmony_ci status &= ~CFG_PIX_FMT_MASK; 54762306a36Sopenharmony_ci status |= LSDC_PF_XRGB8888; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci lsdc_wreg32(ldev, LSDC_CRTC1_CFG_REG, status); 55062306a36Sopenharmony_ci} 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_cistatic const struct lsdc_primary_plane_ops lsdc_primary_plane_hw_ops[2] = { 55362306a36Sopenharmony_ci { 55462306a36Sopenharmony_ci .update_fb_addr = lsdc_primary0_update_fb_addr, 55562306a36Sopenharmony_ci .update_fb_stride = lsdc_primary0_update_fb_stride, 55662306a36Sopenharmony_ci .update_fb_format = lsdc_primary0_update_fb_format, 55762306a36Sopenharmony_ci }, 55862306a36Sopenharmony_ci { 55962306a36Sopenharmony_ci .update_fb_addr = lsdc_primary1_update_fb_addr, 56062306a36Sopenharmony_ci .update_fb_stride = lsdc_primary1_update_fb_stride, 56162306a36Sopenharmony_ci .update_fb_format = lsdc_primary1_update_fb_format, 56262306a36Sopenharmony_ci }, 56362306a36Sopenharmony_ci}; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci/* 56662306a36Sopenharmony_ci * Update location, format, enable and disable state of the cursor, 56762306a36Sopenharmony_ci * For those who have two hardware cursor, let cursor 0 is attach to CRTC-0, 56862306a36Sopenharmony_ci * cursor 1 is attach to CRTC-1. Compositing the primary plane and cursor 56962306a36Sopenharmony_ci * plane is automatically done by hardware, the cursor is alway on the top of 57062306a36Sopenharmony_ci * the primary plane. In other word, z-order is fixed in hardware and cannot 57162306a36Sopenharmony_ci * be changed. For those old DC who has only one hardware cursor, we made it 57262306a36Sopenharmony_ci * shared by the two screen, this works on extend screen mode. 57362306a36Sopenharmony_ci */ 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci/* cursor plane 0 (for pipe 0) related hardware ops */ 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_cistatic void lsdc_cursor0_update_bo_addr(struct lsdc_cursor *cursor, u64 addr) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci struct lsdc_device *ldev = cursor->ldev; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci /* 40-bit width physical address bus */ 58262306a36Sopenharmony_ci lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_HI_REG, (addr >> 32) & 0xFF); 58362306a36Sopenharmony_ci lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_LO_REG, addr); 58462306a36Sopenharmony_ci} 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_cistatic void lsdc_cursor0_update_position(struct lsdc_cursor *cursor, int x, int y) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci struct lsdc_device *ldev = cursor->ldev; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci if (x < 0) 59162306a36Sopenharmony_ci x = 0; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci if (y < 0) 59462306a36Sopenharmony_ci y = 0; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci lsdc_wreg32(ldev, LSDC_CURSOR0_POSITION_REG, (y << 16) | x); 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_cistatic void lsdc_cursor0_update_cfg(struct lsdc_cursor *cursor, 60062306a36Sopenharmony_ci enum lsdc_cursor_size cursor_size, 60162306a36Sopenharmony_ci enum lsdc_cursor_format fmt) 60262306a36Sopenharmony_ci{ 60362306a36Sopenharmony_ci struct lsdc_device *ldev = cursor->ldev; 60462306a36Sopenharmony_ci u32 cfg; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci cfg = CURSOR_ON_CRTC0 << CURSOR_LOCATION_SHIFT | 60762306a36Sopenharmony_ci cursor_size << CURSOR_SIZE_SHIFT | 60862306a36Sopenharmony_ci fmt << CURSOR_FORMAT_SHIFT; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci lsdc_wreg32(ldev, LSDC_CURSOR0_CFG_REG, cfg); 61162306a36Sopenharmony_ci} 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci/* cursor plane 1 (for pipe 1) related hardware ops */ 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_cistatic void lsdc_cursor1_update_bo_addr(struct lsdc_cursor *cursor, u64 addr) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci struct lsdc_device *ldev = cursor->ldev; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci /* 40-bit width physical address bus */ 62062306a36Sopenharmony_ci lsdc_wreg32(ldev, LSDC_CURSOR1_ADDR_HI_REG, (addr >> 32) & 0xFF); 62162306a36Sopenharmony_ci lsdc_wreg32(ldev, LSDC_CURSOR1_ADDR_LO_REG, addr); 62262306a36Sopenharmony_ci} 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_cistatic void lsdc_cursor1_update_position(struct lsdc_cursor *cursor, int x, int y) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci struct lsdc_device *ldev = cursor->ldev; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci if (x < 0) 62962306a36Sopenharmony_ci x = 0; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci if (y < 0) 63262306a36Sopenharmony_ci y = 0; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci lsdc_wreg32(ldev, LSDC_CURSOR1_POSITION_REG, (y << 16) | x); 63562306a36Sopenharmony_ci} 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_cistatic void lsdc_cursor1_update_cfg(struct lsdc_cursor *cursor, 63862306a36Sopenharmony_ci enum lsdc_cursor_size cursor_size, 63962306a36Sopenharmony_ci enum lsdc_cursor_format fmt) 64062306a36Sopenharmony_ci{ 64162306a36Sopenharmony_ci struct lsdc_device *ldev = cursor->ldev; 64262306a36Sopenharmony_ci u32 cfg; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci cfg = CURSOR_ON_CRTC1 << CURSOR_LOCATION_SHIFT | 64562306a36Sopenharmony_ci cursor_size << CURSOR_SIZE_SHIFT | 64662306a36Sopenharmony_ci fmt << CURSOR_FORMAT_SHIFT; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci lsdc_wreg32(ldev, LSDC_CURSOR1_CFG_REG, cfg); 64962306a36Sopenharmony_ci} 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci/* The hardware cursors become normal since ls7a2000/ls2k2000 */ 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_cistatic const struct lsdc_cursor_plane_ops ls7a2000_cursor_hw_ops[2] = { 65462306a36Sopenharmony_ci { 65562306a36Sopenharmony_ci .update_bo_addr = lsdc_cursor0_update_bo_addr, 65662306a36Sopenharmony_ci .update_cfg = lsdc_cursor0_update_cfg, 65762306a36Sopenharmony_ci .update_position = lsdc_cursor0_update_position, 65862306a36Sopenharmony_ci }, 65962306a36Sopenharmony_ci { 66062306a36Sopenharmony_ci .update_bo_addr = lsdc_cursor1_update_bo_addr, 66162306a36Sopenharmony_ci .update_cfg = lsdc_cursor1_update_cfg, 66262306a36Sopenharmony_ci .update_position = lsdc_cursor1_update_position, 66362306a36Sopenharmony_ci }, 66462306a36Sopenharmony_ci}; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci/* Quirks for cursor 1, only for old loongson display controller */ 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic void lsdc_cursor1_update_bo_addr_quirk(struct lsdc_cursor *cursor, u64 addr) 66962306a36Sopenharmony_ci{ 67062306a36Sopenharmony_ci struct lsdc_device *ldev = cursor->ldev; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci /* 40-bit width physical address bus */ 67362306a36Sopenharmony_ci lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_HI_REG, (addr >> 32) & 0xFF); 67462306a36Sopenharmony_ci lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_LO_REG, addr); 67562306a36Sopenharmony_ci} 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_cistatic void lsdc_cursor1_update_position_quirk(struct lsdc_cursor *cursor, int x, int y) 67862306a36Sopenharmony_ci{ 67962306a36Sopenharmony_ci struct lsdc_device *ldev = cursor->ldev; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci if (x < 0) 68262306a36Sopenharmony_ci x = 0; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci if (y < 0) 68562306a36Sopenharmony_ci y = 0; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci lsdc_wreg32(ldev, LSDC_CURSOR0_POSITION_REG, (y << 16) | x); 68862306a36Sopenharmony_ci} 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_cistatic void lsdc_cursor1_update_cfg_quirk(struct lsdc_cursor *cursor, 69162306a36Sopenharmony_ci enum lsdc_cursor_size cursor_size, 69262306a36Sopenharmony_ci enum lsdc_cursor_format fmt) 69362306a36Sopenharmony_ci{ 69462306a36Sopenharmony_ci struct lsdc_device *ldev = cursor->ldev; 69562306a36Sopenharmony_ci u32 cfg; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci cfg = CURSOR_ON_CRTC1 << CURSOR_LOCATION_SHIFT | 69862306a36Sopenharmony_ci cursor_size << CURSOR_SIZE_SHIFT | 69962306a36Sopenharmony_ci fmt << CURSOR_FORMAT_SHIFT; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci lsdc_wreg32(ldev, LSDC_CURSOR0_CFG_REG, cfg); 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci/* 70562306a36Sopenharmony_ci * The unforgiving LS7A1000/LS2K1000 has only one hardware cursors plane 70662306a36Sopenharmony_ci */ 70762306a36Sopenharmony_cistatic const struct lsdc_cursor_plane_ops ls7a1000_cursor_hw_ops[2] = { 70862306a36Sopenharmony_ci { 70962306a36Sopenharmony_ci .update_bo_addr = lsdc_cursor0_update_bo_addr, 71062306a36Sopenharmony_ci .update_cfg = lsdc_cursor0_update_cfg, 71162306a36Sopenharmony_ci .update_position = lsdc_cursor0_update_position, 71262306a36Sopenharmony_ci }, 71362306a36Sopenharmony_ci { 71462306a36Sopenharmony_ci .update_bo_addr = lsdc_cursor1_update_bo_addr_quirk, 71562306a36Sopenharmony_ci .update_cfg = lsdc_cursor1_update_cfg_quirk, 71662306a36Sopenharmony_ci .update_position = lsdc_cursor1_update_position_quirk, 71762306a36Sopenharmony_ci }, 71862306a36Sopenharmony_ci}; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ciint lsdc_primary_plane_init(struct drm_device *ddev, 72162306a36Sopenharmony_ci struct drm_plane *plane, 72262306a36Sopenharmony_ci unsigned int index) 72362306a36Sopenharmony_ci{ 72462306a36Sopenharmony_ci struct lsdc_primary *primary = to_lsdc_primary(plane); 72562306a36Sopenharmony_ci int ret; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci ret = drm_universal_plane_init(ddev, plane, 1 << index, 72862306a36Sopenharmony_ci &lsdc_plane_funcs, 72962306a36Sopenharmony_ci lsdc_primary_formats, 73062306a36Sopenharmony_ci ARRAY_SIZE(lsdc_primary_formats), 73162306a36Sopenharmony_ci lsdc_fb_format_modifiers, 73262306a36Sopenharmony_ci DRM_PLANE_TYPE_PRIMARY, 73362306a36Sopenharmony_ci "ls-primary-plane-%u", index); 73462306a36Sopenharmony_ci if (ret) 73562306a36Sopenharmony_ci return ret; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci drm_plane_helper_add(plane, &lsdc_primary_helper_funcs); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci primary->ldev = to_lsdc(ddev); 74062306a36Sopenharmony_ci primary->ops = &lsdc_primary_plane_hw_ops[index]; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci return 0; 74362306a36Sopenharmony_ci} 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ciint ls7a1000_cursor_plane_init(struct drm_device *ddev, 74662306a36Sopenharmony_ci struct drm_plane *plane, 74762306a36Sopenharmony_ci unsigned int index) 74862306a36Sopenharmony_ci{ 74962306a36Sopenharmony_ci struct lsdc_cursor *cursor = to_lsdc_cursor(plane); 75062306a36Sopenharmony_ci int ret; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci ret = drm_universal_plane_init(ddev, plane, 1 << index, 75362306a36Sopenharmony_ci &lsdc_plane_funcs, 75462306a36Sopenharmony_ci lsdc_cursor_formats, 75562306a36Sopenharmony_ci ARRAY_SIZE(lsdc_cursor_formats), 75662306a36Sopenharmony_ci lsdc_fb_format_modifiers, 75762306a36Sopenharmony_ci DRM_PLANE_TYPE_CURSOR, 75862306a36Sopenharmony_ci "ls-cursor-plane-%u", index); 75962306a36Sopenharmony_ci if (ret) 76062306a36Sopenharmony_ci return ret; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci cursor->ldev = to_lsdc(ddev); 76362306a36Sopenharmony_ci cursor->ops = &ls7a1000_cursor_hw_ops[index]; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci drm_plane_helper_add(plane, &ls7a1000_cursor_plane_helper_funcs); 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci return 0; 76862306a36Sopenharmony_ci} 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ciint ls7a2000_cursor_plane_init(struct drm_device *ddev, 77162306a36Sopenharmony_ci struct drm_plane *plane, 77262306a36Sopenharmony_ci unsigned int index) 77362306a36Sopenharmony_ci{ 77462306a36Sopenharmony_ci struct lsdc_cursor *cursor = to_lsdc_cursor(plane); 77562306a36Sopenharmony_ci int ret; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci ret = drm_universal_plane_init(ddev, plane, 1 << index, 77862306a36Sopenharmony_ci &lsdc_plane_funcs, 77962306a36Sopenharmony_ci lsdc_cursor_formats, 78062306a36Sopenharmony_ci ARRAY_SIZE(lsdc_cursor_formats), 78162306a36Sopenharmony_ci lsdc_fb_format_modifiers, 78262306a36Sopenharmony_ci DRM_PLANE_TYPE_CURSOR, 78362306a36Sopenharmony_ci "ls-cursor-plane-%u", index); 78462306a36Sopenharmony_ci if (ret) 78562306a36Sopenharmony_ci return ret; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci cursor->ldev = to_lsdc(ddev); 78862306a36Sopenharmony_ci cursor->ops = &ls7a2000_cursor_hw_ops[index]; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci drm_plane_helper_add(plane, &ls7a2000_cursor_plane_helper_funcs); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci return 0; 79362306a36Sopenharmony_ci} 794