| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794 |
- // SPDX-License-Identifier: GPL-2.0+
- /*
- * Copyright (C) 2023 Loongson Technology Corporation Limited
- */
- #include <linux/delay.h>
- #include <drm/drm_atomic.h>
- #include <drm/drm_atomic_helper.h>
- #include <drm/drm_framebuffer.h>
- #include <drm/drm_gem_atomic_helper.h>
- #include <drm/drm_print.h>
- #include "lsdc_drv.h"
- #include "lsdc_regs.h"
- #include "lsdc_ttm.h"
- static const u32 lsdc_primary_formats[] = {
- DRM_FORMAT_XRGB8888,
- };
- static const u32 lsdc_cursor_formats[] = {
- DRM_FORMAT_ARGB8888,
- };
- static const u64 lsdc_fb_format_modifiers[] = {
- DRM_FORMAT_MOD_LINEAR,
- DRM_FORMAT_MOD_INVALID
- };
- static unsigned int lsdc_get_fb_offset(struct drm_framebuffer *fb,
- struct drm_plane_state *state)
- {
- unsigned int offset = fb->offsets[0];
- offset += fb->format->cpp[0] * (state->src_x >> 16);
- offset += fb->pitches[0] * (state->src_y >> 16);
- return offset;
- }
- static u64 lsdc_fb_base_addr(struct drm_framebuffer *fb)
- {
- struct lsdc_device *ldev = to_lsdc(fb->dev);
- struct lsdc_bo *lbo = gem_to_lsdc_bo(fb->obj[0]);
- return lsdc_bo_gpu_offset(lbo) + ldev->vram_base;
- }
- static int lsdc_primary_atomic_check(struct drm_plane *plane,
- struct drm_atomic_state *state)
- {
- struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
- struct drm_crtc *crtc = new_plane_state->crtc;
- struct drm_crtc_state *new_crtc_state;
- if (!crtc)
- return 0;
- new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
- return drm_atomic_helper_check_plane_state(new_plane_state,
- new_crtc_state,
- DRM_PLANE_NO_SCALING,
- DRM_PLANE_NO_SCALING,
- false, true);
- }
- static void lsdc_primary_atomic_update(struct drm_plane *plane,
- struct drm_atomic_state *state)
- {
- struct lsdc_primary *primary = to_lsdc_primary(plane);
- const struct lsdc_primary_plane_ops *ops = primary->ops;
- struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
- struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
- struct drm_framebuffer *new_fb = new_plane_state->fb;
- struct drm_framebuffer *old_fb = old_plane_state->fb;
- u64 fb_addr = lsdc_fb_base_addr(new_fb);
- fb_addr += lsdc_get_fb_offset(new_fb, new_plane_state);
- ops->update_fb_addr(primary, fb_addr);
- ops->update_fb_stride(primary, new_fb->pitches[0]);
- if (!old_fb || old_fb->format != new_fb->format)
- ops->update_fb_format(primary, new_fb->format);
- }
- static void lsdc_primary_atomic_disable(struct drm_plane *plane,
- struct drm_atomic_state *state)
- {
- /*
- * Do nothing, just prevent call into atomic_update().
- * Writing the format as LSDC_PF_NONE can disable the primary,
- * But it seems not necessary...
- */
- drm_dbg(plane->dev, "%s disabled\n", plane->name);
- }
- static int lsdc_plane_prepare_fb(struct drm_plane *plane,
- struct drm_plane_state *new_state)
- {
- struct drm_framebuffer *fb = new_state->fb;
- struct lsdc_bo *lbo;
- u64 gpu_vaddr;
- int ret;
- if (!fb)
- return 0;
- lbo = gem_to_lsdc_bo(fb->obj[0]);
- ret = lsdc_bo_reserve(lbo);
- if (unlikely(ret)) {
- drm_err(plane->dev, "bo %p reserve failed\n", lbo);
- return ret;
- }
- ret = lsdc_bo_pin(lbo, LSDC_GEM_DOMAIN_VRAM, &gpu_vaddr);
- lsdc_bo_unreserve(lbo);
- if (unlikely(ret)) {
- drm_err(plane->dev, "bo %p pin failed\n", lbo);
- return ret;
- }
- lsdc_bo_ref(lbo);
- if (plane->type != DRM_PLANE_TYPE_CURSOR)
- drm_dbg(plane->dev,
- "%s[%p] pin at 0x%llx, bo size: %zu\n",
- plane->name, lbo, gpu_vaddr, lsdc_bo_size(lbo));
- return drm_gem_plane_helper_prepare_fb(plane, new_state);
- }
- static void lsdc_plane_cleanup_fb(struct drm_plane *plane,
- struct drm_plane_state *old_state)
- {
- struct drm_framebuffer *fb = old_state->fb;
- struct lsdc_bo *lbo;
- int ret;
- if (!fb)
- return;
- lbo = gem_to_lsdc_bo(fb->obj[0]);
- ret = lsdc_bo_reserve(lbo);
- if (unlikely(ret)) {
- drm_err(plane->dev, "%p reserve failed\n", lbo);
- return;
- }
- lsdc_bo_unpin(lbo);
- lsdc_bo_unreserve(lbo);
- lsdc_bo_unref(lbo);
- if (plane->type != DRM_PLANE_TYPE_CURSOR)
- drm_dbg(plane->dev, "%s unpin\n", plane->name);
- }
- static const struct drm_plane_helper_funcs lsdc_primary_helper_funcs = {
- .prepare_fb = lsdc_plane_prepare_fb,
- .cleanup_fb = lsdc_plane_cleanup_fb,
- .atomic_check = lsdc_primary_atomic_check,
- .atomic_update = lsdc_primary_atomic_update,
- .atomic_disable = lsdc_primary_atomic_disable,
- };
- static int lsdc_cursor_plane_atomic_async_check(struct drm_plane *plane,
- struct drm_atomic_state *state,
- bool flip)
- {
- struct drm_plane_state *new_state;
- struct drm_crtc_state *crtc_state;
- new_state = drm_atomic_get_new_plane_state(state, plane);
- if (!plane->state || !plane->state->fb) {
- drm_dbg(plane->dev, "%s: state is NULL\n", plane->name);
- return -EINVAL;
- }
- if (new_state->crtc_w != new_state->crtc_h) {
- drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n",
- new_state->crtc_w, new_state->crtc_h);
- return -EINVAL;
- }
- if (new_state->crtc_w != 64 && new_state->crtc_w != 32) {
- drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n",
- new_state->crtc_w, new_state->crtc_h);
- return -EINVAL;
- }
- crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
- if (!crtc_state->active)
- return -EINVAL;
- if (plane->state->crtc != new_state->crtc ||
- plane->state->src_w != new_state->src_w ||
- plane->state->src_h != new_state->src_h ||
- plane->state->crtc_w != new_state->crtc_w ||
- plane->state->crtc_h != new_state->crtc_h)
- return -EINVAL;
- if (new_state->visible != plane->state->visible)
- return -EINVAL;
- return drm_atomic_helper_check_plane_state(plane->state,
- crtc_state,
- DRM_PLANE_NO_SCALING,
- DRM_PLANE_NO_SCALING,
- true, true);
- }
- static void lsdc_cursor_plane_atomic_async_update(struct drm_plane *plane,
- struct drm_atomic_state *state)
- {
- struct lsdc_cursor *cursor = to_lsdc_cursor(plane);
- const struct lsdc_cursor_plane_ops *ops = cursor->ops;
- struct drm_framebuffer *old_fb = plane->state->fb;
- struct drm_framebuffer *new_fb;
- struct drm_plane_state *new_state;
- new_state = drm_atomic_get_new_plane_state(state, plane);
- new_fb = plane->state->fb;
- plane->state->crtc_x = new_state->crtc_x;
- plane->state->crtc_y = new_state->crtc_y;
- plane->state->crtc_h = new_state->crtc_h;
- plane->state->crtc_w = new_state->crtc_w;
- plane->state->src_x = new_state->src_x;
- plane->state->src_y = new_state->src_y;
- plane->state->src_h = new_state->src_h;
- plane->state->src_w = new_state->src_w;
- swap(plane->state->fb, new_state->fb);
- if (new_state->visible) {
- enum lsdc_cursor_size cursor_size;
- switch (new_state->crtc_w) {
- case 64:
- cursor_size = CURSOR_SIZE_64X64;
- break;
- case 32:
- cursor_size = CURSOR_SIZE_32X32;
- break;
- default:
- cursor_size = CURSOR_SIZE_32X32;
- break;
- }
- ops->update_position(cursor, new_state->crtc_x, new_state->crtc_y);
- ops->update_cfg(cursor, cursor_size, CURSOR_FORMAT_ARGB8888);
- if (!old_fb || old_fb != new_fb)
- ops->update_bo_addr(cursor, lsdc_fb_base_addr(new_fb));
- }
- }
- /* ls7a1000 cursor plane helpers */
- static int ls7a1000_cursor_plane_atomic_check(struct drm_plane *plane,
- struct drm_atomic_state *state)
- {
- struct drm_plane_state *new_plane_state;
- struct drm_crtc_state *new_crtc_state;
- struct drm_crtc *crtc;
- new_plane_state = drm_atomic_get_new_plane_state(state, plane);
- crtc = new_plane_state->crtc;
- if (!crtc) {
- drm_dbg(plane->dev, "%s is not bind to a crtc\n", plane->name);
- return 0;
- }
- if (new_plane_state->crtc_w != 32 || new_plane_state->crtc_h != 32) {
- drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n",
- new_plane_state->crtc_w, new_plane_state->crtc_h);
- return -EINVAL;
- }
- new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
- return drm_atomic_helper_check_plane_state(new_plane_state,
- new_crtc_state,
- DRM_PLANE_NO_SCALING,
- DRM_PLANE_NO_SCALING,
- true, true);
- }
- static void ls7a1000_cursor_plane_atomic_update(struct drm_plane *plane,
- struct drm_atomic_state *state)
- {
- struct lsdc_cursor *cursor = to_lsdc_cursor(plane);
- struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
- struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
- struct drm_framebuffer *new_fb = new_plane_state->fb;
- struct drm_framebuffer *old_fb = old_plane_state->fb;
- const struct lsdc_cursor_plane_ops *ops = cursor->ops;
- u64 addr = lsdc_fb_base_addr(new_fb);
- if (!new_plane_state->visible)
- return;
- ops->update_position(cursor, new_plane_state->crtc_x, new_plane_state->crtc_y);
- if (!old_fb || old_fb != new_fb)
- ops->update_bo_addr(cursor, addr);
- ops->update_cfg(cursor, CURSOR_SIZE_32X32, CURSOR_FORMAT_ARGB8888);
- }
- static void ls7a1000_cursor_plane_atomic_disable(struct drm_plane *plane,
- struct drm_atomic_state *state)
- {
- struct lsdc_cursor *cursor = to_lsdc_cursor(plane);
- const struct lsdc_cursor_plane_ops *ops = cursor->ops;
- ops->update_cfg(cursor, CURSOR_SIZE_32X32, CURSOR_FORMAT_DISABLE);
- }
- static const struct drm_plane_helper_funcs ls7a1000_cursor_plane_helper_funcs = {
- .prepare_fb = lsdc_plane_prepare_fb,
- .cleanup_fb = lsdc_plane_cleanup_fb,
- .atomic_check = ls7a1000_cursor_plane_atomic_check,
- .atomic_update = ls7a1000_cursor_plane_atomic_update,
- .atomic_disable = ls7a1000_cursor_plane_atomic_disable,
- .atomic_async_check = lsdc_cursor_plane_atomic_async_check,
- .atomic_async_update = lsdc_cursor_plane_atomic_async_update,
- };
- /* ls7a2000 cursor plane helpers */
- static int ls7a2000_cursor_plane_atomic_check(struct drm_plane *plane,
- struct drm_atomic_state *state)
- {
- struct drm_plane_state *new_plane_state;
- struct drm_crtc_state *new_crtc_state;
- struct drm_crtc *crtc;
- new_plane_state = drm_atomic_get_new_plane_state(state, plane);
- crtc = new_plane_state->crtc;
- if (!crtc) {
- drm_dbg(plane->dev, "%s is not bind to a crtc\n", plane->name);
- return 0;
- }
- if (new_plane_state->crtc_w != new_plane_state->crtc_h) {
- drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n",
- new_plane_state->crtc_w, new_plane_state->crtc_h);
- return -EINVAL;
- }
- if (new_plane_state->crtc_w != 64 && new_plane_state->crtc_w != 32) {
- drm_dbg(plane->dev, "unsupported cursor size: %ux%u\n",
- new_plane_state->crtc_w, new_plane_state->crtc_h);
- return -EINVAL;
- }
- new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
- return drm_atomic_helper_check_plane_state(new_plane_state,
- new_crtc_state,
- DRM_PLANE_NO_SCALING,
- DRM_PLANE_NO_SCALING,
- true, true);
- }
- /* Update the format, size and location of the cursor */
- static void ls7a2000_cursor_plane_atomic_update(struct drm_plane *plane,
- struct drm_atomic_state *state)
- {
- struct lsdc_cursor *cursor = to_lsdc_cursor(plane);
- struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
- struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane);
- struct drm_framebuffer *new_fb = new_plane_state->fb;
- struct drm_framebuffer *old_fb = old_plane_state->fb;
- const struct lsdc_cursor_plane_ops *ops = cursor->ops;
- enum lsdc_cursor_size cursor_size;
- if (!new_plane_state->visible)
- return;
- ops->update_position(cursor, new_plane_state->crtc_x, new_plane_state->crtc_y);
- if (!old_fb || new_fb != old_fb) {
- u64 addr = lsdc_fb_base_addr(new_fb);
- ops->update_bo_addr(cursor, addr);
- }
- switch (new_plane_state->crtc_w) {
- case 64:
- cursor_size = CURSOR_SIZE_64X64;
- break;
- case 32:
- cursor_size = CURSOR_SIZE_32X32;
- break;
- default:
- cursor_size = CURSOR_SIZE_64X64;
- break;
- }
- ops->update_cfg(cursor, cursor_size, CURSOR_FORMAT_ARGB8888);
- }
- static void ls7a2000_cursor_plane_atomic_disable(struct drm_plane *plane,
- struct drm_atomic_state *state)
- {
- struct lsdc_cursor *cursor = to_lsdc_cursor(plane);
- const struct lsdc_cursor_plane_ops *hw_ops = cursor->ops;
- hw_ops->update_cfg(cursor, CURSOR_SIZE_64X64, CURSOR_FORMAT_DISABLE);
- }
- static const struct drm_plane_helper_funcs ls7a2000_cursor_plane_helper_funcs = {
- .prepare_fb = lsdc_plane_prepare_fb,
- .cleanup_fb = lsdc_plane_cleanup_fb,
- .atomic_check = ls7a2000_cursor_plane_atomic_check,
- .atomic_update = ls7a2000_cursor_plane_atomic_update,
- .atomic_disable = ls7a2000_cursor_plane_atomic_disable,
- .atomic_async_check = lsdc_cursor_plane_atomic_async_check,
- .atomic_async_update = lsdc_cursor_plane_atomic_async_update,
- };
- static void lsdc_plane_atomic_print_state(struct drm_printer *p,
- const struct drm_plane_state *state)
- {
- struct drm_framebuffer *fb = state->fb;
- u64 addr;
- if (!fb)
- return;
- addr = lsdc_fb_base_addr(fb);
- drm_printf(p, "\tdma addr=%llx\n", addr);
- }
- static const struct drm_plane_funcs lsdc_plane_funcs = {
- .update_plane = drm_atomic_helper_update_plane,
- .disable_plane = drm_atomic_helper_disable_plane,
- .destroy = drm_plane_cleanup,
- .reset = drm_atomic_helper_plane_reset,
- .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
- .atomic_print_state = lsdc_plane_atomic_print_state,
- };
- /* Primary plane 0 hardware related ops */
- static void lsdc_primary0_update_fb_addr(struct lsdc_primary *primary, u64 addr)
- {
- struct lsdc_device *ldev = primary->ldev;
- u32 status;
- u32 lo, hi;
- /* 40-bit width physical address bus */
- lo = addr & 0xFFFFFFFF;
- hi = (addr >> 32) & 0xFF;
- status = lsdc_rreg32(ldev, LSDC_CRTC0_CFG_REG);
- if (status & FB_REG_IN_USING) {
- lsdc_wreg32(ldev, LSDC_CRTC0_FB1_ADDR_LO_REG, lo);
- lsdc_wreg32(ldev, LSDC_CRTC0_FB1_ADDR_HI_REG, hi);
- } else {
- lsdc_wreg32(ldev, LSDC_CRTC0_FB0_ADDR_LO_REG, lo);
- lsdc_wreg32(ldev, LSDC_CRTC0_FB0_ADDR_HI_REG, hi);
- }
- }
- static void lsdc_primary0_update_fb_stride(struct lsdc_primary *primary, u32 stride)
- {
- struct lsdc_device *ldev = primary->ldev;
- lsdc_wreg32(ldev, LSDC_CRTC0_STRIDE_REG, stride);
- }
- static void lsdc_primary0_update_fb_format(struct lsdc_primary *primary,
- const struct drm_format_info *format)
- {
- struct lsdc_device *ldev = primary->ldev;
- u32 status;
- status = lsdc_rreg32(ldev, LSDC_CRTC0_CFG_REG);
- /*
- * TODO: add RGB565 support, only support XRBG8888 at present
- */
- status &= ~CFG_PIX_FMT_MASK;
- status |= LSDC_PF_XRGB8888;
- lsdc_wreg32(ldev, LSDC_CRTC0_CFG_REG, status);
- }
- /* Primary plane 1 hardware related ops */
- static void lsdc_primary1_update_fb_addr(struct lsdc_primary *primary, u64 addr)
- {
- struct lsdc_device *ldev = primary->ldev;
- u32 status;
- u32 lo, hi;
- /* 40-bit width physical address bus */
- lo = addr & 0xFFFFFFFF;
- hi = (addr >> 32) & 0xFF;
- status = lsdc_rreg32(ldev, LSDC_CRTC1_CFG_REG);
- if (status & FB_REG_IN_USING) {
- lsdc_wreg32(ldev, LSDC_CRTC1_FB1_ADDR_LO_REG, lo);
- lsdc_wreg32(ldev, LSDC_CRTC1_FB1_ADDR_HI_REG, hi);
- } else {
- lsdc_wreg32(ldev, LSDC_CRTC1_FB0_ADDR_LO_REG, lo);
- lsdc_wreg32(ldev, LSDC_CRTC1_FB0_ADDR_HI_REG, hi);
- }
- }
- static void lsdc_primary1_update_fb_stride(struct lsdc_primary *primary, u32 stride)
- {
- struct lsdc_device *ldev = primary->ldev;
- lsdc_wreg32(ldev, LSDC_CRTC1_STRIDE_REG, stride);
- }
- static void lsdc_primary1_update_fb_format(struct lsdc_primary *primary,
- const struct drm_format_info *format)
- {
- struct lsdc_device *ldev = primary->ldev;
- u32 status;
- status = lsdc_rreg32(ldev, LSDC_CRTC1_CFG_REG);
- /*
- * TODO: add RGB565 support, only support XRBG8888 at present
- */
- status &= ~CFG_PIX_FMT_MASK;
- status |= LSDC_PF_XRGB8888;
- lsdc_wreg32(ldev, LSDC_CRTC1_CFG_REG, status);
- }
- static const struct lsdc_primary_plane_ops lsdc_primary_plane_hw_ops[2] = {
- {
- .update_fb_addr = lsdc_primary0_update_fb_addr,
- .update_fb_stride = lsdc_primary0_update_fb_stride,
- .update_fb_format = lsdc_primary0_update_fb_format,
- },
- {
- .update_fb_addr = lsdc_primary1_update_fb_addr,
- .update_fb_stride = lsdc_primary1_update_fb_stride,
- .update_fb_format = lsdc_primary1_update_fb_format,
- },
- };
- /*
- * Update location, format, enable and disable state of the cursor,
- * For those who have two hardware cursor, let cursor 0 is attach to CRTC-0,
- * cursor 1 is attach to CRTC-1. Compositing the primary plane and cursor
- * plane is automatically done by hardware, the cursor is alway on the top of
- * the primary plane. In other word, z-order is fixed in hardware and cannot
- * be changed. For those old DC who has only one hardware cursor, we made it
- * shared by the two screen, this works on extend screen mode.
- */
- /* cursor plane 0 (for pipe 0) related hardware ops */
- static void lsdc_cursor0_update_bo_addr(struct lsdc_cursor *cursor, u64 addr)
- {
- struct lsdc_device *ldev = cursor->ldev;
- /* 40-bit width physical address bus */
- lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_HI_REG, (addr >> 32) & 0xFF);
- lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_LO_REG, addr);
- }
- static void lsdc_cursor0_update_position(struct lsdc_cursor *cursor, int x, int y)
- {
- struct lsdc_device *ldev = cursor->ldev;
- if (x < 0)
- x = 0;
- if (y < 0)
- y = 0;
- lsdc_wreg32(ldev, LSDC_CURSOR0_POSITION_REG, (y << 16) | x);
- }
- static void lsdc_cursor0_update_cfg(struct lsdc_cursor *cursor,
- enum lsdc_cursor_size cursor_size,
- enum lsdc_cursor_format fmt)
- {
- struct lsdc_device *ldev = cursor->ldev;
- u32 cfg;
- cfg = CURSOR_ON_CRTC0 << CURSOR_LOCATION_SHIFT |
- cursor_size << CURSOR_SIZE_SHIFT |
- fmt << CURSOR_FORMAT_SHIFT;
- lsdc_wreg32(ldev, LSDC_CURSOR0_CFG_REG, cfg);
- }
- /* cursor plane 1 (for pipe 1) related hardware ops */
- static void lsdc_cursor1_update_bo_addr(struct lsdc_cursor *cursor, u64 addr)
- {
- struct lsdc_device *ldev = cursor->ldev;
- /* 40-bit width physical address bus */
- lsdc_wreg32(ldev, LSDC_CURSOR1_ADDR_HI_REG, (addr >> 32) & 0xFF);
- lsdc_wreg32(ldev, LSDC_CURSOR1_ADDR_LO_REG, addr);
- }
- static void lsdc_cursor1_update_position(struct lsdc_cursor *cursor, int x, int y)
- {
- struct lsdc_device *ldev = cursor->ldev;
- if (x < 0)
- x = 0;
- if (y < 0)
- y = 0;
- lsdc_wreg32(ldev, LSDC_CURSOR1_POSITION_REG, (y << 16) | x);
- }
- static void lsdc_cursor1_update_cfg(struct lsdc_cursor *cursor,
- enum lsdc_cursor_size cursor_size,
- enum lsdc_cursor_format fmt)
- {
- struct lsdc_device *ldev = cursor->ldev;
- u32 cfg;
- cfg = CURSOR_ON_CRTC1 << CURSOR_LOCATION_SHIFT |
- cursor_size << CURSOR_SIZE_SHIFT |
- fmt << CURSOR_FORMAT_SHIFT;
- lsdc_wreg32(ldev, LSDC_CURSOR1_CFG_REG, cfg);
- }
- /* The hardware cursors become normal since ls7a2000/ls2k2000 */
- static const struct lsdc_cursor_plane_ops ls7a2000_cursor_hw_ops[2] = {
- {
- .update_bo_addr = lsdc_cursor0_update_bo_addr,
- .update_cfg = lsdc_cursor0_update_cfg,
- .update_position = lsdc_cursor0_update_position,
- },
- {
- .update_bo_addr = lsdc_cursor1_update_bo_addr,
- .update_cfg = lsdc_cursor1_update_cfg,
- .update_position = lsdc_cursor1_update_position,
- },
- };
- /* Quirks for cursor 1, only for old loongson display controller */
- static void lsdc_cursor1_update_bo_addr_quirk(struct lsdc_cursor *cursor, u64 addr)
- {
- struct lsdc_device *ldev = cursor->ldev;
- /* 40-bit width physical address bus */
- lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_HI_REG, (addr >> 32) & 0xFF);
- lsdc_wreg32(ldev, LSDC_CURSOR0_ADDR_LO_REG, addr);
- }
- static void lsdc_cursor1_update_position_quirk(struct lsdc_cursor *cursor, int x, int y)
- {
- struct lsdc_device *ldev = cursor->ldev;
- if (x < 0)
- x = 0;
- if (y < 0)
- y = 0;
- lsdc_wreg32(ldev, LSDC_CURSOR0_POSITION_REG, (y << 16) | x);
- }
- static void lsdc_cursor1_update_cfg_quirk(struct lsdc_cursor *cursor,
- enum lsdc_cursor_size cursor_size,
- enum lsdc_cursor_format fmt)
- {
- struct lsdc_device *ldev = cursor->ldev;
- u32 cfg;
- cfg = CURSOR_ON_CRTC1 << CURSOR_LOCATION_SHIFT |
- cursor_size << CURSOR_SIZE_SHIFT |
- fmt << CURSOR_FORMAT_SHIFT;
- lsdc_wreg32(ldev, LSDC_CURSOR0_CFG_REG, cfg);
- }
- /*
- * The unforgiving LS7A1000/LS2K1000 has only one hardware cursors plane
- */
- static const struct lsdc_cursor_plane_ops ls7a1000_cursor_hw_ops[2] = {
- {
- .update_bo_addr = lsdc_cursor0_update_bo_addr,
- .update_cfg = lsdc_cursor0_update_cfg,
- .update_position = lsdc_cursor0_update_position,
- },
- {
- .update_bo_addr = lsdc_cursor1_update_bo_addr_quirk,
- .update_cfg = lsdc_cursor1_update_cfg_quirk,
- .update_position = lsdc_cursor1_update_position_quirk,
- },
- };
- int lsdc_primary_plane_init(struct drm_device *ddev,
- struct drm_plane *plane,
- unsigned int index)
- {
- struct lsdc_primary *primary = to_lsdc_primary(plane);
- int ret;
- ret = drm_universal_plane_init(ddev, plane, 1 << index,
- &lsdc_plane_funcs,
- lsdc_primary_formats,
- ARRAY_SIZE(lsdc_primary_formats),
- lsdc_fb_format_modifiers,
- DRM_PLANE_TYPE_PRIMARY,
- "ls-primary-plane-%u", index);
- if (ret)
- return ret;
- drm_plane_helper_add(plane, &lsdc_primary_helper_funcs);
- primary->ldev = to_lsdc(ddev);
- primary->ops = &lsdc_primary_plane_hw_ops[index];
- return 0;
- }
- int ls7a1000_cursor_plane_init(struct drm_device *ddev,
- struct drm_plane *plane,
- unsigned int index)
- {
- struct lsdc_cursor *cursor = to_lsdc_cursor(plane);
- int ret;
- ret = drm_universal_plane_init(ddev, plane, 1 << index,
- &lsdc_plane_funcs,
- lsdc_cursor_formats,
- ARRAY_SIZE(lsdc_cursor_formats),
- lsdc_fb_format_modifiers,
- DRM_PLANE_TYPE_CURSOR,
- "ls-cursor-plane-%u", index);
- if (ret)
- return ret;
- cursor->ldev = to_lsdc(ddev);
- cursor->ops = &ls7a1000_cursor_hw_ops[index];
- drm_plane_helper_add(plane, &ls7a1000_cursor_plane_helper_funcs);
- return 0;
- }
- int ls7a2000_cursor_plane_init(struct drm_device *ddev,
- struct drm_plane *plane,
- unsigned int index)
- {
- struct lsdc_cursor *cursor = to_lsdc_cursor(plane);
- int ret;
- ret = drm_universal_plane_init(ddev, plane, 1 << index,
- &lsdc_plane_funcs,
- lsdc_cursor_formats,
- ARRAY_SIZE(lsdc_cursor_formats),
- lsdc_fb_format_modifiers,
- DRM_PLANE_TYPE_CURSOR,
- "ls-cursor-plane-%u", index);
- if (ret)
- return ret;
- cursor->ldev = to_lsdc(ddev);
- cursor->ops = &ls7a2000_cursor_hw_ops[index];
- drm_plane_helper_add(plane, &ls7a2000_cursor_plane_helper_funcs);
- return 0;
- }
|