DRM full analysis - ADD_FB (4)

Continuing from the previous article: Full analysis of DRM - ADD_FB (3)

This article refers to the following blog posts:

DRM driver (4) ADD_FB

Thanks!

The last chapter explained the first step in the drm_mode_addfb function and the first function drm_core_check_feature. This chapter continues to analyze the drm_mode_addfb function. For ease of understanding, the code is posted again, in drivers/gpu/drm/drm_framebuffer.c, as follows:

/**
 * drm_mode_addfb - add an FB to the graphics configuration
 * @dev: drm device for the ioctl
 * @or: pointer to request structure
 * @file_priv: drm file
 *
 * Add a new FB to the specified CRTC, given a user request. This is the
 * original addfb ioctl which only supported RGB formats.
 *
 * Called by the user via ioctl, or by an in-kernel client.
 *
 * Returns:
 * Zero on success, negative errno on failure.
 */
int drm_mode_addfb(struct drm_device *dev, struct drm_mode_fb_cmd *or,
		   struct drm_file *file_priv)
{
	struct drm_mode_fb_cmd2 r = {};
	int ret;
 
	if (!drm_core_check_feature(dev, DRIVER_MODESET))
		return -EOPNOTSUPP;
 
	r.pixel_format = drm_driver_legacy_fb_format(dev, or->bpp, or->depth);
	if (r.pixel_format == DRM_FORMAT_INVALID) {
		drm_dbg_kms(dev, "bad {bpp:%d, depth:%d}\n", or->bpp, or->depth);
		return -EINVAL;
	}
 
	/* convert to new format and call new ioctl */
	r.fb_id = or->fb_id;
	r.width = or->width;
	r.height = or->height;
	r.pitches[0] = or->pitch;
	r.handles[0] = or->handle;
 
	ret = drm_mode_addfb2(dev, &r, file_priv);
	if (ret)
		return ret;
 
	or->fb_id = r.fb_id;
 
	return 0;
}

The second step is to call the drm_driver_legacy_fb_format function to set the pixel format. The drm_driver_fb_format function is in drivers/gpu/drm/drm_fourcc.c. The code is as follows:

/**
 * drm_driver_legacy_fb_format - compute drm fourcc code from legacy description
 * @dev: DRM device
 * @bpp: bits per pixels
 * @depth: bit depth per pixel
 *
 * Computes a drm fourcc pixel format code for the given @bpp/@depth values.
 * Unlike drm_mode_legacy_fb_format() this looks at the drivers mode_config,
 * and depending on the &drm_mode_config.quirk_addfb_prefer_host_byte_order flag
 * it returns little endian byte order or host byte order framebuffer formats.
 */
uint32_t drm_driver_legacy_fb_format(struct drm_device *dev,
				     uint32_t bpp, uint32_t depth)
{
	uint32_t fmt = drm_mode_legacy_fb_format(bpp, depth);

	if (dev->mode_config.quirk_addfb_prefer_host_byte_order) {
		if (fmt == DRM_FORMAT_XRGB8888)
			fmt = DRM_FORMAT_HOST_XRGB8888;
		if (fmt == DRM_FORMAT_ARGB8888)
			fmt = DRM_FORMAT_HOST_ARGB8888;
		if (fmt == DRM_FORMAT_RGB565)
			fmt = DRM_FORMAT_HOST_RGB565;
		if (fmt == DRM_FORMAT_XRGB1555)
			fmt = DRM_FORMAT_HOST_XRGB1555;
	}

	if (dev->mode_config.quirk_addfb_prefer_xbgr_30bpp &&
	    fmt == DRM_FORMAT_XRGB2101010)
		fmt = DRM_FORMAT_XBGR2101010;

	return fmt;
}
EXPORT_SYMBOL(drm_driver_legacy_fb_format);

The most important thing in the drm_driver_legacy_fb_format function is to call the drm_mode_legacy_fb_format function. This function is just above. The code is as follows:

/**
 * drm_mode_legacy_fb_format - compute drm fourcc code from legacy description
 * @bpp: bits per pixels
 * @depth: bit depth per pixel
 *
 * Computes a drm fourcc pixel format code for the given @bpp/@depth values.
 * Useful in fbdev emulation code, since that deals in those values.
 */
uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth)
{
	uint32_t fmt = DRM_FORMAT_INVALID;

	switch (bpp) {
	case 1:
		if (depth == 1)
			fmt = DRM_FORMAT_C1;
		break;

	case 2:
		if (depth == 2)
			fmt = DRM_FORMAT_C2;
		break;

	case 4:
		if (depth == 4)
			fmt = DRM_FORMAT_C4;
		break;

	case 8:
		if (depth == 8)
			fmt = DRM_FORMAT_C8;
		break;

	case 16:
		switch (depth) {
		case 15:
			fmt = DRM_FORMAT_XRGB1555;
			break;
		case 16:
			fmt = DRM_FORMAT_RGB565;
			break;
		default:
			break;
		}
		break;

	case 24:
		if (depth == 24)
			fmt = DRM_FORMAT_RGB888;
		break;

	case 32:
		switch (depth) {
		case 24:
			fmt = DRM_FORMAT_XRGB8888;
			break;
		case 30:
			fmt = DRM_FORMAT_XRGB2101010;
			break;
		case 32:
			fmt = DRM_FORMAT_ARGB8888;
			break;
		default:
			break;
		}
		break;

	default:
		break;
	}

	return fmt;
}
EXPORT_SYMBOL(drm_mode_legacy_fb_format);

The function of the drm_mode_legacy_fb_format function is clear at a glance. According to the passed parameters bpp and depth, that is, the number of bits per pixel and the bit width per pixel, the format of fmt is determined and returned. Formats include DRM_FORMAT_RGB888, DRM_FORMAT_ARGB8888, etc.

Return to the drm_driver_legacy_fb_format function and determine the final fmt based on the fmt returned by drm_mode_legacy_fb_format. It can be simply understood as performing macro conversion on certain formats and then returning.

There is a question here: Where do bpp and depth come from? As you can see from the code, the parameters in the drm_driver_legacy_fb_format function include bpp and depth:

uint32_t drm_driver_legacy_fb_format(struct drm_device *dev,
				     uint32_t bpp, uint32_t depth)

The actual parameters are passed in when called in the drm_mode_addfb function. The code snippet is as follows:

    r.pixel_format = drm_driver_legacy_fb_format(dev, or->bpp, or->depth);
	if (r.pixel_format == DRM_FORMAT_INVALID) {
		drm_dbg_kms(dev, "bad {bpp:%d, depth:%d}\n", or->bpp, or->depth);
		return -EINVAL;
	}
 

It can be seen that the incoming bpp corresponds to or->bpp, and depth corresponds to or->depth.

So what is this or? According to the drm_mode_addfb function description, or is the "pointer to request structure", which is the pointer to the request structure. The request structure corresponds to struct drm_mode_fb_cmd, which is defined in include/uapi/drm/drm_mode.h. The code is as follows:

struct drm_mode_fb_cmd {
	__u32 fb_id;
	__u32 width;
	__u32 height;
	__u32 pitch;
	__u32 bpp;
	__u32 depth;
	/* driver specific handle */
	__u32 handle;
};

If the drm_driver_legacy_fb_format function called in the drm_mode_addfb function (see the above code snippet) eventually returns DRM_FORMAT_INVALID (macro definition, value is 0, in include/uapi/drm/drm_fourcc.h), then the drm_mode_addfb function returns -EINVAL, indicating invalid parameters.

At this point, the first step in the drm_mode_addfb function: the drm_driver_legacy_fb_format function has been analyzed. The remaining steps and functions will be analyzed in the following articles.

Guess you like

Origin blog.csdn.net/phmatthaus/article/details/132662490