drivers/gpu/drm/msm/msm_fb.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/msm/msm_fb.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/msm/msm_fb.c
Extension
.c
Size
7692 bytes
Lines
298
Domain
Driver Families
Bucket
drivers/gpu
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct msm_framebuffer {
	struct drm_framebuffer base;
	const struct msm_format *format;

	/* Count of # of attached planes which need dirtyfb: */
	refcount_t dirtyfb;

	/* Framebuffer per-plane address, if pinned, else zero: */
	uint64_t iova[DRM_FORMAT_MAX_PLANES];
	atomic_t prepare_count;
};
#define to_msm_framebuffer(x) container_of(x, struct msm_framebuffer, base)

static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
		const struct drm_format_info *info,
		const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos);

static int msm_framebuffer_dirtyfb(struct drm_framebuffer *fb,
				   struct drm_file *file_priv, unsigned int flags,
				   unsigned int color, struct drm_clip_rect *clips,
				   unsigned int num_clips)
{
	struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);

	/* If this fb is not used on any display requiring pixel data to be
	 * flushed, then skip dirtyfb
	 */
	if (refcount_read(&msm_fb->dirtyfb) == 1)
		return 0;

	return drm_atomic_helper_dirtyfb(fb, file_priv, flags, color,
					 clips, num_clips);
}

static const struct drm_framebuffer_funcs msm_framebuffer_funcs = {
	.create_handle = drm_gem_fb_create_handle,
	.destroy = drm_gem_fb_destroy,
	.dirty = msm_framebuffer_dirtyfb,
};

#ifdef CONFIG_DEBUG_FS
void msm_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m)
{
	struct msm_gem_stats stats = {};
	int i, n = fb->format->num_planes;

	seq_printf(m, "fb: %dx%d@%4.4s (%2d, ID:%d)\n",
			fb->width, fb->height, (char *)&fb->format->format,
			drm_framebuffer_read_refcount(fb), fb->base.id);

	for (i = 0; i < n; i++) {
		seq_printf(m, "   %d: offset=%d pitch=%d, obj: ",
				i, fb->offsets[i], fb->pitches[i]);
		msm_gem_describe(fb->obj[i], m, &stats);
	}
}
#endif

/* prepare/pin all the fb's bo's for scanout.
 */
int msm_framebuffer_prepare(struct drm_framebuffer *fb, bool needs_dirtyfb)
{
	struct msm_drm_private *priv = fb->dev->dev_private;
	struct drm_gpuvm *vm = priv->kms->vm;
	struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
	int ret, i, n = fb->format->num_planes;

	if (needs_dirtyfb)
		refcount_inc(&msm_fb->dirtyfb);

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

	for (i = 0; i < n; i++) {
		msm_gem_vma_get(fb->obj[i]);
		ret = msm_gem_get_and_pin_iova(fb->obj[i], vm, &msm_fb->iova[i]);
		drm_dbg_state(fb->dev, "FB[%u]: iova[%d]: %08llx (%d)\n",
			      fb->base.id, i, msm_fb->iova[i], ret);
		if (ret)
			return ret;
	}

	return 0;
}

void msm_framebuffer_cleanup(struct drm_framebuffer *fb, bool needed_dirtyfb)
{
	struct msm_drm_private *priv = fb->dev->dev_private;
	struct drm_gpuvm *vm = priv->kms->vm;
	struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);

Annotation

Implementation Notes