Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 578cdafc authored by Alan Kwong's avatar Alan Kwong
Browse files

drm/msm: add kernel mapping of writeback framebuffer



Add kernel mapping of writeback framebuffer to facilitate
viewing of image framebuffer using debugger tools.

Enable kernel mapping by:

echo 1 > /sys/kernel/debug/dri/0/Virtual-1/fb_kmap

CRs-Fixed: 2009714
Change-Id: I26395f26532858bc6a8bfef2321be76deed69dd2
Signed-off-by: default avatarAlan Kwong <akwong@codeaurora.org>
parent c83b5a77
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -441,6 +441,7 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev,
struct drm_gem_object *msm_gem_import(struct drm_device *dev,
		struct dma_buf *dmabuf, struct sg_table *sgt);

void msm_framebuffer_set_kmap(struct drm_framebuffer *fb, bool enable);
int msm_framebuffer_prepare(struct drm_framebuffer *fb, int id);
void msm_framebuffer_cleanup(struct drm_framebuffer *fb, int id);
uint32_t msm_framebuffer_iova(struct drm_framebuffer *fb, int id, int plane);
+71 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
 * Copyright (C) 2013 Red Hat
 * Author: Rob Clark <robdclark@gmail.com>
 *
@@ -15,16 +16,24 @@
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <linux/dma-mapping.h>
#include <linux/dma-buf.h>

#include "msm_drv.h"
#include "msm_kms.h"

#include "drm_crtc.h"
#include "drm_crtc_helper.h"

#define MSM_FRAMEBUFFER_FLAG_KMAP	BIT(0)

struct msm_framebuffer {
	struct drm_framebuffer base;
	const struct msm_format *format;
	struct drm_gem_object *planes[MAX_PLANE];
	void *vaddr[MAX_PLANE];
	atomic_t kmap_count;
	u32 flags;
};
#define to_msm_framebuffer(x) container_of(x, struct msm_framebuffer, base)

@@ -79,6 +88,61 @@ void msm_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m)
}
#endif

void msm_framebuffer_set_kmap(struct drm_framebuffer *fb, bool enable)
{
	struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);

	if (enable)
		msm_fb->flags |= MSM_FRAMEBUFFER_FLAG_KMAP;
	else
		msm_fb->flags &= ~MSM_FRAMEBUFFER_FLAG_KMAP;
}

static int msm_framebuffer_kmap(struct drm_framebuffer *fb)
{
	struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
	int i, n = drm_format_num_planes(fb->pixel_format);
	struct drm_gem_object *bo;

	if (atomic_inc_return(&msm_fb->kmap_count) > 1)
		return 0;

	for (i = 0; i < n; i++) {
		bo = msm_framebuffer_bo(fb, i);
		if (!bo || !bo->dma_buf) {
			msm_fb->vaddr[i] = NULL;
			continue;
		}
		dma_buf_begin_cpu_access(bo->dma_buf, DMA_BIDIRECTIONAL);
		msm_fb->vaddr[i] = dma_buf_kmap(bo->dma_buf, 0);
		DRM_INFO("FB[%u]: vaddr[%d]:%ux%u:0x%llx\n", fb->base.id, i,
				fb->width, fb->height, (u64) msm_fb->vaddr[i]);
	}

	return 0;
}

static void msm_framebuffer_kunmap(struct drm_framebuffer *fb)
{
	struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
	int i, n = drm_format_num_planes(fb->pixel_format);
	struct drm_gem_object *bo;

	if (atomic_dec_return(&msm_fb->kmap_count) > 0)
		return;

	for (i = 0; i < n; i++) {
		bo = msm_framebuffer_bo(fb, i);
		if (!bo || !msm_fb->vaddr[i])
			continue;
		if (bo->dma_buf) {
			dma_buf_kunmap(bo->dma_buf, 0, msm_fb->vaddr[i]);
			dma_buf_end_cpu_access(bo->dma_buf, DMA_BIDIRECTIONAL);
		}
		msm_fb->vaddr[i] = NULL;
	}
}

/* prepare/pin all the fb's bo's for scanout.  Note that it is not valid
 * to prepare an fb more multiple different initiator 'id's.  But that
 * should be fine, since only the scanout (mdpN) side of things needs
@@ -97,6 +161,9 @@ int msm_framebuffer_prepare(struct drm_framebuffer *fb, int id)
			return ret;
	}

	if (msm_fb->flags & MSM_FRAMEBUFFER_FLAG_KMAP)
		msm_framebuffer_kmap(fb);

	return 0;
}

@@ -105,6 +172,9 @@ void msm_framebuffer_cleanup(struct drm_framebuffer *fb, int id)
	struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
	int i, n = drm_format_num_planes(fb->pixel_format);

	if (msm_fb->flags & MSM_FRAMEBUFFER_FLAG_KMAP)
		msm_framebuffer_kunmap(fb);

	for (i = 0; i < n; i++)
		msm_gem_put_iova(msm_fb->planes[i], id);
}
@@ -195,6 +265,7 @@ struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
	fb = &msm_fb->base;

	msm_fb->format = format;
	atomic_set(&msm_fb->kmap_count, 0);

	if (mode_cmd->flags & DRM_MODE_FB_MODIFIERS) {
		for (i = 0; i < ARRAY_SIZE(mode_cmd->modifier); i++) {
+40 −0
Original line number Diff line number Diff line
@@ -323,6 +323,9 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector,
			SDE_ERROR("failed to look up fb %lld\n", val);
			rc = -EFAULT;
		} else {
			msm_framebuffer_set_kmap(c_state->out_fb,
					c_conn->fb_kmap);

			if (c_state->out_fb->flags & DRM_MODE_FB_SECURE)
				c_state->mmu_id =
				c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE];
@@ -456,6 +459,42 @@ sde_connector_detect(struct drm_connector *connector, bool force)
	return status;
}

#ifdef CONFIG_DEBUG_FS
/**
 * sde_connector_init_debugfs - initialize connector debugfs
 * @connector: Pointer to drm connector
 */
static int sde_connector_init_debugfs(struct drm_connector *connector)
{
	struct sde_connector *sde_connector;

	if (!connector || !connector->debugfs_entry) {
		SDE_ERROR("invalid connector\n");
		return -EINVAL;
	}

	sde_connector = to_sde_connector(connector);

	if (!debugfs_create_bool("fb_kmap", 0644, connector->debugfs_entry,
			&sde_connector->fb_kmap)) {
		SDE_ERROR("failed to create connector fb_kmap\n");
		return -ENOMEM;
	}

	return 0;
}
#else
static int sde_connector_init_debugfs(struct drm_connector *connector)
{
	return 0;
}
#endif

static int sde_connector_late_register(struct drm_connector *connector)
{
	return sde_connector_init_debugfs(connector);
}

static const struct drm_connector_funcs sde_connector_ops = {
	.dpms =                   drm_atomic_helper_connector_dpms,
	.reset =                  sde_connector_atomic_reset,
@@ -467,6 +506,7 @@ static const struct drm_connector_funcs sde_connector_ops = {
	.atomic_set_property =    sde_connector_atomic_set_property,
	.atomic_get_property =    sde_connector_atomic_get_property,
	.set_property =           sde_connector_set_property,
	.late_register =          sde_connector_late_register,
};

static int sde_connector_get_modes(struct drm_connector *connector)
+3 −0
Original line number Diff line number Diff line
@@ -137,6 +137,7 @@ struct sde_connector_ops {
 * @property_info: Private structure for generic property handling
 * @property_data: Array of private data for generic property handling
 * @blob_caps: Pointer to blob structure for 'capabilities' property
 * @fb_kmap: true if kernel mapping of framebuffer is requested
 */
struct sde_connector {
	struct drm_connector base;
@@ -157,6 +158,8 @@ struct sde_connector {
	struct msm_property_info property_info;
	struct msm_property_data property_data[CONNECTOR_PROP_COUNT];
	struct drm_property_blob *blob_caps;

	bool fb_kmap;
};

/**