From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 3F6DFEB64DA for ; Thu, 15 Jun 2023 17:15:16 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 01F7910E525; Thu, 15 Jun 2023 17:15:15 +0000 (UTC) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by gabe.freedesktop.org (Postfix) with ESMTPS id 7493010E528 for ; Thu, 15 Jun 2023 17:15:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1686849310; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=RVZMdSJ7Yf3wR5nc2gLHgtJjQWbjaA/JeSSpNFq6YRc=; b=Y1V7565QC7EtshfeuwUgBz/ivPj9X6HYd9a0RKbPrZXF2Ixl1cbGIOb/jt7b8TwwWbTaN3 gYHvTC1NqWrAAFkYsIQjwEbJnc2AGxUJqCZQI/CsnXIpx2GpKOEpOK6LTMiwrOydxQaUKW eUfkUqCNd3bGxwwU4H00cuVY9dhZ5aw= Received: from mail-wr1-f69.google.com (mail-wr1-f69.google.com [209.85.221.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-395-gsgX16t4OVm-M68HrynnvA-1; Thu, 15 Jun 2023 13:15:08 -0400 X-MC-Unique: gsgX16t4OVm-M68HrynnvA-1 Received: by mail-wr1-f69.google.com with SMTP id ffacd0b85a97d-30fd2a2496eso499364f8f.0 for ; Thu, 15 Jun 2023 10:15:08 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1686849307; x=1689441307; h=content-transfer-encoding:in-reply-to:from:references:to :content-language:subject:user-agent:mime-version:date:message-id :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=RVZMdSJ7Yf3wR5nc2gLHgtJjQWbjaA/JeSSpNFq6YRc=; b=Nnoj8TjRrplSBDPHoH4hUwG3qu0V6ALQQd8TjAzNhha3gLNA6fxqVpjaxF+6yh/BHt eoL49m4TKTFTZjzkF2ly9jZ7VA3XcSRSaxbZ/2gWR8d3xISSYjhbQiW2VJ/kftUhN3xO 2n8oJDhMX2dgH2E+4nVUcwohKJNFTH5g7tZvfj9aFpLo8k7DwYMkudjTz5geAjnSg2Q0 C5htVNMY3fgDl8oZCIBLzWRIUTePFm8RQ1oFakZOtQLzyEogQjJ1+LPH9BjKWIrNmjOa qv9np3uX6wJJbK7UPBslkEdWSYPe4QR0YdzmNZoUPjIoaKOG5F1ZGVg/cdkYNzqNyjys QVzg== X-Gm-Message-State: AC+VfDzIukh5zRKTdXoxPiL2TAjC2VNNIViVcrizQrBjALLV45NN2xwN 7oJyGSh9pV/wMSglBqn9I/CP0Aia+GO7ZB0/TQSjuY3JVJE55MDuI5HNE1SyMn2emTatE7LWnxZ ojrJ7CZ2nqGJopFX6TwBGnsHZD+Oe X-Received: by 2002:a5d:5648:0:b0:311:b18:9ca4 with SMTP id j8-20020a5d5648000000b003110b189ca4mr4921263wrw.17.1686849307084; Thu, 15 Jun 2023 10:15:07 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ5NF9oYjfNc6HM+fr9mP7Xn7zTxGKRVoyXZuz5+NDRLy73H/DJNb9fpa3sFWYcyVx+Spj5XIQ== X-Received: by 2002:a5d:5648:0:b0:311:b18:9ca4 with SMTP id j8-20020a5d5648000000b003110b189ca4mr4921237wrw.17.1686849306601; Thu, 15 Jun 2023 10:15:06 -0700 (PDT) Received: from ?IPV6:2a01:e0a:c:37e0:ced3:55bd:f454:e722? ([2a01:e0a:c:37e0:ced3:55bd:f454:e722]) by smtp.gmail.com with ESMTPSA id e8-20020adff348000000b00304adbeeabbsm21626511wrp.99.2023.06.15.10.15.05 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Thu, 15 Jun 2023 10:15:06 -0700 (PDT) Message-ID: <15b08823-f2c2-5836-2421-f3bc25d51e11@redhat.com> Date: Thu, 15 Jun 2023 19:15:05 +0200 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.10.0 Subject: Re: [PATCH v2 4/4] drm/mgag200: Use DMA to copy the framebuffer to the VRAM To: Thomas Zimmermann , dri-devel@lists.freedesktop.org, airlied@redhat.com, javierm@redhat.com, lyude@redhat.com References: <20230531092110.140564-1-jfalempe@redhat.com> <20230531092110.140564-5-jfalempe@redhat.com> From: Jocelyn Falempe In-Reply-To: X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Language: en-US Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" 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 >> --- >>   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 >> +#include >> +#include >> + >> +#include >> + >> +#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 >