From patchwork Thu Apr 15 08:53:18 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 12204729 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1EAF7C43462 for ; Thu, 15 Apr 2021 08:53:38 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id DA69761074 for ; Thu, 15 Apr 2021 08:53:37 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org DA69761074 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 5E8A46EA01; Thu, 15 Apr 2021 08:53:35 +0000 (UTC) Received: from mx2.suse.de (mx2.suse.de [195.135.220.15]) by gabe.freedesktop.org (Postfix) with ESMTPS id 02B106E9FE for ; Thu, 15 Apr 2021 08:53:32 +0000 (UTC) X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id 8DC05B1C8; Thu, 15 Apr 2021 08:53:30 +0000 (UTC) From: Thomas Zimmermann To: daniel@ffwll.ch, airlied@linux.ie, maarten.lankhorst@linux.intel.com, mripard@kernel.org, kraxel@redhat.com, corbet@lwn.net, lgirdwood@gmail.com, broonie@kernel.org, sam@ravnborg.org, robh@kernel.org, emil.l.velikov@gmail.com, geert+renesas@glider.be, hdegoede@redhat.com, bluescreen_avenger@verizon.net, gregkh@linuxfoundation.org Subject: [PATCH v3 1/9] drm/format-helper: Pass destination pitch to drm_fb_memcpy_dstclip() Date: Thu, 15 Apr 2021 10:53:18 +0200 Message-Id: <20210415085326.8824-2-tzimmermann@suse.de> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210415085326.8824-1-tzimmermann@suse.de> References: <20210415085326.8824-1-tzimmermann@suse.de> MIME-Version: 1.0 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: , Cc: Daniel Vetter , virtualization@lists.linux-foundation.org, Thomas Zimmermann , dri-devel@lists.freedesktop.org, linux-doc@vger.kernel.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" The memcpy's destination buffer might have a different pitch than the source. Support different pitches as function argument. Signed-off-by: Thomas Zimmermann Reviewed-by: Daniel Vetter Tested-by: nerdopolis --- drivers/gpu/drm/drm_format_helper.c | 9 +++++---- drivers/gpu/drm/mgag200/mgag200_mode.c | 2 +- drivers/gpu/drm/tiny/cirrus.c | 2 +- include/drm/drm_format_helper.h | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c index c043ca364c86..8d5a683afea7 100644 --- a/drivers/gpu/drm/drm_format_helper.c +++ b/drivers/gpu/drm/drm_format_helper.c @@ -52,6 +52,7 @@ EXPORT_SYMBOL(drm_fb_memcpy); /** * drm_fb_memcpy_dstclip - Copy clip buffer * @dst: Destination buffer (iomem) + * @dst_pitch: Number of bytes between two consecutive scanlines within dst * @vaddr: Source buffer * @fb: DRM framebuffer * @clip: Clip rectangle area to copy @@ -59,12 +60,12 @@ EXPORT_SYMBOL(drm_fb_memcpy); * This function applies clipping on dst, i.e. the destination is a * full (iomem) framebuffer but only the clip rect content is copied over. */ -void drm_fb_memcpy_dstclip(void __iomem *dst, void *vaddr, - struct drm_framebuffer *fb, +void drm_fb_memcpy_dstclip(void __iomem *dst, unsigned int dst_pitch, + void *vaddr, struct drm_framebuffer *fb, struct drm_rect *clip) { unsigned int cpp = fb->format->cpp[0]; - unsigned int offset = clip_offset(clip, fb->pitches[0], cpp); + unsigned int offset = clip_offset(clip, dst_pitch, cpp); size_t len = (clip->x2 - clip->x1) * cpp; unsigned int y, lines = clip->y2 - clip->y1; @@ -73,7 +74,7 @@ void drm_fb_memcpy_dstclip(void __iomem *dst, void *vaddr, for (y = 0; y < lines; y++) { memcpy_toio(dst, vaddr, len); vaddr += fb->pitches[0]; - dst += fb->pitches[0]; + dst += dst_pitch; } } EXPORT_SYMBOL(drm_fb_memcpy_dstclip); diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index cece3e57fb27..9d576240faed 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -1554,7 +1554,7 @@ mgag200_handle_damage(struct mga_device *mdev, struct drm_framebuffer *fb, { void *vmap = map->vaddr; /* TODO: Use mapping abstraction properly */ - drm_fb_memcpy_dstclip(mdev->vram, vmap, fb, clip); + drm_fb_memcpy_dstclip(mdev->vram, fb->pitches[0], vmap, fb, clip); /* Always scanout image at VRAM offset 0 */ mgag200_set_startadd(mdev, (u32)0); diff --git a/drivers/gpu/drm/tiny/cirrus.c b/drivers/gpu/drm/tiny/cirrus.c index e3afb45d9a5c..42611dacde88 100644 --- a/drivers/gpu/drm/tiny/cirrus.c +++ b/drivers/gpu/drm/tiny/cirrus.c @@ -324,7 +324,7 @@ static int cirrus_fb_blit_rect(struct drm_framebuffer *fb, const struct dma_buf_ return -ENODEV; if (cirrus->cpp == fb->format->cpp[0]) - drm_fb_memcpy_dstclip(cirrus->vram, + drm_fb_memcpy_dstclip(cirrus->vram, fb->pitches[0], vmap, fb, rect); else if (fb->format->cpp[0] == 4 && cirrus->cpp == 2) diff --git a/include/drm/drm_format_helper.h b/include/drm/drm_format_helper.h index 5f9e37032468..2b5036a5fbe7 100644 --- a/include/drm/drm_format_helper.h +++ b/include/drm/drm_format_helper.h @@ -11,7 +11,7 @@ struct drm_rect; void drm_fb_memcpy(void *dst, void *vaddr, struct drm_framebuffer *fb, struct drm_rect *clip); -void drm_fb_memcpy_dstclip(void __iomem *dst, void *vaddr, +void drm_fb_memcpy_dstclip(void __iomem *dst, unsigned int dst_pitch, void *vaddr, struct drm_framebuffer *fb, struct drm_rect *clip); void drm_fb_swab(void *dst, void *src, struct drm_framebuffer *fb, From patchwork Thu Apr 15 08:53:19 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 12204737 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 88DABC4361B for ; Thu, 15 Apr 2021 08:53:49 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id 4C0D061074 for ; Thu, 15 Apr 2021 08:53:49 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 4C0D061074 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 5775B6EA05; Thu, 15 Apr 2021 08:53:39 +0000 (UTC) Received: from mx2.suse.de (mx2.suse.de [195.135.220.15]) by gabe.freedesktop.org (Postfix) with ESMTPS id 93C876E9FE for ; Thu, 15 Apr 2021 08:53:32 +0000 (UTC) X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id 256F1B1CA; Thu, 15 Apr 2021 08:53:31 +0000 (UTC) From: Thomas Zimmermann To: daniel@ffwll.ch, airlied@linux.ie, maarten.lankhorst@linux.intel.com, mripard@kernel.org, kraxel@redhat.com, corbet@lwn.net, lgirdwood@gmail.com, broonie@kernel.org, sam@ravnborg.org, robh@kernel.org, emil.l.velikov@gmail.com, geert+renesas@glider.be, hdegoede@redhat.com, bluescreen_avenger@verizon.net, gregkh@linuxfoundation.org Subject: [PATCH v3 2/9] drm/format-helper: Add blitter functions Date: Thu, 15 Apr 2021 10:53:19 +0200 Message-Id: <20210415085326.8824-3-tzimmermann@suse.de> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210415085326.8824-1-tzimmermann@suse.de> References: <20210415085326.8824-1-tzimmermann@suse.de> MIME-Version: 1.0 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: , Cc: Daniel Vetter , virtualization@lists.linux-foundation.org, Thomas Zimmermann , dri-devel@lists.freedesktop.org, linux-doc@vger.kernel.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" The blitter functions copy a framebuffer to I/O memory using one of the existing conversion functions. Signed-off-by: Thomas Zimmermann Reviewed-by: Daniel Vetter Tested-by: nerdopolis --- drivers/gpu/drm/drm_format_helper.c | 87 +++++++++++++++++++++++++++++ include/drm/drm_format_helper.h | 8 +++ 2 files changed, 95 insertions(+) diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c index 8d5a683afea7..0e885cd34107 100644 --- a/drivers/gpu/drm/drm_format_helper.c +++ b/drivers/gpu/drm/drm_format_helper.c @@ -344,3 +344,90 @@ void drm_fb_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb, } EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8); +/** + * drm_fb_blit_rect_dstclip - Copy parts of a framebuffer to display memory + * @dst: The display memory to copy to + * @dst_pitch: Number of bytes between two consecutive scanlines within dst + * @dst_format: FOURCC code of the display's color format + * @vmap: The framebuffer memory to copy from + * @fb: The framebuffer to copy from + * @clip: Clip rectangle area to copy + * + * This function copies parts of a framebuffer to display memory. If the + * formats of the display and the framebuffer mismatch, the blit function + * will attempt to convert between them. + * + * Use drm_fb_blit_dstclip() to copy the full framebuffer. + * + * Returns: + * 0 on success, or + * -EINVAL if the color-format conversion failed, or + * a negative error code otherwise. + */ +int drm_fb_blit_rect_dstclip(void __iomem *dst, unsigned int dst_pitch, + uint32_t dst_format, void *vmap, + struct drm_framebuffer *fb, + struct drm_rect *clip) +{ + uint32_t fb_format = fb->format->format; + + /* treat alpha channel like filler bits */ + if (fb_format == DRM_FORMAT_ARGB8888) + fb_format = DRM_FORMAT_XRGB8888; + if (dst_format == DRM_FORMAT_ARGB8888) + dst_format = DRM_FORMAT_XRGB8888; + + if (dst_format == fb_format) { + drm_fb_memcpy_dstclip(dst, dst_pitch, vmap, fb, clip); + return 0; + + } else if (dst_format == DRM_FORMAT_RGB565) { + if (fb_format == DRM_FORMAT_XRGB8888) { + drm_fb_xrgb8888_to_rgb565_dstclip(dst, dst_pitch, + vmap, fb, clip, + false); + return 0; + } + } else if (dst_format == DRM_FORMAT_RGB888) { + if (fb_format == DRM_FORMAT_XRGB8888) { + drm_fb_xrgb8888_to_rgb888_dstclip(dst, dst_pitch, + vmap, fb, clip); + return 0; + } + } + + return -EINVAL; +} +EXPORT_SYMBOL(drm_fb_blit_rect_dstclip); + +/** + * drm_fb_blit_dstclip - Copy framebuffer to display memory + * @dst: The display memory to copy to + * @dst_pitch: Number of bytes between two consecutive scanlines within dst + * @dst_format: FOURCC code of the display's color format + * @vmap: The framebuffer memory to copy from + * @fb: The framebuffer to copy from + * + * This function copies a full framebuffer to display memory. If the formats + * of the display and the framebuffer mismatch, the copy function will + * attempt to convert between them. + * + * See drm_fb_blit_rect_dstclip() for more inforamtion. + * + * Returns: + * 0 on success, or a negative error code otherwise. + */ +int drm_fb_blit_dstclip(void __iomem *dst, unsigned int dst_pitch, + uint32_t dst_format, void *vmap, + struct drm_framebuffer *fb) +{ + struct drm_rect fullscreen = { + .x1 = 0, + .x2 = fb->width, + .y1 = 0, + .y2 = fb->height, + }; + return drm_fb_blit_rect_dstclip(dst, dst_pitch, dst_format, vmap, fb, + &fullscreen); +} +EXPORT_SYMBOL(drm_fb_blit_dstclip); diff --git a/include/drm/drm_format_helper.h b/include/drm/drm_format_helper.h index 2b5036a5fbe7..4e0258a61311 100644 --- a/include/drm/drm_format_helper.h +++ b/include/drm/drm_format_helper.h @@ -28,4 +28,12 @@ void drm_fb_xrgb8888_to_rgb888_dstclip(void __iomem *dst, unsigned int dst_pitch void drm_fb_xrgb8888_to_gray8(u8 *dst, void *vaddr, struct drm_framebuffer *fb, struct drm_rect *clip); +int drm_fb_blit_rect_dstclip(void __iomem *dst, unsigned int dst_pitch, + uint32_t dst_format, void *vmap, + struct drm_framebuffer *fb, + struct drm_rect *rect); +int drm_fb_blit_dstclip(void __iomem *dst, unsigned int dst_pitch, + uint32_t dst_format, void *vmap, + struct drm_framebuffer *fb); + #endif /* __LINUX_DRM_FORMAT_HELPER_H */ From patchwork Thu Apr 15 08:53:20 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 12204735 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8B235C43618 for ; Thu, 15 Apr 2021 08:53:45 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id 55FB761074 for ; Thu, 15 Apr 2021 08:53:45 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 55FB761074 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 96FBA6E9FE; Thu, 15 Apr 2021 08:53:38 +0000 (UTC) Received: from mx2.suse.de (mx2.suse.de [195.135.220.15]) by gabe.freedesktop.org (Postfix) with ESMTPS id 2665E6E9FE for ; Thu, 15 Apr 2021 08:53:33 +0000 (UTC) X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id B5FFEB1E6; Thu, 15 Apr 2021 08:53:31 +0000 (UTC) From: Thomas Zimmermann To: daniel@ffwll.ch, airlied@linux.ie, maarten.lankhorst@linux.intel.com, mripard@kernel.org, kraxel@redhat.com, corbet@lwn.net, lgirdwood@gmail.com, broonie@kernel.org, sam@ravnborg.org, robh@kernel.org, emil.l.velikov@gmail.com, geert+renesas@glider.be, hdegoede@redhat.com, bluescreen_avenger@verizon.net, gregkh@linuxfoundation.org Subject: [PATCH v3 3/9] drm/aperture: Add infrastructure for aperture ownership Date: Thu, 15 Apr 2021 10:53:20 +0200 Message-Id: <20210415085326.8824-4-tzimmermann@suse.de> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210415085326.8824-1-tzimmermann@suse.de> References: <20210415085326.8824-1-tzimmermann@suse.de> MIME-Version: 1.0 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: , Cc: Daniel Vetter , virtualization@lists.linux-foundation.org, Thomas Zimmermann , dri-devel@lists.freedesktop.org, linux-doc@vger.kernel.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Platform devices might operate on firmware framebuffers, such as VESA or EFI. Before a native driver for the graphics hardware can take over the device, it has to remove any platform driver that operates on the firmware framebuffer. Aperture helpers provide the infrastructure for platform drivers to acquire firmware framebuffers, and for native drivers to remove them later on. It works similar to the related fbdev mechanism. During initialization, the platform driver acquires the firmware framebuffer's I/O memory and provides a callback to be removed. The native driver later uses this information to remove any platform driver for it's framebuffer I/O memory. The aperture removal code is integrated into the existing code for removing conflicting framebuffers, so native drivers use it automatically. v3: * rebase onto existing aperture infrastructure * release aperture from list during detach; fix dangling apertures * don't export struct drm_aperture * document struct drm_aperture_funcs v2: * rename plaform helpers to aperture helpers * tie to device lifetime with devm_ functions * removed unsued remove() callback * rename kickout to detach * make struct drm_aperture private * rebase onto existing drm_aperture.h header file * use MIT license only for simplicity * documentation Signed-off-by: Thomas Zimmermann Acked-by: Daniel Vetter Tested-by: nerdopolis --- drivers/gpu/drm/drm_aperture.c | 216 ++++++++++++++++++++++++++++++++- include/drm/drm_aperture.h | 36 +++--- 2 files changed, 232 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/drm_aperture.c b/drivers/gpu/drm/drm_aperture.c index e034dd7f9b09..aeddf125d2b4 100644 --- a/drivers/gpu/drm/drm_aperture.c +++ b/drivers/gpu/drm/drm_aperture.c @@ -1,9 +1,17 @@ // SPDX-License-Identifier: MIT +#include #include +#include +#include +#include +#include +#include #include #include +#include +#include /** * DOC: overview @@ -62,8 +70,196 @@ * framebuffer apertures automatically. Device drivers without knowledge of * the framebuffer's location shall call drm_aperture_remove_framebuffers(), * which removes all drivers for known framebuffer. + * + * Drivers that are susceptible to being removed by other drivers, such as + * generic EFI or VESA drivers, have to register themselves as owners of their + * given framebuffer memory. Ownership of the framebuffer memory is achived + * by calling devm_aperture_acquire(). On success, the driver is the owner + * of the framebuffer range. The function fails if the framebuffer is already + * by another driver. See below for an example. + * + * .. code-block:: c + * + * static struct drm_aperture_funcs ap_funcs = { + * .detach = ... + * }; + * + * static int acquire_framebuffers(struct drm_device *dev, struct pci_dev *pdev) + * { + * resource_size_t start, len; + * struct drm_aperture *ap; + * + * base = pci_resource_start(pdev, 0); + * size = pci_resource_len(pdev, 0); + * + * ap = devm_acquire_aperture(dev, base, size, &ap_funcs); + * if (IS_ERR(ap)) + * return PTR_ERR(ap); + * + * return 0; + * } + * + * static int probe(struct pci_dev *pdev) + * { + * struct drm_device *dev; + * int ret; + * + * // ... Initialize the device... + * dev = devm_drm_dev_alloc(); + * ... + * + * // ... and acquire ownership of the framebuffer. + * ret = acquire_framebuffers(dev, pdev); + * if (ret) + * return ret; + * + * drm_dev_register(); + * + * return 0; + * } + * + * The generic driver is now subject to forced removal by other drivers. This + * is when the detach function in struct &drm_aperture_funcs comes into play. + * When a driver calls drm_fb_helper_remove_conflicting_framebuffers() et al + * for the registered framebuffer range, the DRM core calls struct + * &drm_aperture_funcs.detach and the generic driver has to onload itself. It + * may not access the device's registers, framebuffer memory, ROM, etc after + * detach returned. If the driver supports hotplugging, detach can be treated + * like an unplug event. + * + * .. code-block:: c + * + * static void detach_from_device(struct drm_device *dev, + * resource_size_t base, + * resource_size_t size) + * { + * // Signal unplug + * drm_dev_unplug(dev); + * + * // Maybe do other clean-up operations + * ... + * } + * + * static struct drm_aperture_funcs ap_funcs = { + * .detach = detach_from_device, + * }; */ +/* + * struct drm_aperture - Represents a DRM framebuffer aperture + */ +struct drm_aperture { + struct drm_device *dev; + resource_size_t base; + resource_size_t size; + + const struct drm_aperture_funcs *funcs; + + struct list_head lh; +}; + +static LIST_HEAD(drm_apertures); +static DEFINE_MUTEX(drm_apertures_lock); + +static bool overlap(resource_size_t base1, resource_size_t end1, + resource_size_t base2, resource_size_t end2) +{ + return (base1 < end2) && (end1 > base2); +} + +static void devm_aperture_acquire_release(void *data) +{ + struct drm_aperture *ap = data; + bool detached = !ap->dev; + + if (detached) + return; + + mutex_lock(&drm_apertures_lock); + list_del(&ap->lh); + mutex_unlock(&drm_apertures_lock); +} + +/** + * devm_aperture_acquire - Acquires ownership of a framebuffer on behalf of a DRM driver. + * @dev: the DRM device to own the framebuffer memory + * @base: the framebuffer's byte offset in physical memory + * @size: the framebuffer size in bytes + * @funcs: callback functions + * + * Installs the given device as the new owner. The function fails if the + * framebuffer range, or parts of it, is currently owned by another driver. + * To evict current owners, callers should use + * drm_aperture_remove_conflicting_framebuffers() et al. before calling this + * function. Acquired apertures are released automatically if the underlying + * device goes away. + * + * Returns: + * An instance of struct &drm_aperture on success, or a pointer-encoded + * errno value otherwise. + */ +int devm_aperture_acquire(struct drm_device *dev, resource_size_t base, resource_size_t size, + const struct drm_aperture_funcs *funcs) +{ + size_t end = base + size; + struct list_head *pos; + struct drm_aperture *ap; + + mutex_lock(&drm_apertures_lock); + + list_for_each(pos, &drm_apertures) { + ap = container_of(pos, struct drm_aperture, lh); + if (overlap(base, end, ap->base, ap->base + ap->size)) + return -EBUSY; + } + + ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL); + if (!ap) + return -ENOMEM; + + ap->dev = dev; + ap->base = base; + ap->size = size; + ap->funcs = funcs; + INIT_LIST_HEAD(&ap->lh); + + list_add(&ap->lh, &drm_apertures); + + mutex_unlock(&drm_apertures_lock); + + return devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap); +} +EXPORT_SYMBOL(devm_aperture_acquire); + +static void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size) +{ + resource_size_t end = base + size; + struct list_head *pos, *n; + + mutex_lock(&drm_apertures_lock); + + list_for_each_safe(pos, n, &drm_apertures) { + struct drm_aperture *ap = + container_of(pos, struct drm_aperture, lh); + struct drm_device *dev = ap->dev; + + if (WARN_ON_ONCE(!dev)) + continue; + + if (!overlap(base, end, ap->base, ap->base + ap->size)) + continue; + + ap->dev = NULL; /* detach from device */ + list_del(&ap->lh); + + if (drm_WARN_ON(dev, !ap->funcs->detach)) + continue; + ap->funcs->detach(dev, ap->base, ap->size); + } + + mutex_unlock(&drm_apertures_lock); +} + /** * drm_aperture_remove_conflicting_framebuffers - remove existing framebuffers in the given range * @base: the aperture's base address in physical memory @@ -94,10 +290,13 @@ int drm_aperture_remove_conflicting_framebuffers(resource_size_t base, resource_ ret = remove_conflicting_framebuffers(a, name, primary); kfree(a); - return ret; -#else - return 0; + if (ret) + return ret; #endif + + drm_aperture_detach_drivers(base, size); + + return 0; } EXPORT_SYMBOL(drm_aperture_remove_conflicting_framebuffers); @@ -115,7 +314,16 @@ EXPORT_SYMBOL(drm_aperture_remove_conflicting_framebuffers); */ int drm_aperture_remove_conflicting_pci_framebuffers(struct pci_dev *pdev, const char *name) { - int ret = 0; + resource_size_t base, size; + int bar, ret = 0; + + for (bar = 0; bar < PCI_STD_NUM_BARS; ++bar) { + if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) + continue; + base = pci_resource_start(pdev, bar); + size = pci_resource_len(pdev, bar); + drm_aperture_detach_drivers(base, size); + } /* * WARNING: Apparently we must kick fbdev drivers before vgacon, diff --git a/include/drm/drm_aperture.h b/include/drm/drm_aperture.h index 23cc01647ed3..19743240fac3 100644 --- a/include/drm/drm_aperture.h +++ b/include/drm/drm_aperture.h @@ -5,27 +5,31 @@ #include +struct drm_device; struct pci_dev; +/** + * drm_aperture_funcs - Callback functions for aperture ownership + */ +struct drm_aperture_funcs { + /** + * @detach: + * + * Informs the aperture owner to detach itself from the memory range. Called + * when another driver requrests ownership. The driver should release itself + * from the device and maybe unregister the device itself. + * + * See drm_dev_unplug(). + */ + void (*detach)(struct drm_device *dev, resource_size_t base, resource_size_t size); +}; + +int devm_aperture_acquire(struct drm_device *dev, resource_size_t base, resource_size_t size, + const struct drm_aperture_funcs *funcs); + int drm_aperture_remove_conflicting_framebuffers(resource_size_t base, resource_size_t size, bool primary, const char *name); int drm_aperture_remove_conflicting_pci_framebuffers(struct pci_dev *pdev, const char *name); -/** - * drm_aperture_remove_framebuffers - remove all existing framebuffers - * @primary: also kick vga16fb if present - * @name: requesting driver name - * - * This function removes all graphics device drivers. Use this function on systems - * that can have their framebuffer located anywhere in memory. - * - * Returns: - * 0 on success, or a negative errno code otherwise - */ -static inline int drm_aperture_remove_framebuffers(bool primary, const char *name) -{ - return drm_aperture_remove_conflicting_framebuffers(0, (resource_size_t)-1, primary, name); -} - #endif From patchwork Thu Apr 15 08:53:21 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 12204733 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-21.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,MENTIONS_GIT_HOSTING,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4CE85C433ED for ; Thu, 15 Apr 2021 08:53:41 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id 11AFD6124B for ; Thu, 15 Apr 2021 08:53:41 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 11AFD6124B Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 5E43D6EA00; Thu, 15 Apr 2021 08:53:35 +0000 (UTC) Received: from mx2.suse.de (mx2.suse.de [195.135.220.15]) by gabe.freedesktop.org (Postfix) with ESMTPS id BFABD6E9FE for ; Thu, 15 Apr 2021 08:53:33 +0000 (UTC) X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id 563C0B1E8; Thu, 15 Apr 2021 08:53:32 +0000 (UTC) From: Thomas Zimmermann To: daniel@ffwll.ch, airlied@linux.ie, maarten.lankhorst@linux.intel.com, mripard@kernel.org, kraxel@redhat.com, corbet@lwn.net, lgirdwood@gmail.com, broonie@kernel.org, sam@ravnborg.org, robh@kernel.org, emil.l.velikov@gmail.com, geert+renesas@glider.be, hdegoede@redhat.com, bluescreen_avenger@verizon.net, gregkh@linuxfoundation.org Subject: [PATCH v3 4/9] drm: Add simpledrm driver Date: Thu, 15 Apr 2021 10:53:21 +0200 Message-Id: <20210415085326.8824-5-tzimmermann@suse.de> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210415085326.8824-1-tzimmermann@suse.de> References: <20210415085326.8824-1-tzimmermann@suse.de> MIME-Version: 1.0 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: , Cc: virtualization@lists.linux-foundation.org, Thomas Zimmermann , dri-devel@lists.freedesktop.org, linux-doc@vger.kernel.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" The simpledrm driver is a DRM driver for simplefb framebuffers as provided by the kernel's boot code. This driver enables basic graphical output on many different graphics devices that are provided by the platform (e.g., EFI, VESA, embedded framebuffers). With the kernel's simplefb infrastructure, the kernel receives a pre-configured framebuffer from the system (i.e., firmware, boot loader). It creates a platform device to which simpledrm attaches. The system's framebuffer consists of a memory range, size and format. Based on these values, simpledrm creates a DRM devices. No actual modesetting is possible. v3: * add disable function that clears screen to black (Daniel) * set shadow buffering only for fbdev emulation * set platform-driver data during device creation v2: * rename driver to simpledrm * add dri-devel to MAINTAINERS entry * put native format first in primary-plane format list (Daniel) * inline simplekms_device_cleanup() (Daniel) * use helpers for shadow-buffered planes * fix whitespace errors Signed-off-by: Thomas Zimmermann Tested-by: nerdopolis --- MAINTAINERS | 7 + drivers/gpu/drm/tiny/Kconfig | 16 + drivers/gpu/drm/tiny/Makefile | 1 + drivers/gpu/drm/tiny/simpledrm.c | 545 +++++++++++++++++++++++++++++++ 4 files changed, 569 insertions(+) create mode 100644 drivers/gpu/drm/tiny/simpledrm.c diff --git a/MAINTAINERS b/MAINTAINERS index 7c45120759e6..4935776250e4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5765,6 +5765,13 @@ S: Orphan / Obsolete F: drivers/gpu/drm/savage/ F: include/uapi/drm/savage_drm.h +DRM DRIVER FOR SIMPLE FRAMEBUFFERS +M: Thomas Zimmermann +L: dri-devel@lists.freedesktop.org +S: Maintained +T: git git://anongit.freedesktop.org/drm/drm-misc +F: drivers/gpu/drm/tiny/simplekms.c + DRM DRIVER FOR SIS VIDEO CARDS S: Orphan / Obsolete F: drivers/gpu/drm/sis/ diff --git a/drivers/gpu/drm/tiny/Kconfig b/drivers/gpu/drm/tiny/Kconfig index 9bbaa1a69050..d46f95d9196d 100644 --- a/drivers/gpu/drm/tiny/Kconfig +++ b/drivers/gpu/drm/tiny/Kconfig @@ -38,6 +38,22 @@ config DRM_GM12U320 This is a KMS driver for projectors which use the GM12U320 chipset for video transfer over USB2/3, such as the Acer C120 mini projector. +config DRM_SIMPLEDRM + tristate "Simple framebuffer driver" + depends on DRM + select DRM_GEM_SHMEM_HELPER + select DRM_KMS_HELPER + help + DRM driver for simple platform-provided framebuffers. + + This driver assumes that the display hardware has been initialized + by the firmware or bootloader before the kernel boots. Scanout + buffer, size, and display format must be provided via device tree, + UEFI, VESA, etc. + + On x86 and compatible, you should also select CONFIG_X86_SYSFB to + use UEFI and VESA framebuffers. + config TINYDRM_HX8357D tristate "DRM support for HX8357D display panels" depends on DRM && SPI diff --git a/drivers/gpu/drm/tiny/Makefile b/drivers/gpu/drm/tiny/Makefile index bef6780bdd6f..9cc847e756da 100644 --- a/drivers/gpu/drm/tiny/Makefile +++ b/drivers/gpu/drm/tiny/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_DRM_ARCPGU) += arcpgu.o obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus.o obj-$(CONFIG_DRM_GM12U320) += gm12u320.o +obj-$(CONFIG_DRM_SIMPLEDRM) += simpledrm.o obj-$(CONFIG_TINYDRM_HX8357D) += hx8357d.o obj-$(CONFIG_TINYDRM_ILI9225) += ili9225.o obj-$(CONFIG_TINYDRM_ILI9341) += ili9341.o diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c new file mode 100644 index 000000000000..0473a90a4024 --- /dev/null +++ b/drivers/gpu/drm/tiny/simpledrm.c @@ -0,0 +1,545 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "simpledrm" +#define DRIVER_DESC "DRM driver for simple-framebuffer platform devices" +#define DRIVER_DATE "20200625" +#define DRIVER_MAJOR 1 +#define DRIVER_MINOR 0 + +/* + * Assume a monitor resolution of 96 dpi to + * get a somewhat reasonable screen size. + */ +#define RES_MM(d) \ + (((d) * 254ul) / (96ul * 10ul)) + +#define SIMPLEDRM_MODE(hd, vd) \ + DRM_SIMPLE_MODE(hd, vd, RES_MM(hd), RES_MM(vd)) + +/* + * Helpers for simplefb + */ + +static int +simplefb_get_validated_int(struct drm_device *dev, const char *name, + uint32_t value) +{ + if (value > INT_MAX) { + drm_err(dev, "simplefb: invalid framebuffer %s of %u\n", + name, value); + return -EINVAL; + } + return (int)value; +} + +static int +simplefb_get_validated_int0(struct drm_device *dev, const char *name, + uint32_t value) +{ + if (!value) { + drm_err(dev, "simplefb: invalid framebuffer %s of %u\n", + name, value); + return -EINVAL; + } + return simplefb_get_validated_int(dev, name, value); +} + +static const struct drm_format_info * +simplefb_get_validated_format(struct drm_device *dev, const char *format_name) +{ + static const struct simplefb_format formats[] = SIMPLEFB_FORMATS; + const struct simplefb_format *fmt = formats; + const struct simplefb_format *end = fmt + ARRAY_SIZE(formats); + + if (!format_name) { + drm_err(dev, "simplefb: missing framebuffer format\n"); + return ERR_PTR(-EINVAL); + } + + while (fmt < end) { + if (!strcmp(format_name, fmt->name)) + return drm_format_info(fmt->fourcc); + ++fmt; + } + + drm_err(dev, "simplefb: unknown framebuffer format %s\n", + format_name); + + return ERR_PTR(-EINVAL); +} + +static int +simplefb_get_width_pd(struct drm_device *dev, + const struct simplefb_platform_data *pd) +{ + return simplefb_get_validated_int0(dev, "width", pd->width); +} + +static int +simplefb_get_height_pd(struct drm_device *dev, + const struct simplefb_platform_data *pd) +{ + return simplefb_get_validated_int0(dev, "height", pd->height); +} + +static int +simplefb_get_stride_pd(struct drm_device *dev, + const struct simplefb_platform_data *pd) +{ + return simplefb_get_validated_int(dev, "stride", pd->stride); +} + +static const struct drm_format_info * +simplefb_get_format_pd(struct drm_device *dev, + const struct simplefb_platform_data *pd) +{ + return simplefb_get_validated_format(dev, pd->format); +} + +/* + * Simple Framebuffer device + */ + +struct simpledrm_device { + struct drm_device dev; + struct platform_device *pdev; + + /* simplefb settings */ + struct drm_display_mode mode; + const struct drm_format_info *format; + unsigned int pitch; + + /* memory management */ + struct resource *mem; + void __iomem *screen_base; + + /* modesetting */ + uint32_t formats[8]; + size_t nformats; + struct drm_connector connector; + struct drm_simple_display_pipe pipe; +}; + +static struct simpledrm_device *simpledrm_device_of_dev(struct drm_device *dev) +{ + return container_of(dev, struct simpledrm_device, dev); +} + +/* + * Simplefb settings + */ + +static struct drm_display_mode simpledrm_mode(unsigned int width, + unsigned int height) +{ + struct drm_display_mode mode = { SIMPLEDRM_MODE(width, height) }; + + mode.clock = 60 /* Hz */ * mode.hdisplay * mode.vdisplay; + drm_mode_set_name(&mode); + + return mode; +} + +static int simpledrm_device_init_fb(struct simpledrm_device *sdev) +{ + int width, height, stride; + const struct drm_format_info *format; + struct drm_format_name_buf buf; + struct drm_device *dev = &sdev->dev; + struct platform_device *pdev = sdev->pdev; + const struct simplefb_platform_data *pd = dev_get_platdata(&pdev->dev); + + if (pd) { + width = simplefb_get_width_pd(dev, pd); + if (width < 0) + return width; + height = simplefb_get_height_pd(dev, pd); + if (height < 0) + return height; + stride = simplefb_get_stride_pd(dev, pd); + if (stride < 0) + return stride; + format = simplefb_get_format_pd(dev, pd); + if (IS_ERR(format)) + return PTR_ERR(format); + } else { + drm_err(dev, "no simplefb configuration found\n"); + return -ENODEV; + } + + sdev->mode = simpledrm_mode(width, height); + sdev->format = format; + sdev->pitch = stride; + + drm_dbg_kms(dev, "display mode={" DRM_MODE_FMT "}\n", + DRM_MODE_ARG(&sdev->mode)); + drm_dbg_kms(dev, + "framebuffer format=\"%s\", size=%dx%d, stride=%d byte\n", + drm_get_format_name(format->format, &buf), width, + height, stride); + + return 0; +} + +/* + * Memory management + */ + +static int simpledrm_device_init_mm(struct simpledrm_device *sdev) +{ + struct platform_device *pdev = sdev->pdev; + struct resource *mem; + void __iomem *screen_base; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) + return -EINVAL; + + screen_base = devm_ioremap_wc(&pdev->dev, mem->start, + resource_size(mem)); + if (!screen_base) + return -ENOMEM; + + sdev->mem = mem; + sdev->screen_base = screen_base; + + return 0; +} + +/* + * Modesetting + */ + +/* + * Support all formats of simplefb and maybe more; in order + * of preference. The display's update function will do any + * conversion necessary. + * + * TODO: Add blit helpers for remaining formats and uncomment + * constants. + */ +static const uint32_t simpledrm_default_formats[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_RGB565, + //DRM_FORMAT_XRGB1555, + //DRM_FORMAT_ARGB1555, + DRM_FORMAT_RGB888, + //DRM_FORMAT_XRGB2101010, + //DRM_FORMAT_ARGB2101010, +}; + +static const uint64_t simpledrm_format_modifiers[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID +}; + +static int simpledrm_connector_helper_get_modes(struct drm_connector *connector) +{ + struct simpledrm_device *sdev = simpledrm_device_of_dev(connector->dev); + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->dev, &sdev->mode); + if (!mode) + return 0; + + if (mode->name[0] == '\0') + drm_mode_set_name(mode); + + mode->type |= DRM_MODE_TYPE_PREFERRED; + drm_mode_probed_add(connector, mode); + + if (mode->width_mm) + connector->display_info.width_mm = mode->width_mm; + if (mode->height_mm) + connector->display_info.height_mm = mode->height_mm; + + return 1; +} + +static const struct drm_connector_helper_funcs simpledrm_connector_helper_funcs = { + .get_modes = simpledrm_connector_helper_get_modes, +}; + +static const struct drm_connector_funcs simpledrm_connector_funcs = { + .reset = drm_atomic_helper_connector_reset, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = drm_connector_cleanup, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static int +simpledrm_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe, + const struct drm_display_mode *mode) +{ + struct simpledrm_device *sdev = simpledrm_device_of_dev(pipe->crtc.dev); + + if (mode->hdisplay != sdev->mode.hdisplay && + mode->vdisplay != sdev->mode.vdisplay) + return MODE_ONE_SIZE; + else if (mode->hdisplay != sdev->mode.hdisplay) + return MODE_ONE_WIDTH; + else if (mode->vdisplay != sdev->mode.vdisplay) + return MODE_ONE_HEIGHT; + + return MODE_OK; +} + +static void +simpledrm_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe, + struct drm_crtc_state *crtc_state, + struct drm_plane_state *plane_state) +{ + struct simpledrm_device *sdev = simpledrm_device_of_dev(pipe->crtc.dev); + struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); + struct drm_framebuffer *fb = plane_state->fb; + void *vmap = shadow_plane_state->map[0].vaddr; /* TODO: Use mapping abstraction properly */ + + if (!fb) + return; + + drm_fb_blit_dstclip(sdev->screen_base, sdev->pitch, + sdev->format->format, vmap, fb); +} + +static void +simpledrm_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe) +{ + struct simpledrm_device *sdev = simpledrm_device_of_dev(pipe->crtc.dev); + struct drm_device *dev = &sdev->dev; + int idx; + + if (!drm_dev_enter(dev, &idx)) + return; + + /* Clear screen to black if disabled */ + memset_io(sdev->screen_base, 0, sdev->pitch * sdev->mode.vdisplay); + + drm_dev_exit(idx); +} + +static void +simpledrm_simple_display_pipe_update(struct drm_simple_display_pipe *pipe, + struct drm_plane_state *old_plane_state) +{ + struct simpledrm_device *sdev = simpledrm_device_of_dev(pipe->crtc.dev); + struct drm_plane_state *plane_state = pipe->plane.state; + struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); + void *vmap = shadow_plane_state->map[0].vaddr; /* TODO: Use mapping abstraction properly */ + struct drm_framebuffer *fb = plane_state->fb; + struct drm_rect clip; + + if (!fb) + return; + + if (!drm_atomic_helper_damage_merged(old_plane_state, plane_state, &clip)) + return; + + drm_fb_blit_rect_dstclip(sdev->screen_base, sdev->pitch, + sdev->format->format, vmap, fb, &clip); +} + +static const struct drm_simple_display_pipe_funcs +simpledrm_simple_display_pipe_funcs = { + .mode_valid = simpledrm_simple_display_pipe_mode_valid, + .enable = simpledrm_simple_display_pipe_enable, + .disable = simpledrm_simple_display_pipe_disable, + .update = simpledrm_simple_display_pipe_update, + DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS, +}; + +static const struct drm_mode_config_funcs simpledrm_mode_config_funcs = { + .fb_create = drm_gem_fb_create_with_dirty, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, +}; + +static const uint32_t *simpledrm_device_formats(struct simpledrm_device *sdev, + size_t *nformats_out) +{ + struct drm_device *dev = &sdev->dev; + size_t i; + + if (sdev->nformats) + goto out; /* don't rebuild list on recurring calls */ + + /* native format goes first */ + sdev->formats[0] = sdev->format->format; + sdev->nformats = 1; + + /* default formats go second */ + for (i = 0; i < ARRAY_SIZE(simpledrm_default_formats); ++i) { + if (simpledrm_default_formats[i] == sdev->format->format) + continue; /* native format already went first */ + sdev->formats[sdev->nformats] = simpledrm_default_formats[i]; + sdev->nformats++; + } + + /* + * TODO: The simpledrm driver converts framebuffers to the native + * format when copying them to device memory. If there are more + * formats listed than supported by the driver, the native format + * is not supported by the conversion helpers. Therefore *only* + * support the native format and add a conversion helper ASAP. + */ + if (drm_WARN_ONCE(dev, i != sdev->nformats, + "format conversion helpers required for %p4cc", + &sdev->format->format)) { + sdev->nformats = 1; + } + +out: + *nformats_out = sdev->nformats; + return sdev->formats; +} + +static int simpledrm_device_init_modeset(struct simpledrm_device *sdev) +{ + struct drm_device *dev = &sdev->dev; + struct drm_display_mode *mode = &sdev->mode; + struct drm_connector *connector = &sdev->connector; + struct drm_simple_display_pipe *pipe = &sdev->pipe; + const uint32_t *formats; + size_t nformats; + int ret; + + ret = drmm_mode_config_init(dev); + if (ret) + return ret; + + dev->mode_config.min_width = mode->hdisplay; + dev->mode_config.max_width = mode->hdisplay; + dev->mode_config.min_height = mode->vdisplay; + dev->mode_config.max_height = mode->vdisplay; + dev->mode_config.prefer_shadow_fbdev = true; + dev->mode_config.preferred_depth = sdev->format->cpp[0] * 8; + dev->mode_config.funcs = &simpledrm_mode_config_funcs; + + ret = drm_connector_init(dev, connector, &simpledrm_connector_funcs, + DRM_MODE_CONNECTOR_Unknown); + if (ret) + return ret; + drm_connector_helper_add(connector, &simpledrm_connector_helper_funcs); + + formats = simpledrm_device_formats(sdev, &nformats); + + ret = drm_simple_display_pipe_init(dev, pipe, &simpledrm_simple_display_pipe_funcs, + formats, nformats, simpledrm_format_modifiers, + connector); + if (ret) + return ret; + + drm_mode_config_reset(dev); + + return 0; +} + +/* + * Init / Cleanup + */ + +static struct simpledrm_device * +simpledrm_device_create(struct drm_driver *drv, struct platform_device *pdev) +{ + struct simpledrm_device *sdev; + int ret; + + sdev = devm_drm_dev_alloc(&pdev->dev, drv, struct simpledrm_device, + dev); + if (IS_ERR(sdev)) + return ERR_CAST(sdev); + sdev->pdev = pdev; + platform_set_drvdata(pdev, sdev); + + ret = simpledrm_device_init_fb(sdev); + if (ret) + return ERR_PTR(ret); + ret = simpledrm_device_init_mm(sdev); + if (ret) + return ERR_PTR(ret); + ret = simpledrm_device_init_modeset(sdev); + if (ret) + return ERR_PTR(ret); + + return sdev; +} + +/* + * DRM driver + */ + +DEFINE_DRM_GEM_FOPS(simpledrm_fops); + +static struct drm_driver simpledrm_driver = { + DRM_GEM_SHMEM_DRIVER_OPS, + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .driver_features = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET, + .fops = &simpledrm_fops, +}; + +/* + * Platform driver + */ + +static int simpledrm_probe(struct platform_device *pdev) +{ + struct simpledrm_device *sdev; + struct drm_device *dev; + int ret; + + sdev = simpledrm_device_create(&simpledrm_driver, pdev); + if (IS_ERR(sdev)) + return PTR_ERR(sdev); + dev = &sdev->dev; + + ret = drm_dev_register(dev, 0); + if (ret) + return ret; + + return 0; +} + +static int simpledrm_remove(struct platform_device *pdev) +{ + struct simpledrm_device *sdev = platform_get_drvdata(pdev); + struct drm_device *dev = &sdev->dev; + + drm_dev_unregister(dev); + + return 0; +} + +static struct platform_driver simpledrm_platform_driver = { + .driver = { + .name = "simple-framebuffer", /* connect to sysfb */ + }, + .probe = simpledrm_probe, + .remove = simpledrm_remove, +}; + +module_platform_driver(simpledrm_platform_driver); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL v2"); From patchwork Thu Apr 15 08:53:22 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 12204731 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 99AE4C43603 for ; Thu, 15 Apr 2021 08:53:43 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id 5D1DE61074 for ; Thu, 15 Apr 2021 08:53:43 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 5D1DE61074 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id D789E6EA03; Thu, 15 Apr 2021 08:53:35 +0000 (UTC) Received: from mx2.suse.de (mx2.suse.de [195.135.220.15]) by gabe.freedesktop.org (Postfix) with ESMTPS id 58E2E6E9FE for ; Thu, 15 Apr 2021 08:53:34 +0000 (UTC) X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id E6C89B1B7; Thu, 15 Apr 2021 08:53:32 +0000 (UTC) From: Thomas Zimmermann To: daniel@ffwll.ch, airlied@linux.ie, maarten.lankhorst@linux.intel.com, mripard@kernel.org, kraxel@redhat.com, corbet@lwn.net, lgirdwood@gmail.com, broonie@kernel.org, sam@ravnborg.org, robh@kernel.org, emil.l.velikov@gmail.com, geert+renesas@glider.be, hdegoede@redhat.com, bluescreen_avenger@verizon.net, gregkh@linuxfoundation.org Subject: [PATCH v3 5/9] drm/simpledrm: Add fbdev emulation Date: Thu, 15 Apr 2021 10:53:22 +0200 Message-Id: <20210415085326.8824-6-tzimmermann@suse.de> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210415085326.8824-1-tzimmermann@suse.de> References: <20210415085326.8824-1-tzimmermann@suse.de> MIME-Version: 1.0 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: , Cc: Daniel Vetter , virtualization@lists.linux-foundation.org, Thomas Zimmermann , dri-devel@lists.freedesktop.org, linux-doc@vger.kernel.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" This displays a console on simpledrm's framebuffer. The default framebuffer format is being used. Signed-off-by: Thomas Zimmermann Reviewed-by: Daniel Vetter Tested-by: nerdopolis --- drivers/gpu/drm/tiny/simpledrm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c index 0473a90a4024..64e8a8581d9a 100644 --- a/drivers/gpu/drm/tiny/simpledrm.c +++ b/drivers/gpu/drm/tiny/simpledrm.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -518,6 +519,8 @@ static int simpledrm_probe(struct platform_device *pdev) if (ret) return ret; + drm_fbdev_generic_setup(dev, 0); + return 0; } From patchwork Thu Apr 15 08:53:23 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 12204745 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E38BAC4363E for ; Thu, 15 Apr 2021 08:53:53 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id 99B1961074 for ; Thu, 15 Apr 2021 08:53:53 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 99B1961074 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id CA7056EA0C; Thu, 15 Apr 2021 08:53:45 +0000 (UTC) Received: from mx2.suse.de (mx2.suse.de [195.135.220.15]) by gabe.freedesktop.org (Postfix) with ESMTPS id E98B86E9FE for ; Thu, 15 Apr 2021 08:53:34 +0000 (UTC) X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id 79E76B1C8; Thu, 15 Apr 2021 08:53:33 +0000 (UTC) From: Thomas Zimmermann To: daniel@ffwll.ch, airlied@linux.ie, maarten.lankhorst@linux.intel.com, mripard@kernel.org, kraxel@redhat.com, corbet@lwn.net, lgirdwood@gmail.com, broonie@kernel.org, sam@ravnborg.org, robh@kernel.org, emil.l.velikov@gmail.com, geert+renesas@glider.be, hdegoede@redhat.com, bluescreen_avenger@verizon.net, gregkh@linuxfoundation.org Subject: [PATCH v3 6/9] drm/simpledrm: Initialize framebuffer data from device-tree node Date: Thu, 15 Apr 2021 10:53:23 +0200 Message-Id: <20210415085326.8824-7-tzimmermann@suse.de> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210415085326.8824-1-tzimmermann@suse.de> References: <20210415085326.8824-1-tzimmermann@suse.de> MIME-Version: 1.0 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: , Cc: virtualization@lists.linux-foundation.org, Thomas Zimmermann , dri-devel@lists.freedesktop.org, linux-doc@vger.kernel.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" A firmware framebuffer might also be specified via device-tree files. If no device platform data is given, try the DT device node. v2: * add Device Tree match table * clean-up parser wrappers Signed-off-by: Thomas Zimmermann Tested-by: nerdopolis --- drivers/gpu/drm/tiny/simpledrm.c | 89 ++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c index 64e8a8581d9a..53d6bec7d0b2 100644 --- a/drivers/gpu/drm/tiny/simpledrm.c +++ b/drivers/gpu/drm/tiny/simpledrm.c @@ -114,6 +114,74 @@ simplefb_get_format_pd(struct drm_device *dev, return simplefb_get_validated_format(dev, pd->format); } +static int +simplefb_read_u32_of(struct drm_device *dev, struct device_node *of_node, + const char *name, u32 *value) +{ + int ret = of_property_read_u32(of_node, name, value); + + if (ret) + drm_err(dev, "simplefb: cannot parse framebuffer %s: error %d\n", + name, ret); + return ret; +} + +static int +simplefb_read_string_of(struct drm_device *dev, struct device_node *of_node, + const char *name, const char **value) +{ + int ret = of_property_read_string(of_node, name, value); + + if (ret) + drm_err(dev, "simplefb: cannot parse framebuffer %s: error %d\n", + name, ret); + return ret; +} + +static int +simplefb_get_width_of(struct drm_device *dev, struct device_node *of_node) +{ + u32 width; + int ret = simplefb_read_u32_of(dev, of_node, "width", &width); + + if (ret) + return ret; + return simplefb_get_validated_int0(dev, "width", width); +} + +static int +simplefb_get_height_of(struct drm_device *dev, struct device_node *of_node) +{ + u32 height; + int ret = simplefb_read_u32_of(dev, of_node, "height", &height); + + if (ret) + return ret; + return simplefb_get_validated_int0(dev, "height", height); +} + +static int +simplefb_get_stride_of(struct drm_device *dev, struct device_node *of_node) +{ + u32 stride; + int ret = simplefb_read_u32_of(dev, of_node, "stride", &stride); + + if (ret) + return ret; + return simplefb_get_validated_int(dev, "stride", stride); +} + +static const struct drm_format_info * +simplefb_get_format_of(struct drm_device *dev, struct device_node *of_node) +{ + const char *format; + int ret = simplefb_read_string_of(dev, of_node, "format", &format); + + if (ret) + return ERR_PTR(ret); + return simplefb_get_validated_format(dev, format); +} + /* * Simple Framebuffer device */ @@ -166,6 +234,7 @@ static int simpledrm_device_init_fb(struct simpledrm_device *sdev) struct drm_device *dev = &sdev->dev; struct platform_device *pdev = sdev->pdev; const struct simplefb_platform_data *pd = dev_get_platdata(&pdev->dev); + struct device_node *of_node = pdev->dev.of_node; if (pd) { width = simplefb_get_width_pd(dev, pd); @@ -180,6 +249,19 @@ static int simpledrm_device_init_fb(struct simpledrm_device *sdev) format = simplefb_get_format_pd(dev, pd); if (IS_ERR(format)) return PTR_ERR(format); + } else if (of_node) { + width = simplefb_get_width_of(dev, of_node); + if (width < 0) + return width; + height = simplefb_get_height_of(dev, of_node); + if (height < 0) + return height; + stride = simplefb_get_stride_of(dev, of_node); + if (stride < 0) + return stride; + format = simplefb_get_format_of(dev, of_node); + if (IS_ERR(format)) + return PTR_ERR(format); } else { drm_err(dev, "no simplefb configuration found\n"); return -ENODEV; @@ -534,9 +616,16 @@ static int simpledrm_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id simpledrm_of_match_table[] = { + { .compatible = "simple-framebuffer", }, + { }, +}; +MODULE_DEVICE_TABLE(of, simpledrm_of_match_table); + static struct platform_driver simpledrm_platform_driver = { .driver = { .name = "simple-framebuffer", /* connect to sysfb */ + .of_match_table = simpledrm_of_match_table, }, .probe = simpledrm_probe, .remove = simpledrm_remove, From patchwork Thu Apr 15 08:53:24 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 12204741 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 14F91C4363C for ; Thu, 15 Apr 2021 08:53:51 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id BD9AF61074 for ; Thu, 15 Apr 2021 08:53:50 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org BD9AF61074 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 69E856EA07; Thu, 15 Apr 2021 08:53:39 +0000 (UTC) Received: from mx2.suse.de (mx2.suse.de [195.135.220.15]) by gabe.freedesktop.org (Postfix) with ESMTPS id 77A956E9FE for ; Thu, 15 Apr 2021 08:53:35 +0000 (UTC) X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id 0ACBAB1FA; Thu, 15 Apr 2021 08:53:34 +0000 (UTC) From: Thomas Zimmermann To: daniel@ffwll.ch, airlied@linux.ie, maarten.lankhorst@linux.intel.com, mripard@kernel.org, kraxel@redhat.com, corbet@lwn.net, lgirdwood@gmail.com, broonie@kernel.org, sam@ravnborg.org, robh@kernel.org, emil.l.velikov@gmail.com, geert+renesas@glider.be, hdegoede@redhat.com, bluescreen_avenger@verizon.net, gregkh@linuxfoundation.org Subject: [PATCH v3 7/9] drm/simpledrm: Acquire clocks from DT device node Date: Thu, 15 Apr 2021 10:53:24 +0200 Message-Id: <20210415085326.8824-8-tzimmermann@suse.de> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210415085326.8824-1-tzimmermann@suse.de> References: <20210415085326.8824-1-tzimmermann@suse.de> MIME-Version: 1.0 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: , Cc: virtualization@lists.linux-foundation.org, Thomas Zimmermann , dri-devel@lists.freedesktop.org, linux-doc@vger.kernel.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Make sure required hardware clocks are enabled while the firmware framebuffer is in use. The basic code has been taken from the simplefb driver and adapted to DRM. Clocks are released automatically via devres helpers. Signed-off-by: Thomas Zimmermann Tested-by: nerdopolis --- drivers/gpu/drm/tiny/simpledrm.c | 108 +++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c index 53d6bec7d0b2..996318500abf 100644 --- a/drivers/gpu/drm/tiny/simpledrm.c +++ b/drivers/gpu/drm/tiny/simpledrm.c @@ -1,5 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only +#include +#include #include #include @@ -190,6 +192,12 @@ struct simpledrm_device { struct drm_device dev; struct platform_device *pdev; + /* clocks */ +#if defined CONFIG_OF && defined CONFIG_COMMON_CLK + unsigned int clk_count; + struct clk **clks; +#endif + /* simplefb settings */ struct drm_display_mode mode; const struct drm_format_info *format; @@ -211,6 +219,103 @@ static struct simpledrm_device *simpledrm_device_of_dev(struct drm_device *dev) return container_of(dev, struct simpledrm_device, dev); } +/* + * Hardware + */ + +#if defined CONFIG_OF && defined CONFIG_COMMON_CLK +/* + * Clock handling code. + * + * Here we handle the clocks property of our "simple-framebuffer" dt node. + * This is necessary so that we can make sure that any clocks needed by + * the display engine that the bootloader set up for us (and for which it + * provided a simplefb dt node), stay up, for the life of the simplefb + * driver. + * + * When the driver unloads, we cleanly disable, and then release the clocks. + * + * We only complain about errors here, no action is taken as the most likely + * error can only happen due to a mismatch between the bootloader which set + * up simplefb, and the clock definitions in the device tree. Chances are + * that there are no adverse effects, and if there are, a clean teardown of + * the fb probe will not help us much either. So just complain and carry on, + * and hope that the user actually gets a working fb at the end of things. + */ + +static void simpledrm_device_release_clocks(void *res) +{ + struct simpledrm_device *sdev = simpledrm_device_of_dev(res); + unsigned int i; + + for (i = 0; i < sdev->clk_count; ++i) { + if (sdev->clks[i]) { + clk_disable_unprepare(sdev->clks[i]); + clk_put(sdev->clks[i]); + } + } +} + +static int simpledrm_device_init_clocks(struct simpledrm_device *sdev) +{ + struct drm_device *dev = &sdev->dev; + struct platform_device *pdev = sdev->pdev; + struct device_node *of_node = pdev->dev.of_node; + struct clk *clock; + unsigned int i; + int ret; + + if (dev_get_platdata(&pdev->dev) || !of_node) + return 0; + + sdev->clk_count = of_clk_get_parent_count(of_node); + if (!sdev->clk_count) + return 0; + + sdev->clks = drmm_kzalloc(dev, sdev->clk_count * sizeof(sdev->clks[0]), + GFP_KERNEL); + if (!sdev->clks) + return -ENOMEM; + + for (i = 0; i < sdev->clk_count; ++i) { + clock = of_clk_get(of_node, i); + if (IS_ERR(clock)) { + ret = PTR_ERR(clock); + if (ret == -EPROBE_DEFER) + goto err; + drm_err(dev, "clock %u not found: %d\n", i, ret); + continue; + } + ret = clk_prepare_enable(clock); + if (ret) { + drm_err(dev, "failed to enable clock %u: %d\n", + i, ret); + clk_put(clock); + } + sdev->clks[i] = clock; + } + + return devm_add_action_or_reset(&pdev->dev, + simpledrm_device_release_clocks, + sdev); + +err: + while (i) { + --i; + if (sdev->clks[i]) { + clk_disable_unprepare(sdev->clks[i]); + clk_put(sdev->clks[i]); + } + } + return ret; +} +#else +static int simpledrm_device_init_clocks(struct simpledrm_device *sdev) +{ + return 0; +} +#endif + /* * Simplefb settings */ @@ -552,6 +657,9 @@ simpledrm_device_create(struct drm_driver *drv, struct platform_device *pdev) sdev->pdev = pdev; platform_set_drvdata(pdev, sdev); + ret = simpledrm_device_init_clocks(sdev); + if (ret) + return ERR_PTR(ret); ret = simpledrm_device_init_fb(sdev); if (ret) return ERR_PTR(ret); From patchwork Thu Apr 15 08:53:25 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 12204739 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B522FC43619 for ; Thu, 15 Apr 2021 08:53:47 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id 7269261074 for ; Thu, 15 Apr 2021 08:53:47 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 7269261074 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 0BB6B6EA04; Thu, 15 Apr 2021 08:53:39 +0000 (UTC) Received: from mx2.suse.de (mx2.suse.de [195.135.220.15]) by gabe.freedesktop.org (Postfix) with ESMTPS id 0FD256EA04 for ; Thu, 15 Apr 2021 08:53:36 +0000 (UTC) X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id 984A2B1E9; Thu, 15 Apr 2021 08:53:34 +0000 (UTC) From: Thomas Zimmermann To: daniel@ffwll.ch, airlied@linux.ie, maarten.lankhorst@linux.intel.com, mripard@kernel.org, kraxel@redhat.com, corbet@lwn.net, lgirdwood@gmail.com, broonie@kernel.org, sam@ravnborg.org, robh@kernel.org, emil.l.velikov@gmail.com, geert+renesas@glider.be, hdegoede@redhat.com, bluescreen_avenger@verizon.net, gregkh@linuxfoundation.org Subject: [PATCH v3 8/9] drm/simpledrm: Acquire regulators from DT device node Date: Thu, 15 Apr 2021 10:53:25 +0200 Message-Id: <20210415085326.8824-9-tzimmermann@suse.de> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210415085326.8824-1-tzimmermann@suse.de> References: <20210415085326.8824-1-tzimmermann@suse.de> MIME-Version: 1.0 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: , Cc: virtualization@lists.linux-foundation.org, Thomas Zimmermann , dri-devel@lists.freedesktop.org, linux-doc@vger.kernel.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Make sure required hardware regulators are enabled while the firmware framebuffer is in use. The basic code has been taken from the simplefb driver and adapted to DRM. Regulators are released automatically via devres helpers. v2: * use strscpy() Signed-off-by: Thomas Zimmermann Tested-by: nerdopolis --- drivers/gpu/drm/tiny/simpledrm.c | 128 +++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c index 996318500abf..9d522473cd7c 100644 --- a/drivers/gpu/drm/tiny/simpledrm.c +++ b/drivers/gpu/drm/tiny/simpledrm.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -197,6 +198,11 @@ struct simpledrm_device { unsigned int clk_count; struct clk **clks; #endif + /* regulators */ +#if defined CONFIG_OF && defined CONFIG_REGULATOR + unsigned int regulator_count; + struct regulator **regulators; +#endif /* simplefb settings */ struct drm_display_mode mode; @@ -316,6 +322,125 @@ static int simpledrm_device_init_clocks(struct simpledrm_device *sdev) } #endif +#if defined CONFIG_OF && defined CONFIG_REGULATOR + +#define SUPPLY_SUFFIX "-supply" + +/* + * Regulator handling code. + * + * Here we handle the num-supplies and vin*-supply properties of our + * "simple-framebuffer" dt node. This is necessary so that we can make sure + * that any regulators needed by the display hardware that the bootloader + * set up for us (and for which it provided a simplefb dt node), stay up, + * for the life of the simplefb driver. + * + * When the driver unloads, we cleanly disable, and then release the + * regulators. + * + * We only complain about errors here, no action is taken as the most likely + * error can only happen due to a mismatch between the bootloader which set + * up simplefb, and the regulator definitions in the device tree. Chances are + * that there are no adverse effects, and if there are, a clean teardown of + * the fb probe will not help us much either. So just complain and carry on, + * and hope that the user actually gets a working fb at the end of things. + */ + +static void simpledrm_device_release_regulators(void *res) +{ + struct simpledrm_device *sdev = simpledrm_device_of_dev(res); + unsigned int i; + + for (i = 0; i < sdev->regulator_count; ++i) { + if (sdev->regulators[i]) { + regulator_disable(sdev->regulators[i]); + regulator_put(sdev->regulators[i]); + } + } +} + +static int simpledrm_device_init_regulators(struct simpledrm_device *sdev) +{ + struct drm_device *dev = &sdev->dev; + struct platform_device *pdev = sdev->pdev; + struct device_node *of_node = pdev->dev.of_node; + struct property *prop; + struct regulator *regulator; + const char *p; + unsigned int count = 0, i = 0; + int ret; + + if (dev_get_platdata(&pdev->dev) || !of_node) + return 0; + + /* Count the number of regulator supplies */ + for_each_property_of_node(of_node, prop) { + p = strstr(prop->name, SUPPLY_SUFFIX); + if (p && p != prop->name) + ++count; + } + + if (!count) + return 0; + + sdev->regulators = drmm_kzalloc(dev, + count * sizeof(sdev->regulators[0]), + GFP_KERNEL); + if (!sdev->regulators) + return -ENOMEM; + + for_each_property_of_node(of_node, prop) { + char name[32]; /* 32 is max size of property name */ + size_t len; + + p = strstr(prop->name, SUPPLY_SUFFIX); + if (!p || p == prop->name) + continue; + len = strlen(prop->name) - strlen(SUPPLY_SUFFIX) + 1; + strscpy(name, prop->name, min(sizeof(name), len)); + + regulator = regulator_get_optional(&pdev->dev, name); + if (IS_ERR(regulator)) { + ret = PTR_ERR(regulator); + if (ret == -EPROBE_DEFER) + goto err; + drm_err(dev, "regulator %s not found: %d\n", + name, ret); + continue; + } + + ret = regulator_enable(regulator); + if (ret) { + drm_err(dev, "failed to enable regulator %u: %d\n", + i, ret); + regulator_put(regulator); + } + + sdev->regulators[i++] = regulator; + } + sdev->regulator_count = i; + + return devm_add_action_or_reset(&pdev->dev, + simpledrm_device_release_regulators, + sdev); + +err: + while (i) { + --i; + if (sdev->regulators[i]) { + regulator_disable(sdev->regulators[i]); + regulator_put(sdev->regulators[i]); + } + } + return ret; +} +#else +static int simpledrm_device_init_regulators(struct simpledrm_device *sdev) +{ + return 0; +} +#endif + /* * Simplefb settings */ @@ -658,6 +783,9 @@ simpledrm_device_create(struct drm_driver *drv, struct platform_device *pdev) platform_set_drvdata(pdev, sdev); ret = simpledrm_device_init_clocks(sdev); + if (ret) + return ERR_PTR(ret); + ret = simpledrm_device_init_regulators(sdev); if (ret) return ERR_PTR(ret); ret = simpledrm_device_init_fb(sdev); From patchwork Thu Apr 15 08:53:26 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 12204743 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A5FDCC4363F for ; Thu, 15 Apr 2021 08:53:52 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id 623E361074 for ; Thu, 15 Apr 2021 08:53:52 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 623E361074 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id AACE86EA09; Thu, 15 Apr 2021 08:53:39 +0000 (UTC) Received: from mx2.suse.de (mx2.suse.de [195.135.220.15]) by gabe.freedesktop.org (Postfix) with ESMTPS id A9F356EA05 for ; Thu, 15 Apr 2021 08:53:36 +0000 (UTC) X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id 2A513B1EC; Thu, 15 Apr 2021 08:53:35 +0000 (UTC) From: Thomas Zimmermann To: daniel@ffwll.ch, airlied@linux.ie, maarten.lankhorst@linux.intel.com, mripard@kernel.org, kraxel@redhat.com, corbet@lwn.net, lgirdwood@gmail.com, broonie@kernel.org, sam@ravnborg.org, robh@kernel.org, emil.l.velikov@gmail.com, geert+renesas@glider.be, hdegoede@redhat.com, bluescreen_avenger@verizon.net, gregkh@linuxfoundation.org Subject: [PATCH v3 9/9] drm/simpledrm: Acquire memory aperture for framebuffer Date: Thu, 15 Apr 2021 10:53:26 +0200 Message-Id: <20210415085326.8824-10-tzimmermann@suse.de> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210415085326.8824-1-tzimmermann@suse.de> References: <20210415085326.8824-1-tzimmermann@suse.de> MIME-Version: 1.0 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: , Cc: virtualization@lists.linux-foundation.org, Thomas Zimmermann , dri-devel@lists.freedesktop.org, linux-doc@vger.kernel.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" We register the simplekms device with the DRM platform helpers. A native driver for the graphics hardware will kick-out the simpledrm driver before taking over the device. The original generic platform device from the simple-framebuffer boot code will be unregistered. The native driver will use whatever native hardware device it received. v3: * use platform_device_unregister() and handle detachment like hot-unplug event (Daniel) v2: * adapt to aperture changes * use drm_dev_unplug() and drm_dev_enter/exit() * don't split error string Signed-off-by: Thomas Zimmermann Tested-by: nerdopolis --- drivers/gpu/drm/tiny/simpledrm.c | 49 +++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c index 9d522473cd7c..14473e1bccab 100644 --- a/drivers/gpu/drm/tiny/simpledrm.c +++ b/drivers/gpu/drm/tiny/simpledrm.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -515,16 +516,49 @@ static int simpledrm_device_init_fb(struct simpledrm_device *sdev) * Memory management */ +static void simpledrm_aperture_detach(struct drm_device *dev, resource_size_t base, + resource_size_t size) +{ + struct simpledrm_device *sdev = simpledrm_device_of_dev(dev); + struct platform_device *pdev = sdev->pdev; + + /* + * Remove the device from the bus itself. This is the right thing to + * do for the generic DRM drivers, such as EFI, VESA or VGA. When the + * new driver takes over the hardware, the generic device's state will + * be lost. + * + * If the aperture helpers need to handle native drivers, this call + * would only have to unplug the DRM device, so that the hardware device + * stays around after detachment. + */ + platform_device_unregister(pdev); +} + +static const struct drm_aperture_funcs simpledrm_aperture_funcs = { + .detach = simpledrm_aperture_detach, +}; + static int simpledrm_device_init_mm(struct simpledrm_device *sdev) { + struct drm_device *dev = &sdev->dev; struct platform_device *pdev = sdev->pdev; struct resource *mem; void __iomem *screen_base; + int ret; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) return -EINVAL; + ret = devm_aperture_acquire(dev, mem->start, resource_size(mem), + &simpledrm_aperture_funcs); + if (ret) { + drm_err(dev, "could not acquire memory range [0x%llx:0x%llx]: error %d\n", + mem->start, mem->end, ret); + return ret; + } + screen_base = devm_ioremap_wc(&pdev->dev, mem->start, resource_size(mem)); if (!screen_base) @@ -625,12 +659,18 @@ simpledrm_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe, struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); struct drm_framebuffer *fb = plane_state->fb; void *vmap = shadow_plane_state->map[0].vaddr; /* TODO: Use mapping abstraction properly */ + struct drm_device *dev = &sdev->dev; + int idx; if (!fb) return; + if (!drm_dev_enter(dev, &idx)) + return; + drm_fb_blit_dstclip(sdev->screen_base, sdev->pitch, sdev->format->format, vmap, fb); + drm_dev_exit(idx); } static void @@ -658,7 +698,9 @@ simpledrm_simple_display_pipe_update(struct drm_simple_display_pipe *pipe, struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); void *vmap = shadow_plane_state->map[0].vaddr; /* TODO: Use mapping abstraction properly */ struct drm_framebuffer *fb = plane_state->fb; + struct drm_device *dev = &sdev->dev; struct drm_rect clip; + int idx; if (!fb) return; @@ -666,8 +708,13 @@ simpledrm_simple_display_pipe_update(struct drm_simple_display_pipe *pipe, if (!drm_atomic_helper_damage_merged(old_plane_state, plane_state, &clip)) return; + if (!drm_dev_enter(dev, &idx)) + return; + drm_fb_blit_rect_dstclip(sdev->screen_base, sdev->pitch, sdev->format->format, vmap, fb, &clip); + + drm_dev_exit(idx); } static const struct drm_simple_display_pipe_funcs @@ -847,7 +894,7 @@ static int simpledrm_remove(struct platform_device *pdev) struct simpledrm_device *sdev = platform_get_drvdata(pdev); struct drm_device *dev = &sdev->dev; - drm_dev_unregister(dev); + drm_dev_unplug(dev); return 0; }