DRM driver code analysis: layer parameter update

Foreword:
Staying at home without a job, working behind closed doors. All corrections are very welcome.
Some code processes are based on code analysis, without verifying whether they are correct.
I don’t know many things about the DRM framework, so some places will be relatively blunt. It takes time to get familiar with learning, and articles piled up in the draft box may reduce my enthusiasm, so I still publish the article first, and then slowly improve it.

1. How does the DRM driver obtain parameters such as the width and height of the layer

1.1 What are the layer parameters?

drivers\gpu\drm\drm_blend.c

standard plane properties
SRC_X &drm_framebuffer The x-coordinate offset value of the source rectangle. Must be positive.
SRC_Y &drm_framebuffer The y-coordinate offset value of the source rectangle. Must be positive.
SRC_W &drm_framebuffer the width of the original rectangle. SRC_X plus SRC_W is less than the width of the source framebuffer. Must be positive.
SRC_H &drm_framebuffer The height of the original rectangle. SRC_Y plus SRC_H ​​should be less than the height of source framebuffer. Must be positive.
CRTC_X The x-coordinate offset of the target rectangle, can be negative.
CRTC_Y The y-coordinate offset of the destination rectangle, which can be negative.
CRTC_W The width of the target rectangle. CRTC_X plus CRTC_W can exceed the current visible horizontal area of ​​&drm_crtc
CRTC_H The height of the target rectangle. CRTC_Y plus CRTC_H can exceed the current visible vertical area of ​​&drm_crtc
FB_ID Mode object ID of the &drm_framebuffer this plane should scan out.
CRTC_ID Mode object ID of the &drm_crtc this plane should be connected to.
additional plane properties
alpha Transparency, the value range is 0 (transparent) ~ 0xfff (opaque). Some formats have a transparency per pixel, such as the ARGB8888 format.
drm_plane_create_alpha_property()
rotation Rotation angle (including flipping)
drm_plane_create_rotation_property()
zpos z order, specifies the order of the layers.
drm_plane_create_zpos_immutable_property() * drm_plane_create_zpos_property()
pixel blend mode Composite method, which describes the compositing method between the pixels of the current layer and the background layer.

" None ": ignore pixel alpha
out.rgb = plane_alpha * fg.rgb + (1 - plane_alpha) * bg.rgb

" Pre-multiplied ": pixel rgb value and pixel alpha have been premultiplied.
out.rgb = plane_alpha * fg.rgb + (1 - (plane_alpha * fg.alpha)) * bg.rgb

" Coverage ": pixel rgb value and pixel alpha are not premultiplied.
out.rgb = plane_alpha * fg.alpha * fg.rgb + (1 - (plane_alpha * fg.alpha)) * bg.rgb

drm_plane_create_blend_mode_property()
SCALING_FILTER Indicates scaling filter to be used for plane scaler.
drm_plane_create_scaling_filter_property

1.2 struct drm_plane_state

include/drm/drm_plane.h
struct drm_plane_state {
    
    
	...
	struct drm_framebuffer *fb;
	...
	int32_t crtc_x;
	int32_t crtc_y;
	uint32_t crtc_w, crtc_h;
	uint32_t src_x;
	uint32_t src_y;
	uint32_t src_h, src_w;
	u16 alpha;
	uint16_t pixel_blend_mode;
	unsigned int rotation;
	unsigned int zpos;
	...
};



Some parameters crtc_x of the layer are stored in struct drm_plane_state , the left position (pos x) of the visible area of ​​the layer on the CRTC. The data type is int32_t signed integer, and the position can be outside the screen (how to deal with it in the code?).

crtc_y , the upper position (pos y) of the visible area of ​​the layer on the CRTC. The data type is int32_t signed integer, and the position can be off-screen.

crtc_w , the width of the visible area of ​​the layer on the CRTC

crtc_h , the height of the visible area of ​​the layer on the CRTC

src_x , the left position of the visible area of ​​the layer on the layer (crop start x)

src_y , the visible area of ​​the layer on the layer The upper position (crop start y)

src_h , the height of the visible area of ​​the layer

src_w , the width of the visible area of ​​the layer

alpha , the transparency of the layer, 0 means completely transparent, 0xffff means completely opaque

pixel_blend_mode , the selection of the transparency synthesis formula, indicating the current How the pixels of the layer are combined with the background layer.

rotation , the rotation angle

zpos of the layer , the priority (zorder) of the layer on the CRTC

normalized_zpos , the normalized zpos, the range is 0~N-1, where N is the effective layer of the CRTC

1.3 Update layer properties (plane property)

drivers\gpu\drm\drm_ioctl.c
DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATOMIC, drm_mode_atomic_ioctl, DRM_MASTER),
drivers\gpu\drm\drm_atomic_uapi.c
int drm_mode_atomic_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv)
for (j = 0; j < count_props; j++)
		ret = drm_atomic_set_property(state, file_priv, obj, prop, prop_value);
drivers\gpu\drm\drm_atomic_uapi.c
int drm_atomic_set_property(struct drm_atomic_state *state, struct drm_file *file_priv,
			    struct drm_mode_object *obj, struct drm_property *prop, uint64_t prop_value)
case DRM_MODE_OBJECT_PLANE:
ret = drm_atomic_plane_set_property(plane, plane_state, file_priv, prop, prop_value);
drivers\gpu\drm\drm_atomic_uapi.c
static int drm_atomic_plane_set_property(struct drm_plane *plane, struct drm_plane_state *state,
									struct drm_file *file_priv, struct drm_property *property, uint64_t val)
if (property == config->prop_fb_id) {
    
    
		struct drm_framebuffer *fb;
	
		fb = drm_framebuffer_lookup(dev, file_priv, val);
		drm_atomic_set_fb_for_plane(state, fb);
		if (fb)
			drm_framebuffer_put(fb);
	} else if (property == config->prop_in_fence_fd) {
    
    
	      ...
	} else if (property == config->prop_crtc_x) {
    
    
		state->crtc_x = U642I64(val);
	} else if (property == config->prop_crtc_y) {
    
    
		state->crtc_y = U642I64(val);
	} else if (property == config->prop_crtc_w) {
    
    
		state->crtc_w = val;
	} else if (property == config->prop_crtc_h) {
    
    
		state->crtc_h = val;
	} else if (property == config->prop_src_x) {
    
    
		state->src_x = val;
	} else if (property == config->prop_src_y) {
    
    
		state->src_y = val;
	} else if (property == config->prop_src_w) {
    
    
		state->src_w = val;
	} else if (property == config->prop_src_h) {
    
    
		state->src_h = val;
	} else if (property == plane->alpha_property) {
    
    
		state->alpha = val;
	} else if (property == plane->blend_mode_property) {
    
    
		state->pixel_blend_mode = val;
	} else if (property == plane->rotation_property) {
    
    
		...
		state->rotation = val;
	} else if (property == plane->zpos_property) {
    
    
		state->zpos = val;
	} else if (property == plane->color_encoding_property)
	...
	} else if (plane->funcs->atomic_set_property) {
    
    
		return plane->funcs->atomic_set_property(plane, state,
				property, val);
	} else
	...

Update the values ​​of crtc_x, crtc_y, crtc_w, crtc_h, src_x, src_y, src_w, src_h, alpha, blend_mode, rotation, zpos and other attributes in drm_plane_state.

If there is a driver-private plane-related attribute, the update of the attribute value needs to implement the following functions in struct drm_plane_funcs:
int (*atomic_set_property)(struct drm_plane *plane, struct drm_plane_state *state, struct drm_property *property, uint64_t val);
such as Qualcomm implementation :
static int sde_plane_atomic_set_property(struct drm_plane *plane, struct drm_plane_state *state, struct drm_property *property, uint64_t val)

1.4 struct drm_plane_helper_funcs

include\drm\drm_modeset_helper_vtables.h
struct drm_plane_helper_funcs {
    
    
	int (*prepare_fb)(struct drm_plane *plane, struct drm_plane_state *new_state);
	void (*cleanup_fb)(struct drm_plane *plane, struct drm_plane_state *old_state);
	int (*atomic_check)(struct drm_plane *plane, struct drm_atomic_state *state);
	void (*atomic_update)(struct drm_plane *plane, struct drm_atomic_state *state);
	void (*atomic_disable)(struct drm_plane *plane, struct drm_atomic_state *state);
	int (*atomic_async_check)(struct drm_plane *plane, struct drm_atomic_state *state);
	void (*atomic_async_update)(struct drm_plane *plane, struct drm_atomic_state *state);
};

prepare_fb , prepare framebuffer. eg pinning its backing storage or relocating it into a contiguous block of VRAM. Other possible preparatory work includes flushing caches.

cleanup_fb clears the framebuffer and layer configuration generated by prepare_fb.

atomic_check , check layer

atomic_update , update layer state, need to be called between &drm_crtc_helper_funcs.atomic_begin and drm_crtc_helper_funcs.atomic_flush callbacks. The input parameter state is old, and plane->state is updated.

atomic_disable , disable the layer

atomic_async_check , check whether the atomic state of the layer can be updated asynchronously. The asynchronous here refers to "not vblank synchronized"

atomic_async_update , the layer is updated asynchronously

1.5 Assign the updated attribute value to the device register

drivers\gpu\drm\drm_atomic_helper.c
void drm_atomic_helper_commit_planes(struct drm_device *dev, struct drm_atomic_state *old_state, uint32_t flags)
funcs->atomic_update(plane, old_state);
vendor\qcom\opensource\display-drivers\msm\sde\sde_plane.c
static const struct drm_plane_helper_funcs sde_plane_helper_funcs = {
    
    
		.prepare_fb = sde_plane_prepare_fb,
		.cleanup_fb = sde_plane_cleanup_fb,
		.atomic_check = sde_plane_atomic_check,
		.atomic_update = sde_plane_atomic_update,
};
vendor\qcom\opensource\display-drivers\msm\sde\sde_plane.c
static void sde_plane_atomic_update(struct drm_plane *plane, struct drm_plane_state *old_state)
ret = sde_plane_sspp_atomic_update(plane, old_state);
static int sde_plane_sspp_atomic_update(struct drm_plane *plane,	struct drm_plane_state *old_state)
_sde_plane_set_scanout(plane, pstate, &psde->pipe_cfg, fb);
_sde_plane_update_properties(plane, crtc, fb);
static void _sde_plane_update_properties(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb)
struct drm_plane_state *state;
struct sde_plane_state *pstate;

pstate = to_sde_plane_state(state);
_sde_plane_update_format_and_rects(psde, pstate, fmt);
static void _sde_plane_update_format_and_rects(struct sde_plane *psde, struct sde_plane_state *pstate,
													const struct sde_format *fmt)
psde->pipe_hw->ops.setup_format(psde->pipe_hw, fmt, pstate->const_alpha_en, src_flags, pstate->multirect_index);
vendor\qcom\opensource\display-drivers\msm\sde\sde_hw_sspp.c
static void sde_hw_sspp_setup_format(struct sde_hw_pipe *ctx, const struct sde_format *fmt,
		bool const_alpha_en, u32 flags, enum sde_sspp_multirect_index rect_mode)
SDE_REG_WRITE(c, format_off + idx, src_format);

Update the SDE layer format parameter register

Some attribute values ​​in drm_plane_state will be saved in variables defined by Qualcomm itself.

todo : Look at the Qualcomm code, and decide to update all parameters or update parameters that have changed according to psde->revalidate. (Is this better? Will it be time consuming to update all parameters?)

2. How does the DRM driver obtain the memory address of the layer

2.1 struct drm_gem_object

struct drm_gem_object {
    
    
	struct kref refcount;
	unsigned handle_count;
	struct drm_device *dev;
	struct file *filp;
	struct drm_vma_offset_node vma_node;
	size_t size;
	int name;
	struct dma_buf *dma_buf;
	struct dma_buf_attachment *import_attach;
	struct dma_resv *resv;
	struct dma_resv _resv;
	const struct drm_gem_object_funcs *funcs;
};


refcount , gem object count

handle_count , file private handle count

dev , drm device

filp , SHMEM file node used as backing storage for swappable buffer objects. GEM also supports driver private objects with driver-specific backing storage (contiguous CMA memory, special re served blocks ). In this case @filp is NULL.

vma_node is used for mmap mapping information.

size , the size of the gem object in bytes.

name , the global name of the gem object, starting from 1. 0 means unnamed.

dma_buf , dma_buf

import_attach of gem object , dma_buf_attachment of gem object.
                struct dma_buf_attachment stores the connection relationship between dma-buf and device [2] .

resv , reserved object pointer

_resv , reserved object

funcs , optional. Replace the corresponding function in &drm_driver GEM callbacks.

2.2 Obtain the memory address of the layer through the fd id of dma buf

Tablet Description](https://img-blog.csdnimg.cn/a45e36ee8ce14e758c03eef9968f22f5.png)

Obtain dma-buf through fb id (prime_fd) of dma-buf

insert image description here

dma_buf_attach: add the device to the attachment list

dma_buf_map_attachment: generate sg_table. sg_table stores information about physical memory.
About the concept of sg_table read wowotech's Linux kernel scatterlist API introduction

gem_prime_import_sg_table: generate drm_gem_object

obj->import_attach = attach: assign attachment to gem object

The upper layer calls IOCTL to pass down the fd id of dma buf to realize the transformation from prime_fd to handle. During this process, sg_table is also generated, and the relevant information is stored in drm_gem_object.
Then you can get the address of the layer memory through drm_gem_object, which is convenient for setting the layer address register.

insert image description here

The configuration of the layer address register is also done in sde_plane_atomic_update.
Get SG_Table in the following order, and get the memory address of the layer. MENT *
Import_attach -> Struct SG_Table -> Struct Scatterlist-> Struct Page-> PFN-> phys addr

insert image description here

There are two cases of seeing the value of plane_addr in _sde_format_populate_addrs_linear, which come from msm_framebuffer_iova() and msm_framebuffer_phys() respectively. From the function name, the former should be the IO virtual address, and the latter is the physical address.

insert image description here

For the concepts of page, pfn, and memory model, you can read this article. The article "Linux Memory Model" by wowotech linuxer
is really well written. I didn't understand some parts, and I will study it later.

3. Abbreviation

SSPP:Source Surface Processor Pipes

4. References

[1] DRM application advanced (Property)
[2] dma-buf from shallow to deep (3) —— map attachment
[3] Linux kernel scatterlist API introduction

Guess you like

Origin blog.csdn.net/yuuu_cheer/article/details/129293692