From: Kevin Brace <kevinbrace@xxxxxxxxxxxxxxxxxxxx> Signed-off-by: Kevin Brace <kevinbrace@xxxxxxxxxxxxxxxxxxxx> --- drivers/gpu/drm/via/via_cursor.c | 419 +++++++++++++++++++++++++++++++ 1 file changed, 419 insertions(+) create mode 100644 drivers/gpu/drm/via/via_cursor.c diff --git a/drivers/gpu/drm/via/via_cursor.c b/drivers/gpu/drm/via/via_cursor.c new file mode 100644 index 000000000000..9a6bce1cf922 --- /dev/null +++ b/drivers/gpu/drm/via/via_cursor.c @@ -0,0 +1,419 @@ +/* + * Copyright © 2019-2020 Kevin Brace. + * Copyright 2012 James Simmons. All Rights Reserved. + * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2009 S3 Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) OR COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Author(s): + * Kevin Brace <kevinbrace@xxxxxxxxxxxxxxxxxxxx> + * James Simmons <jsimmons@xxxxxxxxxxxxx> + */ + +#include <linux/pci.h> +#include <linux/pci_ids.h> + +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_atomic_state_helper.h> +#include <drm/drm_crtc.h> +#include <drm/drm_fourcc.h> +#include <drm/drm_framebuffer.h> +#include <drm/drm_gem.h> +#include <drm/drm_mode.h> +#include <drm/drm_modeset_helper_vtables.h> +#include <drm/drm_plane.h> +#include <drm/drm_plane_helper.h> + +#include <drm/ttm/ttm_bo_api.h> +#include <drm/ttm/ttm_bo_driver.h> + +#include "via_drv.h" + + +static void via_hide_cursor(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct pci_dev *pdev = to_pci_dev(dev->dev); + struct via_crtc *iga = container_of(crtc, + struct via_crtc, base); + struct via_drm_priv *dev_priv = to_via_drm_priv(dev); + uint32_t temp; + + switch (pdev->device) { + case PCI_DEVICE_ID_VIA_VT3157: + case PCI_DEVICE_ID_VIA_VT3343: + case PCI_DEVICE_ID_VIA_P4M900: + case PCI_DEVICE_ID_VIA_VT1122: + case PCI_DEVICE_ID_VIA_VX875: + case PCI_DEVICE_ID_VIA_VX900_VGA: + if (iga->index) { + temp = VIA_READ(HI_CONTROL); + VIA_WRITE(HI_CONTROL, temp & 0xFFFFFFFA); + } else { + temp = VIA_READ(PRIM_HI_CTRL); + VIA_WRITE(PRIM_HI_CTRL, temp & 0xFFFFFFFA); + } + + break; + default: + temp = VIA_READ(HI_CONTROL); + VIA_WRITE(HI_CONTROL, temp & 0xFFFFFFFA); + break; + } +} + +static void via_show_cursor(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct pci_dev *pdev = to_pci_dev(dev->dev); + struct via_crtc *iga = container_of(crtc, + struct via_crtc, base); + struct via_drm_priv *dev_priv = to_via_drm_priv(dev); + + switch (pdev->device) { + case PCI_DEVICE_ID_VIA_VT3157: + case PCI_DEVICE_ID_VIA_VT3343: + case PCI_DEVICE_ID_VIA_P4M900: + case PCI_DEVICE_ID_VIA_VT1122: + case PCI_DEVICE_ID_VIA_VX875: + case PCI_DEVICE_ID_VIA_VX900_VGA: + /* + * Program Hardware Icon (HI) FIFO, foreground color, + * and background color. + */ + if (iga->index) { + VIA_WRITE(HI_TRANSPARENT_COLOR, 0x00000000); + VIA_WRITE(HI_INVTCOLOR, 0x00FFFFFF); + VIA_WRITE(ALPHA_V3_PREFIFO_CONTROL, + 0x000E0000); + VIA_WRITE(ALPHA_V3_FIFO_CONTROL, 0x0E0F0000); + } else { + VIA_WRITE(PRIM_HI_TRANSCOLOR, 0x00000000); + VIA_WRITE(PRIM_HI_INVTCOLOR, 0x00FFFFFF); + VIA_WRITE(V327_HI_INVTCOLOR, 0x00FFFFFF); + VIA_WRITE(PRIM_HI_FIFO, 0x0D000D0F); + } + + break; + default: + /* + * Program Hardware Icon (HI) FIFO, foreground color, + * and background color. + */ + VIA_WRITE(HI_TRANSPARENT_COLOR, 0x00000000); + VIA_WRITE(HI_INVTCOLOR, 0x00FFFFFF); + VIA_WRITE(ALPHA_V3_PREFIFO_CONTROL, 0x000E0000); + VIA_WRITE(ALPHA_V3_FIFO_CONTROL, 0xE0F0000); + break; + } + + switch (pdev->device) { + case PCI_DEVICE_ID_VIA_VT3157: + case PCI_DEVICE_ID_VIA_VT3343: + case PCI_DEVICE_ID_VIA_P4M900: + case PCI_DEVICE_ID_VIA_VT1122: + case PCI_DEVICE_ID_VIA_VX875: + case PCI_DEVICE_ID_VIA_VX900_VGA: + /* + * Turn on Hardware Icon (HI). + */ + if (iga->index) { + VIA_WRITE(HI_CONTROL, 0xB6000005); + } else { + VIA_WRITE(PRIM_HI_CTRL, 0x36000005); + } + + break; + default: + /* + * Turn on Hardware Icon (HI). + */ + if (iga->index) { + VIA_WRITE(HI_CONTROL, 0xB6000005); + } else { + VIA_WRITE(HI_CONTROL, 0x36000005); + } + + break; + } +} + +static void via_cursor_address(struct drm_crtc *crtc, + struct ttm_buffer_object *ttm_bo) +{ + struct drm_device *dev = crtc->dev; + struct pci_dev *pdev = to_pci_dev(dev->dev); + struct via_crtc *iga = container_of(crtc, + struct via_crtc, base); + struct via_drm_priv *dev_priv = to_via_drm_priv(dev); + + switch (pdev->device) { + case PCI_DEVICE_ID_VIA_VT3157: + case PCI_DEVICE_ID_VIA_VT3343: + case PCI_DEVICE_ID_VIA_P4M900: + case PCI_DEVICE_ID_VIA_VT1122: + case PCI_DEVICE_ID_VIA_VX875: + case PCI_DEVICE_ID_VIA_VX900_VGA: + /* + * Program Hardware Icon (HI) offset. + */ + if (iga->index) { + VIA_WRITE(HI_FBOFFSET, + ttm_bo->resource->start << PAGE_SHIFT); + } else { + VIA_WRITE(PRIM_HI_FBOFFSET, + ttm_bo->resource->start << PAGE_SHIFT); + } + break; + default: + /* + * Program Hardware Icon (HI) offset. + */ + VIA_WRITE(HI_FBOFFSET, ttm_bo->resource->start << PAGE_SHIFT); + break; + } + + return; +} + +static void via_set_hi_location(struct drm_crtc *crtc, int crtc_x, int crtc_y) +{ + struct drm_device *dev = crtc->dev; + struct pci_dev *pdev = to_pci_dev(dev->dev); + struct via_crtc *iga = container_of(crtc, + struct via_crtc, base); + struct via_drm_priv *dev_priv = to_via_drm_priv(dev); + uint32_t location_x = 0, location_y = 0; + uint32_t offset_x = 0, offset_y = 0; + + if (crtc_x < 0) { + offset_x = -crtc_x; + } else { + location_x = crtc_x; + } + + if (crtc_y < 0) { + offset_y = -crtc_y; + } else { + location_y = crtc_y; + } + + switch (pdev->device) { + case PCI_DEVICE_ID_VIA_VT3157: + case PCI_DEVICE_ID_VIA_VT3343: + case PCI_DEVICE_ID_VIA_P4M900: + case PCI_DEVICE_ID_VIA_VT1122: + case PCI_DEVICE_ID_VIA_VX875: + case PCI_DEVICE_ID_VIA_VX900_VGA: + if (iga->index) { + VIA_WRITE(HI_POSSTART, + (((location_x & 0x07ff) << 16) | + (location_y & 0x07ff))); + VIA_WRITE(HI_CENTEROFFSET, + (((offset_x & 0x07ff) << 16) | + (offset_y & 0x07ff))); + } else { + VIA_WRITE(PRIM_HI_POSSTART, + (((location_x & 0x07ff) << 16) | + (location_y & 0x07ff))); + VIA_WRITE(PRIM_HI_CENTEROFFSET, + (((offset_x & 0x07ff) << 16) | + (offset_y & 0x07ff))); + } + + break; + default: + VIA_WRITE(HI_POSSTART, + (((location_x & 0x07ff) << 16) | + (location_y & 0x07ff))); + VIA_WRITE(HI_CENTEROFFSET, + (((offset_x & 0x07ff) << 16) | + (offset_y & 0x07ff))); + break; + } +} + +static int via_cursor_prepare_fb(struct drm_plane *plane, + struct drm_plane_state *new_state) +{ + struct drm_gem_object *gem; + struct ttm_buffer_object *ttm_bo; + struct via_bo *bo; + int ret = 0; + + DRM_DEBUG_KMS("Entered %s.\n", __func__); + + if (!new_state->fb) { + goto exit; + } + + gem = new_state->fb->obj[0]; + ttm_bo = container_of(gem, struct ttm_buffer_object, base); + bo = to_ttm_bo(ttm_bo); + + ret = ttm_bo_reserve(ttm_bo, true, false, NULL); + if (ret) { + goto exit; + } + + ret = via_bo_pin(bo, TTM_PL_VRAM); + ttm_bo_unreserve(ttm_bo); + ret = ttm_bo_kmap(ttm_bo, 0, ttm_bo->resource->num_pages, &bo->kmap); + if (ret) { + goto exit; + } + +exit: + DRM_DEBUG_KMS("Exiting %s.\n", __func__); + return ret; +} + +static void via_cursor_cleanup_fb(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct drm_gem_object *gem; + struct ttm_buffer_object *ttm_bo; + struct via_bo *bo; + int ret; + + DRM_DEBUG_KMS("Entered %s.\n", __func__); + + if (!old_state->fb) { + goto exit; + } + + gem = old_state->fb->obj[0]; + ttm_bo = container_of(gem, struct ttm_buffer_object, base); + bo = to_ttm_bo(ttm_bo); + + ttm_bo_kunmap(&bo->kmap); + ret = ttm_bo_reserve(ttm_bo, true, false, NULL); + if (ret) { + goto exit; + } + + via_bo_unpin(bo); + ttm_bo_unreserve(ttm_bo); + +exit: + DRM_DEBUG_KMS("Exiting %s.\n", __func__); +} + +static int via_cursor_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_state *new_crtc_state; + struct drm_framebuffer *fb = new_plane_state->fb; + int ret = 0; + + DRM_DEBUG_KMS("Entered %s.\n", __func__); + + if ((!new_plane_state->crtc) || (!new_plane_state->visible)) { + goto exit; + } + + if (fb->width != fb->height) { + DRM_ERROR("Hardware cursor is expected to have " + "square dimensions.\n"); + ret = -EINVAL; + goto exit; + } + + new_crtc_state = drm_atomic_get_new_crtc_state(state, + new_plane_state->crtc); + ret = drm_atomic_helper_check_plane_state( + new_plane_state, + new_crtc_state, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + true, true); +exit: + DRM_DEBUG_KMS("Exiting %s.\n", __func__); + return ret; +} + +static void via_cursor_atomic_update(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_plane_state *new_state = + drm_atomic_get_new_plane_state(state, plane); + struct drm_plane_state *old_state = + drm_atomic_get_old_plane_state(state, plane); + struct drm_crtc *crtc = new_state->crtc; + struct drm_gem_object *gem; + struct ttm_buffer_object *ttm_bo; + + DRM_DEBUG_KMS("Entered %s.\n", __func__); + + if (new_state->fb != old_state->fb) { + gem = new_state->fb->obj[0]; + ttm_bo = container_of(gem, struct ttm_buffer_object, base); + via_cursor_address(crtc, ttm_bo); + } + + via_set_hi_location(crtc, new_state->crtc_x, new_state->crtc_y); + via_show_cursor(crtc); + + DRM_DEBUG_KMS("Exiting %s.\n", __func__); +} + +void via_cursor_atomic_disable(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_plane_state *new_state = + drm_atomic_get_new_plane_state(state, plane); + struct drm_crtc *crtc = new_state->crtc; + + DRM_DEBUG_KMS("Entered %s.\n", __func__); + + if (crtc) { + via_hide_cursor(crtc); + } + + DRM_DEBUG_KMS("Exiting %s.\n", __func__); +} + +const struct drm_plane_helper_funcs via_cursor_drm_plane_helper_funcs = { + .prepare_fb = via_cursor_prepare_fb, + .cleanup_fb = via_cursor_cleanup_fb, + .atomic_check = via_cursor_atomic_check, + .atomic_update = via_cursor_atomic_update, + .atomic_disable = via_cursor_atomic_disable, +}; + +const struct drm_plane_funcs via_cursor_drm_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, +}; + +const uint32_t via_cursor_formats[] = { + DRM_FORMAT_ARGB8888, +}; + +const unsigned int via_cursor_formats_size = + ARRAY_SIZE(via_cursor_formats); -- 2.35.1