[PATCH 08/28] drm/via: Add via_cursor.c
Kevin Brace
kevinbrace at gmx.com
Fri Jun 24 20:26:13 UTC 2022
From: Kevin Brace <kevinbrace at bracecomputerlab.com>
Signed-off-by: Kevin Brace <kevinbrace at bracecomputerlab.com>
---
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 at bracecomputerlab.com>
+ * James Simmons <jsimmons at infradead.org>
+ */
+
+#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
More information about the dri-devel
mailing list