[PATCH v2 4/4] drm/mgag200: Use DMA to copy the framebuffer to the VRAM
Jocelyn Falempe
jfalempe at redhat.com
Thu Jun 15 17:15:05 UTC 2023
On 15/06/2023 16:24, Thomas Zimmermann wrote:
> Hi Jocelyn
>
> Am 31.05.23 um 11:21 schrieb Jocelyn Falempe:
>> Even if the transfer is not faster, it brings significant
>> improvement in latencies and CPU usage.
>>
>> CPU usage drops from 100% of one core to 3% when continuously
>> refreshing the screen.
>
> I tried your patchset on a HP Proliant server with a G200EH. I can see
> that the CPU usage goes down, but the time until the screen update
> reaches the hardware's video memory has increased significantly.
Thanks for taking time to test it.
Can you check if there is something in the dmesg ?
The 1s looks suspicious, if the IRQ is not working, there is a 1s
timeout, which can explain why it will display only one frame per
second. (logs should be filled with "DMA transfer timed out")
I will see if I can get access to a G200EH, and if I can reproduce this.
Best regards,
--
Jocelyn
>
> Any display update that is more than just moving the mouse results in
> tearing. I can see how the individial scanlines are updated from top to
> bottom. That takes ~1 sec per full frame. So this patch renders the
> display from slow to barely usable.
>
> Best regards
> Thomas
>
>>
>> The primary DMA is used to send commands (register write), and
>> the secondary DMA to send the pixel data.
>> It uses the ILOAD command (chapter 4.5.7 in G200 specification),
>> which allows to load an image, or a part of an image from system
>> memory to VRAM.
>> The last command sent, is a softrap command, which triggers an IRQ
>> when the DMA transfer is complete.
>> For 16bits and 24bits pixel width, each line is padded to make sure,
>> the DMA transfer is a multiple of 32bits. The padded bytes won't be
>> drawn on the screen, so they don't need to be initialized.
>>
>> Signed-off-by: Jocelyn Falempe <jfalempe at redhat.com>
>> ---
>> drivers/gpu/drm/mgag200/Makefile | 3 +-
>> drivers/gpu/drm/mgag200/mgag200_dma.c | 237 ++++++++++++++++++++++
>> drivers/gpu/drm/mgag200/mgag200_drv.c | 4 +-
>> drivers/gpu/drm/mgag200/mgag200_drv.h | 29 +++
>> drivers/gpu/drm/mgag200/mgag200_g200.c | 4 +
>> drivers/gpu/drm/mgag200/mgag200_g200eh.c | 4 +
>> drivers/gpu/drm/mgag200/mgag200_g200eh3.c | 4 +
>> drivers/gpu/drm/mgag200/mgag200_g200er.c | 4 +
>> drivers/gpu/drm/mgag200/mgag200_g200ev.c | 4 +
>> drivers/gpu/drm/mgag200/mgag200_g200ew3.c | 4 +
>> drivers/gpu/drm/mgag200/mgag200_g200se.c | 4 +
>> drivers/gpu/drm/mgag200/mgag200_g200wb.c | 4 +
>> drivers/gpu/drm/mgag200/mgag200_mode.c | 15 +-
>> drivers/gpu/drm/mgag200/mgag200_reg.h | 25 +++
>> 14 files changed, 333 insertions(+), 12 deletions(-)
>> create mode 100644 drivers/gpu/drm/mgag200/mgag200_dma.c
>>
>> diff --git a/drivers/gpu/drm/mgag200/Makefile
>> b/drivers/gpu/drm/mgag200/Makefile
>> index 182e224c460d..96e23dc5572c 100644
>> --- a/drivers/gpu/drm/mgag200/Makefile
>> +++ b/drivers/gpu/drm/mgag200/Makefile
>> @@ -11,6 +11,7 @@ mgag200-y := \
>> mgag200_g200se.o \
>> mgag200_g200wb.o \
>> mgag200_i2c.o \
>> - mgag200_mode.o
>> + mgag200_mode.o \
>> + mgag200_dma.o
>> obj-$(CONFIG_DRM_MGAG200) += mgag200.o
>> diff --git a/drivers/gpu/drm/mgag200/mgag200_dma.c
>> b/drivers/gpu/drm/mgag200/mgag200_dma.c
>> new file mode 100644
>> index 000000000000..7e9b59ef08d9
>> --- /dev/null
>> +++ b/drivers/gpu/drm/mgag200/mgag200_dma.c
>> @@ -0,0 +1,237 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright 2023 Red Hat
>> + *
>> + * Authors: Jocelyn Falempe
>> + *
>> + */
>> +
>> +#include <linux/dma-mapping.h>
>> +#include <linux/iosys-map.h>
>> +#include <linux/wait.h>
>> +
>> +#include <drm/drm_framebuffer.h>
>> +
>> +#include "mgag200_drv.h"
>> +#include "mgag200_reg.h"
>> +
>> +/* Maximum number of command block for one DMA transfer
>> + * iload should only use 4 blocks
>> + */
>> +#define MGA_MAX_CMD 50
>> +
>> +#define MGA_DMA_SIZE (4 * 1024 * 1024)
>> +#define MGA_MIN_DMA_SIZE (64 * 1024)
>> +
>> +/*
>> + * Allocate coherent buffers for DMA transfer.
>> + * We need two buffers, one for the commands, and one for the data.
>> + */
>> +int mgag200_dma_init(struct mga_device *mdev)
>> +{
>> + struct drm_device *dev = &mdev->base;
>> + struct mga_dma *dma = &mdev->dma;
>> + int size;
>> + /* Allocate the command buffer */
>> + dma->cmd = dmam_alloc_coherent(dev->dev, MGA_MAX_CMD *
>> sizeof(*dma->cmd),
>> + &dma->cmd_handle, GFP_KERNEL);
>> +
>> + if (!dma->cmd) {
>> + drm_err(dev, "DMA command buffer allocation failed\n");
>> + return -ENOMEM;
>> + }
>> +
>> + for (size = MGA_DMA_SIZE; size >= MGA_MIN_DMA_SIZE; size = size
>> >> 1) {
>> + dma->buf = dmam_alloc_coherent(dev->dev, size, &dma->handle,
>> GFP_KERNEL);
>> + if (dma->buf)
>> + break;
>> + }
>> + if (!dma->buf) {
>> + drm_err(dev, "DMA data buffer allocation failed\n");
>> + return -ENOMEM;
>> + }
>> + dma->size = size;
>> + drm_info(dev, "Using DMA with a %dk data buffer\n", size / 1024);
>> +
>> + init_waitqueue_head(&dma->waitq);
>> + return 0;
>> +}
>> +
>> +/*
>> + * Matrox uses a command block to program the hardware through DMA.
>> + * Each command is a register write, and each block contains 4 commands
>> + * packed in 5 dwords(u32).
>> + * First dword is the 4 register index (8bit) to write for the 4
>> commands,
>> + * followed by the four values to be written.
>> + */
>> +static void mgag200_dma_add_block(struct mga_device *mdev,
>> + u32 reg0, u32 val0,
>> + u32 reg1, u32 val1,
>> + u32 reg2, u32 val2,
>> + u32 reg3, u32 val3)
>> +{
>> + if (mdev->dma.cmd_idx >= MGA_MAX_CMD) {
>> + pr_err("mgag200: exceeding the DMA command buffer size\n");
>> + return;
>> + }
>> +
>> + mdev->dma.cmd[mdev->dma.cmd_idx] = (struct mga_cmd_block) {
>> + .cmd = DMAREG(reg0) | DMAREG(reg1) << 8 | DMAREG(reg2) << 16
>> | DMAREG(reg3) << 24,
>> + .v0 = val0,
>> + .v1 = val1,
>> + .v2 = val2,
>> + .v3 = val3};
>> + mdev->dma.cmd_idx++;
>> +}
>> +
>> +static void mgag200_dma_run_cmd(struct mga_device *mdev)
>> +{
>> + struct drm_device *dev = &mdev->base;
>> + u32 primend;
>> +
>> + /* Add a last block to trigger the softrap interrupt */
>> + mgag200_dma_add_block(mdev,
>> + MGAREG_DMAPAD, 0,
>> + MGAREG_DMAPAD, 0,
>> + MGAREG_DMAPAD, 0,
>> + MGAREG_SOFTRAP, 0);
>> +
>> + primend = mdev->dma.cmd_handle + mdev->dma.cmd_idx *
>> sizeof(struct mga_cmd_block);
>> +
>> + // Use primary DMA to send the commands
>> + WREG32(MGAREG_PRIMADDR, (u32) mdev->dma.cmd_handle);
>> + mdev->dma.in_use = 1;
>> + WREG32(MGAREG_PRIMEND, primend);
>> +
>> + wait_event_timeout(mdev->dma.waitq, mdev->dma.in_use == 0, HZ);
>> +
>> + if (mdev->dma.in_use) {
>> + drm_err(dev, "DMA transfer timed out\n");
>> + /* something goes wrong, reset the DMA engine */
>> + WREG8(MGAREG_OPMODE, MGAOPM_DMA_BLIT);
>> + mdev->dma.in_use = 0;
>> + }
>> +
>> + /* reset command index to start a new sequence */
>> + mdev->dma.cmd_idx = 0;
>> +}
>> +
>> +/*
>> + * ILOAD allows to load an image from system memory to the VRAM, and
>> with FXBNDRY, YDST and YDSTLEN,
>> + * you can transfer a rectangle, so it's perfect when used with a
>> damage clip.
>> + */
>> +static void mgag200_iload_cmd(struct mga_device *mdev, int x, int y,
>> int width, int height,
>> + int width_padded, int cpp)
>> +{
>> + int size = width_padded * height;
>> + u32 iload;
>> +
>> + iload = MGADWG_ILOAD | MGADWG_SGNZERO | MGADWG_SHIFTZERO |
>> MGADWG_REPLACE | MGADWG_CLIPDIS
>> + | MGADWG_BFCOL;
>> +
>> + mgag200_dma_add_block(mdev,
>> + MGAREG_DWGCTL, iload,
>> + MGAREG_FXBNDRY, (((x + width - 1) << 16) | x),
>> + MGAREG_AR0, (width_padded / cpp) - 1,
>> + MGAREG_AR3, 0);
>> +
>> + mgag200_dma_add_block(mdev,
>> + MGAREG_AR5, 0,
>> + MGAREG_YDST, y,
>> + MGAREG_DMAPAD, 0,
>> + MGAREG_DMAPAD, 0);
>> +
>> + mgag200_dma_add_block(mdev,
>> + MGAREG_DMAPAD, 0,
>> + MGAREG_LEN | MGAREG_EXEC, height,
>> + MGAREG_SECADDR, mdev->dma.handle | 1,
>> + /* Writing SECEND should always be the last command of a
>> block */
>> + MGAREG_SECEND, mdev->dma.handle + size);
>> +}
>> +
>> +static void mgag200_dma_copy(struct mga_device *mdev, const void
>> *src, u32 pitch,
>> + struct drm_rect *clip, int cpp)
>> +{
>> + int i;
>> + int width = drm_rect_width(clip);
>> + int height = drm_rect_height(clip);
>> +
>> + /* pad each line to 32bits boundaries see section 4.5.7 of G200
>> Specification */
>> + int width_padded = round_up(width * cpp, 4);
>> +
>> + for (i = 0; i < height; i++)
>> + memcpy(mdev->dma.buf + width_padded * i,
>> + src + (((clip->y1 + i) * pitch) + clip->x1 * cpp),
>> + width * cpp);
>> +
>> + mgag200_iload_cmd(mdev, clip->x1, clip->y1, width, height,
>> width_padded, cpp);
>> + mgag200_dma_run_cmd(mdev);
>> +}
>> +
>> +/*
>> + * If the DMA coherent buffer is smaller than damage rectangle, we
>> need to
>> + * split it into multiple DMA transfers.
>> + */
>> +void mgag200_dma_damage(struct mga_device *mdev, const struct
>> iosys_map *vmap,
>> + struct drm_framebuffer *fb, struct drm_rect *clip)
>> +{
>> + u32 pitch = fb->pitches[0];
>> + const void *src = vmap[0].vaddr;
>> + struct drm_rect subclip;
>> + int y1;
>> + int lines;
>> + int cpp = fb->format->cpp[0];
>> +
>> + /* Number of lines that fit in one DMA buffer */
>> + lines = min(drm_rect_height(clip), (int) mdev->dma.size /
>> (drm_rect_width(clip) * cpp));
>> +
>> + subclip.x1 = clip->x1;
>> + subclip.x2 = clip->x2;
>> +
>> + for (y1 = clip->y1; y1 < clip->y2; y1 += lines) {
>> + subclip.y1 = y1;
>> + subclip.y2 = min(clip->y2, y1 + lines);
>> + mgag200_dma_copy(mdev, src, pitch, &subclip, cpp);
>> + }
>> +}
>> +
>> +/*
>> + * Setup the drawing engine (DWG) registers
>> + * Color format, framebuffer width, ...
>> + * This must be done before using any DWGCTL command
>> + */
>> +void mgag200_dma_dwg_setup(struct mga_device *mdev, struct
>> drm_framebuffer *fb)
>> +{
>> + u32 maccess;
>> +
>> + drm_dbg(&mdev->base, "Setup DWG with %dx%d %p4cc\n",
>> + fb->width, fb->height, &fb->format->format);
>> +
>> + switch (fb->format->format) {
>> + case DRM_FORMAT_RGB565:
>> + maccess = MGAMAC_PW16;
>> + break;
>> + case DRM_FORMAT_RGB888:
>> + maccess = MGAMAC_PW24;
>> + break;
>> + case DRM_FORMAT_XRGB8888:
>> + maccess = MGAMAC_PW32;
>> + break;
>> + }
>> + WREG32(MGAREG_MACCESS, maccess);
>> +
>> + /* Framebuffer width in pixel */
>> + WREG32(MGAREG_PITCH, fb->width);
>> +
>> + /* Sane default value for the drawing engine registers */
>> + WREG32(MGAREG_DSTORG, 0);
>> + WREG32(MGAREG_YDSTORG, 0);
>> + WREG32(MGAREG_SRCORG, 0);
>> + WREG32(MGAREG_CXBNDRY, 0x0FFF0000);
>> + WREG32(MGAREG_YTOP, 0);
>> + WREG32(MGAREG_YBOT, 0x00FFFFFF);
>> +
>> + /* Activate blit mode DMA, only write the low part of the
>> register */
>> + WREG8(MGAREG_OPMODE, MGAOPM_DMA_BLIT);
>> +}
>> +
>> diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c
>> b/drivers/gpu/drm/mgag200/mgag200_drv.c
>> index a5851dcc6bdd..07f34e4df1b0 100644
>> --- a/drivers/gpu/drm/mgag200/mgag200_drv.c
>> +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c
>> @@ -119,6 +119,8 @@ static irqreturn_t mgag200_driver_irq_handler(int
>> irq, void *arg)
>> if (status & MGAIRQ_SOFTRAP) {
>> WREG32(MGAREG_ICLEAR, MGAIRQ_SOFTRAP);
>> + mdev->dma.in_use = 0;
>> + wake_up(&mdev->dma.waitq);
>> return IRQ_HANDLED;
>> }
>> return IRQ_NONE;
>> @@ -187,7 +189,7 @@ int mgag200_device_preinit(struct mga_device *mdev)
>> IRQF_SHARED, "mgag200_irq", mdev);
>> if (ret < 0) {
>> drm_err(dev, "devm_request_irq(VRAM) failed %d\n", ret);
>> - return -ENXIO;
>> + return ret;
>> }
>> return 0;
>> }
>> diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h
>> b/drivers/gpu/drm/mgag200/mgag200_drv.h
>> index 9e604dbb8e44..af69f61a11b7 100644
>> --- a/drivers/gpu/drm/mgag200/mgag200_drv.h
>> +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h
>> @@ -277,6 +277,27 @@ struct mgag200_device_funcs {
>> void (*pixpllc_atomic_update)(struct drm_crtc *crtc, struct
>> drm_atomic_state *old_state);
>> };
>> +struct mga_cmd_block {
>> + u32 cmd;
>> + u32 v0;
>> + u32 v1;
>> + u32 v2;
>> + u32 v3;
>> +} __packed;
>> +
>> +struct mga_dma {
>> + void *buf;
>> + size_t size;
>> + dma_addr_t handle;
>> +
>> + struct mga_cmd_block *cmd;
>> + int cmd_idx;
>> + dma_addr_t cmd_handle;
>> +
>> + wait_queue_head_t waitq;
>> + int in_use;
>> +};
>> +
>> struct mga_device {
>> struct drm_device base;
>> @@ -291,6 +312,8 @@ struct mga_device {
>> void __iomem *vram;
>> resource_size_t vram_available;
>> + struct mga_dma dma;
>> +
>> struct drm_plane primary_plane;
>> struct drm_crtc crtc;
>> struct drm_encoder encoder;
>> @@ -443,4 +466,10 @@ void mgag200_bmc_enable_vidrst(struct mga_device
>> *mdev);
>> /* mgag200_i2c.c */
>> int mgag200_i2c_init(struct mga_device *mdev, struct mga_i2c_chan
>> *i2c);
>> +/* mgag200_dma.c */
>> +int mgag200_dma_init(struct mga_device *mdev);
>> +void mgag200_dma_damage(struct mga_device *mdev, const struct
>> iosys_map *vmap,
>> + struct drm_framebuffer *fb, struct drm_rect *clip);
>> +void mgag200_dma_dwg_setup(struct mga_device *mdev, struct
>> drm_framebuffer *fb);
>> +
>> #endif /* __MGAG200_DRV_H__ */
>> diff --git a/drivers/gpu/drm/mgag200/mgag200_g200.c
>> b/drivers/gpu/drm/mgag200/mgag200_g200.c
>> index bf5d7fe525a3..4e972518733a 100644
>> --- a/drivers/gpu/drm/mgag200/mgag200_g200.c
>> +++ b/drivers/gpu/drm/mgag200/mgag200_g200.c
>> @@ -424,6 +424,10 @@ struct mga_device
>> *mgag200_g200_device_create(struct pci_dev *pdev, const struct
>> mgag200_g200_init_refclk(g200);
>> + ret = mgag200_dma_init(mdev);
>> + if (ret)
>> + return ERR_PTR(ret);
>> +
>> ret = mgag200_device_init(mdev, &mgag200_g200_device_info,
>> &mgag200_g200_device_funcs);
>> if (ret)
>> diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh.c
>> b/drivers/gpu/drm/mgag200/mgag200_g200eh.c
>> index fad62453a91d..6628b891118d 100644
>> --- a/drivers/gpu/drm/mgag200/mgag200_g200eh.c
>> +++ b/drivers/gpu/drm/mgag200/mgag200_g200eh.c
>> @@ -296,6 +296,10 @@ struct mga_device
>> *mgag200_g200eh_device_create(struct pci_dev *pdev, const stru
>> if (ret)
>> return ERR_PTR(ret);
>> + ret = mgag200_dma_init(mdev);
>> + if (ret)
>> + return ERR_PTR(ret);
>> +
>> ret = mgag200_device_init(mdev, &mgag200_g200eh_device_info,
>> &mgag200_g200eh_device_funcs);
>> if (ret)
>> diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c
>> b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c
>> index 0f7d8112cd49..35219fbe364f 100644
>> --- a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c
>> +++ b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c
>> @@ -201,6 +201,10 @@ struct mga_device
>> *mgag200_g200eh3_device_create(struct pci_dev *pdev,
>> if (ret)
>> return ERR_PTR(ret);
>> + ret = mgag200_dma_init(mdev);
>> + if (ret)
>> + return ERR_PTR(ret);
>> +
>> ret = mgag200_device_init(mdev, &mgag200_g200eh3_device_info,
>> &mgag200_g200eh3_device_funcs);
>> if (ret)
>> diff --git a/drivers/gpu/drm/mgag200/mgag200_g200er.c
>> b/drivers/gpu/drm/mgag200/mgag200_g200er.c
>> index bce267e0f7de..fc6df2ffd99d 100644
>> --- a/drivers/gpu/drm/mgag200/mgag200_g200er.c
>> +++ b/drivers/gpu/drm/mgag200/mgag200_g200er.c
>> @@ -330,6 +330,10 @@ struct mga_device
>> *mgag200_g200er_device_create(struct pci_dev *pdev, const stru
>> if (ret)
>> return ERR_PTR(ret);
>> + ret = mgag200_dma_init(mdev);
>> + if (ret)
>> + return ERR_PTR(ret);
>> +
>> ret = mgag200_device_init(mdev, &mgag200_g200er_device_info,
>> &mgag200_g200er_device_funcs);
>> if (ret)
>> diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ev.c
>> b/drivers/gpu/drm/mgag200/mgag200_g200ev.c
>> index ac957f42abe1..190c358aba7e 100644
>> --- a/drivers/gpu/drm/mgag200/mgag200_g200ev.c
>> +++ b/drivers/gpu/drm/mgag200/mgag200_g200ev.c
>> @@ -335,6 +335,10 @@ struct mga_device
>> *mgag200_g200ev_device_create(struct pci_dev *pdev, const stru
>> if (ret)
>> return ERR_PTR(ret);
>> + ret = mgag200_dma_init(mdev);
>> + if (ret)
>> + return ERR_PTR(ret);
>> +
>> ret = mgag200_device_init(mdev, &mgag200_g200ev_device_info,
>> &mgag200_g200ev_device_funcs);
>> if (ret)
>> diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c
>> b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c
>> index 170934414d7d..5de7ccbc575c 100644
>> --- a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c
>> +++ b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c
>> @@ -221,6 +221,10 @@ struct mga_device
>> *mgag200_g200ew3_device_create(struct pci_dev *pdev,
>> if (ret)
>> return ERR_PTR(ret);
>> + ret = mgag200_dma_init(mdev);
>> + if (ret)
>> + return ERR_PTR(ret);
>> +
>> ret = mgag200_device_init(mdev, &mgag200_g200ew3_device_info,
>> &mgag200_g200ew3_device_funcs);
>> if (ret)
>> diff --git a/drivers/gpu/drm/mgag200/mgag200_g200se.c
>> b/drivers/gpu/drm/mgag200/mgag200_g200se.c
>> index bd6e573c9a1a..3edb930598dd 100644
>> --- a/drivers/gpu/drm/mgag200/mgag200_g200se.c
>> +++ b/drivers/gpu/drm/mgag200/mgag200_g200se.c
>> @@ -506,6 +506,10 @@ struct mga_device
>> *mgag200_g200se_device_create(struct pci_dev *pdev, const stru
>> if (ret)
>> return ERR_PTR(ret);
>> + ret = mgag200_dma_init(mdev);
>> + if (ret)
>> + return ERR_PTR(ret);
>> +
>> ret = mgag200_g200se_init_unique_rev_id(g200se);
>> if (ret)
>> return ERR_PTR(ret);
>> diff --git a/drivers/gpu/drm/mgag200/mgag200_g200wb.c
>> b/drivers/gpu/drm/mgag200/mgag200_g200wb.c
>> index 9baa727ac6f9..6e731da89a5f 100644
>> --- a/drivers/gpu/drm/mgag200/mgag200_g200wb.c
>> +++ b/drivers/gpu/drm/mgag200/mgag200_g200wb.c
>> @@ -345,6 +345,10 @@ struct mga_device
>> *mgag200_g200wb_device_create(struct pci_dev *pdev, const stru
>> if (ret)
>> return ERR_PTR(ret);
>> + ret = mgag200_dma_init(mdev);
>> + if (ret)
>> + return ERR_PTR(ret);
>> +
>> ret = mgag200_device_init(mdev, &mgag200_g200wb_device_info,
>> &mgag200_g200wb_device_funcs);
>> if (ret)
>> diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c
>> b/drivers/gpu/drm/mgag200/mgag200_mode.c
>> index 7d8c65372ac4..adfc61428df6 100644
>> --- a/drivers/gpu/drm/mgag200/mgag200_mode.c
>> +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
>> @@ -398,15 +398,6 @@ static void mgag200_disable_display(struct
>> mga_device *mdev)
>> WREG_ECRT(0x01, crtcext1);
>> }
>> -static void mgag200_handle_damage(struct mga_device *mdev, const
>> struct iosys_map *vmap,
>> - struct drm_framebuffer *fb, struct drm_rect *clip)
>> -{
>> - struct iosys_map dst = IOSYS_MAP_INIT_VADDR_IOMEM(mdev->vram);
>> -
>> - iosys_map_incr(&dst, drm_fb_clip_offset(fb->pitches[0],
>> fb->format, clip));
>> - drm_fb_memcpy(&dst, fb->pitches, vmap, fb, clip);
>> -}
>> -
>> /*
>> * Primary plane
>> */
>> @@ -475,9 +466,13 @@ void
>> mgag200_primary_plane_helper_atomic_update(struct drm_plane *plane,
>> if (!fb)
>> return;
>> + if (!old_plane_state->fb || fb->format !=
>> old_plane_state->fb->format
>> + || fb->width != old_plane_state->fb->width)
>> + mgag200_dma_dwg_setup(mdev, fb);
>> +
>> drm_atomic_helper_damage_iter_init(&iter, old_plane_state,
>> plane_state);
>> drm_atomic_for_each_plane_damage(&iter, &damage) {
>> - mgag200_handle_damage(mdev, shadow_plane_state->data, fb,
>> &damage);
>> + mgag200_dma_damage(mdev, shadow_plane_state->data, fb, &damage);
>> }
>> /* Always scanout image at VRAM offset 0 */
>> diff --git a/drivers/gpu/drm/mgag200/mgag200_reg.h
>> b/drivers/gpu/drm/mgag200/mgag200_reg.h
>> index 748c8e18e938..256ac92dae56 100644
>> --- a/drivers/gpu/drm/mgag200/mgag200_reg.h
>> +++ b/drivers/gpu/drm/mgag200/mgag200_reg.h
>> @@ -116,6 +116,9 @@
>> #define MGAREG_OPMODE 0x1e54
>> +#define MGAREG_PRIMADDR 0x1e58
>> +#define MGAREG_PRIMEND 0x1e5c
>> +
>> /* Warp Registers */
>> #define MGAREG_WIADDR 0x1dc0
>> #define MGAREG_WIADDR2 0x1dd8
>> @@ -200,6 +203,8 @@
>> /* See table on 4-43 for bop ALU operations */
>> +#define MGADWG_REPLACE (0xC << 16)
>> +
>> /* See table on 4-44 for translucidity masks */
>> #define MGADWG_BMONOLEF ( 0x00 << 25 )
>> @@ -218,6 +223,8 @@
>> #define MGADWG_PATTERN ( 0x01 << 29 )
>> #define MGADWG_TRANSC ( 0x01 << 30 )
>> +#define MGADWG_CLIPDIS ( 0x01 << 31 )
>> +
>> #define MGAREG_MISC_WRITE 0x3c2
>> #define MGAREG_MISC_READ 0x3cc
>> #define MGAREG_MEM_MISC_WRITE 0x1fc2
>> @@ -605,6 +612,9 @@
>> # define MGA_TC2_SELECT_TMU1 (0x80000000)
>> #define MGAREG_TEXTRANS 0x2c34
>> #define MGAREG_TEXTRANSHIGH 0x2c38
>> +#define MGAREG_SECADDR 0x2c40
>> +#define MGAREG_SECEND 0x2c44
>> +#define MGAREG_SOFTRAP 0x2c48
>> #define MGAREG_TEXFILTER 0x2c58
>> # define MGA_MIN_NRST (0x00000000)
>> # define MGA_MIN_BILIN (0x00000002)
>> @@ -691,4 +701,19 @@
>> #define MGA_AGP2XPLL_ENABLE 0x1
>> #define MGA_AGP2XPLL_DISABLE 0x0
>> +
>> +#define DWGREG0 0x1c00
>> +#define DWGREG0_END 0x1dff
>> +#define DWGREG1 0x2c00
>> +#define DWGREG1_END 0x2dff
>> +
>> +/* These macros convert register address to the 8 bit command index
>> used with DMA
>> + * It remaps 0x1c00-0x1dff to 0x00-0x7f (REG0)
>> + * and 0x2c00-0x2dff to 0x80-0xff (REG1)
>> + */
>> +#define ISREG0(r) (r >= DWGREG0 && r <= DWGREG0_END)
>> +#define DMAREG0(r) ((u8)((r - DWGREG0) >> 2))
>> +#define DMAREG1(r) ((u8)(((r - DWGREG1) >> 2) | 0x80))
>> +#define DMAREG(r) (ISREG0((r)) ? DMAREG0((r)) : DMAREG1((r)))
>> +
>> #endif
>
More information about the dri-devel
mailing list