brintos

brintos / linux-shallow public Read only

0
0
Text · 8.8 KiB · 8643ff2 Raw
347 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * RZ/G2L Display Unit VSP-Based Compositor4 *5 * Copyright (C) 2023 Renesas Electronics Corporation6 *7 * Based on rcar_du_vsp.c8 */9 10#include <drm/drm_atomic.h>11#include <drm/drm_atomic_helper.h>12#include <drm/drm_blend.h>13#include <drm/drm_crtc.h>14#include <drm/drm_fb_dma_helper.h>15#include <drm/drm_fourcc.h>16#include <drm/drm_framebuffer.h>17#include <drm/drm_gem_atomic_helper.h>18#include <drm/drm_gem_dma_helper.h>19#include <drm/drm_managed.h>20#include <drm/drm_vblank.h>21 22#include <linux/bitops.h>23#include <linux/dma-mapping.h>24#include <linux/of_platform.h>25#include <linux/platform_device.h>26#include <linux/scatterlist.h>27 28#include <media/vsp1.h>29 30#include "rzg2l_du_drv.h"31#include "rzg2l_du_kms.h"32#include "rzg2l_du_vsp.h"33 34static void rzg2l_du_vsp_complete(void *private, unsigned int status, u32 crc)35{36	struct rzg2l_du_crtc *crtc = private;37 38	if (crtc->vblank_enable)39		drm_crtc_handle_vblank(&crtc->crtc);40 41	if (status & VSP1_DU_STATUS_COMPLETE)42		rzg2l_du_crtc_finish_page_flip(crtc);43 44	drm_crtc_add_crc_entry(&crtc->crtc, false, 0, &crc);45}46 47void rzg2l_du_vsp_enable(struct rzg2l_du_crtc *crtc)48{49	const struct drm_display_mode *mode = &crtc->crtc.state->adjusted_mode;50	struct vsp1_du_lif_config cfg = {51		.width = mode->hdisplay,52		.height = mode->vdisplay,53		.interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE,54		.callback = rzg2l_du_vsp_complete,55		.callback_data = crtc,56	};57 58	vsp1_du_setup_lif(crtc->vsp->vsp, crtc->vsp_pipe, &cfg);59}60 61void rzg2l_du_vsp_disable(struct rzg2l_du_crtc *crtc)62{63	vsp1_du_setup_lif(crtc->vsp->vsp, crtc->vsp_pipe, NULL);64}65 66void rzg2l_du_vsp_atomic_flush(struct rzg2l_du_crtc *crtc)67{68	struct vsp1_du_atomic_pipe_config cfg = { { 0, } };69 70	vsp1_du_atomic_flush(crtc->vsp->vsp, crtc->vsp_pipe, &cfg);71}72 73struct drm_plane *rzg2l_du_vsp_get_drm_plane(struct rzg2l_du_crtc *crtc,74					     unsigned int pipe_index)75{76	struct rzg2l_du_device *rcdu = crtc->vsp->dev;77	struct drm_plane *plane = NULL;78 79	drm_for_each_plane(plane, &rcdu->ddev) {80		struct rzg2l_du_vsp_plane *vsp_plane = to_rzg2l_vsp_plane(plane);81 82		if (vsp_plane->index == pipe_index)83			break;84	}85 86	return plane ? plane : ERR_PTR(-EINVAL);87}88 89static const u32 rzg2l_du_vsp_formats[] = {90	DRM_FORMAT_RGB332,91	DRM_FORMAT_ARGB4444,92	DRM_FORMAT_XRGB4444,93	DRM_FORMAT_ARGB1555,94	DRM_FORMAT_XRGB1555,95	DRM_FORMAT_RGB565,96	DRM_FORMAT_BGR888,97	DRM_FORMAT_RGB888,98	DRM_FORMAT_BGRA8888,99	DRM_FORMAT_BGRX8888,100	DRM_FORMAT_ARGB8888,101	DRM_FORMAT_XRGB8888,102	DRM_FORMAT_UYVY,103	DRM_FORMAT_YUYV,104	DRM_FORMAT_YVYU,105	DRM_FORMAT_NV12,106	DRM_FORMAT_NV21,107	DRM_FORMAT_NV16,108	DRM_FORMAT_NV61,109	DRM_FORMAT_YUV420,110	DRM_FORMAT_YVU420,111	DRM_FORMAT_YUV422,112	DRM_FORMAT_YVU422,113	DRM_FORMAT_YUV444,114	DRM_FORMAT_YVU444,115};116 117static void rzg2l_du_vsp_plane_setup(struct rzg2l_du_vsp_plane *plane)118{119	struct rzg2l_du_vsp_plane_state *state =120		to_rzg2l_vsp_plane_state(plane->plane.state);121	struct rzg2l_du_crtc *crtc = to_rzg2l_crtc(state->state.crtc);122	struct drm_framebuffer *fb = plane->plane.state->fb;123	const struct rzg2l_du_format_info *format;124	struct vsp1_du_atomic_config cfg = {125		.pixelformat = 0,126		.pitch = fb->pitches[0],127		.alpha = state->state.alpha >> 8,128		.zpos = state->state.zpos,129	};130	u32 fourcc = state->format->fourcc;131	unsigned int i;132 133	cfg.src.left = state->state.src.x1 >> 16;134	cfg.src.top = state->state.src.y1 >> 16;135	cfg.src.width = drm_rect_width(&state->state.src) >> 16;136	cfg.src.height = drm_rect_height(&state->state.src) >> 16;137 138	cfg.dst.left = state->state.dst.x1;139	cfg.dst.top = state->state.dst.y1;140	cfg.dst.width = drm_rect_width(&state->state.dst);141	cfg.dst.height = drm_rect_height(&state->state.dst);142 143	for (i = 0; i < state->format->planes; ++i) {144		struct drm_gem_dma_object *gem;145 146		gem = drm_fb_dma_get_gem_obj(fb, i);147		cfg.mem[i] = gem->dma_addr + fb->offsets[i];148	}149 150	if (state->state.pixel_blend_mode == DRM_MODE_BLEND_PIXEL_NONE) {151		switch (fourcc) {152		case DRM_FORMAT_ARGB1555:153			fourcc = DRM_FORMAT_XRGB1555;154			break;155 156		case DRM_FORMAT_ARGB4444:157			fourcc = DRM_FORMAT_XRGB4444;158			break;159 160		case DRM_FORMAT_ARGB8888:161			fourcc = DRM_FORMAT_XRGB8888;162			break;163		}164	}165 166	format = rzg2l_du_format_info(fourcc);167	cfg.pixelformat = format->v4l2;168 169	cfg.premult = state->state.pixel_blend_mode == DRM_MODE_BLEND_PREMULTI;170 171	vsp1_du_atomic_update(plane->vsp->vsp, crtc->vsp_pipe,172			      plane->index, &cfg);173}174 175static int __rzg2l_du_vsp_plane_atomic_check(struct drm_plane *plane,176					     struct drm_plane_state *state,177					     const struct rzg2l_du_format_info **format)178{179	struct drm_crtc_state *crtc_state;180	int ret;181 182	if (!state->crtc) {183		/*184		 * The visible field is not reset by the DRM core but only185		 * updated by drm_atomic_helper_check_plane_state, set it186		 * manually.187		 */188		state->visible = false;189		*format = NULL;190		return 0;191	}192 193	crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);194	if (IS_ERR(crtc_state))195		return PTR_ERR(crtc_state);196 197	ret = drm_atomic_helper_check_plane_state(state, crtc_state,198						  DRM_PLANE_NO_SCALING,199						  DRM_PLANE_NO_SCALING,200						  true, true);201	if (ret < 0)202		return ret;203 204	if (!state->visible) {205		*format = NULL;206		return 0;207	}208 209	*format = rzg2l_du_format_info(state->fb->format->format);210 211	return 0;212}213 214static int rzg2l_du_vsp_plane_atomic_check(struct drm_plane *plane,215					   struct drm_atomic_state *state)216{217	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,218										 plane);219	struct rzg2l_du_vsp_plane_state *rstate = to_rzg2l_vsp_plane_state(new_plane_state);220 221	return __rzg2l_du_vsp_plane_atomic_check(plane, new_plane_state, &rstate->format);222}223 224static void rzg2l_du_vsp_plane_atomic_update(struct drm_plane *plane,225					     struct drm_atomic_state *state)226{227	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane);228	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);229	struct rzg2l_du_vsp_plane *rplane = to_rzg2l_vsp_plane(plane);230	struct rzg2l_du_crtc *crtc = to_rzg2l_crtc(old_state->crtc);231 232	if (new_state->visible)233		rzg2l_du_vsp_plane_setup(rplane);234	else if (old_state->crtc)235		vsp1_du_atomic_update(rplane->vsp->vsp, crtc->vsp_pipe,236				      rplane->index, NULL);237}238 239static const struct drm_plane_helper_funcs rzg2l_du_vsp_plane_helper_funcs = {240	.atomic_check = rzg2l_du_vsp_plane_atomic_check,241	.atomic_update = rzg2l_du_vsp_plane_atomic_update,242};243 244static struct drm_plane_state *245rzg2l_du_vsp_plane_atomic_duplicate_state(struct drm_plane *plane)246{247	struct rzg2l_du_vsp_plane_state *copy;248 249	if (WARN_ON(!plane->state))250		return NULL;251 252	copy = kzalloc(sizeof(*copy), GFP_KERNEL);253	if (!copy)254		return NULL;255 256	__drm_atomic_helper_plane_duplicate_state(plane, &copy->state);257 258	return &copy->state;259}260 261static void rzg2l_du_vsp_plane_atomic_destroy_state(struct drm_plane *plane,262						    struct drm_plane_state *state)263{264	__drm_atomic_helper_plane_destroy_state(state);265	kfree(to_rzg2l_vsp_plane_state(state));266}267 268static void rzg2l_du_vsp_plane_reset(struct drm_plane *plane)269{270	struct rzg2l_du_vsp_plane_state *state;271 272	if (plane->state) {273		rzg2l_du_vsp_plane_atomic_destroy_state(plane, plane->state);274		plane->state = NULL;275	}276 277	state = kzalloc(sizeof(*state), GFP_KERNEL);278	if (!state)279		return;280 281	__drm_atomic_helper_plane_reset(plane, &state->state);282}283 284static const struct drm_plane_funcs rzg2l_du_vsp_plane_funcs = {285	.update_plane = drm_atomic_helper_update_plane,286	.disable_plane = drm_atomic_helper_disable_plane,287	.reset = rzg2l_du_vsp_plane_reset,288	.atomic_duplicate_state = rzg2l_du_vsp_plane_atomic_duplicate_state,289	.atomic_destroy_state = rzg2l_du_vsp_plane_atomic_destroy_state,290};291 292static void rzg2l_du_vsp_cleanup(struct drm_device *dev, void *res)293{294	struct rzg2l_du_vsp *vsp = res;295 296	put_device(vsp->vsp);297}298 299int rzg2l_du_vsp_init(struct rzg2l_du_vsp *vsp, struct device_node *np,300		      unsigned int crtcs)301{302	struct rzg2l_du_device *rcdu = vsp->dev;303	struct platform_device *pdev;304	unsigned int num_crtcs = hweight32(crtcs);305	unsigned int num_planes = 2;306	unsigned int i;307	int ret;308 309	/* Find the VSP device and initialize it. */310	pdev = of_find_device_by_node(np);311	if (!pdev)312		return -ENXIO;313 314	vsp->vsp = &pdev->dev;315 316	ret = drmm_add_action_or_reset(&rcdu->ddev, rzg2l_du_vsp_cleanup, vsp);317	if (ret < 0)318		return ret;319 320	ret = vsp1_du_init(vsp->vsp);321	if (ret < 0)322		return ret;323 324	for (i = 0; i < num_planes; ++i) {325		enum drm_plane_type type = i < num_crtcs326					 ? DRM_PLANE_TYPE_PRIMARY327					 : DRM_PLANE_TYPE_OVERLAY;328		struct rzg2l_du_vsp_plane *plane;329 330		plane = drmm_universal_plane_alloc(&rcdu->ddev, struct rzg2l_du_vsp_plane,331						   plane, crtcs, &rzg2l_du_vsp_plane_funcs,332						   rzg2l_du_vsp_formats,333						   ARRAY_SIZE(rzg2l_du_vsp_formats),334						   NULL, type, NULL);335		if (IS_ERR(plane))336			return PTR_ERR(plane);337 338		plane->vsp = vsp;339		plane->index = i;340 341		drm_plane_helper_add(&plane->plane,342				     &rzg2l_du_vsp_plane_helper_funcs);343	}344 345	return 0;346}347