xref: /linux/drivers/gpu/drm/verisilicon/vs_primary_plane.c (revision 0fc8f6200d2313278fbf4539bbab74677c685531)
1*dbf21777SIcenowy Zheng // SPDX-License-Identifier: GPL-2.0-only
2*dbf21777SIcenowy Zheng /*
3*dbf21777SIcenowy Zheng  * Copyright (C) 2025 Icenowy Zheng <uwu@icenowy.me>
4*dbf21777SIcenowy Zheng  */
5*dbf21777SIcenowy Zheng 
6*dbf21777SIcenowy Zheng #include <linux/regmap.h>
7*dbf21777SIcenowy Zheng 
8*dbf21777SIcenowy Zheng #include <drm/drm_atomic.h>
9*dbf21777SIcenowy Zheng #include <drm/drm_atomic_helper.h>
10*dbf21777SIcenowy Zheng #include <drm/drm_crtc.h>
11*dbf21777SIcenowy Zheng #include <drm/drm_fourcc.h>
12*dbf21777SIcenowy Zheng #include <drm/drm_framebuffer.h>
13*dbf21777SIcenowy Zheng #include <drm/drm_gem_atomic_helper.h>
14*dbf21777SIcenowy Zheng #include <drm/drm_modeset_helper_vtables.h>
15*dbf21777SIcenowy Zheng #include <drm/drm_plane.h>
16*dbf21777SIcenowy Zheng #include <drm/drm_print.h>
17*dbf21777SIcenowy Zheng 
18*dbf21777SIcenowy Zheng #include "vs_crtc.h"
19*dbf21777SIcenowy Zheng #include "vs_plane.h"
20*dbf21777SIcenowy Zheng #include "vs_dc.h"
21*dbf21777SIcenowy Zheng #include "vs_primary_plane_regs.h"
22*dbf21777SIcenowy Zheng 
23*dbf21777SIcenowy Zheng static int vs_primary_plane_atomic_check(struct drm_plane *plane,
24*dbf21777SIcenowy Zheng 					 struct drm_atomic_state *state)
25*dbf21777SIcenowy Zheng {
26*dbf21777SIcenowy Zheng 	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
27*dbf21777SIcenowy Zheng 										 plane);
28*dbf21777SIcenowy Zheng 	struct drm_crtc *crtc = new_plane_state->crtc;
29*dbf21777SIcenowy Zheng 	struct drm_crtc_state *crtc_state;
30*dbf21777SIcenowy Zheng 
31*dbf21777SIcenowy Zheng 	if (!crtc)
32*dbf21777SIcenowy Zheng 		return 0;
33*dbf21777SIcenowy Zheng 
34*dbf21777SIcenowy Zheng 	crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
35*dbf21777SIcenowy Zheng 	if (WARN_ON(!crtc_state))
36*dbf21777SIcenowy Zheng 		return -EINVAL;
37*dbf21777SIcenowy Zheng 
38*dbf21777SIcenowy Zheng 	return drm_atomic_helper_check_plane_state(new_plane_state,
39*dbf21777SIcenowy Zheng 						   crtc_state,
40*dbf21777SIcenowy Zheng 						   DRM_PLANE_NO_SCALING,
41*dbf21777SIcenowy Zheng 						   DRM_PLANE_NO_SCALING,
42*dbf21777SIcenowy Zheng 						   false, true);
43*dbf21777SIcenowy Zheng }
44*dbf21777SIcenowy Zheng 
45*dbf21777SIcenowy Zheng static void vs_primary_plane_commit(struct vs_dc *dc, unsigned int output)
46*dbf21777SIcenowy Zheng {
47*dbf21777SIcenowy Zheng 	regmap_set_bits(dc->regs, VSDC_FB_CONFIG_EX(output),
48*dbf21777SIcenowy Zheng 			VSDC_FB_CONFIG_EX_COMMIT);
49*dbf21777SIcenowy Zheng }
50*dbf21777SIcenowy Zheng 
51*dbf21777SIcenowy Zheng static void vs_primary_plane_atomic_enable(struct drm_plane *plane,
52*dbf21777SIcenowy Zheng 					   struct drm_atomic_state *atomic_state)
53*dbf21777SIcenowy Zheng {
54*dbf21777SIcenowy Zheng 	struct drm_plane_state *state = drm_atomic_get_new_plane_state(atomic_state,
55*dbf21777SIcenowy Zheng 								       plane);
56*dbf21777SIcenowy Zheng 	struct drm_crtc *crtc = state->crtc;
57*dbf21777SIcenowy Zheng 	struct vs_crtc *vcrtc = drm_crtc_to_vs_crtc(crtc);
58*dbf21777SIcenowy Zheng 	unsigned int output = vcrtc->id;
59*dbf21777SIcenowy Zheng 	struct vs_dc *dc = vcrtc->dc;
60*dbf21777SIcenowy Zheng 
61*dbf21777SIcenowy Zheng 	regmap_set_bits(dc->regs, VSDC_FB_CONFIG_EX(output),
62*dbf21777SIcenowy Zheng 			VSDC_FB_CONFIG_EX_FB_EN);
63*dbf21777SIcenowy Zheng 	regmap_update_bits(dc->regs, VSDC_FB_CONFIG_EX(output),
64*dbf21777SIcenowy Zheng 			   VSDC_FB_CONFIG_EX_DISPLAY_ID_MASK,
65*dbf21777SIcenowy Zheng 			   VSDC_FB_CONFIG_EX_DISPLAY_ID(output));
66*dbf21777SIcenowy Zheng 
67*dbf21777SIcenowy Zheng 	vs_primary_plane_commit(dc, output);
68*dbf21777SIcenowy Zheng }
69*dbf21777SIcenowy Zheng 
70*dbf21777SIcenowy Zheng static void vs_primary_plane_atomic_disable(struct drm_plane *plane,
71*dbf21777SIcenowy Zheng 					    struct drm_atomic_state *atomic_state)
72*dbf21777SIcenowy Zheng {
73*dbf21777SIcenowy Zheng 	struct drm_plane_state *state = drm_atomic_get_old_plane_state(atomic_state,
74*dbf21777SIcenowy Zheng 								       plane);
75*dbf21777SIcenowy Zheng 	struct drm_crtc *crtc = state->crtc;
76*dbf21777SIcenowy Zheng 	struct vs_crtc *vcrtc = drm_crtc_to_vs_crtc(crtc);
77*dbf21777SIcenowy Zheng 	unsigned int output = vcrtc->id;
78*dbf21777SIcenowy Zheng 	struct vs_dc *dc = vcrtc->dc;
79*dbf21777SIcenowy Zheng 
80*dbf21777SIcenowy Zheng 	regmap_set_bits(dc->regs, VSDC_FB_CONFIG_EX(output),
81*dbf21777SIcenowy Zheng 			VSDC_FB_CONFIG_EX_FB_EN);
82*dbf21777SIcenowy Zheng 
83*dbf21777SIcenowy Zheng 	vs_primary_plane_commit(dc, output);
84*dbf21777SIcenowy Zheng }
85*dbf21777SIcenowy Zheng 
86*dbf21777SIcenowy Zheng static void vs_primary_plane_atomic_update(struct drm_plane *plane,
87*dbf21777SIcenowy Zheng 					   struct drm_atomic_state *atomic_state)
88*dbf21777SIcenowy Zheng {
89*dbf21777SIcenowy Zheng 	struct drm_plane_state *state = drm_atomic_get_new_plane_state(atomic_state,
90*dbf21777SIcenowy Zheng 								       plane);
91*dbf21777SIcenowy Zheng 	struct drm_framebuffer *fb = state->fb;
92*dbf21777SIcenowy Zheng 	struct drm_crtc *crtc = state->crtc;
93*dbf21777SIcenowy Zheng 	struct vs_dc *dc;
94*dbf21777SIcenowy Zheng 	struct vs_crtc *vcrtc;
95*dbf21777SIcenowy Zheng 	struct vs_format fmt;
96*dbf21777SIcenowy Zheng 	unsigned int output;
97*dbf21777SIcenowy Zheng 	dma_addr_t dma_addr;
98*dbf21777SIcenowy Zheng 
99*dbf21777SIcenowy Zheng 	if (!state->visible) {
100*dbf21777SIcenowy Zheng 		vs_primary_plane_atomic_disable(plane, atomic_state);
101*dbf21777SIcenowy Zheng 		return;
102*dbf21777SIcenowy Zheng 	}
103*dbf21777SIcenowy Zheng 
104*dbf21777SIcenowy Zheng 	vcrtc = drm_crtc_to_vs_crtc(crtc);
105*dbf21777SIcenowy Zheng 	output = vcrtc->id;
106*dbf21777SIcenowy Zheng 	dc = vcrtc->dc;
107*dbf21777SIcenowy Zheng 
108*dbf21777SIcenowy Zheng 	drm_format_to_vs_format(state->fb->format->format, &fmt);
109*dbf21777SIcenowy Zheng 
110*dbf21777SIcenowy Zheng 	regmap_update_bits(dc->regs, VSDC_FB_CONFIG(output),
111*dbf21777SIcenowy Zheng 			   VSDC_FB_CONFIG_FMT_MASK,
112*dbf21777SIcenowy Zheng 			   VSDC_FB_CONFIG_FMT(fmt.color));
113*dbf21777SIcenowy Zheng 	regmap_update_bits(dc->regs, VSDC_FB_CONFIG(output),
114*dbf21777SIcenowy Zheng 			   VSDC_FB_CONFIG_SWIZZLE_MASK,
115*dbf21777SIcenowy Zheng 			   VSDC_FB_CONFIG_SWIZZLE(fmt.swizzle));
116*dbf21777SIcenowy Zheng 	regmap_assign_bits(dc->regs, VSDC_FB_CONFIG(output),
117*dbf21777SIcenowy Zheng 			   VSDC_FB_CONFIG_UV_SWIZZLE_EN, fmt.uv_swizzle);
118*dbf21777SIcenowy Zheng 
119*dbf21777SIcenowy Zheng 	dma_addr = vs_fb_get_dma_addr(fb, &state->src);
120*dbf21777SIcenowy Zheng 
121*dbf21777SIcenowy Zheng 	regmap_write(dc->regs, VSDC_FB_ADDRESS(output),
122*dbf21777SIcenowy Zheng 		     lower_32_bits(dma_addr));
123*dbf21777SIcenowy Zheng 	regmap_write(dc->regs, VSDC_FB_STRIDE(output),
124*dbf21777SIcenowy Zheng 		     fb->pitches[0]);
125*dbf21777SIcenowy Zheng 
126*dbf21777SIcenowy Zheng 	regmap_write(dc->regs, VSDC_FB_TOP_LEFT(output),
127*dbf21777SIcenowy Zheng 		     VSDC_MAKE_PLANE_POS(state->crtc_x, state->crtc_y));
128*dbf21777SIcenowy Zheng 	regmap_write(dc->regs, VSDC_FB_BOTTOM_RIGHT(output),
129*dbf21777SIcenowy Zheng 		     VSDC_MAKE_PLANE_POS(state->crtc_x + state->crtc_w,
130*dbf21777SIcenowy Zheng 					 state->crtc_y + state->crtc_h));
131*dbf21777SIcenowy Zheng 	regmap_write(dc->regs, VSDC_FB_SIZE(output),
132*dbf21777SIcenowy Zheng 		     VSDC_MAKE_PLANE_SIZE(state->crtc_w, state->crtc_h));
133*dbf21777SIcenowy Zheng 
134*dbf21777SIcenowy Zheng 	regmap_write(dc->regs, VSDC_FB_BLEND_CONFIG(output),
135*dbf21777SIcenowy Zheng 		     VSDC_FB_BLEND_CONFIG_BLEND_DISABLE);
136*dbf21777SIcenowy Zheng 
137*dbf21777SIcenowy Zheng 	vs_primary_plane_commit(dc, output);
138*dbf21777SIcenowy Zheng }
139*dbf21777SIcenowy Zheng 
140*dbf21777SIcenowy Zheng static const struct drm_plane_helper_funcs vs_primary_plane_helper_funcs = {
141*dbf21777SIcenowy Zheng 	.atomic_check	= vs_primary_plane_atomic_check,
142*dbf21777SIcenowy Zheng 	.atomic_update	= vs_primary_plane_atomic_update,
143*dbf21777SIcenowy Zheng 	.atomic_enable	= vs_primary_plane_atomic_enable,
144*dbf21777SIcenowy Zheng 	.atomic_disable	= vs_primary_plane_atomic_disable,
145*dbf21777SIcenowy Zheng };
146*dbf21777SIcenowy Zheng 
147*dbf21777SIcenowy Zheng static const struct drm_plane_funcs vs_primary_plane_funcs = {
148*dbf21777SIcenowy Zheng 	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
149*dbf21777SIcenowy Zheng 	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
150*dbf21777SIcenowy Zheng 	.disable_plane		= drm_atomic_helper_disable_plane,
151*dbf21777SIcenowy Zheng 	.reset			= drm_atomic_helper_plane_reset,
152*dbf21777SIcenowy Zheng 	.update_plane		= drm_atomic_helper_update_plane,
153*dbf21777SIcenowy Zheng };
154*dbf21777SIcenowy Zheng 
155*dbf21777SIcenowy Zheng struct drm_plane *vs_primary_plane_init(struct drm_device *drm_dev, struct vs_dc *dc)
156*dbf21777SIcenowy Zheng {
157*dbf21777SIcenowy Zheng 	struct drm_plane *plane;
158*dbf21777SIcenowy Zheng 
159*dbf21777SIcenowy Zheng 	plane = drmm_universal_plane_alloc(drm_dev, struct drm_plane, dev, 0,
160*dbf21777SIcenowy Zheng 					   &vs_primary_plane_funcs,
161*dbf21777SIcenowy Zheng 					   dc->identity.formats->array,
162*dbf21777SIcenowy Zheng 					   dc->identity.formats->num,
163*dbf21777SIcenowy Zheng 					   NULL,
164*dbf21777SIcenowy Zheng 					   DRM_PLANE_TYPE_PRIMARY,
165*dbf21777SIcenowy Zheng 					   NULL);
166*dbf21777SIcenowy Zheng 
167*dbf21777SIcenowy Zheng 	if (IS_ERR(plane))
168*dbf21777SIcenowy Zheng 		return plane;
169*dbf21777SIcenowy Zheng 
170*dbf21777SIcenowy Zheng 	drm_plane_helper_add(plane, &vs_primary_plane_helper_funcs);
171*dbf21777SIcenowy Zheng 
172*dbf21777SIcenowy Zheng 	return plane;
173*dbf21777SIcenowy Zheng }
174